- Fix mupdf incompatibility errors by adding mupdf-0.23.0.patch - Add fix-sqlite-memory-leak.patch. OBS-URL: https://build.opensuse.org/request/show/1115028 OBS-URL: https://build.opensuse.org/package/show/Publishing/sioyek?expand=0&rev=17
131949 lines
5.3 MiB
131949 lines
5.3 MiB
From d3198a1e8bdf1f73dbcc867cad0f1fcadc32988c Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?H=C3=A5kon=20Harnes?= <hakon@harnes.dev>
|
|
Date: Sun, 16 Apr 2023 15:41:28 +0200
|
|
Subject: [PATCH 1/3] fix: sqlite3 memory leak fix
|
|
|
|
---
|
|
pdf_viewer/sqlite3.c | 6 ++++--
|
|
1 file changed, 4 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/pdf_viewer/sqlite3.c b/pdf_viewer/sqlite3.c
|
|
index 55dc686ee..636296dc9 100644
|
|
--- a/pdf_viewer/sqlite3.c
|
|
+++ b/pdf_viewer/sqlite3.c
|
|
@@ -23578,11 +23578,13 @@ static void *sqlite3MemRealloc(void *pPrior, int nByte){
|
|
assert( pPrior!=0 && nByte>0 );
|
|
assert( nByte==ROUND8(nByte) ); /* EV: R-46199-30249 */
|
|
p--;
|
|
- p = SQLITE_REALLOC(p, nByte+8 );
|
|
- if( p ){
|
|
+ void *new_p = SQLITE_REALLOC(p, nByte+8 );
|
|
+ if( new_p ){
|
|
+ p = (sqlite3_int64 *)new_p;
|
|
p[0] = nByte;
|
|
p++;
|
|
}else{
|
|
+ SQLITE_FREE(p);
|
|
testcase( sqlite3GlobalConfig.xLog!=0 );
|
|
sqlite3_log(SQLITE_NOMEM,
|
|
"failed memory resize %u to %u bytes",
|
|
|
|
From eaf3ed96bf5d73ff5d4c8c511ba49ca9a5c05a72 Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?H=C3=A5kon=20Harnes?= <hakon@harnes.dev>
|
|
Date: Sun, 16 Apr 2023 16:23:36 +0200
|
|
Subject: [PATCH 2/3] update sqlite
|
|
|
|
---
|
|
pdf_viewer/sqlite3.c | 65557 ++++++++++++++++++++++++++---------------
|
|
1 file changed, 41181 insertions(+), 24376 deletions(-)
|
|
|
|
diff --git a/pdf_viewer/sqlite3.c b/pdf_viewer/sqlite3.c
|
|
index 636296dc9..947a15455 100644
|
|
--- a/pdf_viewer/sqlite3.c
|
|
+++ b/pdf_viewer/sqlite3.c
|
|
@@ -1,6 +1,6 @@
|
|
/******************************************************************************
|
|
** This file is an amalgamation of many separate C source files from SQLite
|
|
-** version 3.31.1. By combining all the individual C code files into this
|
|
+** version 3.41.2. 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
|
|
@@ -22,774 +22,6 @@
|
|
#ifndef SQLITE_PRIVATE
|
|
# define SQLITE_PRIVATE static
|
|
#endif
|
|
-/************** Begin file ctime.c *******************************************/
|
|
-/*
|
|
-** 2010 February 23
|
|
-**
|
|
-** The author disclaims copyright to this source code. In place of
|
|
-** a legal notice, here is a blessing:
|
|
-**
|
|
-** May you do good and not evil.
|
|
-** May you find forgiveness for yourself and forgive others.
|
|
-** May you share freely, never taking more than you give.
|
|
-**
|
|
-*************************************************************************
|
|
-**
|
|
-** This file implements routines used to report what compile-time options
|
|
-** SQLite was built with.
|
|
-*/
|
|
-
|
|
-#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS /* IMP: R-16824-07538 */
|
|
-
|
|
-/*
|
|
-** Include the configuration header output by 'configure' if we're using the
|
|
-** autoconf-based build
|
|
-*/
|
|
-#if defined(_HAVE_SQLITE_CONFIG_H) && !defined(SQLITECONFIG_H)
|
|
-#include "config.h"
|
|
-#define SQLITECONFIG_H 1
|
|
-#endif
|
|
-
|
|
-/* These macros are provided to "stringify" the value of the define
|
|
-** for those options in which the value is meaningful. */
|
|
-#define CTIMEOPT_VAL_(opt) #opt
|
|
-#define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt)
|
|
-
|
|
-/* Like CTIMEOPT_VAL, but especially for SQLITE_DEFAULT_LOOKASIDE. This
|
|
-** option requires a separate macro because legal values contain a single
|
|
-** comma. e.g. (-DSQLITE_DEFAULT_LOOKASIDE="100,100") */
|
|
-#define CTIMEOPT_VAL2_(opt1,opt2) #opt1 "," #opt2
|
|
-#define CTIMEOPT_VAL2(opt) CTIMEOPT_VAL2_(opt)
|
|
-
|
|
-/*
|
|
-** An array of names of all compile-time options. This array should
|
|
-** be sorted A-Z.
|
|
-**
|
|
-** This array looks large, but in a typical installation actually uses
|
|
-** only a handful of compile-time options, so most times this array is usually
|
|
-** rather short and uses little memory space.
|
|
-*/
|
|
-static const char * const sqlite3azCompileOpt[] = {
|
|
-
|
|
-/*
|
|
-** BEGIN CODE GENERATED BY tool/mkctime.tcl
|
|
-*/
|
|
-#if SQLITE_32BIT_ROWID
|
|
- "32BIT_ROWID",
|
|
-#endif
|
|
-#if SQLITE_4_BYTE_ALIGNED_MALLOC
|
|
- "4_BYTE_ALIGNED_MALLOC",
|
|
-#endif
|
|
-#if SQLITE_64BIT_STATS
|
|
- "64BIT_STATS",
|
|
-#endif
|
|
-#if SQLITE_ALLOW_COVERING_INDEX_SCAN
|
|
- "ALLOW_COVERING_INDEX_SCAN",
|
|
-#endif
|
|
-#if SQLITE_ALLOW_URI_AUTHORITY
|
|
- "ALLOW_URI_AUTHORITY",
|
|
-#endif
|
|
-#ifdef SQLITE_BITMASK_TYPE
|
|
- "BITMASK_TYPE=" CTIMEOPT_VAL(SQLITE_BITMASK_TYPE),
|
|
-#endif
|
|
-#if SQLITE_BUG_COMPATIBLE_20160819
|
|
- "BUG_COMPATIBLE_20160819",
|
|
-#endif
|
|
-#if SQLITE_CASE_SENSITIVE_LIKE
|
|
- "CASE_SENSITIVE_LIKE",
|
|
-#endif
|
|
-#if SQLITE_CHECK_PAGES
|
|
- "CHECK_PAGES",
|
|
-#endif
|
|
-#if defined(__clang__) && defined(__clang_major__)
|
|
- "COMPILER=clang-" CTIMEOPT_VAL(__clang_major__) "."
|
|
- CTIMEOPT_VAL(__clang_minor__) "."
|
|
- CTIMEOPT_VAL(__clang_patchlevel__),
|
|
-#elif defined(_MSC_VER)
|
|
- "COMPILER=msvc-" CTIMEOPT_VAL(_MSC_VER),
|
|
-#elif defined(__GNUC__) && defined(__VERSION__)
|
|
- "COMPILER=gcc-" __VERSION__,
|
|
-#endif
|
|
-#if SQLITE_COVERAGE_TEST
|
|
- "COVERAGE_TEST",
|
|
-#endif
|
|
-#if SQLITE_DEBUG
|
|
- "DEBUG",
|
|
-#endif
|
|
-#if SQLITE_DEFAULT_AUTOMATIC_INDEX
|
|
- "DEFAULT_AUTOMATIC_INDEX",
|
|
-#endif
|
|
-#if SQLITE_DEFAULT_AUTOVACUUM
|
|
- "DEFAULT_AUTOVACUUM",
|
|
-#endif
|
|
-#ifdef SQLITE_DEFAULT_CACHE_SIZE
|
|
- "DEFAULT_CACHE_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_CACHE_SIZE),
|
|
-#endif
|
|
-#if SQLITE_DEFAULT_CKPTFULLFSYNC
|
|
- "DEFAULT_CKPTFULLFSYNC",
|
|
-#endif
|
|
-#ifdef SQLITE_DEFAULT_FILE_FORMAT
|
|
- "DEFAULT_FILE_FORMAT=" CTIMEOPT_VAL(SQLITE_DEFAULT_FILE_FORMAT),
|
|
-#endif
|
|
-#ifdef SQLITE_DEFAULT_FILE_PERMISSIONS
|
|
- "DEFAULT_FILE_PERMISSIONS=" CTIMEOPT_VAL(SQLITE_DEFAULT_FILE_PERMISSIONS),
|
|
-#endif
|
|
-#if SQLITE_DEFAULT_FOREIGN_KEYS
|
|
- "DEFAULT_FOREIGN_KEYS",
|
|
-#endif
|
|
-#ifdef SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT
|
|
- "DEFAULT_JOURNAL_SIZE_LIMIT=" CTIMEOPT_VAL(SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT),
|
|
-#endif
|
|
-#ifdef SQLITE_DEFAULT_LOCKING_MODE
|
|
- "DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE),
|
|
-#endif
|
|
-#ifdef SQLITE_DEFAULT_LOOKASIDE
|
|
- "DEFAULT_LOOKASIDE=" CTIMEOPT_VAL2(SQLITE_DEFAULT_LOOKASIDE),
|
|
-#endif
|
|
-#if SQLITE_DEFAULT_MEMSTATUS
|
|
- "DEFAULT_MEMSTATUS",
|
|
-#endif
|
|
-#ifdef SQLITE_DEFAULT_MMAP_SIZE
|
|
- "DEFAULT_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_MMAP_SIZE),
|
|
-#endif
|
|
-#ifdef SQLITE_DEFAULT_PAGE_SIZE
|
|
- "DEFAULT_PAGE_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_PAGE_SIZE),
|
|
-#endif
|
|
-#ifdef SQLITE_DEFAULT_PCACHE_INITSZ
|
|
- "DEFAULT_PCACHE_INITSZ=" CTIMEOPT_VAL(SQLITE_DEFAULT_PCACHE_INITSZ),
|
|
-#endif
|
|
-#ifdef SQLITE_DEFAULT_PROXYDIR_PERMISSIONS
|
|
- "DEFAULT_PROXYDIR_PERMISSIONS=" CTIMEOPT_VAL(SQLITE_DEFAULT_PROXYDIR_PERMISSIONS),
|
|
-#endif
|
|
-#if SQLITE_DEFAULT_RECURSIVE_TRIGGERS
|
|
- "DEFAULT_RECURSIVE_TRIGGERS",
|
|
-#endif
|
|
-#ifdef SQLITE_DEFAULT_ROWEST
|
|
- "DEFAULT_ROWEST=" CTIMEOPT_VAL(SQLITE_DEFAULT_ROWEST),
|
|
-#endif
|
|
-#ifdef SQLITE_DEFAULT_SECTOR_SIZE
|
|
- "DEFAULT_SECTOR_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_SECTOR_SIZE),
|
|
-#endif
|
|
-#ifdef SQLITE_DEFAULT_SYNCHRONOUS
|
|
- "DEFAULT_SYNCHRONOUS=" CTIMEOPT_VAL(SQLITE_DEFAULT_SYNCHRONOUS),
|
|
-#endif
|
|
-#ifdef SQLITE_DEFAULT_WAL_AUTOCHECKPOINT
|
|
- "DEFAULT_WAL_AUTOCHECKPOINT=" CTIMEOPT_VAL(SQLITE_DEFAULT_WAL_AUTOCHECKPOINT),
|
|
-#endif
|
|
-#ifdef SQLITE_DEFAULT_WAL_SYNCHRONOUS
|
|
- "DEFAULT_WAL_SYNCHRONOUS=" CTIMEOPT_VAL(SQLITE_DEFAULT_WAL_SYNCHRONOUS),
|
|
-#endif
|
|
-#ifdef SQLITE_DEFAULT_WORKER_THREADS
|
|
- "DEFAULT_WORKER_THREADS=" CTIMEOPT_VAL(SQLITE_DEFAULT_WORKER_THREADS),
|
|
-#endif
|
|
-#if SQLITE_DIRECT_OVERFLOW_READ
|
|
- "DIRECT_OVERFLOW_READ",
|
|
-#endif
|
|
-#if SQLITE_DISABLE_DIRSYNC
|
|
- "DISABLE_DIRSYNC",
|
|
-#endif
|
|
-#if SQLITE_DISABLE_FTS3_UNICODE
|
|
- "DISABLE_FTS3_UNICODE",
|
|
-#endif
|
|
-#if SQLITE_DISABLE_FTS4_DEFERRED
|
|
- "DISABLE_FTS4_DEFERRED",
|
|
-#endif
|
|
-#if SQLITE_DISABLE_INTRINSIC
|
|
- "DISABLE_INTRINSIC",
|
|
-#endif
|
|
-#if SQLITE_DISABLE_LFS
|
|
- "DISABLE_LFS",
|
|
-#endif
|
|
-#if SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS
|
|
- "DISABLE_PAGECACHE_OVERFLOW_STATS",
|
|
-#endif
|
|
-#if SQLITE_DISABLE_SKIPAHEAD_DISTINCT
|
|
- "DISABLE_SKIPAHEAD_DISTINCT",
|
|
-#endif
|
|
-#ifdef SQLITE_ENABLE_8_3_NAMES
|
|
- "ENABLE_8_3_NAMES=" CTIMEOPT_VAL(SQLITE_ENABLE_8_3_NAMES),
|
|
-#endif
|
|
-#if SQLITE_ENABLE_API_ARMOR
|
|
- "ENABLE_API_ARMOR",
|
|
-#endif
|
|
-#if SQLITE_ENABLE_ATOMIC_WRITE
|
|
- "ENABLE_ATOMIC_WRITE",
|
|
-#endif
|
|
-#if SQLITE_ENABLE_BATCH_ATOMIC_WRITE
|
|
- "ENABLE_BATCH_ATOMIC_WRITE",
|
|
-#endif
|
|
-#if SQLITE_ENABLE_CEROD
|
|
- "ENABLE_CEROD=" CTIMEOPT_VAL(SQLITE_ENABLE_CEROD),
|
|
-#endif
|
|
-#if SQLITE_ENABLE_COLUMN_METADATA
|
|
- "ENABLE_COLUMN_METADATA",
|
|
-#endif
|
|
-#if SQLITE_ENABLE_COLUMN_USED_MASK
|
|
- "ENABLE_COLUMN_USED_MASK",
|
|
-#endif
|
|
-#if SQLITE_ENABLE_COSTMULT
|
|
- "ENABLE_COSTMULT",
|
|
-#endif
|
|
-#if SQLITE_ENABLE_CURSOR_HINTS
|
|
- "ENABLE_CURSOR_HINTS",
|
|
-#endif
|
|
-#if SQLITE_ENABLE_DBSTAT_VTAB
|
|
- "ENABLE_DBSTAT_VTAB",
|
|
-#endif
|
|
-#if SQLITE_ENABLE_EXPENSIVE_ASSERT
|
|
- "ENABLE_EXPENSIVE_ASSERT",
|
|
-#endif
|
|
-#if SQLITE_ENABLE_FTS1
|
|
- "ENABLE_FTS1",
|
|
-#endif
|
|
-#if SQLITE_ENABLE_FTS2
|
|
- "ENABLE_FTS2",
|
|
-#endif
|
|
-#if SQLITE_ENABLE_FTS3
|
|
- "ENABLE_FTS3",
|
|
-#endif
|
|
-#if SQLITE_ENABLE_FTS3_PARENTHESIS
|
|
- "ENABLE_FTS3_PARENTHESIS",
|
|
-#endif
|
|
-#if SQLITE_ENABLE_FTS3_TOKENIZER
|
|
- "ENABLE_FTS3_TOKENIZER",
|
|
-#endif
|
|
-#if SQLITE_ENABLE_FTS4
|
|
- "ENABLE_FTS4",
|
|
-#endif
|
|
-#if SQLITE_ENABLE_FTS5
|
|
- "ENABLE_FTS5",
|
|
-#endif
|
|
-#if SQLITE_ENABLE_GEOPOLY
|
|
- "ENABLE_GEOPOLY",
|
|
-#endif
|
|
-#if SQLITE_ENABLE_HIDDEN_COLUMNS
|
|
- "ENABLE_HIDDEN_COLUMNS",
|
|
-#endif
|
|
-#if SQLITE_ENABLE_ICU
|
|
- "ENABLE_ICU",
|
|
-#endif
|
|
-#if SQLITE_ENABLE_IOTRACE
|
|
- "ENABLE_IOTRACE",
|
|
-#endif
|
|
-#if SQLITE_ENABLE_JSON1
|
|
- "ENABLE_JSON1",
|
|
-#endif
|
|
-#if SQLITE_ENABLE_LOAD_EXTENSION
|
|
- "ENABLE_LOAD_EXTENSION",
|
|
-#endif
|
|
-#ifdef SQLITE_ENABLE_LOCKING_STYLE
|
|
- "ENABLE_LOCKING_STYLE=" CTIMEOPT_VAL(SQLITE_ENABLE_LOCKING_STYLE),
|
|
-#endif
|
|
-#if SQLITE_ENABLE_MEMORY_MANAGEMENT
|
|
- "ENABLE_MEMORY_MANAGEMENT",
|
|
-#endif
|
|
-#if SQLITE_ENABLE_MEMSYS3
|
|
- "ENABLE_MEMSYS3",
|
|
-#endif
|
|
-#if SQLITE_ENABLE_MEMSYS5
|
|
- "ENABLE_MEMSYS5",
|
|
-#endif
|
|
-#if SQLITE_ENABLE_MULTIPLEX
|
|
- "ENABLE_MULTIPLEX",
|
|
-#endif
|
|
-#if SQLITE_ENABLE_NORMALIZE
|
|
- "ENABLE_NORMALIZE",
|
|
-#endif
|
|
-#if SQLITE_ENABLE_NULL_TRIM
|
|
- "ENABLE_NULL_TRIM",
|
|
-#endif
|
|
-#if SQLITE_ENABLE_OVERSIZE_CELL_CHECK
|
|
- "ENABLE_OVERSIZE_CELL_CHECK",
|
|
-#endif
|
|
-#if SQLITE_ENABLE_PREUPDATE_HOOK
|
|
- "ENABLE_PREUPDATE_HOOK",
|
|
-#endif
|
|
-#if SQLITE_ENABLE_QPSG
|
|
- "ENABLE_QPSG",
|
|
-#endif
|
|
-#if SQLITE_ENABLE_RBU
|
|
- "ENABLE_RBU",
|
|
-#endif
|
|
-#if SQLITE_ENABLE_RTREE
|
|
- "ENABLE_RTREE",
|
|
-#endif
|
|
-#if SQLITE_ENABLE_SELECTTRACE
|
|
- "ENABLE_SELECTTRACE",
|
|
-#endif
|
|
-#if SQLITE_ENABLE_SESSION
|
|
- "ENABLE_SESSION",
|
|
-#endif
|
|
-#if SQLITE_ENABLE_SNAPSHOT
|
|
- "ENABLE_SNAPSHOT",
|
|
-#endif
|
|
-#if SQLITE_ENABLE_SORTER_REFERENCES
|
|
- "ENABLE_SORTER_REFERENCES",
|
|
-#endif
|
|
-#if SQLITE_ENABLE_SQLLOG
|
|
- "ENABLE_SQLLOG",
|
|
-#endif
|
|
-#if defined(SQLITE_ENABLE_STAT4)
|
|
- "ENABLE_STAT4",
|
|
-#endif
|
|
-#if SQLITE_ENABLE_STMTVTAB
|
|
- "ENABLE_STMTVTAB",
|
|
-#endif
|
|
-#if SQLITE_ENABLE_STMT_SCANSTATUS
|
|
- "ENABLE_STMT_SCANSTATUS",
|
|
-#endif
|
|
-#if SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
|
|
- "ENABLE_UNKNOWN_SQL_FUNCTION",
|
|
-#endif
|
|
-#if SQLITE_ENABLE_UNLOCK_NOTIFY
|
|
- "ENABLE_UNLOCK_NOTIFY",
|
|
-#endif
|
|
-#if SQLITE_ENABLE_UPDATE_DELETE_LIMIT
|
|
- "ENABLE_UPDATE_DELETE_LIMIT",
|
|
-#endif
|
|
-#if SQLITE_ENABLE_URI_00_ERROR
|
|
- "ENABLE_URI_00_ERROR",
|
|
-#endif
|
|
-#if SQLITE_ENABLE_VFSTRACE
|
|
- "ENABLE_VFSTRACE",
|
|
-#endif
|
|
-#if SQLITE_ENABLE_WHERETRACE
|
|
- "ENABLE_WHERETRACE",
|
|
-#endif
|
|
-#if SQLITE_ENABLE_ZIPVFS
|
|
- "ENABLE_ZIPVFS",
|
|
-#endif
|
|
-#if SQLITE_EXPLAIN_ESTIMATED_ROWS
|
|
- "EXPLAIN_ESTIMATED_ROWS",
|
|
-#endif
|
|
-#if SQLITE_EXTRA_IFNULLROW
|
|
- "EXTRA_IFNULLROW",
|
|
-#endif
|
|
-#ifdef SQLITE_EXTRA_INIT
|
|
- "EXTRA_INIT=" CTIMEOPT_VAL(SQLITE_EXTRA_INIT),
|
|
-#endif
|
|
-#ifdef SQLITE_EXTRA_SHUTDOWN
|
|
- "EXTRA_SHUTDOWN=" CTIMEOPT_VAL(SQLITE_EXTRA_SHUTDOWN),
|
|
-#endif
|
|
-#ifdef SQLITE_FTS3_MAX_EXPR_DEPTH
|
|
- "FTS3_MAX_EXPR_DEPTH=" CTIMEOPT_VAL(SQLITE_FTS3_MAX_EXPR_DEPTH),
|
|
-#endif
|
|
-#if SQLITE_FTS5_ENABLE_TEST_MI
|
|
- "FTS5_ENABLE_TEST_MI",
|
|
-#endif
|
|
-#if SQLITE_FTS5_NO_WITHOUT_ROWID
|
|
- "FTS5_NO_WITHOUT_ROWID",
|
|
-#endif
|
|
-#if SQLITE_HAS_CODEC
|
|
- "HAS_CODEC",
|
|
-#endif
|
|
-#if HAVE_ISNAN || SQLITE_HAVE_ISNAN
|
|
- "HAVE_ISNAN",
|
|
-#endif
|
|
-#if SQLITE_HOMEGROWN_RECURSIVE_MUTEX
|
|
- "HOMEGROWN_RECURSIVE_MUTEX",
|
|
-#endif
|
|
-#if SQLITE_IGNORE_AFP_LOCK_ERRORS
|
|
- "IGNORE_AFP_LOCK_ERRORS",
|
|
-#endif
|
|
-#if SQLITE_IGNORE_FLOCK_LOCK_ERRORS
|
|
- "IGNORE_FLOCK_LOCK_ERRORS",
|
|
-#endif
|
|
-#if SQLITE_INLINE_MEMCPY
|
|
- "INLINE_MEMCPY",
|
|
-#endif
|
|
-#if SQLITE_INT64_TYPE
|
|
- "INT64_TYPE",
|
|
-#endif
|
|
-#ifdef SQLITE_INTEGRITY_CHECK_ERROR_MAX
|
|
- "INTEGRITY_CHECK_ERROR_MAX=" CTIMEOPT_VAL(SQLITE_INTEGRITY_CHECK_ERROR_MAX),
|
|
-#endif
|
|
-#if SQLITE_LIKE_DOESNT_MATCH_BLOBS
|
|
- "LIKE_DOESNT_MATCH_BLOBS",
|
|
-#endif
|
|
-#if SQLITE_LOCK_TRACE
|
|
- "LOCK_TRACE",
|
|
-#endif
|
|
-#if SQLITE_LOG_CACHE_SPILL
|
|
- "LOG_CACHE_SPILL",
|
|
-#endif
|
|
-#ifdef SQLITE_MALLOC_SOFT_LIMIT
|
|
- "MALLOC_SOFT_LIMIT=" CTIMEOPT_VAL(SQLITE_MALLOC_SOFT_LIMIT),
|
|
-#endif
|
|
-#ifdef SQLITE_MAX_ATTACHED
|
|
- "MAX_ATTACHED=" CTIMEOPT_VAL(SQLITE_MAX_ATTACHED),
|
|
-#endif
|
|
-#ifdef SQLITE_MAX_COLUMN
|
|
- "MAX_COLUMN=" CTIMEOPT_VAL(SQLITE_MAX_COLUMN),
|
|
-#endif
|
|
-#ifdef SQLITE_MAX_COMPOUND_SELECT
|
|
- "MAX_COMPOUND_SELECT=" CTIMEOPT_VAL(SQLITE_MAX_COMPOUND_SELECT),
|
|
-#endif
|
|
-#ifdef SQLITE_MAX_DEFAULT_PAGE_SIZE
|
|
- "MAX_DEFAULT_PAGE_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_DEFAULT_PAGE_SIZE),
|
|
-#endif
|
|
-#ifdef SQLITE_MAX_EXPR_DEPTH
|
|
- "MAX_EXPR_DEPTH=" CTIMEOPT_VAL(SQLITE_MAX_EXPR_DEPTH),
|
|
-#endif
|
|
-#ifdef SQLITE_MAX_FUNCTION_ARG
|
|
- "MAX_FUNCTION_ARG=" CTIMEOPT_VAL(SQLITE_MAX_FUNCTION_ARG),
|
|
-#endif
|
|
-#ifdef SQLITE_MAX_LENGTH
|
|
- "MAX_LENGTH=" CTIMEOPT_VAL(SQLITE_MAX_LENGTH),
|
|
-#endif
|
|
-#ifdef SQLITE_MAX_LIKE_PATTERN_LENGTH
|
|
- "MAX_LIKE_PATTERN_LENGTH=" CTIMEOPT_VAL(SQLITE_MAX_LIKE_PATTERN_LENGTH),
|
|
-#endif
|
|
-#ifdef SQLITE_MAX_MEMORY
|
|
- "MAX_MEMORY=" CTIMEOPT_VAL(SQLITE_MAX_MEMORY),
|
|
-#endif
|
|
-#ifdef SQLITE_MAX_MMAP_SIZE
|
|
- "MAX_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_MMAP_SIZE),
|
|
-#endif
|
|
-#ifdef SQLITE_MAX_MMAP_SIZE_
|
|
- "MAX_MMAP_SIZE_=" CTIMEOPT_VAL(SQLITE_MAX_MMAP_SIZE_),
|
|
-#endif
|
|
-#ifdef SQLITE_MAX_PAGE_COUNT
|
|
- "MAX_PAGE_COUNT=" CTIMEOPT_VAL(SQLITE_MAX_PAGE_COUNT),
|
|
-#endif
|
|
-#ifdef SQLITE_MAX_PAGE_SIZE
|
|
- "MAX_PAGE_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_PAGE_SIZE),
|
|
-#endif
|
|
-#ifdef SQLITE_MAX_SCHEMA_RETRY
|
|
- "MAX_SCHEMA_RETRY=" CTIMEOPT_VAL(SQLITE_MAX_SCHEMA_RETRY),
|
|
-#endif
|
|
-#ifdef SQLITE_MAX_SQL_LENGTH
|
|
- "MAX_SQL_LENGTH=" CTIMEOPT_VAL(SQLITE_MAX_SQL_LENGTH),
|
|
-#endif
|
|
-#ifdef SQLITE_MAX_TRIGGER_DEPTH
|
|
- "MAX_TRIGGER_DEPTH=" CTIMEOPT_VAL(SQLITE_MAX_TRIGGER_DEPTH),
|
|
-#endif
|
|
-#ifdef SQLITE_MAX_VARIABLE_NUMBER
|
|
- "MAX_VARIABLE_NUMBER=" CTIMEOPT_VAL(SQLITE_MAX_VARIABLE_NUMBER),
|
|
-#endif
|
|
-#ifdef SQLITE_MAX_VDBE_OP
|
|
- "MAX_VDBE_OP=" CTIMEOPT_VAL(SQLITE_MAX_VDBE_OP),
|
|
-#endif
|
|
-#ifdef SQLITE_MAX_WORKER_THREADS
|
|
- "MAX_WORKER_THREADS=" CTIMEOPT_VAL(SQLITE_MAX_WORKER_THREADS),
|
|
-#endif
|
|
-#if SQLITE_MEMDEBUG
|
|
- "MEMDEBUG",
|
|
-#endif
|
|
-#if SQLITE_MIXED_ENDIAN_64BIT_FLOAT
|
|
- "MIXED_ENDIAN_64BIT_FLOAT",
|
|
-#endif
|
|
-#if SQLITE_MMAP_READWRITE
|
|
- "MMAP_READWRITE",
|
|
-#endif
|
|
-#if SQLITE_MUTEX_NOOP
|
|
- "MUTEX_NOOP",
|
|
-#endif
|
|
-#if SQLITE_MUTEX_NREF
|
|
- "MUTEX_NREF",
|
|
-#endif
|
|
-#if SQLITE_MUTEX_OMIT
|
|
- "MUTEX_OMIT",
|
|
-#endif
|
|
-#if SQLITE_MUTEX_PTHREADS
|
|
- "MUTEX_PTHREADS",
|
|
-#endif
|
|
-#if SQLITE_MUTEX_W32
|
|
- "MUTEX_W32",
|
|
-#endif
|
|
-#if SQLITE_NEED_ERR_NAME
|
|
- "NEED_ERR_NAME",
|
|
-#endif
|
|
-#if SQLITE_NOINLINE
|
|
- "NOINLINE",
|
|
-#endif
|
|
-#if SQLITE_NO_SYNC
|
|
- "NO_SYNC",
|
|
-#endif
|
|
-#if SQLITE_OMIT_ALTERTABLE
|
|
- "OMIT_ALTERTABLE",
|
|
-#endif
|
|
-#if SQLITE_OMIT_ANALYZE
|
|
- "OMIT_ANALYZE",
|
|
-#endif
|
|
-#if SQLITE_OMIT_ATTACH
|
|
- "OMIT_ATTACH",
|
|
-#endif
|
|
-#if SQLITE_OMIT_AUTHORIZATION
|
|
- "OMIT_AUTHORIZATION",
|
|
-#endif
|
|
-#if SQLITE_OMIT_AUTOINCREMENT
|
|
- "OMIT_AUTOINCREMENT",
|
|
-#endif
|
|
-#if SQLITE_OMIT_AUTOINIT
|
|
- "OMIT_AUTOINIT",
|
|
-#endif
|
|
-#if SQLITE_OMIT_AUTOMATIC_INDEX
|
|
- "OMIT_AUTOMATIC_INDEX",
|
|
-#endif
|
|
-#if SQLITE_OMIT_AUTORESET
|
|
- "OMIT_AUTORESET",
|
|
-#endif
|
|
-#if SQLITE_OMIT_AUTOVACUUM
|
|
- "OMIT_AUTOVACUUM",
|
|
-#endif
|
|
-#if SQLITE_OMIT_BETWEEN_OPTIMIZATION
|
|
- "OMIT_BETWEEN_OPTIMIZATION",
|
|
-#endif
|
|
-#if SQLITE_OMIT_BLOB_LITERAL
|
|
- "OMIT_BLOB_LITERAL",
|
|
-#endif
|
|
-#if SQLITE_OMIT_BTREECOUNT
|
|
- "OMIT_BTREECOUNT",
|
|
-#endif
|
|
-#if SQLITE_OMIT_CAST
|
|
- "OMIT_CAST",
|
|
-#endif
|
|
-#if SQLITE_OMIT_CHECK
|
|
- "OMIT_CHECK",
|
|
-#endif
|
|
-#if SQLITE_OMIT_COMPLETE
|
|
- "OMIT_COMPLETE",
|
|
-#endif
|
|
-#if SQLITE_OMIT_COMPOUND_SELECT
|
|
- "OMIT_COMPOUND_SELECT",
|
|
-#endif
|
|
-#if SQLITE_OMIT_CONFLICT_CLAUSE
|
|
- "OMIT_CONFLICT_CLAUSE",
|
|
-#endif
|
|
-#if SQLITE_OMIT_CTE
|
|
- "OMIT_CTE",
|
|
-#endif
|
|
-#if SQLITE_OMIT_DATETIME_FUNCS
|
|
- "OMIT_DATETIME_FUNCS",
|
|
-#endif
|
|
-#if SQLITE_OMIT_DECLTYPE
|
|
- "OMIT_DECLTYPE",
|
|
-#endif
|
|
-#if SQLITE_OMIT_DEPRECATED
|
|
- "OMIT_DEPRECATED",
|
|
-#endif
|
|
-#if SQLITE_OMIT_DISKIO
|
|
- "OMIT_DISKIO",
|
|
-#endif
|
|
-#if SQLITE_OMIT_EXPLAIN
|
|
- "OMIT_EXPLAIN",
|
|
-#endif
|
|
-#if SQLITE_OMIT_FLAG_PRAGMAS
|
|
- "OMIT_FLAG_PRAGMAS",
|
|
-#endif
|
|
-#if SQLITE_OMIT_FLOATING_POINT
|
|
- "OMIT_FLOATING_POINT",
|
|
-#endif
|
|
-#if SQLITE_OMIT_FOREIGN_KEY
|
|
- "OMIT_FOREIGN_KEY",
|
|
-#endif
|
|
-#if SQLITE_OMIT_GET_TABLE
|
|
- "OMIT_GET_TABLE",
|
|
-#endif
|
|
-#if SQLITE_OMIT_HEX_INTEGER
|
|
- "OMIT_HEX_INTEGER",
|
|
-#endif
|
|
-#if SQLITE_OMIT_INCRBLOB
|
|
- "OMIT_INCRBLOB",
|
|
-#endif
|
|
-#if SQLITE_OMIT_INTEGRITY_CHECK
|
|
- "OMIT_INTEGRITY_CHECK",
|
|
-#endif
|
|
-#if SQLITE_OMIT_LIKE_OPTIMIZATION
|
|
- "OMIT_LIKE_OPTIMIZATION",
|
|
-#endif
|
|
-#if SQLITE_OMIT_LOAD_EXTENSION
|
|
- "OMIT_LOAD_EXTENSION",
|
|
-#endif
|
|
-#if SQLITE_OMIT_LOCALTIME
|
|
- "OMIT_LOCALTIME",
|
|
-#endif
|
|
-#if SQLITE_OMIT_LOOKASIDE
|
|
- "OMIT_LOOKASIDE",
|
|
-#endif
|
|
-#if SQLITE_OMIT_MEMORYDB
|
|
- "OMIT_MEMORYDB",
|
|
-#endif
|
|
-#if SQLITE_OMIT_OR_OPTIMIZATION
|
|
- "OMIT_OR_OPTIMIZATION",
|
|
-#endif
|
|
-#if SQLITE_OMIT_PAGER_PRAGMAS
|
|
- "OMIT_PAGER_PRAGMAS",
|
|
-#endif
|
|
-#if SQLITE_OMIT_PARSER_TRACE
|
|
- "OMIT_PARSER_TRACE",
|
|
-#endif
|
|
-#if SQLITE_OMIT_POPEN
|
|
- "OMIT_POPEN",
|
|
-#endif
|
|
-#if SQLITE_OMIT_PRAGMA
|
|
- "OMIT_PRAGMA",
|
|
-#endif
|
|
-#if SQLITE_OMIT_PROGRESS_CALLBACK
|
|
- "OMIT_PROGRESS_CALLBACK",
|
|
-#endif
|
|
-#if SQLITE_OMIT_QUICKBALANCE
|
|
- "OMIT_QUICKBALANCE",
|
|
-#endif
|
|
-#if SQLITE_OMIT_REINDEX
|
|
- "OMIT_REINDEX",
|
|
-#endif
|
|
-#if SQLITE_OMIT_SCHEMA_PRAGMAS
|
|
- "OMIT_SCHEMA_PRAGMAS",
|
|
-#endif
|
|
-#if SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS
|
|
- "OMIT_SCHEMA_VERSION_PRAGMAS",
|
|
-#endif
|
|
-#if SQLITE_OMIT_SHARED_CACHE
|
|
- "OMIT_SHARED_CACHE",
|
|
-#endif
|
|
-#if SQLITE_OMIT_SHUTDOWN_DIRECTORIES
|
|
- "OMIT_SHUTDOWN_DIRECTORIES",
|
|
-#endif
|
|
-#if SQLITE_OMIT_SUBQUERY
|
|
- "OMIT_SUBQUERY",
|
|
-#endif
|
|
-#if SQLITE_OMIT_TCL_VARIABLE
|
|
- "OMIT_TCL_VARIABLE",
|
|
-#endif
|
|
-#if SQLITE_OMIT_TEMPDB
|
|
- "OMIT_TEMPDB",
|
|
-#endif
|
|
-#if SQLITE_OMIT_TEST_CONTROL
|
|
- "OMIT_TEST_CONTROL",
|
|
-#endif
|
|
-#if SQLITE_OMIT_TRACE
|
|
- "OMIT_TRACE",
|
|
-#endif
|
|
-#if SQLITE_OMIT_TRIGGER
|
|
- "OMIT_TRIGGER",
|
|
-#endif
|
|
-#if SQLITE_OMIT_TRUNCATE_OPTIMIZATION
|
|
- "OMIT_TRUNCATE_OPTIMIZATION",
|
|
-#endif
|
|
-#if SQLITE_OMIT_UTF16
|
|
- "OMIT_UTF16",
|
|
-#endif
|
|
-#if SQLITE_OMIT_VACUUM
|
|
- "OMIT_VACUUM",
|
|
-#endif
|
|
-#if SQLITE_OMIT_VIEW
|
|
- "OMIT_VIEW",
|
|
-#endif
|
|
-#if SQLITE_OMIT_VIRTUALTABLE
|
|
- "OMIT_VIRTUALTABLE",
|
|
-#endif
|
|
-#if SQLITE_OMIT_WAL
|
|
- "OMIT_WAL",
|
|
-#endif
|
|
-#if SQLITE_OMIT_WSD
|
|
- "OMIT_WSD",
|
|
-#endif
|
|
-#if SQLITE_OMIT_XFER_OPT
|
|
- "OMIT_XFER_OPT",
|
|
-#endif
|
|
-#if SQLITE_PCACHE_SEPARATE_HEADER
|
|
- "PCACHE_SEPARATE_HEADER",
|
|
-#endif
|
|
-#if SQLITE_PERFORMANCE_TRACE
|
|
- "PERFORMANCE_TRACE",
|
|
-#endif
|
|
-#if SQLITE_POWERSAFE_OVERWRITE
|
|
- "POWERSAFE_OVERWRITE",
|
|
-#endif
|
|
-#if SQLITE_PREFER_PROXY_LOCKING
|
|
- "PREFER_PROXY_LOCKING",
|
|
-#endif
|
|
-#if SQLITE_PROXY_DEBUG
|
|
- "PROXY_DEBUG",
|
|
-#endif
|
|
-#if SQLITE_REVERSE_UNORDERED_SELECTS
|
|
- "REVERSE_UNORDERED_SELECTS",
|
|
-#endif
|
|
-#if SQLITE_RTREE_INT_ONLY
|
|
- "RTREE_INT_ONLY",
|
|
-#endif
|
|
-#if SQLITE_SECURE_DELETE
|
|
- "SECURE_DELETE",
|
|
-#endif
|
|
-#if SQLITE_SMALL_STACK
|
|
- "SMALL_STACK",
|
|
-#endif
|
|
-#ifdef SQLITE_SORTER_PMASZ
|
|
- "SORTER_PMASZ=" CTIMEOPT_VAL(SQLITE_SORTER_PMASZ),
|
|
-#endif
|
|
-#if SQLITE_SOUNDEX
|
|
- "SOUNDEX",
|
|
-#endif
|
|
-#ifdef SQLITE_STAT4_SAMPLES
|
|
- "STAT4_SAMPLES=" CTIMEOPT_VAL(SQLITE_STAT4_SAMPLES),
|
|
-#endif
|
|
-#ifdef SQLITE_STMTJRNL_SPILL
|
|
- "STMTJRNL_SPILL=" CTIMEOPT_VAL(SQLITE_STMTJRNL_SPILL),
|
|
-#endif
|
|
-#if SQLITE_SUBSTR_COMPATIBILITY
|
|
- "SUBSTR_COMPATIBILITY",
|
|
-#endif
|
|
-#if SQLITE_SYSTEM_MALLOC
|
|
- "SYSTEM_MALLOC",
|
|
-#endif
|
|
-#if SQLITE_TCL
|
|
- "TCL",
|
|
-#endif
|
|
-#ifdef SQLITE_TEMP_STORE
|
|
- "TEMP_STORE=" CTIMEOPT_VAL(SQLITE_TEMP_STORE),
|
|
-#endif
|
|
-#if SQLITE_TEST
|
|
- "TEST",
|
|
-#endif
|
|
-#if defined(SQLITE_THREADSAFE)
|
|
- "THREADSAFE=" CTIMEOPT_VAL(SQLITE_THREADSAFE),
|
|
-#elif defined(THREADSAFE)
|
|
- "THREADSAFE=" CTIMEOPT_VAL(THREADSAFE),
|
|
-#else
|
|
- "THREADSAFE=1",
|
|
-#endif
|
|
-#if SQLITE_UNLINK_AFTER_CLOSE
|
|
- "UNLINK_AFTER_CLOSE",
|
|
-#endif
|
|
-#if SQLITE_UNTESTABLE
|
|
- "UNTESTABLE",
|
|
-#endif
|
|
-#if SQLITE_USER_AUTHENTICATION
|
|
- "USER_AUTHENTICATION",
|
|
-#endif
|
|
-#if SQLITE_USE_ALLOCA
|
|
- "USE_ALLOCA",
|
|
-#endif
|
|
-#if SQLITE_USE_FCNTL_TRACE
|
|
- "USE_FCNTL_TRACE",
|
|
-#endif
|
|
-#if SQLITE_USE_URI
|
|
- "USE_URI",
|
|
-#endif
|
|
-#if SQLITE_VDBE_COVERAGE
|
|
- "VDBE_COVERAGE",
|
|
-#endif
|
|
-#if SQLITE_WIN32_MALLOC
|
|
- "WIN32_MALLOC",
|
|
-#endif
|
|
-#if SQLITE_ZERO_MALLOC
|
|
- "ZERO_MALLOC",
|
|
-#endif
|
|
-/*
|
|
-** END CODE GENERATED BY tool/mkctime.tcl
|
|
-*/
|
|
-};
|
|
-
|
|
-SQLITE_PRIVATE const char **sqlite3CompileOptions(int *pnOpt){
|
|
- *pnOpt = sizeof(sqlite3azCompileOpt) / sizeof(sqlite3azCompileOpt[0]);
|
|
- return (const char**)sqlite3azCompileOpt;
|
|
-}
|
|
-
|
|
-#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
|
|
-
|
|
-/************** End of ctime.c ***********************************************/
|
|
/************** Begin file sqliteInt.h ***************************************/
|
|
/*
|
|
** 2001 September 15
|
|
@@ -828,10 +60,10 @@ SQLITE_PRIVATE const char **sqlite3CompileOptions(int *pnOpt){
|
|
**
|
|
** PREVENTS-HARMLESS-OVERREAD - This branch prevents a buffer overread
|
|
** that would be harmless and undetectable
|
|
-** if it did occur.
|
|
+** if it did occur.
|
|
**
|
|
** In all cases, the special comment must be enclosed in the usual
|
|
-** slash-asterisk...asterisk-slash comment marks, with no spaces between the
|
|
+** slash-asterisk...asterisk-slash comment marks, with no spaces between the
|
|
** asterisks and the comment text.
|
|
*/
|
|
|
|
@@ -993,6 +225,18 @@ SQLITE_PRIVATE const char **sqlite3CompileOptions(int *pnOpt){
|
|
# define MSVC_VERSION 0
|
|
#endif
|
|
|
|
+/*
|
|
+** Some C99 functions in "math.h" are only present for MSVC when its version
|
|
+** is associated with Visual Studio 2013 or higher.
|
|
+*/
|
|
+#ifndef SQLITE_HAVE_C99_MATH_FUNCS
|
|
+# if MSVC_VERSION==0 || MSVC_VERSION>=1800
|
|
+# define SQLITE_HAVE_C99_MATH_FUNCS (1)
|
|
+# else
|
|
+# define SQLITE_HAVE_C99_MATH_FUNCS (0)
|
|
+# endif
|
|
+#endif
|
|
+
|
|
/* Needed for various definitions... */
|
|
#if defined(__GNUC__) && !defined(_GNU_SOURCE)
|
|
# define _GNU_SOURCE
|
|
@@ -1002,6 +246,15 @@ SQLITE_PRIVATE const char **sqlite3CompileOptions(int *pnOpt){
|
|
# define _BSD_SOURCE
|
|
#endif
|
|
|
|
+/*
|
|
+** Macro to disable warnings about missing "break" at the end of a "case".
|
|
+*/
|
|
+#if GCC_VERSION>=7000000
|
|
+# define deliberate_fall_through __attribute__((fallthrough));
|
|
+#else
|
|
+# define deliberate_fall_through
|
|
+#endif
|
|
+
|
|
/*
|
|
** For MinGW, check to see if we can include the header file containing its
|
|
** version information, among other things. Normally, this internal MinGW
|
|
@@ -1034,6 +287,17 @@ SQLITE_PRIVATE const char **sqlite3CompileOptions(int *pnOpt){
|
|
# define _USE_32BIT_TIME_T
|
|
#endif
|
|
|
|
+/* Optionally #include a user-defined header, whereby compilation options
|
|
+** may be set prior to where they take effect, but after platform setup.
|
|
+** If SQLITE_CUSTOM_INCLUDE=? is defined, its value names the #include
|
|
+** file.
|
|
+*/
|
|
+#ifdef SQLITE_CUSTOM_INCLUDE
|
|
+# define INC_STRINGIFY_(f) #f
|
|
+# define INC_STRINGIFY(f) INC_STRINGIFY_(f)
|
|
+# include INC_STRINGIFY(SQLITE_CUSTOM_INCLUDE)
|
|
+#endif
|
|
+
|
|
/* The public SQLite interface. The _FILE_OFFSET_BITS macro must appear
|
|
** first in QNX. Also, the _USE_32BIT_TIME_T macro must appear first for
|
|
** MinGW.
|
|
@@ -1085,7 +349,30 @@ extern "C" {
|
|
|
|
|
|
/*
|
|
-** Provide the ability to override linkage features of the interface.
|
|
+** Facilitate override of interface linkage and calling conventions.
|
|
+** Be aware that these macros may not be used within this particular
|
|
+** translation of the amalgamation and its associated header file.
|
|
+**
|
|
+** The SQLITE_EXTERN and SQLITE_API macros are used to instruct the
|
|
+** compiler that the target identifier should have external linkage.
|
|
+**
|
|
+** The SQLITE_CDECL macro is used to set the calling convention for
|
|
+** public functions that accept a variable number of arguments.
|
|
+**
|
|
+** The SQLITE_APICALL macro is used to set the calling convention for
|
|
+** public functions that accept a fixed number of arguments.
|
|
+**
|
|
+** The SQLITE_STDCALL macro is no longer used and is now deprecated.
|
|
+**
|
|
+** The SQLITE_CALLBACK macro is used to set the calling convention for
|
|
+** function pointers.
|
|
+**
|
|
+** The SQLITE_SYSAPI macro is used to set the calling convention for
|
|
+** functions provided by the operating system.
|
|
+**
|
|
+** Currently, the SQLITE_CDECL, SQLITE_APICALL, SQLITE_CALLBACK, and
|
|
+** SQLITE_SYSAPI macros are used only when building for environments
|
|
+** that require non-default calling conventions.
|
|
*/
|
|
#ifndef SQLITE_EXTERN
|
|
# define SQLITE_EXTERN extern
|
|
@@ -1150,7 +437,7 @@ extern "C" {
|
|
** be held constant and Z will be incremented or else Y will be incremented
|
|
** and Z will be reset to zero.
|
|
**
|
|
-** Since [version 3.6.18] ([dateof:3.6.18]),
|
|
+** Since [version 3.6.18] ([dateof:3.6.18]),
|
|
** SQLite source code has been stored in the
|
|
** <a href="http://www.fossil-scm.org/">Fossil configuration management
|
|
** system</a>. ^The SQLITE_SOURCE_ID macro evaluates to
|
|
@@ -1165,9 +452,9 @@ extern "C" {
|
|
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
|
|
** [sqlite_version()] and [sqlite_source_id()].
|
|
*/
|
|
-#define SQLITE_VERSION "3.31.1"
|
|
-#define SQLITE_VERSION_NUMBER 3031001
|
|
-#define SQLITE_SOURCE_ID "2020-01-27 19:55:54 3bfa9cc97da10598521b342961df8f5f68c7388fa117345eeb516eaa837bb4d6"
|
|
+#define SQLITE_VERSION "3.41.2"
|
|
+#define SQLITE_VERSION_NUMBER 3041002
|
|
+#define SQLITE_SOURCE_ID "2023-03-22 11:56:21 0d1fc92f94cb6b76bffe3ec34d69cffde2924203304e8ffc4155597af0c191da"
|
|
|
|
/*
|
|
** CAPI3REF: Run-Time Library Version Numbers
|
|
@@ -1193,8 +480,8 @@ extern "C" {
|
|
** function is provided for use in DLLs since DLL users usually do not have
|
|
** direct access to string constants within the DLL. ^The
|
|
** sqlite3_libversion_number() function returns an integer equal to
|
|
-** [SQLITE_VERSION_NUMBER]. ^(The sqlite3_sourceid() function returns
|
|
-** a pointer to a string constant whose value is the same as the
|
|
+** [SQLITE_VERSION_NUMBER]. ^(The sqlite3_sourceid() function returns
|
|
+** a pointer to a string constant whose value is the same as the
|
|
** [SQLITE_SOURCE_ID] C preprocessor macro. Except if SQLite is built
|
|
** using an edited copy of [the amalgamation], then the last four characters
|
|
** of the hash might be different from [SQLITE_SOURCE_ID].)^
|
|
@@ -1209,20 +496,20 @@ SQLITE_API int sqlite3_libversion_number(void);
|
|
/*
|
|
** CAPI3REF: Run-Time Library Compilation Options Diagnostics
|
|
**
|
|
-** ^The sqlite3_compileoption_used() function returns 0 or 1
|
|
-** indicating whether the specified option was defined at
|
|
-** compile time. ^The SQLITE_ prefix may be omitted from the
|
|
-** option name passed to sqlite3_compileoption_used().
|
|
+** ^The sqlite3_compileoption_used() function returns 0 or 1
|
|
+** indicating whether the specified option was defined at
|
|
+** compile time. ^The SQLITE_ prefix may be omitted from the
|
|
+** option name passed to sqlite3_compileoption_used().
|
|
**
|
|
** ^The sqlite3_compileoption_get() function allows iterating
|
|
** over the list of options that were defined at compile time by
|
|
** returning the N-th compile time option string. ^If N is out of range,
|
|
-** sqlite3_compileoption_get() returns a NULL pointer. ^The SQLITE_
|
|
-** prefix is omitted from any strings returned by
|
|
+** sqlite3_compileoption_get() returns a NULL pointer. ^The SQLITE_
|
|
+** prefix is omitted from any strings returned by
|
|
** sqlite3_compileoption_get().
|
|
**
|
|
** ^Support for the diagnostic functions sqlite3_compileoption_used()
|
|
-** and sqlite3_compileoption_get() may be omitted by specifying the
|
|
+** and sqlite3_compileoption_get() may be omitted by specifying the
|
|
** [SQLITE_OMIT_COMPILEOPTION_DIAGS] option at compile time.
|
|
**
|
|
** See also: SQL functions [sqlite_compileoption_used()] and
|
|
@@ -1246,7 +533,7 @@ SQLITE_API const char *sqlite3_compileoption_get(int N);
|
|
** SQLite can be compiled with or without mutexes. When
|
|
** the [SQLITE_THREADSAFE] C preprocessor macro is 1 or 2, mutexes
|
|
** are enabled and SQLite is threadsafe. When the
|
|
-** [SQLITE_THREADSAFE] macro is 0,
|
|
+** [SQLITE_THREADSAFE] macro is 0,
|
|
** the mutexes are omitted. Without the mutexes, it is not safe
|
|
** to use SQLite concurrently from more than one thread.
|
|
**
|
|
@@ -1303,14 +590,14 @@ typedef struct sqlite3 sqlite3;
|
|
**
|
|
** ^The sqlite3_int64 and sqlite_int64 types can store integer values
|
|
** between -9223372036854775808 and +9223372036854775807 inclusive. ^The
|
|
-** sqlite3_uint64 and sqlite_uint64 types can store integer values
|
|
+** sqlite3_uint64 and sqlite_uint64 types can store integer values
|
|
** between 0 and +18446744073709551615 inclusive.
|
|
*/
|
|
#ifdef SQLITE_INT64_TYPE
|
|
typedef SQLITE_INT64_TYPE sqlite_int64;
|
|
# ifdef SQLITE_UINT64_TYPE
|
|
typedef SQLITE_UINT64_TYPE sqlite_uint64;
|
|
-# else
|
|
+# else
|
|
typedef unsigned SQLITE_INT64_TYPE sqlite_uint64;
|
|
# endif
|
|
#elif defined(_MSC_VER) || defined(__BORLANDC__)
|
|
@@ -1341,26 +628,22 @@ typedef sqlite_uint64 sqlite3_uint64;
|
|
** the [sqlite3] object is successfully destroyed and all associated
|
|
** resources are deallocated.
|
|
**
|
|
-** ^If the database connection is associated with unfinalized prepared
|
|
-** statements or unfinished sqlite3_backup objects then sqlite3_close()
|
|
-** will leave the database connection open and return [SQLITE_BUSY].
|
|
-** ^If sqlite3_close_v2() is called with unfinalized prepared statements
|
|
-** and/or unfinished sqlite3_backups, then the database connection becomes
|
|
-** an unusable "zombie" which will automatically be deallocated when the
|
|
-** last prepared statement is finalized or the last sqlite3_backup is
|
|
-** finished. The sqlite3_close_v2() interface is intended for use with
|
|
-** host languages that are garbage collected, and where the order in which
|
|
-** destructors are called is arbitrary.
|
|
-**
|
|
-** Applications should [sqlite3_finalize | finalize] all [prepared statements],
|
|
-** [sqlite3_blob_close | close] all [BLOB handles], and
|
|
+** Ideally, applications should [sqlite3_finalize | finalize] all
|
|
+** [prepared statements], [sqlite3_blob_close | close] all [BLOB handles], and
|
|
** [sqlite3_backup_finish | finish] all [sqlite3_backup] objects associated
|
|
-** with the [sqlite3] object prior to attempting to close the object. ^If
|
|
-** sqlite3_close_v2() is called on a [database connection] that still has
|
|
-** outstanding [prepared statements], [BLOB handles], and/or
|
|
-** [sqlite3_backup] objects then it returns [SQLITE_OK] and the deallocation
|
|
-** of resources is deferred until all [prepared statements], [BLOB handles],
|
|
-** and [sqlite3_backup] objects are also destroyed.
|
|
+** with the [sqlite3] object prior to attempting to close the object.
|
|
+** ^If the database connection is associated with unfinalized prepared
|
|
+** statements, BLOB handlers, and/or unfinished sqlite3_backup objects then
|
|
+** sqlite3_close() will leave the database connection open and return
|
|
+** [SQLITE_BUSY]. ^If sqlite3_close_v2() is called with unfinalized prepared
|
|
+** statements, unclosed BLOB handlers, and/or unfinished sqlite3_backups,
|
|
+** it returns [SQLITE_OK] regardless, but instead of deallocating the database
|
|
+** connection immediately, it marks the database connection as an unusable
|
|
+** "zombie" and makes arrangements to automatically deallocate the database
|
|
+** connection after all prepared statements are finalized, all BLOB handles
|
|
+** are closed, and all backups have finished. The sqlite3_close_v2() interface
|
|
+** is intended for use with host languages that are garbage collected, and
|
|
+** where the order in which destructors are called is arbitrary.
|
|
**
|
|
** ^If an [sqlite3] object is destroyed while a transaction is open,
|
|
** the transaction is automatically rolled back.
|
|
@@ -1390,7 +673,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
|
|
** The sqlite3_exec() interface is a convenience wrapper around
|
|
** [sqlite3_prepare_v2()], [sqlite3_step()], and [sqlite3_finalize()],
|
|
** that allows an application to run multiple statements of SQL
|
|
-** without having to use a lot of C code.
|
|
+** without having to use a lot of C code.
|
|
**
|
|
** ^The sqlite3_exec() interface runs zero or more UTF-8 encoded,
|
|
** semicolon-separate SQL statements passed into its 2nd argument,
|
|
@@ -1430,7 +713,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
|
|
** from [sqlite3_column_name()].
|
|
**
|
|
** ^If the 2nd parameter to sqlite3_exec() is a NULL pointer, a pointer
|
|
-** to an empty string, or a pointer that contains only whitespace and/or
|
|
+** to an empty string, or a pointer that contains only whitespace and/or
|
|
** SQL comments, then no SQL statements are evaluated and the database
|
|
** is not changed.
|
|
**
|
|
@@ -1549,10 +832,13 @@ SQLITE_API int sqlite3_exec(
|
|
#define SQLITE_IOERR_BEGIN_ATOMIC (SQLITE_IOERR | (29<<8))
|
|
#define SQLITE_IOERR_COMMIT_ATOMIC (SQLITE_IOERR | (30<<8))
|
|
#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_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
|
|
#define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8))
|
|
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
|
|
#define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8))
|
|
+#define SQLITE_BUSY_TIMEOUT (SQLITE_BUSY | (3<<8))
|
|
#define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8))
|
|
#define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8))
|
|
#define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8))
|
|
@@ -1561,6 +847,7 @@ SQLITE_API int sqlite3_exec(
|
|
#define SQLITE_CANTOPEN_SYMLINK (SQLITE_CANTOPEN | (6<<8))
|
|
#define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8))
|
|
#define SQLITE_CORRUPT_SEQUENCE (SQLITE_CORRUPT | (2<<8))
|
|
+#define SQLITE_CORRUPT_INDEX (SQLITE_CORRUPT | (3<<8))
|
|
#define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8))
|
|
#define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8))
|
|
#define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8))
|
|
@@ -1579,12 +866,14 @@ SQLITE_API int sqlite3_exec(
|
|
#define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9<<8))
|
|
#define SQLITE_CONSTRAINT_ROWID (SQLITE_CONSTRAINT |(10<<8))
|
|
#define SQLITE_CONSTRAINT_PINNED (SQLITE_CONSTRAINT |(11<<8))
|
|
+#define SQLITE_CONSTRAINT_DATATYPE (SQLITE_CONSTRAINT |(12<<8))
|
|
#define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8))
|
|
#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8))
|
|
+#define SQLITE_NOTICE_RBU (SQLITE_NOTICE | (3<<8))
|
|
#define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8))
|
|
#define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8))
|
|
#define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1<<8))
|
|
-#define SQLITE_OK_SYMLINK (SQLITE_OK | (2<<8))
|
|
+#define SQLITE_OK_SYMLINK (SQLITE_OK | (2<<8)) /* internal use only */
|
|
|
|
/*
|
|
** CAPI3REF: Flags For File Open Operations
|
|
@@ -1592,6 +881,19 @@ SQLITE_API int sqlite3_exec(
|
|
** These bit values are intended for use in the
|
|
** 3rd parameter to the [sqlite3_open_v2()] interface and
|
|
** in the 4th parameter to the [sqlite3_vfs.xOpen] method.
|
|
+**
|
|
+** Only those flags marked as "Ok for sqlite3_open_v2()" may be
|
|
+** used as the third argument to the [sqlite3_open_v2()] interface.
|
|
+** The other flags have historically been ignored by sqlite3_open_v2(),
|
|
+** though future versions of SQLite might change so that an error is
|
|
+** raised if any of the disallowed bits are passed into sqlite3_open_v2().
|
|
+** Applications should not depend on the historical behavior.
|
|
+**
|
|
+** Note in particular that passing the SQLITE_OPEN_EXCLUSIVE flag into
|
|
+** [sqlite3_open_v2()] does *not* cause the underlying database file
|
|
+** to be opened using O_EXCL. Passing SQLITE_OPEN_EXCLUSIVE into
|
|
+** [sqlite3_open_v2()] has historically be a no-op and might become an
|
|
+** error in future versions of SQLite.
|
|
*/
|
|
#define SQLITE_OPEN_READONLY 0x00000001 /* Ok for sqlite3_open_v2() */
|
|
#define SQLITE_OPEN_READWRITE 0x00000002 /* Ok for sqlite3_open_v2() */
|
|
@@ -1607,15 +909,19 @@ SQLITE_API int sqlite3_exec(
|
|
#define SQLITE_OPEN_MAIN_JOURNAL 0x00000800 /* VFS only */
|
|
#define SQLITE_OPEN_TEMP_JOURNAL 0x00001000 /* VFS only */
|
|
#define SQLITE_OPEN_SUBJOURNAL 0x00002000 /* VFS only */
|
|
-#define SQLITE_OPEN_MASTER_JOURNAL 0x00004000 /* VFS only */
|
|
+#define SQLITE_OPEN_SUPER_JOURNAL 0x00004000 /* VFS only */
|
|
#define SQLITE_OPEN_NOMUTEX 0x00008000 /* Ok for sqlite3_open_v2() */
|
|
#define SQLITE_OPEN_FULLMUTEX 0x00010000 /* Ok for sqlite3_open_v2() */
|
|
#define SQLITE_OPEN_SHAREDCACHE 0x00020000 /* Ok for sqlite3_open_v2() */
|
|
#define SQLITE_OPEN_PRIVATECACHE 0x00040000 /* Ok for sqlite3_open_v2() */
|
|
#define SQLITE_OPEN_WAL 0x00080000 /* VFS only */
|
|
#define SQLITE_OPEN_NOFOLLOW 0x01000000 /* Ok for sqlite3_open_v2() */
|
|
+#define SQLITE_OPEN_EXRESCODE 0x02000000 /* Extended result codes */
|
|
|
|
/* Reserved: 0x00F00000 */
|
|
+/* Legacy compatibility: */
|
|
+#define SQLITE_OPEN_MASTER_JOURNAL 0x00004000 /* VFS only */
|
|
+
|
|
|
|
/*
|
|
** CAPI3REF: Device Characteristics
|
|
@@ -1671,13 +977,17 @@ SQLITE_API int sqlite3_exec(
|
|
**
|
|
** SQLite uses one of these integer values as the second
|
|
** argument to calls it makes to the xLock() and xUnlock() methods
|
|
-** of an [sqlite3_io_methods] object.
|
|
+** of an [sqlite3_io_methods] object. These values are ordered from
|
|
+** lest restrictive to most restrictive.
|
|
+**
|
|
+** The argument to xLock() is always SHARED or higher. The argument to
|
|
+** xUnlock is either SHARED or NONE.
|
|
*/
|
|
-#define SQLITE_LOCK_NONE 0
|
|
-#define SQLITE_LOCK_SHARED 1
|
|
-#define SQLITE_LOCK_RESERVED 2
|
|
-#define SQLITE_LOCK_PENDING 3
|
|
-#define SQLITE_LOCK_EXCLUSIVE 4
|
|
+#define SQLITE_LOCK_NONE 0 /* xUnlock() only */
|
|
+#define SQLITE_LOCK_SHARED 1 /* xLock() or xUnlock() */
|
|
+#define SQLITE_LOCK_RESERVED 2 /* xLock() only */
|
|
+#define SQLITE_LOCK_PENDING 3 /* xLock() only */
|
|
+#define SQLITE_LOCK_EXCLUSIVE 4 /* xLock() only */
|
|
|
|
/*
|
|
** CAPI3REF: Synchronization Type Flags
|
|
@@ -1712,7 +1022,7 @@ SQLITE_API int sqlite3_exec(
|
|
/*
|
|
** CAPI3REF: OS Interface Open File Handle
|
|
**
|
|
-** An [sqlite3_file] object represents an open file in the
|
|
+** An [sqlite3_file] object represents an open file in the
|
|
** [sqlite3_vfs | OS interface layer]. Individual OS interface
|
|
** implementations will
|
|
** want to subclass this object by appending additional fields
|
|
@@ -1734,7 +1044,7 @@ struct sqlite3_file {
|
|
** This object defines the methods used to perform various operations
|
|
** against the open file represented by the [sqlite3_file] object.
|
|
**
|
|
-** If the [sqlite3_vfs.xOpen] method sets the sqlite3_file.pMethods element
|
|
+** If the [sqlite3_vfs.xOpen] method sets the sqlite3_file.pMethods element
|
|
** to a non-NULL pointer, then the sqlite3_io_methods.xClose method
|
|
** may be invoked even if the [sqlite3_vfs.xOpen] reported that it failed. The
|
|
** only way to prevent a call to xClose following a failed [sqlite3_vfs.xOpen]
|
|
@@ -1755,7 +1065,14 @@ struct sqlite3_file {
|
|
** <li> [SQLITE_LOCK_PENDING], or
|
|
** <li> [SQLITE_LOCK_EXCLUSIVE].
|
|
** </ul>
|
|
-** xLock() increases the lock. xUnlock() decreases the lock.
|
|
+** xLock() upgrades the database file lock. In other words, xLock() moves the
|
|
+** database file lock in the direction NONE toward EXCLUSIVE. The argument to
|
|
+** xLock() is always on of SHARED, RESERVED, PENDING, or EXCLUSIVE, never
|
|
+** SQLITE_LOCK_NONE. If the database file lock is already at or above the
|
|
+** requested lock, then the call to xLock() is a no-op.
|
|
+** xUnlock() downgrades the database file lock to either SHARED or NONE.
|
|
+* If the lock is already at or below the requested lock state, then the call
|
|
+** to xUnlock() is a no-op.
|
|
** The xCheckReservedLock() method checks whether any database connection,
|
|
** either in this process or in some other process, is holding a RESERVED,
|
|
** PENDING, or EXCLUSIVE lock on the file. It returns true
|
|
@@ -1860,9 +1177,8 @@ struct sqlite3_io_methods {
|
|
** opcode causes the xFileControl method to write the current state of
|
|
** the lock (one of [SQLITE_LOCK_NONE], [SQLITE_LOCK_SHARED],
|
|
** [SQLITE_LOCK_RESERVED], [SQLITE_LOCK_PENDING], or [SQLITE_LOCK_EXCLUSIVE])
|
|
-** into an integer that the pArg argument points to. This capability
|
|
-** is used during testing and is only available when the SQLITE_TEST
|
|
-** compile-time option is used.
|
|
+** into an integer that the pArg argument points to.
|
|
+** This capability is only available if SQLite is compiled with [SQLITE_DEBUG].
|
|
**
|
|
** <li>[[SQLITE_FCNTL_SIZE_HINT]]
|
|
** The [SQLITE_FCNTL_SIZE_HINT] opcode is used by SQLite to give the VFS
|
|
@@ -1884,7 +1200,7 @@ struct sqlite3_io_methods {
|
|
** <li>[[SQLITE_FCNTL_CHUNK_SIZE]]
|
|
** The [SQLITE_FCNTL_CHUNK_SIZE] opcode is used to request that the VFS
|
|
** extends and truncates the database file in chunks of a size specified
|
|
-** by the user. The fourth argument to [sqlite3_file_control()] should
|
|
+** by the user. The fourth argument to [sqlite3_file_control()] should
|
|
** point to an integer (type int) containing the new chunk-size to use
|
|
** for the nominated database. Allocating database file space in large
|
|
** chunks (say 1MB at a time), may reduce file-system fragmentation and
|
|
@@ -1907,24 +1223,24 @@ struct sqlite3_io_methods {
|
|
** <li>[[SQLITE_FCNTL_SYNC]]
|
|
** The [SQLITE_FCNTL_SYNC] opcode is generated internally by SQLite and
|
|
** sent to the VFS immediately before the xSync method is invoked on a
|
|
-** database file descriptor. Or, if the xSync method is not invoked
|
|
-** because the user has configured SQLite with
|
|
-** [PRAGMA synchronous | PRAGMA synchronous=OFF] it is invoked in place
|
|
+** database file descriptor. Or, if the xSync method is not invoked
|
|
+** because the user has configured SQLite with
|
|
+** [PRAGMA synchronous | PRAGMA synchronous=OFF] it is invoked in place
|
|
** of the xSync method. In most cases, the pointer argument passed with
|
|
** this file-control is NULL. However, if the database file is being synced
|
|
** as part of a multi-database commit, the argument points to a nul-terminated
|
|
-** string containing the transactions master-journal file name. VFSes that
|
|
-** do not need this signal should silently ignore this opcode. Applications
|
|
-** should not call [sqlite3_file_control()] with this opcode as doing so may
|
|
-** disrupt the operation of the specialized VFSes that do require it.
|
|
+** string containing the transactions super-journal file name. VFSes that
|
|
+** do not need this signal should silently ignore this opcode. Applications
|
|
+** should not call [sqlite3_file_control()] with this opcode as doing so may
|
|
+** disrupt the operation of the specialized VFSes that do require it.
|
|
**
|
|
** <li>[[SQLITE_FCNTL_COMMIT_PHASETWO]]
|
|
** The [SQLITE_FCNTL_COMMIT_PHASETWO] opcode is generated internally by SQLite
|
|
** and sent to the VFS after a transaction has been committed immediately
|
|
** but before the database is unlocked. VFSes that do not need this signal
|
|
** should silently ignore this opcode. Applications should not call
|
|
-** [sqlite3_file_control()] with this opcode as doing so may disrupt the
|
|
-** operation of the specialized VFSes that do require it.
|
|
+** [sqlite3_file_control()] with this opcode as doing so may disrupt the
|
|
+** operation of the specialized VFSes that do require it.
|
|
**
|
|
** <li>[[SQLITE_FCNTL_WIN32_AV_RETRY]]
|
|
** ^The [SQLITE_FCNTL_WIN32_AV_RETRY] opcode is used to configure automatic
|
|
@@ -1972,13 +1288,13 @@ struct sqlite3_io_methods {
|
|
** <li>[[SQLITE_FCNTL_OVERWRITE]]
|
|
** ^The [SQLITE_FCNTL_OVERWRITE] opcode is invoked by SQLite after opening
|
|
** a write transaction to indicate that, unless it is rolled back for some
|
|
-** reason, the entire database file will be overwritten by the current
|
|
+** reason, the entire database file will be overwritten by the current
|
|
** transaction. This is used by VACUUM operations.
|
|
**
|
|
** <li>[[SQLITE_FCNTL_VFSNAME]]
|
|
** ^The [SQLITE_FCNTL_VFSNAME] opcode can be used to obtain the names of
|
|
** all [VFSes] in the VFS stack. The names are of all VFS shims and the
|
|
-** final bottom-level VFS are written into memory obtained from
|
|
+** final bottom-level VFS are written into memory obtained from
|
|
** [sqlite3_malloc()] and the result is stored in the char* variable
|
|
** that the fourth parameter of [sqlite3_file_control()] points to.
|
|
** The caller is responsible for freeing the memory when done. As with
|
|
@@ -1997,7 +1313,7 @@ struct sqlite3_io_methods {
|
|
** upper-most shim only.
|
|
**
|
|
** <li>[[SQLITE_FCNTL_PRAGMA]]
|
|
-** ^Whenever a [PRAGMA] statement is parsed, an [SQLITE_FCNTL_PRAGMA]
|
|
+** ^Whenever a [PRAGMA] statement is parsed, an [SQLITE_FCNTL_PRAGMA]
|
|
** file control is sent to the open [sqlite3_file] object corresponding
|
|
** to the database file to which the pragma statement refers. ^The argument
|
|
** to the [SQLITE_FCNTL_PRAGMA] file control is an array of
|
|
@@ -2008,7 +1324,7 @@ struct sqlite3_io_methods {
|
|
** of the char** argument point to a string obtained from [sqlite3_mprintf()]
|
|
** or the equivalent and that string will become the result of the pragma or
|
|
** the error message if the pragma fails. ^If the
|
|
-** [SQLITE_FCNTL_PRAGMA] file control returns [SQLITE_NOTFOUND], then normal
|
|
+** [SQLITE_FCNTL_PRAGMA] file control returns [SQLITE_NOTFOUND], then normal
|
|
** [PRAGMA] processing continues. ^If the [SQLITE_FCNTL_PRAGMA]
|
|
** file control returns [SQLITE_OK], then the parser assumes that the
|
|
** VFS has handled the PRAGMA itself and the parser generates a no-op
|
|
@@ -2048,7 +1364,7 @@ struct sqlite3_io_methods {
|
|
** The argument is a pointer to a value of type sqlite3_int64 that
|
|
** is an advisory maximum number of bytes in the file to memory map. The
|
|
** pointer is overwritten with the old value. The limit is not changed if
|
|
-** the value originally pointed to is negative, and so the current limit
|
|
+** the value originally pointed to is negative, and so the current limit
|
|
** can be queried by passing in a pointer to a negative number. This
|
|
** file-control is used internally to implement [PRAGMA mmap_size].
|
|
**
|
|
@@ -2092,7 +1408,7 @@ struct sqlite3_io_methods {
|
|
** <li>[[SQLITE_FCNTL_RBU]]
|
|
** The [SQLITE_FCNTL_RBU] opcode is implemented by the special VFS used by
|
|
** the RBU extension only. All other VFS should return SQLITE_NOTFOUND for
|
|
-** this opcode.
|
|
+** this opcode.
|
|
**
|
|
** <li>[[SQLITE_FCNTL_BEGIN_ATOMIC_WRITE]]
|
|
** If the [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] opcode returns SQLITE_OK, then
|
|
@@ -2109,7 +1425,7 @@ struct sqlite3_io_methods {
|
|
**
|
|
** <li>[[SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]]
|
|
** The [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE] opcode causes all write
|
|
-** operations since the previous successful call to
|
|
+** operations since the previous successful call to
|
|
** [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] to be performed atomically.
|
|
** This file control returns [SQLITE_OK] if and only if the writes were
|
|
** all performed successfully and have been committed to persistent storage.
|
|
@@ -2121,7 +1437,7 @@ struct sqlite3_io_methods {
|
|
**
|
|
** <li>[[SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE]]
|
|
** The [SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE] opcode causes all write
|
|
-** operations since the previous successful call to
|
|
+** operations since the previous successful call to
|
|
** [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] to be rolled back.
|
|
** ^This file control takes the file descriptor out of batch write mode
|
|
** so that all subsequent write operations are independent.
|
|
@@ -2129,10 +1445,12 @@ struct sqlite3_io_methods {
|
|
** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE].
|
|
**
|
|
** <li>[[SQLITE_FCNTL_LOCK_TIMEOUT]]
|
|
-** The [SQLITE_FCNTL_LOCK_TIMEOUT] opcode causes attempts to obtain
|
|
-** a file lock using the xLock or xShmLock methods of the VFS to wait
|
|
-** for up to M milliseconds before failing, where M is the single
|
|
-** unsigned integer parameter.
|
|
+** The [SQLITE_FCNTL_LOCK_TIMEOUT] opcode is used to configure a VFS
|
|
+** to block for up to M milliseconds before failing when attempting to
|
|
+** obtain a file lock using the xLock or xShmLock methods of the VFS.
|
|
+** The parameter is a pointer to a 32-bit signed integer that contains
|
|
+** the value that M is to be set to. Before returning, the 32-bit signed
|
|
+** integer is overwritten with the previous value of M.
|
|
**
|
|
** <li>[[SQLITE_FCNTL_DATA_VERSION]]
|
|
** The [SQLITE_FCNTL_DATA_VERSION] opcode is used to detect changes to
|
|
@@ -2154,11 +1472,38 @@ struct sqlite3_io_methods {
|
|
** happen either internally or externally and that are associated with
|
|
** a particular attached database.
|
|
**
|
|
+** <li>[[SQLITE_FCNTL_CKPT_START]]
|
|
+** The [SQLITE_FCNTL_CKPT_START] opcode is invoked from within a checkpoint
|
|
+** in wal mode before the client starts to copy pages from the wal
|
|
+** file to the database file.
|
|
+**
|
|
** <li>[[SQLITE_FCNTL_CKPT_DONE]]
|
|
** The [SQLITE_FCNTL_CKPT_DONE] opcode is invoked from within a checkpoint
|
|
** in wal mode after the client has finished copying pages from the wal
|
|
** file to the database file, but before the *-shm file is updated to
|
|
** record the fact that the pages have been checkpointed.
|
|
+**
|
|
+** <li>[[SQLITE_FCNTL_EXTERNAL_READER]]
|
|
+** The EXPERIMENTAL [SQLITE_FCNTL_EXTERNAL_READER] opcode is used to detect
|
|
+** whether or not there is a database client in another process with a wal-mode
|
|
+** transaction open on the database or not. It is only available on unix.The
|
|
+** (void*) argument passed with this file-control should be a pointer to a
|
|
+** value of type (int). The integer value is set to 1 if the database is a wal
|
|
+** mode database and there exists at least one client in another process that
|
|
+** currently has an SQL transaction open on the database. It is set to 0 if
|
|
+** the database is not a wal-mode db, or if there is no such connection in any
|
|
+** other process. This opcode cannot be used to detect transactions opened
|
|
+** by clients within the current process, only within other processes.
|
|
+**
|
|
+** <li>[[SQLITE_FCNTL_CKSM_FILE]]
|
|
+** The [SQLITE_FCNTL_CKSM_FILE] opcode is for use interally by the
|
|
+** [checksum VFS shim] only.
|
|
+**
|
|
+** <li>[[SQLITE_FCNTL_RESET_CACHE]]
|
|
+** If there is currently no transaction open on the database, and the
|
|
+** database is not a temp db, then the [SQLITE_FCNTL_RESET_CACHE] file-control
|
|
+** purges the contents of the in-memory page cache. If there is an open
|
|
+** transaction, or if the db is a temp-db, this opcode is a no-op, not an error.
|
|
** </ul>
|
|
*/
|
|
#define SQLITE_FCNTL_LOCKSTATE 1
|
|
@@ -2197,6 +1542,11 @@ struct sqlite3_io_methods {
|
|
#define SQLITE_FCNTL_DATA_VERSION 35
|
|
#define SQLITE_FCNTL_SIZE_LIMIT 36
|
|
#define SQLITE_FCNTL_CKPT_DONE 37
|
|
+#define SQLITE_FCNTL_RESERVE_BYTES 38
|
|
+#define SQLITE_FCNTL_CKPT_START 39
|
|
+#define SQLITE_FCNTL_EXTERNAL_READER 40
|
|
+#define SQLITE_FCNTL_CKSM_FILE 41
|
|
+#define SQLITE_FCNTL_RESET_CACHE 42
|
|
|
|
/* deprecated names */
|
|
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
|
|
@@ -2226,6 +1576,26 @@ typedef struct sqlite3_mutex sqlite3_mutex;
|
|
*/
|
|
typedef struct sqlite3_api_routines sqlite3_api_routines;
|
|
|
|
+/*
|
|
+** CAPI3REF: File Name
|
|
+**
|
|
+** Type [sqlite3_filename] is used by SQLite to pass filenames to the
|
|
+** xOpen method of a [VFS]. It may be cast to (const char*) and treated
|
|
+** as a normal, nul-terminated, UTF-8 buffer containing the filename, but
|
|
+** may also be passed to special APIs such as:
|
|
+**
|
|
+** <ul>
|
|
+** <li> sqlite3_filename_database()
|
|
+** <li> sqlite3_filename_journal()
|
|
+** <li> sqlite3_filename_wal()
|
|
+** <li> sqlite3_uri_parameter()
|
|
+** <li> sqlite3_uri_boolean()
|
|
+** <li> sqlite3_uri_int64()
|
|
+** <li> sqlite3_uri_key()
|
|
+** </ul>
|
|
+*/
|
|
+typedef const char *sqlite3_filename;
|
|
+
|
|
/*
|
|
** CAPI3REF: OS Interface Object
|
|
**
|
|
@@ -2280,14 +1650,14 @@ typedef struct sqlite3_api_routines sqlite3_api_routines;
|
|
** the [sqlite3_file] can safely store a pointer to the
|
|
** filename if it needs to remember the filename for some reason.
|
|
** If the zFilename parameter to xOpen is a NULL pointer then xOpen
|
|
-** must invent its own temporary name for the file. ^Whenever the
|
|
+** must invent its own temporary name for the file. ^Whenever the
|
|
** xFilename parameter is NULL it will also be the case that the
|
|
** flags parameter will include [SQLITE_OPEN_DELETEONCLOSE].
|
|
**
|
|
** The flags argument to xOpen() includes all bits set in
|
|
** the flags argument to [sqlite3_open_v2()]. Or if [sqlite3_open()]
|
|
** or [sqlite3_open16()] is used, then flags includes at least
|
|
-** [SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE].
|
|
+** [SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE].
|
|
** If xOpen() opens a file read-only then it sets *pOutFlags to
|
|
** include [SQLITE_OPEN_READONLY]. Other bits in *pOutFlags may be set.
|
|
**
|
|
@@ -2301,7 +1671,7 @@ typedef struct sqlite3_api_routines sqlite3_api_routines;
|
|
** <li> [SQLITE_OPEN_TEMP_JOURNAL]
|
|
** <li> [SQLITE_OPEN_TRANSIENT_DB]
|
|
** <li> [SQLITE_OPEN_SUBJOURNAL]
|
|
-** <li> [SQLITE_OPEN_MASTER_JOURNAL]
|
|
+** <li> [SQLITE_OPEN_SUPER_JOURNAL]
|
|
** <li> [SQLITE_OPEN_WAL]
|
|
** </ul>)^
|
|
**
|
|
@@ -2329,10 +1699,10 @@ typedef struct sqlite3_api_routines sqlite3_api_routines;
|
|
** ^The [SQLITE_OPEN_EXCLUSIVE] flag is always used in conjunction
|
|
** with the [SQLITE_OPEN_CREATE] flag, which are both directly
|
|
** analogous to the O_EXCL and O_CREAT flags of the POSIX open()
|
|
-** API. The SQLITE_OPEN_EXCLUSIVE flag, when paired with the
|
|
+** API. The SQLITE_OPEN_EXCLUSIVE flag, when paired with the
|
|
** SQLITE_OPEN_CREATE, is used to indicate that file should always
|
|
** be created, and that it is an error if it already exists.
|
|
-** It is <i>not</i> used to indicate the file should be opened
|
|
+** It is <i>not</i> used to indicate the file should be opened
|
|
** for exclusive access.
|
|
**
|
|
** ^At least szOsFile bytes of memory are allocated by SQLite
|
|
@@ -2356,7 +1726,7 @@ typedef struct sqlite3_api_routines sqlite3_api_routines;
|
|
** non-zero error code if there is an I/O error or if the name of
|
|
** the file given in the second argument is illegal. If SQLITE_OK
|
|
** is returned, then non-zero or zero is written into *pResOut to indicate
|
|
-** whether or not the file is accessible.
|
|
+** whether or not the file is accessible.
|
|
**
|
|
** ^SQLite will always allocate at least mxPathname+1 bytes for the
|
|
** output buffer xFullPathname. The exact size of the output buffer
|
|
@@ -2376,16 +1746,16 @@ typedef struct sqlite3_api_routines sqlite3_api_routines;
|
|
** method returns a Julian Day Number for the current date and time as
|
|
** a floating point value.
|
|
** ^The xCurrentTimeInt64() method returns, as an integer, the Julian
|
|
-** Day Number multiplied by 86400000 (the number of milliseconds in
|
|
-** a 24-hour day).
|
|
+** Day Number multiplied by 86400000 (the number of milliseconds in
|
|
+** a 24-hour day).
|
|
** ^SQLite will use the xCurrentTimeInt64() method to get the current
|
|
-** date and time if that method is available (if iVersion is 2 or
|
|
+** date and time if that method is available (if iVersion is 2 or
|
|
** greater and the function pointer is not NULL) and will fall back
|
|
** to xCurrentTime() if xCurrentTimeInt64() is unavailable.
|
|
**
|
|
** ^The xSetSystemCall(), xGetSystemCall(), and xNestSystemCall() interfaces
|
|
** are not used by the SQLite core. These optional interfaces are provided
|
|
-** by some VFSes to facilitate testing of the VFS code. By overriding
|
|
+** by some VFSes to facilitate testing of the VFS code. By overriding
|
|
** system calls with functions under its control, a test program can
|
|
** simulate faults and error conditions that would otherwise be difficult
|
|
** or impossible to induce. The set of system calls that can be overridden
|
|
@@ -2404,7 +1774,7 @@ struct sqlite3_vfs {
|
|
sqlite3_vfs *pNext; /* Next registered VFS */
|
|
const char *zName; /* Name of this virtual file system */
|
|
void *pAppData; /* Pointer to application-specific data */
|
|
- int (*xOpen)(sqlite3_vfs*, const char *zName, sqlite3_file*,
|
|
+ int (*xOpen)(sqlite3_vfs*, sqlite3_filename zName, sqlite3_file*,
|
|
int flags, int *pOutFlags);
|
|
int (*xDelete)(sqlite3_vfs*, const char *zName, int syncDir);
|
|
int (*xAccess)(sqlite3_vfs*, const char *zName, int flags, int *pResOut);
|
|
@@ -2432,7 +1802,7 @@ struct sqlite3_vfs {
|
|
/*
|
|
** The methods above are in versions 1 through 3 of the sqlite_vfs object.
|
|
** New fields may be appended in future versions. The iVersion
|
|
- ** value will increment whenever this happens.
|
|
+ ** value will increment whenever this happens.
|
|
*/
|
|
};
|
|
|
|
@@ -2476,7 +1846,7 @@ struct sqlite3_vfs {
|
|
** </ul>
|
|
**
|
|
** When unlocking, the same SHARED or EXCLUSIVE flag must be supplied as
|
|
-** was given on the corresponding lock.
|
|
+** was given on the corresponding lock.
|
|
**
|
|
** The xShmLock method can transition between unlocked and SHARED or
|
|
** between unlocked and EXCLUSIVE. It cannot transition between SHARED
|
|
@@ -2621,7 +1991,7 @@ SQLITE_API int sqlite3_config(int, ...);
|
|
** [database connection] (specified in the first argument).
|
|
**
|
|
** The second argument to sqlite3_db_config(D,V,...) is the
|
|
-** [SQLITE_DBCONFIG_LOOKASIDE | configuration verb] - an integer code
|
|
+** [SQLITE_DBCONFIG_LOOKASIDE | configuration verb] - an integer code
|
|
** that indicates what aspect of the [database connection] is being configured.
|
|
** Subsequent arguments vary depending on the configuration verb.
|
|
**
|
|
@@ -2639,7 +2009,7 @@ SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...);
|
|
** This object is used in only one place in the SQLite interface.
|
|
** A pointer to an instance of this object is the argument to
|
|
** [sqlite3_config()] when the configuration option is
|
|
-** [SQLITE_CONFIG_MALLOC] or [SQLITE_CONFIG_GETMALLOC].
|
|
+** [SQLITE_CONFIG_MALLOC] or [SQLITE_CONFIG_GETMALLOC].
|
|
** By creating an instance of this object
|
|
** and passing it to [sqlite3_config]([SQLITE_CONFIG_MALLOC])
|
|
** during configuration, an application can specify an alternative
|
|
@@ -2669,7 +2039,7 @@ SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...);
|
|
** allocators round up memory allocations at least to the next multiple
|
|
** of 8. Some allocators round up to a larger multiple or to a power of 2.
|
|
** Every memory allocation request coming in through [sqlite3_malloc()]
|
|
-** or [sqlite3_realloc()] first calls xRoundup. If xRoundup returns 0,
|
|
+** or [sqlite3_realloc()] first calls xRoundup. If xRoundup returns 0,
|
|
** that causes the corresponding memory allocation to fail.
|
|
**
|
|
** The xInit method initializes the memory allocator. For example,
|
|
@@ -2679,7 +2049,7 @@ SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...);
|
|
** by xInit. The pAppData pointer is used as the only parameter to
|
|
** xInit and xShutdown.
|
|
**
|
|
-** SQLite holds the [SQLITE_MUTEX_STATIC_MASTER] mutex when it invokes
|
|
+** SQLite holds the [SQLITE_MUTEX_STATIC_MAIN] mutex when it invokes
|
|
** the xInit method, so the xInit method need not be threadsafe. The
|
|
** xShutdown method is only called from [sqlite3_shutdown()] so it does
|
|
** not need to be threadsafe either. For all other methods, SQLite
|
|
@@ -2727,7 +2097,7 @@ struct sqlite3_mem_methods {
|
|
** by a single thread. ^If SQLite is compiled with
|
|
** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then
|
|
** it is not possible to change the [threading mode] from its default
|
|
-** value of Single-thread and so [sqlite3_config()] will return
|
|
+** value of Single-thread and so [sqlite3_config()] will return
|
|
** [SQLITE_ERROR] if called with the SQLITE_CONFIG_SINGLETHREAD
|
|
** configuration option.</dd>
|
|
**
|
|
@@ -2762,7 +2132,7 @@ struct sqlite3_mem_methods {
|
|
** SQLITE_CONFIG_SERIALIZED configuration option.</dd>
|
|
**
|
|
** [[SQLITE_CONFIG_MALLOC]] <dt>SQLITE_CONFIG_MALLOC</dt>
|
|
-** <dd> ^(The SQLITE_CONFIG_MALLOC option takes a single argument which is
|
|
+** <dd> ^(The SQLITE_CONFIG_MALLOC option takes a single argument which is
|
|
** a pointer to an instance of the [sqlite3_mem_methods] structure.
|
|
** The argument specifies
|
|
** alternative low-level memory allocation routines to be used in place of
|
|
@@ -2813,7 +2183,7 @@ struct sqlite3_mem_methods {
|
|
** [[SQLITE_CONFIG_PAGECACHE]] <dt>SQLITE_CONFIG_PAGECACHE</dt>
|
|
** <dd> ^The SQLITE_CONFIG_PAGECACHE option specifies a memory pool
|
|
** that SQLite can use for the database page cache with the default page
|
|
-** cache implementation.
|
|
+** cache implementation.
|
|
** This configuration option is a no-op if an application-defined page
|
|
** cache implementation is loaded using the [SQLITE_CONFIG_PCACHE2].
|
|
** ^There are three arguments to SQLITE_CONFIG_PAGECACHE: A pointer to
|
|
@@ -2841,7 +2211,7 @@ struct sqlite3_mem_methods {
|
|
** additional cache line. </dd>
|
|
**
|
|
** [[SQLITE_CONFIG_HEAP]] <dt>SQLITE_CONFIG_HEAP</dt>
|
|
-** <dd> ^The SQLITE_CONFIG_HEAP option specifies a static memory buffer
|
|
+** <dd> ^The SQLITE_CONFIG_HEAP option specifies a static memory buffer
|
|
** that SQLite will use for all of its dynamic memory allocation needs
|
|
** beyond those provided for by [SQLITE_CONFIG_PAGECACHE].
|
|
** ^The SQLITE_CONFIG_HEAP option is only available if SQLite is compiled
|
|
@@ -2896,7 +2266,7 @@ struct sqlite3_mem_methods {
|
|
** configuration on individual connections.)^ </dd>
|
|
**
|
|
** [[SQLITE_CONFIG_PCACHE2]] <dt>SQLITE_CONFIG_PCACHE2</dt>
|
|
-** <dd> ^(The SQLITE_CONFIG_PCACHE2 option takes a single argument which is
|
|
+** <dd> ^(The SQLITE_CONFIG_PCACHE2 option takes a single argument which is
|
|
** a pointer to an [sqlite3_pcache_methods2] object. This object specifies
|
|
** the interface to a custom page cache implementation.)^
|
|
** ^SQLite makes a copy of the [sqlite3_pcache_methods2] object.</dd>
|
|
@@ -2910,7 +2280,7 @@ struct sqlite3_mem_methods {
|
|
** <dd> The SQLITE_CONFIG_LOG option is used to configure the SQLite
|
|
** global [error log].
|
|
** (^The SQLITE_CONFIG_LOG option takes two arguments: a pointer to a
|
|
-** function with a call signature of void(*)(void*,int,const char*),
|
|
+** function with a call signature of void(*)(void*,int,const char*),
|
|
** and a pointer to void. ^If the function pointer is not NULL, it is
|
|
** invoked by [sqlite3_log()] to process each logging event. ^If the
|
|
** function pointer is NULL, the [sqlite3_log()] interface becomes a no-op.
|
|
@@ -3019,7 +2389,7 @@ struct sqlite3_mem_methods {
|
|
** [[SQLITE_CONFIG_STMTJRNL_SPILL]]
|
|
** <dt>SQLITE_CONFIG_STMTJRNL_SPILL
|
|
** <dd>^The SQLITE_CONFIG_STMTJRNL_SPILL option takes a single parameter which
|
|
-** becomes the [statement journal] spill-to-disk threshold.
|
|
+** becomes the [statement journal] spill-to-disk threshold.
|
|
** [Statement journals] are held in memory until their size (in bytes)
|
|
** exceeds this threshold, at which point they are written to disk.
|
|
** Or if the threshold is -1, statement journals are always held
|
|
@@ -3041,7 +2411,7 @@ struct sqlite3_mem_methods {
|
|
** than the configured sorter-reference size threshold - then a reference
|
|
** 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
|
|
+** value for this option is to never use this optimization. Specifying a
|
|
** negative value for this option restores the default behaviour.
|
|
** This option is only available if SQLite is compiled with the
|
|
** [SQLITE_ENABLE_SORTER_REFERENCES] compile-time option.
|
|
@@ -3069,7 +2439,7 @@ struct sqlite3_mem_methods {
|
|
#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. */
|
|
+/* 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 */
|
|
@@ -3104,7 +2474,7 @@ struct sqlite3_mem_methods {
|
|
** <dl>
|
|
** [[SQLITE_DBCONFIG_LOOKASIDE]]
|
|
** <dt>SQLITE_DBCONFIG_LOOKASIDE</dt>
|
|
-** <dd> ^This option takes three additional arguments that determine the
|
|
+** <dd> ^This option takes three additional arguments that determine the
|
|
** [lookaside memory allocator] configuration for the [database connection].
|
|
** ^The first argument (the third parameter to [sqlite3_db_config()] is a
|
|
** pointer to a memory buffer to use for lookaside memory.
|
|
@@ -3120,9 +2490,9 @@ struct sqlite3_mem_methods {
|
|
** configuration for a database connection can only be changed when that
|
|
** connection is not currently using lookaside memory, or in other words
|
|
** when the "current value" returned by
|
|
-** [sqlite3_db_status](D,[SQLITE_CONFIG_LOOKASIDE],...) is zero.
|
|
+** [sqlite3_db_status](D,[SQLITE_DBSTATUS_LOOKASIDE_USED],...) is zero.
|
|
** Any attempt to change the lookaside memory configuration when lookaside
|
|
-** memory is in use leaves the configuration unchanged and returns
|
|
+** memory is in use leaves the configuration unchanged and returns
|
|
** [SQLITE_BUSY].)^</dd>
|
|
**
|
|
** [[SQLITE_DBCONFIG_ENABLE_FKEY]]
|
|
@@ -3145,7 +2515,13 @@ struct sqlite3_mem_methods {
|
|
** The second parameter is a pointer to an integer into which
|
|
** is written 0 or 1 to indicate whether triggers are disabled or enabled
|
|
** following this call. The second parameter may be a NULL pointer, in
|
|
-** which case the trigger setting is not reported back. </dd>
|
|
+** which case the trigger setting is not reported back.
|
|
+**
|
|
+** <p>Originally this option disabled all triggers. ^(However, since
|
|
+** SQLite version 3.35.0, TEMP triggers are still allowed even if
|
|
+** this option is off. So, in other words, this option now only disables
|
|
+** triggers in the main database schema or in the schemas of ATTACH-ed
|
|
+** databases.)^ </dd>
|
|
**
|
|
** [[SQLITE_DBCONFIG_ENABLE_VIEW]]
|
|
** <dt>SQLITE_DBCONFIG_ENABLE_VIEW</dt>
|
|
@@ -3156,7 +2532,13 @@ struct sqlite3_mem_methods {
|
|
** The second parameter is a pointer to an integer into which
|
|
** is written 0 or 1 to indicate whether views are disabled or enabled
|
|
** following this call. The second parameter may be a NULL pointer, in
|
|
-** which case the view setting is not reported back. </dd>
|
|
+** which case the view setting is not reported back.
|
|
+**
|
|
+** <p>Originally this option disabled all views. ^(However, since
|
|
+** SQLite version 3.35.0, TEMP views are still allowed even if
|
|
+** this option is off. So, in other words, this option now only disables
|
|
+** views in the main database schema or in the schemas of ATTACH-ed
|
|
+** databases.)^ </dd>
|
|
**
|
|
** [[SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER]]
|
|
** <dt>SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER</dt>
|
|
@@ -3199,11 +2581,11 @@ struct sqlite3_mem_methods {
|
|
** until after the database connection closes.
|
|
** </dd>
|
|
**
|
|
-** [[SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE]]
|
|
+** [[SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE]]
|
|
** <dt>SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE</dt>
|
|
-** <dd> Usually, when a database in wal mode is closed or detached from a
|
|
-** 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
|
|
+** <dd> Usually, when a database in wal mode is closed or detached from a
|
|
+** 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
|
|
** is an integer - positive to disable checkpoints-on-close, or zero (the
|
|
@@ -3222,7 +2604,7 @@ struct sqlite3_mem_methods {
|
|
** slower. But the QPSG has the advantage of more predictable behavior. With
|
|
** the QPSG active, SQLite will always use the same query plan in the field as
|
|
** was used during testing in the lab.
|
|
-** The first argument to this setting is an integer which is 0 to disable
|
|
+** The first argument to this setting is an integer which is 0 to disable
|
|
** the QPSG, positive to enable QPSG, or negative to leave the setting
|
|
** unchanged. The second parameter is a pointer to an integer into which
|
|
** is written 0 or 1 to indicate whether the QPSG is disabled or enabled
|
|
@@ -3230,15 +2612,15 @@ struct sqlite3_mem_methods {
|
|
** </dd>
|
|
**
|
|
** [[SQLITE_DBCONFIG_TRIGGER_EQP]] <dt>SQLITE_DBCONFIG_TRIGGER_EQP</dt>
|
|
-** <dd> By default, the output of EXPLAIN QUERY PLAN commands does not
|
|
+** <dd> By default, the output of EXPLAIN QUERY PLAN commands does not
|
|
** include output for any operations performed by trigger programs. This
|
|
** option is used to set or clear (the default) a flag that governs this
|
|
** behavior. The first parameter passed to this operation is an integer -
|
|
** positive to enable output for trigger programs, or zero to disable it,
|
|
** or negative to leave the setting unchanged.
|
|
-** The second parameter is a pointer to an integer into which is written
|
|
-** 0 or 1 to indicate whether output-for-triggers has been disabled - 0 if
|
|
-** it is not disabled, 1 if it is.
|
|
+** The second parameter is a pointer to an integer into which is written
|
|
+** 0 or 1 to indicate whether output-for-triggers has been disabled - 0 if
|
|
+** it is not disabled, 1 if it is.
|
|
** </dd>
|
|
**
|
|
** [[SQLITE_DBCONFIG_RESET_DATABASE]] <dt>SQLITE_DBCONFIG_RESET_DATABASE</dt>
|
|
@@ -3252,24 +2634,29 @@ struct sqlite3_mem_methods {
|
|
** database, or calling sqlite3_table_column_metadata(), ignoring any
|
|
** errors. This step is only necessary if the application desires to keep
|
|
** the database in WAL mode after the reset if it was in WAL mode before
|
|
-** the reset.
|
|
+** the reset.
|
|
** <li> sqlite3_db_config(db, SQLITE_DBCONFIG_RESET_DATABASE, 1, 0);
|
|
** <li> [sqlite3_exec](db, "[VACUUM]", 0, 0, 0);
|
|
** <li> sqlite3_db_config(db, SQLITE_DBCONFIG_RESET_DATABASE, 0, 0);
|
|
** </ol>
|
|
** Because resetting a database is destructive and irreversible, the
|
|
-** process requires the use of this obscure API and multiple steps to help
|
|
-** ensure that it does not happen by accident.
|
|
+** process requires the use of this obscure API and multiple steps to
|
|
+** help ensure that it does not happen by accident. Because this
|
|
+** feature must be capable of resetting corrupt databases, and
|
|
+** shutting down virtual tables may require access to that corrupt
|
|
+** storage, the library must abandon any installed virtual tables
|
|
+** without calling their xDestroy() methods.
|
|
**
|
|
** [[SQLITE_DBCONFIG_DEFENSIVE]] <dt>SQLITE_DBCONFIG_DEFENSIVE</dt>
|
|
** <dd>The SQLITE_DBCONFIG_DEFENSIVE option activates or deactivates the
|
|
** "defensive" flag for a database connection. When the defensive
|
|
-** flag is enabled, language features that allow ordinary SQL to
|
|
+** flag is enabled, language features that allow ordinary SQL to
|
|
** deliberately corrupt the database file are disabled. The disabled
|
|
** features include but are not limited to the following:
|
|
** <ul>
|
|
** <li> The [PRAGMA writable_schema=ON] statement.
|
|
** <li> The [PRAGMA journal_mode=OFF] statement.
|
|
+** <li> The [PRAGMA schema_version=N] statement.
|
|
** <li> Writes to the [sqlite_dbpage] virtual table.
|
|
** <li> Direct writes to [shadow tables].
|
|
** </ul>
|
|
@@ -3279,7 +2666,7 @@ struct sqlite3_mem_methods {
|
|
** <dd>The SQLITE_DBCONFIG_WRITABLE_SCHEMA option activates or deactivates the
|
|
** "writable_schema" flag. This has the same effect and is logically equivalent
|
|
** to setting [PRAGMA writable_schema=ON] or [PRAGMA writable_schema=OFF].
|
|
-** The first argument to this setting is an integer which is 0 to disable
|
|
+** The first argument to this setting is an integer which is 0 to disable
|
|
** the writable_schema, positive to enable writable_schema, or negative to
|
|
** leave the setting unchanged. The second parameter is a pointer to an
|
|
** integer into which is written 0 or 1 to indicate whether the writable_schema
|
|
@@ -3317,14 +2704,13 @@ struct sqlite3_mem_methods {
|
|
** [[SQLITE_DBCONFIG_TRUSTED_SCHEMA]]
|
|
** <dt>SQLITE_DBCONFIG_TRUSTED_SCHEMA</td>
|
|
** <dd>The SQLITE_DBCONFIG_TRUSTED_SCHEMA option tells SQLite to
|
|
-** assume that database schemas (the contents of the [sqlite_master] tables)
|
|
-** are untainted by malicious content.
|
|
+** assume that database schemas are untainted by malicious content.
|
|
** When the SQLITE_DBCONFIG_TRUSTED_SCHEMA option is disabled, SQLite
|
|
** takes additional defensive steps to protect the application from harm
|
|
** including:
|
|
** <ul>
|
|
** <li> Prohibit the use of SQL functions inside triggers, views,
|
|
-** CHECK constraints, DEFAULT clauses, expression indexes,
|
|
+** CHECK constraints, DEFAULT clauses, expression indexes,
|
|
** partial indexes, or generated columns
|
|
** unless those functions are tagged with [SQLITE_INNOCUOUS].
|
|
** <li> Prohibit the use of virtual tables inside of triggers or views
|
|
@@ -3345,7 +2731,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 generated database files that are compatible
|
|
** all the way back to version 3.0.0, and so this setting is of little
|
|
** practical use, but is provided so that SQLite can continue to claim the
|
|
** ability to generate new database files that are compatible with version
|
|
@@ -3403,8 +2789,8 @@ SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff);
|
|
** ^The sqlite3_last_insert_rowid(D) interface usually returns the [rowid] of
|
|
** the most recent successful [INSERT] into a rowid table or [virtual table]
|
|
** on database connection D. ^Inserts into [WITHOUT ROWID] tables are not
|
|
-** recorded. ^If no successful [INSERT]s into rowid tables have ever occurred
|
|
-** on the database connection D, then sqlite3_last_insert_rowid(D) returns
|
|
+** recorded. ^If no successful [INSERT]s into rowid tables have ever occurred
|
|
+** on the database connection D, then sqlite3_last_insert_rowid(D) returns
|
|
** zero.
|
|
**
|
|
** As well as being set automatically as rows are inserted into database
|
|
@@ -3414,15 +2800,15 @@ SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff);
|
|
** Some virtual table implementations may INSERT rows into rowid tables as
|
|
** part of committing a transaction (e.g. to flush data accumulated in memory
|
|
** to disk). In this case subsequent calls to this function return the rowid
|
|
-** associated with these internal INSERT operations, which leads to
|
|
+** associated with these internal INSERT operations, which leads to
|
|
** unintuitive results. Virtual table implementations that do write to rowid
|
|
-** tables in this way can avoid this problem by restoring the original
|
|
-** rowid value using [sqlite3_set_last_insert_rowid()] before returning
|
|
+** tables in this way can avoid this problem by restoring the original
|
|
+** rowid value using [sqlite3_set_last_insert_rowid()] before returning
|
|
** control to the user.
|
|
**
|
|
-** ^(If an [INSERT] occurs within a trigger then this routine will
|
|
-** return the [rowid] of the inserted row as long as the trigger is
|
|
-** running. Once the trigger program ends, the value returned
|
|
+** ^(If an [INSERT] occurs within a trigger then this routine will
|
|
+** return the [rowid] of the inserted row as long as the trigger is
|
|
+** running. Once the trigger program ends, the value returned
|
|
** by this routine reverts to what it was before the trigger was fired.)^
|
|
**
|
|
** ^An [INSERT] that fails due to a constraint violation is not a
|
|
@@ -3455,7 +2841,7 @@ SQLITE_API sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*);
|
|
** METHOD: sqlite3
|
|
**
|
|
** The sqlite3_set_last_insert_rowid(D, R) method allows the application to
|
|
-** set the value returned by calling sqlite3_last_insert_rowid(D) to R
|
|
+** set the value returned by calling sqlite3_last_insert_rowid(D) to R
|
|
** without inserting a row into the database.
|
|
*/
|
|
SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3*,sqlite3_int64);
|
|
@@ -3464,44 +2850,47 @@ SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3*,sqlite3_int64);
|
|
** CAPI3REF: Count The Number Of Rows Modified
|
|
** METHOD: sqlite3
|
|
**
|
|
-** ^This function returns the number of rows modified, inserted or
|
|
+** ^These functions return the number of rows modified, inserted or
|
|
** deleted by the most recently completed INSERT, UPDATE or DELETE
|
|
** statement on the database connection specified by the only parameter.
|
|
-** ^Executing any other type of SQL statement does not modify the value
|
|
-** returned by this function.
|
|
+** The two functions are identical except for the type of the return value
|
|
+** and that if the number of rows modified by the most recent INSERT, UPDATE
|
|
+** or DELETE is greater than the maximum value supported by type "int", then
|
|
+** the return value of sqlite3_changes() is undefined. ^Executing any other
|
|
+** type of SQL statement does not modify the value returned by these functions.
|
|
**
|
|
** ^Only changes made directly by the INSERT, UPDATE or DELETE statement are
|
|
-** considered - auxiliary changes caused by [CREATE TRIGGER | triggers],
|
|
+** considered - auxiliary changes caused by [CREATE TRIGGER | triggers],
|
|
** [foreign key actions] or [REPLACE] constraint resolution are not counted.
|
|
-**
|
|
-** Changes to a view that are intercepted by
|
|
-** [INSTEAD OF trigger | INSTEAD OF triggers] are not counted. ^The value
|
|
-** returned by sqlite3_changes() immediately after an INSERT, UPDATE or
|
|
-** DELETE statement run on a view is always zero. Only changes made to real
|
|
+**
|
|
+** Changes to a view that are intercepted by
|
|
+** [INSTEAD OF trigger | INSTEAD OF triggers] are not counted. ^The value
|
|
+** returned by sqlite3_changes() immediately after an INSERT, UPDATE or
|
|
+** DELETE statement run on a view is always zero. Only changes made to real
|
|
** tables are counted.
|
|
**
|
|
** Things are more complicated if the sqlite3_changes() function is
|
|
** executed while a trigger program is running. This may happen if the
|
|
** program uses the [changes() SQL function], or if some other callback
|
|
** function invokes sqlite3_changes() directly. Essentially:
|
|
-**
|
|
+**
|
|
** <ul>
|
|
** <li> ^(Before entering a trigger program the value returned by
|
|
-** sqlite3_changes() function is saved. After the trigger program
|
|
+** sqlite3_changes() function is saved. After the trigger program
|
|
** has finished, the original value is restored.)^
|
|
-**
|
|
-** <li> ^(Within a trigger program each INSERT, UPDATE and DELETE
|
|
-** statement sets the value returned by sqlite3_changes()
|
|
-** upon completion as normal. Of course, this value will not include
|
|
-** any changes performed by sub-triggers, as the sqlite3_changes()
|
|
+**
|
|
+** <li> ^(Within a trigger program each INSERT, UPDATE and DELETE
|
|
+** statement sets the value returned by sqlite3_changes()
|
|
+** upon completion as normal. Of course, this value will not include
|
|
+** any changes performed by sub-triggers, as the sqlite3_changes()
|
|
** value will be saved and restored after each sub-trigger has run.)^
|
|
** </ul>
|
|
-**
|
|
+**
|
|
** ^This means that if the changes() SQL function (or similar) is used
|
|
-** by the first INSERT, UPDATE or DELETE statement within a trigger, it
|
|
+** by the first INSERT, UPDATE or DELETE statement within a trigger, it
|
|
** returns the value as set when the calling statement began executing.
|
|
-** ^If it is used by the second or subsequent such statement within a trigger
|
|
-** program, the value returned reflects the number of rows modified by the
|
|
+** ^If it is used by the second or subsequent such statement within a trigger
|
|
+** program, the value returned reflects the number of rows modified by the
|
|
** previous INSERT, UPDATE or DELETE statement within the same trigger.
|
|
**
|
|
** If a separate thread makes changes on the same database connection
|
|
@@ -3517,20 +2906,25 @@ SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3*,sqlite3_int64);
|
|
** </ul>
|
|
*/
|
|
SQLITE_API int sqlite3_changes(sqlite3*);
|
|
+SQLITE_API sqlite3_int64 sqlite3_changes64(sqlite3*);
|
|
|
|
/*
|
|
** CAPI3REF: Total Number Of Rows Modified
|
|
** METHOD: sqlite3
|
|
**
|
|
-** ^This function returns the total number of rows inserted, modified or
|
|
+** ^These functions return the total number of rows inserted, modified or
|
|
** deleted by all [INSERT], [UPDATE] or [DELETE] statements completed
|
|
** since the database connection was opened, including those executed as
|
|
-** part of trigger programs. ^Executing any other type of SQL statement
|
|
-** does not affect the value returned by sqlite3_total_changes().
|
|
-**
|
|
+** part of trigger programs. The two functions are identical except for the
|
|
+** type of the return value and that if the number of rows modified by the
|
|
+** connection exceeds the maximum value supported by type "int", then
|
|
+** the return value of sqlite3_total_changes() is undefined. ^Executing
|
|
+** any other type of SQL statement does not affect the value returned by
|
|
+** sqlite3_total_changes().
|
|
+**
|
|
** ^Changes made as part of [foreign key actions] are included in the
|
|
** count, but those made as part of REPLACE constraint resolution are
|
|
-** not. ^Changes to a view that are intercepted by INSTEAD OF triggers
|
|
+** not. ^Changes to a view that are intercepted by INSTEAD OF triggers
|
|
** are not counted.
|
|
**
|
|
** The [sqlite3_total_changes(D)] interface only reports the number
|
|
@@ -3539,7 +2933,7 @@ SQLITE_API int sqlite3_changes(sqlite3*);
|
|
** To detect changes against a database file from other database
|
|
** connections use the [PRAGMA data_version] command or the
|
|
** [SQLITE_FCNTL_DATA_VERSION] [file control].
|
|
-**
|
|
+**
|
|
** If a separate thread makes changes on the same database connection
|
|
** while [sqlite3_total_changes()] is running then the value
|
|
** returned is unpredictable and not meaningful.
|
|
@@ -3554,6 +2948,7 @@ SQLITE_API int sqlite3_changes(sqlite3*);
|
|
** </ul>
|
|
*/
|
|
SQLITE_API int sqlite3_total_changes(sqlite3*);
|
|
+SQLITE_API sqlite3_int64 sqlite3_total_changes64(sqlite3*);
|
|
|
|
/*
|
|
** CAPI3REF: Interrupt A Long-Running Query
|
|
@@ -3581,7 +2976,7 @@ SQLITE_API int sqlite3_total_changes(sqlite3*);
|
|
**
|
|
** ^The sqlite3_interrupt(D) call is in effect until all currently running
|
|
** SQL statements on [database connection] D complete. ^Any new SQL statements
|
|
-** that are started after the sqlite3_interrupt() call and before the
|
|
+** that are started after the sqlite3_interrupt() call and before the
|
|
** running statement count reaches zero are interrupted as if they had been
|
|
** running prior to the sqlite3_interrupt() call. ^New SQL statements
|
|
** that are started after the running statement count reaches zero are
|
|
@@ -3589,8 +2984,12 @@ SQLITE_API int sqlite3_total_changes(sqlite3*);
|
|
** ^A call to sqlite3_interrupt(D) that occurs when there are no running
|
|
** SQL statements is a no-op and has no effect on SQL statements
|
|
** that are started after the sqlite3_interrupt() call returns.
|
|
+**
|
|
+** ^The [sqlite3_is_interrupted(D)] interface can be used to determine whether
|
|
+** or not an interrupt is currently in effect for [database connection] D.
|
|
*/
|
|
SQLITE_API void sqlite3_interrupt(sqlite3*);
|
|
+SQLITE_API int sqlite3_is_interrupted(sqlite3*);
|
|
|
|
/*
|
|
** CAPI3REF: Determine If An SQL Statement Is Complete
|
|
@@ -3613,7 +3012,7 @@ SQLITE_API void sqlite3_interrupt(sqlite3*);
|
|
** ^These routines do not parse the SQL statements thus
|
|
** will not detect syntactically incorrect SQL.
|
|
**
|
|
-** ^(If SQLite has not been initialized using [sqlite3_initialize()] prior
|
|
+** ^(If SQLite has not been initialized using [sqlite3_initialize()] prior
|
|
** to invoking sqlite3_complete16() then sqlite3_initialize() is invoked
|
|
** automatically by sqlite3_complete16(). If that initialization fails,
|
|
** then the return value from sqlite3_complete16() will be non-zero
|
|
@@ -3658,7 +3057,7 @@ SQLITE_API int sqlite3_complete16(const void *sql);
|
|
** The presence of a busy handler does not guarantee that it will be invoked
|
|
** when there is lock contention. ^If SQLite determines that invoking the busy
|
|
** handler could result in a deadlock, it will go ahead and return [SQLITE_BUSY]
|
|
-** to the application instead of invoking the
|
|
+** to the application instead of invoking the
|
|
** busy handler.
|
|
** Consider a scenario where one process is holding a read lock that
|
|
** it is trying to promote to a reserved lock and
|
|
@@ -3683,7 +3082,7 @@ SQLITE_API int sqlite3_complete16(const void *sql);
|
|
** database connection that invoked the busy handler. In other words,
|
|
** the busy handler is not reentrant. Any such actions
|
|
** result in undefined behavior.
|
|
-**
|
|
+**
|
|
** A busy handler must not close the database connection
|
|
** or [prepared statement] that invoked the busy handler.
|
|
*/
|
|
@@ -3801,7 +3200,7 @@ SQLITE_API void sqlite3_free_table(char **result);
|
|
** These routines are work-alikes of the "printf()" family of functions
|
|
** from the standard C library.
|
|
** These routines understand most of the common formatting options from
|
|
-** the standard library printf()
|
|
+** the standard library printf()
|
|
** plus some additional non-standard formats ([%q], [%Q], [%w], and [%z]).
|
|
** See the [built-in printf()] documentation for details.
|
|
**
|
|
@@ -3997,7 +3396,7 @@ SQLITE_API void sqlite3_randomness(int N, void *P);
|
|
** requested is ok. ^When the callback returns [SQLITE_DENY], the
|
|
** [sqlite3_prepare_v2()] or equivalent call that triggered the
|
|
** authorizer will fail with an error message explaining that
|
|
-** access is denied.
|
|
+** access is denied.
|
|
**
|
|
** ^The first parameter to the authorizer callback is a copy of the third
|
|
** parameter to the sqlite3_set_authorizer() interface. ^The second parameter
|
|
@@ -4050,7 +3449,7 @@ SQLITE_API void sqlite3_randomness(int N, void *P);
|
|
** database connections for the meaning of "modify" in this paragraph.
|
|
**
|
|
** ^When [sqlite3_prepare_v2()] is used to prepare a statement, the
|
|
-** statement might be re-prepared during [sqlite3_step()] due to a
|
|
+** statement might be re-prepared during [sqlite3_step()] due to a
|
|
** schema change. Hence, the application should ensure that the
|
|
** correct authorizer callback remains in place during the [sqlite3_step()].
|
|
**
|
|
@@ -4198,7 +3597,7 @@ SQLITE_API SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*,
|
|
** execution of the prepared statement, such as at the start of each
|
|
** trigger subprogram. ^The P argument is a pointer to the
|
|
** [prepared statement]. ^The X argument is a pointer to a string which
|
|
-** is the unexpanded SQL text of the prepared statement or an SQL comment
|
|
+** is the unexpanded SQL text of the prepared statement or an SQL comment
|
|
** that indicates the invocation of a trigger. ^The callback can compute
|
|
** the same text that would have been returned by the legacy [sqlite3_trace()]
|
|
** interface by using the X argument when X begins with "--" and invoking
|
|
@@ -4208,13 +3607,13 @@ SQLITE_API SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*,
|
|
** <dd>^An SQLITE_TRACE_PROFILE callback provides approximately the same
|
|
** information as is provided by the [sqlite3_profile()] callback.
|
|
** ^The P argument is a pointer to the [prepared statement] and the
|
|
-** X argument points to a 64-bit integer which is the estimated of
|
|
-** the number of nanosecond that the prepared statement took to run.
|
|
+** X argument points to a 64-bit integer which is approximately
|
|
+** the number of nanoseconds that the prepared statement took to run.
|
|
** ^The SQLITE_TRACE_PROFILE callback is invoked when the statement finishes.
|
|
**
|
|
** [[SQLITE_TRACE_ROW]] <dt>SQLITE_TRACE_ROW</dt>
|
|
** <dd>^An SQLITE_TRACE_ROW callback is invoked whenever a prepared
|
|
-** statement generates a single row of result.
|
|
+** statement generates a single row of result.
|
|
** ^The P argument is a pointer to the [prepared statement] and the
|
|
** X argument is unused.
|
|
**
|
|
@@ -4241,10 +3640,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
|
|
+** ^Each call to either sqlite3_trace() or sqlite3_trace_v2() overrides
|
|
** (cancels) any prior calls to sqlite3_trace() or sqlite3_trace_v2().
|
|
**
|
|
-** ^The X callback is invoked whenever any of the events identified by
|
|
+** ^The X callback is invoked whenever any of the events identified by
|
|
** mask M occur. ^The integer return value from the callback is currently
|
|
** ignored, though this may change in future releases. Callback
|
|
** implementations should return zero to ensure future compatibility.
|
|
@@ -4272,12 +3671,12 @@ SQLITE_API int sqlite3_trace_v2(
|
|
**
|
|
** ^The sqlite3_progress_handler(D,N,X,P) interface causes the callback
|
|
** function X to be invoked periodically during long running calls to
|
|
-** [sqlite3_exec()], [sqlite3_step()] and [sqlite3_get_table()] for
|
|
+** [sqlite3_step()] and [sqlite3_prepare()] and similar for
|
|
** database connection D. An example use for this
|
|
** interface is to keep a GUI updated during a large query.
|
|
**
|
|
-** ^The parameter P is passed through as the only parameter to the
|
|
-** callback function X. ^The parameter N is the approximate number of
|
|
+** ^The parameter P is passed through as the only parameter to the
|
|
+** callback function X. ^The parameter N is the approximate number of
|
|
** [virtual machine instructions] that are evaluated between successive
|
|
** invocations of the callback X. ^If N is less than one then the progress
|
|
** handler is disabled.
|
|
@@ -4297,6 +3696,13 @@ SQLITE_API int sqlite3_trace_v2(
|
|
** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their
|
|
** database connections for the meaning of "modify" in this paragraph.
|
|
**
|
|
+** The progress handler callback would originally only be invoked from the
|
|
+** bytecode engine. It still might be invoked during [sqlite3_prepare()]
|
|
+** and similar because those routines might force a reparse of the schema
|
|
+** which involves running the bytecode engine. However, beginning with
|
|
+** SQLite version 3.41.0, the progress handler callback might also be
|
|
+** invoked directly from [sqlite3_prepare()] while analyzing and generating
|
|
+** code for complex queries.
|
|
*/
|
|
SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
|
|
|
|
@@ -4304,7 +3710,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
|
|
** CAPI3REF: Opening A New Database Connection
|
|
** CONSTRUCTOR: sqlite3
|
|
**
|
|
-** ^These routines open an SQLite database file as specified by the
|
|
+** ^These routines open an SQLite database file as specified by the
|
|
** filename argument. ^The filename argument is interpreted as UTF-8 for
|
|
** sqlite3_open() and sqlite3_open_v2() and as UTF-16 in the native byte
|
|
** order for sqlite3_open16(). ^(A [database connection] handle is usually
|
|
@@ -4333,13 +3739,18 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
|
|
**
|
|
** <dl>
|
|
** ^(<dt>[SQLITE_OPEN_READONLY]</dt>
|
|
-** <dd>The database is opened in read-only mode. If the database does not
|
|
-** already exist, an error is returned.</dd>)^
|
|
+** <dd>The database is opened in read-only mode. If the database does
|
|
+** not already exist, an error is returned.</dd>)^
|
|
**
|
|
** ^(<dt>[SQLITE_OPEN_READWRITE]</dt>
|
|
-** <dd>The database is opened for reading and writing if possible, or reading
|
|
-** only if the file is write protected by the operating system. In either
|
|
-** case the database must already exist, otherwise an error is returned.</dd>)^
|
|
+** <dd>The database is opened for reading and writing if possible, or
|
|
+** reading only if the file is write protected by the operating
|
|
+** system. In either case the database must already exist, otherwise
|
|
+** an error is returned. For historical reasons, if opening in
|
|
+** read-write mode fails due to OS-level permissions, an attempt is
|
|
+** made to open it in read-only mode. [sqlite3_db_readonly()] can be
|
|
+** used to determine whether the database is actually
|
|
+** read-write.</dd>)^
|
|
**
|
|
** ^(<dt>[SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]</dt>
|
|
** <dd>The database is opened for reading and writing, and is created if
|
|
@@ -4377,20 +3788,39 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
|
|
** <dd>The database is opened [shared cache] enabled, overriding
|
|
** the default shared cache setting provided by
|
|
** [sqlite3_enable_shared_cache()].)^
|
|
+** The [use of shared cache mode is discouraged] and hence shared cache
|
|
+** capabilities may be omitted from many builds of SQLite. In such cases,
|
|
+** this option is a no-op.
|
|
**
|
|
** ^(<dt>[SQLITE_OPEN_PRIVATECACHE]</dt>
|
|
** <dd>The database is opened [shared cache] disabled, overriding
|
|
** the default shared cache setting provided by
|
|
** [sqlite3_enable_shared_cache()].)^
|
|
**
|
|
+** [[OPEN_EXRESCODE]] ^(<dt>[SQLITE_OPEN_EXRESCODE]</dt>
|
|
+** <dd>The database connection comes up in "extended result code mode".
|
|
+** In other words, the database behaves has if
|
|
+** [sqlite3_extended_result_codes(db,1)] where called on the database
|
|
+** connection as soon as the connection is created. In addition to setting
|
|
+** the extended result code mode, this flag also causes [sqlite3_open_v2()]
|
|
+** to return an extended result code.</dd>
|
|
+**
|
|
** [[OPEN_NOFOLLOW]] ^(<dt>[SQLITE_OPEN_NOFOLLOW]</dt>
|
|
-** <dd>The database filename is not allowed to be a symbolic link</dd>
|
|
+** <dd>The database filename is not allowed to contain a symbolic link</dd>
|
|
** </dl>)^
|
|
**
|
|
** If the 3rd parameter to sqlite3_open_v2() is not one of the
|
|
** required combinations shown above optionally combined with other
|
|
** [SQLITE_OPEN_READONLY | SQLITE_OPEN_* bits]
|
|
-** then the behavior is undefined.
|
|
+** then the behavior is undefined. Historic versions of SQLite
|
|
+** have silently ignored surplus bits in the flags parameter to
|
|
+** sqlite3_open_v2(), however that behavior might not be carried through
|
|
+** into future versions of SQLite and so applications should not rely
|
|
+** upon it. Note in particular that the SQLITE_OPEN_EXCLUSIVE flag is a no-op
|
|
+** for sqlite3_open_v2(). The SQLITE_OPEN_EXCLUSIVE does *not* cause
|
|
+** the open to fail if the database already exists. The SQLITE_OPEN_EXCLUSIVE
|
|
+** flag is intended for use by the [sqlite3_vfs|VFS interface] only, and not
|
|
+** by sqlite3_open_v2().
|
|
**
|
|
** ^The fourth parameter to sqlite3_open_v2() is the name of the
|
|
** [sqlite3_vfs] object that defines the operating system interface that
|
|
@@ -4423,17 +3853,17 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
|
|
** information.
|
|
**
|
|
** URI filenames are parsed according to RFC 3986. ^If the URI contains an
|
|
-** authority, then it must be either an empty string or the string
|
|
-** "localhost". ^If the authority is not an empty string or "localhost", an
|
|
-** error is returned to the caller. ^The fragment component of a URI, if
|
|
+** authority, then it must be either an empty string or the string
|
|
+** "localhost". ^If the authority is not an empty string or "localhost", an
|
|
+** error is returned to the caller. ^The fragment component of a URI, if
|
|
** present, is ignored.
|
|
**
|
|
** ^SQLite uses the path component of the URI as the name of the disk file
|
|
-** which contains the database. ^If the path begins with a '/' character,
|
|
-** then it is interpreted as an absolute path. ^If the path does not begin
|
|
+** which contains the database. ^If the path begins with a '/' character,
|
|
+** then it is interpreted as an absolute path. ^If the path does not begin
|
|
** with a '/' (meaning that the authority section is omitted from the URI)
|
|
-** then the path is interpreted as a relative path.
|
|
-** ^(On windows, the first component of an absolute path
|
|
+** then the path is interpreted as a relative path.
|
|
+** ^(On windows, the first component of an absolute path
|
|
** is a drive specification (e.g. "C:").)^
|
|
**
|
|
** [[core URI query parameters]]
|
|
@@ -4453,13 +3883,13 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
|
|
**
|
|
** <li> <b>mode</b>: ^(The mode parameter may be set to either "ro", "rw",
|
|
** "rwc", or "memory". Attempting to set it to any other value is
|
|
-** an error)^.
|
|
-** ^If "ro" is specified, then the database is opened for read-only
|
|
-** access, just as if the [SQLITE_OPEN_READONLY] flag had been set in the
|
|
-** third argument to sqlite3_open_v2(). ^If the mode option is set to
|
|
-** "rw", then the database is opened for read-write (but not create)
|
|
-** access, as if SQLITE_OPEN_READWRITE (but not SQLITE_OPEN_CREATE) had
|
|
-** been set. ^Value "rwc" is equivalent to setting both
|
|
+** an error)^.
|
|
+** ^If "ro" is specified, then the database is opened for read-only
|
|
+** access, just as if the [SQLITE_OPEN_READONLY] flag had been set in the
|
|
+** third argument to sqlite3_open_v2(). ^If the mode option is set to
|
|
+** "rw", then the database is opened for read-write (but not create)
|
|
+** access, as if SQLITE_OPEN_READWRITE (but not SQLITE_OPEN_CREATE) had
|
|
+** been set. ^Value "rwc" is equivalent to setting both
|
|
** SQLITE_OPEN_READWRITE and SQLITE_OPEN_CREATE. ^If the mode option is
|
|
** set to "memory" then a pure [in-memory database] that never reads
|
|
** or writes from disk is used. ^It is an error to specify a value for
|
|
@@ -4469,7 +3899,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
|
|
** <li> <b>cache</b>: ^The cache parameter may be set to either "shared" or
|
|
** "private". ^Setting it to "shared" is equivalent to setting the
|
|
** SQLITE_OPEN_SHAREDCACHE bit in the flags argument passed to
|
|
-** sqlite3_open_v2(). ^Setting the cache parameter to "private" is
|
|
+** sqlite3_open_v2(). ^Setting the cache parameter to "private" is
|
|
** equivalent to setting the SQLITE_OPEN_PRIVATECACHE bit.
|
|
** ^If sqlite3_open_v2() is used and the "cache" parameter is present in
|
|
** a URI filename, its value overrides any behavior requested by setting
|
|
@@ -4495,7 +3925,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
|
|
** property on a database file that does in fact change can result
|
|
** in incorrect query results and/or [SQLITE_CORRUPT] errors.
|
|
** See also: [SQLITE_IOCAP_IMMUTABLE].
|
|
-**
|
|
+**
|
|
** </ul>
|
|
**
|
|
** ^Specifying an unknown parameter in the query component of a URI is not an
|
|
@@ -4507,36 +3937,37 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
|
|
**
|
|
** <table border="1" align=center cellpadding=5>
|
|
** <tr><th> URI filenames <th> Results
|
|
-** <tr><td> file:data.db <td>
|
|
+** <tr><td> file:data.db <td>
|
|
** Open the file "data.db" in the current directory.
|
|
** <tr><td> file:/home/fred/data.db<br>
|
|
-** file:///home/fred/data.db <br>
|
|
-** file://localhost/home/fred/data.db <br> <td>
|
|
+** file:///home/fred/data.db <br>
|
|
+** file://localhost/home/fred/data.db <br> <td>
|
|
** Open the database file "/home/fred/data.db".
|
|
-** <tr><td> file://darkstar/home/fred/data.db <td>
|
|
+** <tr><td> file://darkstar/home/fred/data.db <td>
|
|
** An error. "darkstar" is not a recognized authority.
|
|
-** <tr><td style="white-space:nowrap">
|
|
+** <tr><td style="white-space:nowrap">
|
|
** file:///C:/Documents%20and%20Settings/fred/Desktop/data.db
|
|
** <td> Windows only: Open the file "data.db" on fred's desktop on drive
|
|
-** C:. Note that the %20 escaping in this example is not strictly
|
|
+** C:. Note that the %20 escaping in this example is not strictly
|
|
** necessary - space characters can be used literally
|
|
** in URI filenames.
|
|
-** <tr><td> file:data.db?mode=ro&cache=private <td>
|
|
+** <tr><td> file:data.db?mode=ro&cache=private <td>
|
|
** Open file "data.db" in the current directory for read-only access.
|
|
** Regardless of whether or not shared-cache mode is enabled by
|
|
** default, use a private cache.
|
|
** <tr><td> file:/home/fred/data.db?vfs=unix-dotfile <td>
|
|
** Open file "/home/fred/data.db". Use the special VFS "unix-dotfile"
|
|
** that uses dot-files in place of posix advisory locking.
|
|
-** <tr><td> file:data.db?mode=readonly <td>
|
|
+** <tr><td> file:data.db?mode=readonly <td>
|
|
** An error. "readonly" is not a valid option for the "mode" parameter.
|
|
+** Use "ro" instead: "file:data.db?mode=ro".
|
|
** </table>
|
|
**
|
|
** ^URI hexadecimal escape sequences (%HH) are supported within the path and
|
|
** query components of a URI. A hexadecimal escape sequence consists of a
|
|
-** percent sign - "%" - followed by exactly two hexadecimal digits
|
|
+** percent sign - "%" - followed by exactly two hexadecimal digits
|
|
** specifying an octet value. ^Before the path or query components of a
|
|
-** URI filename are interpreted, they are encoded using UTF-8 and all
|
|
+** URI filename are interpreted, they are encoded using UTF-8 and all
|
|
** hexadecimal escape sequences replaced by a single byte containing the
|
|
** corresponding octet. If this process generates an invalid UTF-8 encoding,
|
|
** the results are undefined.
|
|
@@ -4572,14 +4003,25 @@ SQLITE_API int sqlite3_open_v2(
|
|
** CAPI3REF: Obtain Values For URI Parameters
|
|
**
|
|
** These are utility routines, useful to [VFS|custom VFS implementations],
|
|
-** that check if a database file was a URI that contained a specific query
|
|
+** that check if a database file was a URI that contained a specific query
|
|
** parameter, and if so obtains the value of that query parameter.
|
|
**
|
|
-** If F is the database filename pointer passed into the xOpen() method of
|
|
-** a VFS implementation or it is the return value of [sqlite3_db_filename()]
|
|
+** The first parameter to these interfaces (hereafter referred to
|
|
+** as F) must be one of:
|
|
+** <ul>
|
|
+** <li> A database filename pointer created by the SQLite core and
|
|
+** passed into the xOpen() method of a VFS implemention, or
|
|
+** <li> A filename obtained from [sqlite3_db_filename()], or
|
|
+** <li> A new filename constructed using [sqlite3_create_filename()].
|
|
+** </ul>
|
|
+** If the F parameter is not one of the above, then the behavior is
|
|
+** undefined and probably undesirable. Older versions of SQLite were
|
|
+** more tolerant of invalid F parameters than newer versions.
|
|
+**
|
|
+** If F is a suitable filename (as described in the previous paragraph)
|
|
** and if P is the name of the query parameter, then
|
|
** sqlite3_uri_parameter(F,P) returns the value of the P
|
|
-** parameter if it exists or a NULL pointer if P does not appear as a
|
|
+** parameter if it exists or a NULL pointer if P does not appear as a
|
|
** query parameter on F. If P is a query parameter of F and it
|
|
** has no explicit value, then sqlite3_uri_parameter(F,P) returns
|
|
** a pointer to an empty string.
|
|
@@ -4588,7 +4030,7 @@ SQLITE_API int sqlite3_open_v2(
|
|
** parameter and returns true (1) or false (0) according to the value
|
|
** of P. The sqlite3_uri_boolean(F,P,B) routine returns true (1) if the
|
|
** value of query parameter P is one of "yes", "true", or "on" in any
|
|
-** case or if the value begins with a non-zero number. The
|
|
+** case or if the value begins with a non-zero number. The
|
|
** sqlite3_uri_boolean(F,P,B) routines returns false (0) if the value of
|
|
** query parameter P is one of "no", "false", or "off" in any case or
|
|
** if the value begins with a numeric zero. If P is not a query
|
|
@@ -4606,7 +4048,7 @@ SQLITE_API int sqlite3_open_v2(
|
|
** parameters minus 1. The N value is zero-based so N should be 0 to obtain
|
|
** the name of the first query parameter, 1 for the second parameter, and
|
|
** so forth.
|
|
-**
|
|
+**
|
|
** If F is a NULL pointer, then sqlite3_uri_parameter(F,P) returns NULL and
|
|
** sqlite3_uri_boolean(F,P,B) returns B. If F is not a NULL pointer and
|
|
** is not a database file pathname pointer that the SQLite core passed
|
|
@@ -4623,10 +4065,10 @@ SQLITE_API int sqlite3_open_v2(
|
|
**
|
|
** See the [URI filename] documentation for additional information.
|
|
*/
|
|
-SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam);
|
|
-SQLITE_API int sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault);
|
|
-SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int64);
|
|
-SQLITE_API const char *sqlite3_uri_key(const char *zFilename, int N);
|
|
+SQLITE_API const char *sqlite3_uri_parameter(sqlite3_filename z, const char *zParam);
|
|
+SQLITE_API int sqlite3_uri_boolean(sqlite3_filename z, const char *zParam, int bDefault);
|
|
+SQLITE_API sqlite3_int64 sqlite3_uri_int64(sqlite3_filename, const char*, sqlite3_int64);
|
|
+SQLITE_API const char *sqlite3_uri_key(sqlite3_filename z, int N);
|
|
|
|
/*
|
|
** CAPI3REF: Translate filenames
|
|
@@ -4655,21 +4097,93 @@ SQLITE_API const char *sqlite3_uri_key(const char *zFilename, int N);
|
|
** return value from [sqlite3_db_filename()], then the result is
|
|
** undefined and is likely a memory access violation.
|
|
*/
|
|
-SQLITE_API const char *sqlite3_filename_database(const char*);
|
|
-SQLITE_API const char *sqlite3_filename_journal(const char*);
|
|
-SQLITE_API const char *sqlite3_filename_wal(const char*);
|
|
+SQLITE_API const char *sqlite3_filename_database(sqlite3_filename);
|
|
+SQLITE_API const char *sqlite3_filename_journal(sqlite3_filename);
|
|
+SQLITE_API const char *sqlite3_filename_wal(sqlite3_filename);
|
|
|
|
+/*
|
|
+** CAPI3REF: Database File Corresponding To A Journal
|
|
+**
|
|
+** ^If X is the name of a rollback or WAL-mode journal file that is
|
|
+** passed into the xOpen method of [sqlite3_vfs], then
|
|
+** sqlite3_database_file_object(X) returns a pointer to the [sqlite3_file]
|
|
+** object that represents the main database file.
|
|
+**
|
|
+** This routine is intended for use in custom [VFS] implementations
|
|
+** only. It is not a general-purpose interface.
|
|
+** The argument sqlite3_file_object(X) must be a filename pointer that
|
|
+** has been passed into [sqlite3_vfs].xOpen method where the
|
|
+** flags parameter to xOpen contains one of the bits
|
|
+** [SQLITE_OPEN_MAIN_JOURNAL] or [SQLITE_OPEN_WAL]. Any other use
|
|
+** of this routine results in undefined and probably undesirable
|
|
+** behavior.
|
|
+*/
|
|
+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
|
|
+** are not useful outside of that context.
|
|
+**
|
|
+** The sqlite3_create_filename(D,J,W,N,P) allocates memory to hold a version of
|
|
+** database filename D with corresponding journal file J and WAL file W and
|
|
+** with N URI parameters key/values pairs in the array P. The result from
|
|
+** sqlite3_create_filename(D,J,W,N,P) is a pointer to a database filename that
|
|
+** is safe to pass to routines like:
|
|
+** <ul>
|
|
+** <li> [sqlite3_uri_parameter()],
|
|
+** <li> [sqlite3_uri_boolean()],
|
|
+** <li> [sqlite3_uri_int64()],
|
|
+** <li> [sqlite3_uri_key()],
|
|
+** <li> [sqlite3_filename_database()],
|
|
+** <li> [sqlite3_filename_journal()], or
|
|
+** <li> [sqlite3_filename_wal()].
|
|
+** </ul>
|
|
+** If a memory allocation error occurs, sqlite3_create_filename() might
|
|
+** return a NULL pointer. The memory obtained from sqlite3_create_filename(X)
|
|
+** must be released by a corresponding call to sqlite3_free_filename(Y).
|
|
+**
|
|
+** The P parameter in sqlite3_create_filename(D,J,W,N,P) should be an array
|
|
+** of 2*N pointers to strings. Each pair of pointers in this array corresponds
|
|
+** to a key and value for a query parameter. The P parameter may be a NULL
|
|
+** pointer if N is zero. None of the 2*N pointers in the P array may be
|
|
+** NULL pointers and key pointers should not be empty strings.
|
|
+** None of the D, J, or W parameters to sqlite3_create_filename(D,J,W,N,P) may
|
|
+** be NULL pointers, though they can be empty strings.
|
|
+**
|
|
+** The sqlite3_free_filename(Y) routine releases a memory allocation
|
|
+** previously obtained from sqlite3_create_filename(). Invoking
|
|
+** sqlite3_free_filename(Y) where Y is a NULL pointer is a harmless no-op.
|
|
+**
|
|
+** If the Y parameter to sqlite3_free_filename(Y) is anything other
|
|
+** than a NULL pointer or a pointer previously acquired from
|
|
+** sqlite3_create_filename(), then bad things such as heap
|
|
+** corruption or segfaults may occur. The value Y should not be
|
|
+** used again after sqlite3_free_filename(Y) has been called. This means
|
|
+** that if the [sqlite3_vfs.xOpen()] method of a VFS has been called using Y,
|
|
+** then the corresponding [sqlite3_module.xClose() method should also be
|
|
+** invoked prior to calling sqlite3_free_filename(Y).
|
|
+*/
|
|
+SQLITE_API sqlite3_filename sqlite3_create_filename(
|
|
+ const char *zDatabase,
|
|
+ const char *zJournal,
|
|
+ const char *zWal,
|
|
+ int nParam,
|
|
+ const char **azParam
|
|
+);
|
|
+SQLITE_API void sqlite3_free_filename(sqlite3_filename);
|
|
|
|
/*
|
|
** CAPI3REF: Error Codes And Messages
|
|
** METHOD: sqlite3
|
|
**
|
|
-** ^If the most recent sqlite3_* API call associated with
|
|
+** ^If the most recent sqlite3_* API call associated with
|
|
** [database connection] D failed, then the sqlite3_errcode(D) interface
|
|
** returns the numeric [result code] or [extended result code] for that
|
|
** API call.
|
|
** ^The sqlite3_extended_errcode()
|
|
-** interface is the same except that it always returns the
|
|
+** interface is the same except that it always returns the
|
|
** [extended result code] even when extended result codes are
|
|
** disabled.
|
|
**
|
|
@@ -4677,13 +4191,14 @@ SQLITE_API const char *sqlite3_filename_wal(const char*);
|
|
** sqlite3_extended_errcode() might change with each API call.
|
|
** Except, there are some interfaces that are guaranteed to never
|
|
** change the value of the error code. The error-code preserving
|
|
-** interfaces are:
|
|
+** interfaces include the following:
|
|
**
|
|
** <ul>
|
|
** <li> sqlite3_errcode()
|
|
** <li> sqlite3_extended_errcode()
|
|
** <li> sqlite3_errmsg()
|
|
** <li> sqlite3_errmsg16()
|
|
+** <li> sqlite3_error_offset()
|
|
** </ul>
|
|
**
|
|
** ^The sqlite3_errmsg() and sqlite3_errmsg16() return English-language
|
|
@@ -4698,6 +4213,13 @@ SQLITE_API const char *sqlite3_filename_wal(const char*);
|
|
** ^(Memory to hold the error message string is managed internally
|
|
** and must not be freed by the application)^.
|
|
**
|
|
+** ^If the most recent error references a specific token in the input
|
|
+** SQL, the sqlite3_error_offset() interface returns the byte offset
|
|
+** of the start of that token. ^The byte offset returned by
|
|
+** sqlite3_error_offset() assumes that the input SQL is UTF8.
|
|
+** ^If the most recent error does not reference a specific token in the input
|
|
+** SQL, then the sqlite3_error_offset() function returns -1.
|
|
+**
|
|
** When the serialized [threading mode] is in use, it might be the
|
|
** case that a second error occurs on a separate thread in between
|
|
** the time of the first error and the call to these interfaces.
|
|
@@ -4717,6 +4239,7 @@ SQLITE_API int sqlite3_extended_errcode(sqlite3 *db);
|
|
SQLITE_API const char *sqlite3_errmsg(sqlite3*);
|
|
SQLITE_API const void *sqlite3_errmsg16(sqlite3*);
|
|
SQLITE_API const char *sqlite3_errstr(int);
|
|
+SQLITE_API int sqlite3_error_offset(sqlite3 *db);
|
|
|
|
/*
|
|
** CAPI3REF: Prepared Statement Object
|
|
@@ -4726,7 +4249,7 @@ SQLITE_API const char *sqlite3_errstr(int);
|
|
** has been compiled into binary form and is ready to be evaluated.
|
|
**
|
|
** Think of each SQL statement as a separate computer program. The
|
|
-** original SQL text is source code. A prepared statement object
|
|
+** original SQL text is source code. A prepared statement object
|
|
** is the compiled object code. All SQL must be converted into a
|
|
** prepared statement before it can be run.
|
|
**
|
|
@@ -4756,7 +4279,7 @@ typedef struct sqlite3_stmt sqlite3_stmt;
|
|
** new limit for that construct.)^
|
|
**
|
|
** ^If the new limit is a negative number, the limit is unchanged.
|
|
-** ^(For each limit category SQLITE_LIMIT_<i>NAME</i> there is a
|
|
+** ^(For each limit category SQLITE_LIMIT_<i>NAME</i> there is a
|
|
** [limits | hard upper bound]
|
|
** set at compile-time by a C preprocessor macro called
|
|
** [limits | SQLITE_MAX_<i>NAME</i>].
|
|
@@ -4764,7 +4287,7 @@ typedef struct sqlite3_stmt sqlite3_stmt;
|
|
** ^Attempts to increase a limit above its hard upper bound are
|
|
** silently truncated to the hard upper bound.
|
|
**
|
|
-** ^Regardless of whether or not the limit was changed, the
|
|
+** ^Regardless of whether or not the limit was changed, the
|
|
** [sqlite3_limit()] interface returns the prior value of the limit.
|
|
** ^Hence, to find the current value of a limit without changing it,
|
|
** simply invoke this interface with the third parameter set to -1.
|
|
@@ -4869,7 +4392,7 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
|
|
** <dd>The SQLITE_PREPARE_PERSISTENT flag is a hint to the query planner
|
|
** that the prepared statement will be retained for a long time and
|
|
** probably reused many times.)^ ^Without this flag, [sqlite3_prepare_v3()]
|
|
-** and [sqlite3_prepare16_v3()] assume that the prepared statement will
|
|
+** and [sqlite3_prepare16_v3()] assume that the prepared statement will
|
|
** be used just once or at most a few times and then destroyed using
|
|
** [sqlite3_finalize()] relatively soon. The current implementation acts
|
|
** on this hint by avoiding the use of [lookaside memory] so as not to
|
|
@@ -4976,12 +4499,12 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
|
|
** </li>
|
|
**
|
|
** <li>
|
|
-** ^If the specific value bound to a [parameter | host parameter] in the
|
|
+** ^If the specific value bound to a [parameter | host parameter] in the
|
|
** WHERE clause might influence the choice of query plan for a statement,
|
|
-** then the statement will be automatically recompiled, as if there had been
|
|
+** then the statement will be automatically recompiled, as if there had been
|
|
** a schema change, on the first [sqlite3_step()] call following any change
|
|
-** to the [sqlite3_bind_text | bindings] of that [parameter].
|
|
-** ^The specific value of a WHERE-clause [parameter] might influence the
|
|
+** to the [sqlite3_bind_text | bindings] of that [parameter].
|
|
+** ^The specific value of a WHERE-clause [parameter] might influence the
|
|
** choice of query plan if the parameter is the left-hand side of a [LIKE]
|
|
** or [GLOB] operator or if the parameter is compared to an indexed column
|
|
** and the [SQLITE_ENABLE_STAT4] compile-time option is enabled.
|
|
@@ -5074,12 +4597,17 @@ SQLITE_API int sqlite3_prepare16_v3(
|
|
** are managed by SQLite and are automatically freed when the prepared
|
|
** statement is finalized.
|
|
** ^The string returned by sqlite3_expanded_sql(P), on the other hand,
|
|
-** is obtained from [sqlite3_malloc()] and must be free by the application
|
|
+** is obtained from [sqlite3_malloc()] and must be freed by the application
|
|
** by passing it to [sqlite3_free()].
|
|
+**
|
|
+** ^The sqlite3_normalized_sql() interface is only available if
|
|
+** the [SQLITE_ENABLE_NORMALIZE] compile-time option is defined.
|
|
*/
|
|
SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt);
|
|
SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt);
|
|
+#ifdef SQLITE_ENABLE_NORMALIZE
|
|
SQLITE_API const char *sqlite3_normalized_sql(sqlite3_stmt *pStmt);
|
|
+#endif
|
|
|
|
/*
|
|
** CAPI3REF: Determine If An SQL Statement Writes The Database
|
|
@@ -5090,8 +4618,8 @@ SQLITE_API const char *sqlite3_normalized_sql(sqlite3_stmt *pStmt);
|
|
** the content of the database file.
|
|
**
|
|
** Note that [application-defined SQL functions] or
|
|
-** [virtual tables] might change the database indirectly as a side effect.
|
|
-** ^(For example, if an application defines a function "eval()" that
|
|
+** [virtual tables] might change the database indirectly as a side effect.
|
|
+** ^(For example, if an application defines a function "eval()" that
|
|
** calls [sqlite3_exec()], then the following SQL statement would
|
|
** change the database file through side-effects:
|
|
**
|
|
@@ -5105,15 +4633,28 @@ SQLITE_API const char *sqlite3_normalized_sql(sqlite3_stmt *pStmt);
|
|
** ^Transaction control statements such as [BEGIN], [COMMIT], [ROLLBACK],
|
|
** [SAVEPOINT], and [RELEASE] cause sqlite3_stmt_readonly() to return true,
|
|
** since the statements themselves do not actually modify the database but
|
|
-** rather they control the timing of when other statements modify the
|
|
+** rather they control the timing of when other statements modify the
|
|
** database. ^The [ATTACH] and [DETACH] statements also cause
|
|
** sqlite3_stmt_readonly() to return true since, while those statements
|
|
-** change the configuration of a database connection, they do not make
|
|
+** change the configuration of a database connection, they do not make
|
|
** changes to the content of the database files on disk.
|
|
** ^The sqlite3_stmt_readonly() interface returns true for [BEGIN] since
|
|
** [BEGIN] merely sets internal flags, but the [BEGIN|BEGIN IMMEDIATE] and
|
|
** [BEGIN|BEGIN EXCLUSIVE] commands do touch the database and so
|
|
** sqlite3_stmt_readonly() returns false for those commands.
|
|
+**
|
|
+** ^This routine returns false if there is any possibility that the
|
|
+** statement might change the database file. ^A false return does
|
|
+** not guarantee that the statement will change the database file.
|
|
+** ^For example, an UPDATE statement might have a WHERE clause that
|
|
+** makes it a no-op, but the sqlite3_stmt_readonly() result would still
|
|
+** be false. ^Similarly, a CREATE TABLE IF NOT EXISTS statement is a
|
|
+** read-only no-op if the table already exists, but
|
|
+** sqlite3_stmt_readonly() still returns false for such a statement.
|
|
+**
|
|
+** ^If prepared statement X is an [EXPLAIN] or [EXPLAIN QUERY PLAN]
|
|
+** statement, then sqlite3_stmt_readonly(X) returns the same value as
|
|
+** if the EXPLAIN or EXPLAIN QUERY PLAN prefix were omitted.
|
|
*/
|
|
SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
|
|
|
|
@@ -5134,18 +4675,18 @@ SQLITE_API int sqlite3_stmt_isexplain(sqlite3_stmt *pStmt);
|
|
** METHOD: sqlite3_stmt
|
|
**
|
|
** ^The sqlite3_stmt_busy(S) interface returns true (non-zero) if the
|
|
-** [prepared statement] S has been stepped at least once using
|
|
+** [prepared statement] S has been stepped at least once using
|
|
** [sqlite3_step(S)] but has neither run to completion (returned
|
|
** [SQLITE_DONE] from [sqlite3_step(S)]) nor
|
|
** been reset using [sqlite3_reset(S)]. ^The sqlite3_stmt_busy(S)
|
|
-** interface returns false if S is a NULL pointer. If S is not a
|
|
+** interface returns false if S is a NULL pointer. If S is not a
|
|
** NULL pointer and is not a pointer to a valid [prepared statement]
|
|
** object, then the behavior is undefined and probably undesirable.
|
|
**
|
|
** This interface can be used in combination [sqlite3_next_stmt()]
|
|
-** to locate all prepared statements associated with a database
|
|
+** to locate all prepared statements associated with a database
|
|
** connection that are in need of being reset. This can be used,
|
|
-** for example, in diagnostic routines to search for prepared
|
|
+** for example, in diagnostic routines to search for prepared
|
|
** statements that are holding a transaction open.
|
|
*/
|
|
SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*);
|
|
@@ -5164,7 +4705,7 @@ SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*);
|
|
** will accept either a protected or an unprotected sqlite3_value.
|
|
** Every interface that accepts sqlite3_value arguments specifies
|
|
** whether or not it requires a protected sqlite3_value. The
|
|
-** [sqlite3_value_dup()] interface can be used to construct a new
|
|
+** [sqlite3_value_dup()] interface can be used to construct a new
|
|
** protected sqlite3_value from an unprotected sqlite3_value.
|
|
**
|
|
** The terms "protected" and "unprotected" refer to whether or not
|
|
@@ -5172,7 +4713,7 @@ SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*);
|
|
** sqlite3_value object but no mutex is held for an unprotected
|
|
** sqlite3_value object. If SQLite is compiled to be single-threaded
|
|
** (with [SQLITE_THREADSAFE=0] and with [sqlite3_threadsafe()] returning 0)
|
|
-** or if SQLite is run in one of reduced mutex modes
|
|
+** or if SQLite is run in one of reduced mutex modes
|
|
** [SQLITE_CONFIG_SINGLETHREAD] or [SQLITE_CONFIG_MULTITHREAD]
|
|
** then there is no distinction between protected and unprotected
|
|
** sqlite3_value objects and they can be used interchangeably. However,
|
|
@@ -5182,6 +4723,8 @@ SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*);
|
|
**
|
|
** ^The sqlite3_value objects that are passed as parameters into the
|
|
** implementation of [application-defined SQL functions] are protected.
|
|
+** ^The sqlite3_value objects returned by [sqlite3_vtab_rhs_value()]
|
|
+** are protected.
|
|
** ^The sqlite3_value object returned by
|
|
** [sqlite3_column_value()] is unprotected.
|
|
** Unprotected sqlite3_value objects may only be used as arguments
|
|
@@ -5241,12 +4784,30 @@ typedef struct sqlite3_context sqlite3_context;
|
|
** [sqlite3_bind_parameter_index()] API if desired. ^The index
|
|
** for "?NNN" parameters is the value of NNN.
|
|
** ^The NNN value must be between 1 and the [sqlite3_limit()]
|
|
-** parameter [SQLITE_LIMIT_VARIABLE_NUMBER] (default value: 999).
|
|
+** parameter [SQLITE_LIMIT_VARIABLE_NUMBER] (default value: 32766).
|
|
**
|
|
** ^The third argument is the value to bind to the parameter.
|
|
** ^If the third parameter to sqlite3_bind_text() or sqlite3_bind_text16()
|
|
** or sqlite3_bind_blob() is a NULL pointer then the fourth parameter
|
|
** is ignored and the end result is the same as sqlite3_bind_null().
|
|
+** ^If the third parameter to sqlite3_bind_text() is not NULL, then
|
|
+** it should be a pointer to well-formed UTF8 text.
|
|
+** ^If the third parameter to sqlite3_bind_text16() is not NULL, then
|
|
+** it should be a pointer to well-formed UTF16 text.
|
|
+** ^If the third parameter to sqlite3_bind_text64() is not NULL, then
|
|
+** it should be a pointer to a well-formed unicode string that is
|
|
+** either UTF8 if the sixth parameter is SQLITE_UTF8, or UTF16
|
|
+** otherwise.
|
|
+**
|
|
+** [[byte-order determination rules]] ^The byte-order of
|
|
+** UTF16 input text is determined by the byte-order mark (BOM, U+FEFF)
|
|
+** found in first character, which is removed, or in the absence of a BOM
|
|
+** the byte order is the native byte order of the host
|
|
+** machine for sqlite3_bind_text16() or the byte order specified in
|
|
+** the 6th parameter for sqlite3_bind_text64().)^
|
|
+** ^If UTF16 input text contains invalid unicode
|
|
+** characters, then SQLite might change those invalid characters
|
|
+** into the unicode replacement character: U+FFFD.
|
|
**
|
|
** ^(In those routines that have a fourth argument, its value is the
|
|
** number of bytes in the parameter. To be clear: the value is the
|
|
@@ -5260,23 +4821,27 @@ typedef struct sqlite3_context sqlite3_context;
|
|
** or sqlite3_bind_text16() or sqlite3_bind_text64() then
|
|
** that parameter must be the byte offset
|
|
** where the NUL terminator would occur assuming the string were NUL
|
|
-** terminated. If any NUL characters occur at byte offsets less than
|
|
+** terminated. If any NUL characters occurs at byte offsets less than
|
|
** the value of the fourth parameter then the resulting string value will
|
|
** contain embedded NULs. The result of expressions involving strings
|
|
** with embedded NULs is undefined.
|
|
**
|
|
-** ^The fifth argument to the BLOB and string binding interfaces
|
|
-** is a destructor used to dispose of the BLOB or
|
|
-** string after SQLite has finished with it. ^The destructor 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.
|
|
-** ^If the fifth argument is
|
|
-** the special value [SQLITE_STATIC], then SQLite assumes that the
|
|
-** information is in static, unmanaged space and does not need to be freed.
|
|
-** ^If the fifth argument has the value [SQLITE_TRANSIENT], then
|
|
-** SQLite makes its own private copy of the data immediately, before
|
|
-** the sqlite3_bind_*() routine returns.
|
|
+** ^The fifth argument to the BLOB and string binding interfaces controls
|
|
+** or indicates the lifetime of the object referenced by the third parameter.
|
|
+** These three options exist:
|
|
+** ^ (1) A destructor to dispose of the BLOB or string after SQLite has finished
|
|
+** 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
|
|
+** 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
|
|
+** bound to something else, whichever occurs sooner.
|
|
+** ^ (3) The constant, [SQLITE_TRANSIENT], may be passed to indicate that the
|
|
+** object is to be copied prior to the return from sqlite3_bind_*(). ^The
|
|
+** object and pointer to it must remain valid until then. ^SQLite will then
|
|
+** manage the lifetime of its private copy.
|
|
**
|
|
** ^The sixth argument to sqlite3_bind_text64() must be one of
|
|
** [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE]
|
|
@@ -5422,7 +4987,7 @@ SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt*);
|
|
** METHOD: sqlite3_stmt
|
|
**
|
|
** ^Return the number of columns in the result set returned by the
|
|
-** [prepared statement]. ^If this routine returns 0, that means the
|
|
+** [prepared statement]. ^If this routine returns 0, that means the
|
|
** [prepared statement] returns no data (for example an [UPDATE]).
|
|
** ^However, just because this routine returns a positive number does not
|
|
** mean that one or more rows of data will be returned. ^A SELECT statement
|
|
@@ -5604,7 +5169,7 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int);
|
|
** For all versions of SQLite up to and including 3.6.23.1, a call to
|
|
** [sqlite3_reset()] was required after sqlite3_step() returned anything
|
|
** other than [SQLITE_ROW] before any subsequent invocation of
|
|
-** sqlite3_step(). Failure to reset the prepared statement using
|
|
+** sqlite3_step(). Failure to reset the prepared statement using
|
|
** [sqlite3_reset()] would result in an [SQLITE_MISUSE] return from
|
|
** sqlite3_step(). But after [version 3.6.23.1] ([dateof:3.6.23.1],
|
|
** sqlite3_step() began
|
|
@@ -5695,7 +5260,7 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
|
|
** <tr><td><b>sqlite3_column_int64</b><td>→<td>64-bit INTEGER result
|
|
** <tr><td><b>sqlite3_column_text</b><td>→<td>UTF-8 TEXT result
|
|
** <tr><td><b>sqlite3_column_text16</b><td>→<td>UTF-16 TEXT result
|
|
-** <tr><td><b>sqlite3_column_value</b><td>→<td>The result as an
|
|
+** <tr><td><b>sqlite3_column_value</b><td>→<td>The result as an
|
|
** [sqlite3_value|unprotected sqlite3_value] object.
|
|
** <tr><td> <td> <td>
|
|
** <tr><td><b>sqlite3_column_bytes</b><td>→<td>Size of a BLOB
|
|
@@ -5743,7 +5308,7 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
|
|
** The return value of sqlite3_column_type() can be used to decide which
|
|
** of the first six interface should be used to extract the column value.
|
|
** The value returned by sqlite3_column_type() is only meaningful if no
|
|
-** automatic type conversions have occurred for the value in question.
|
|
+** automatic type conversions have occurred for the value in question.
|
|
** After a type conversion, the result of calling sqlite3_column_type()
|
|
** is undefined, though harmless. Future
|
|
** versions of SQLite may change the behavior of sqlite3_column_type()
|
|
@@ -5771,7 +5336,7 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
|
|
** the number of bytes in that string.
|
|
** ^If the result is NULL, then sqlite3_column_bytes16() returns zero.
|
|
**
|
|
-** ^The values returned by [sqlite3_column_bytes()] and
|
|
+** ^The values returned by [sqlite3_column_bytes()] and
|
|
** [sqlite3_column_bytes16()] do not include the zero terminators at the end
|
|
** of the string. ^For clarity: the values returned by
|
|
** [sqlite3_column_bytes()] and [sqlite3_column_bytes16()] are the number of
|
|
@@ -5781,6 +5346,10 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
|
|
** even empty strings, are always zero-terminated. ^The return
|
|
** value from sqlite3_column_blob() for a zero-length BLOB is a NULL pointer.
|
|
**
|
|
+** ^Strings returned by sqlite3_column_text16() always have the endianness
|
|
+** which is native to the platform, regardless of the text encoding set
|
|
+** for the database.
|
|
+**
|
|
** <b>Warning:</b> ^The object returned by [sqlite3_column_value()] is an
|
|
** [unprotected sqlite3_value] object. In a multithreaded environment,
|
|
** an unprotected sqlite3_value object may only be used safely with
|
|
@@ -5790,11 +5359,11 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
|
|
** to routines like [sqlite3_value_int()], [sqlite3_value_text()],
|
|
** or [sqlite3_value_bytes()], the behavior is not threadsafe.
|
|
** Hence, the sqlite3_column_value() interface
|
|
-** is normally only useful within the implementation of
|
|
+** is normally only useful within the implementation of
|
|
** [application-defined SQL functions] or [virtual tables], not within
|
|
** top-level application code.
|
|
**
|
|
-** The these routines may attempt to convert the datatype of the result.
|
|
+** These routines may attempt to convert the datatype of the result.
|
|
** ^For example, if the internal representation is FLOAT and a text result
|
|
** is requested, [sqlite3_snprintf()] is used internally to perform the
|
|
** conversion automatically. ^(The following table details the conversions
|
|
@@ -5819,7 +5388,7 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
|
|
** <tr><td> TEXT <td> BLOB <td> No change
|
|
** <tr><td> BLOB <td> INTEGER <td> [CAST] to INTEGER
|
|
** <tr><td> BLOB <td> FLOAT <td> [CAST] to REAL
|
|
-** <tr><td> BLOB <td> TEXT <td> Add a zero terminator if needed
|
|
+** <tr><td> BLOB <td> TEXT <td> [CAST] to TEXT, ensure zero terminator
|
|
** </table>
|
|
** </blockquote>)^
|
|
**
|
|
@@ -5965,8 +5534,8 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
|
|
** ^These functions (collectively known as "function creation routines")
|
|
** are used to add SQL functions or aggregates or to redefine the behavior
|
|
** of existing SQL functions or aggregates. The only differences between
|
|
-** the three "sqlite3_create_function*" routines are the text encoding
|
|
-** expected for the second parameter (the name of the function being
|
|
+** the three "sqlite3_create_function*" routines are the text encoding
|
|
+** expected for the second parameter (the name of the function being
|
|
** created) and the presence or absence of a destructor callback for
|
|
** the application data pointer. Function sqlite3_create_window_function()
|
|
** is similar, but allows the user to supply the extra callback functions
|
|
@@ -5980,7 +5549,7 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
|
|
** ^The second parameter is the name of the SQL function to be created or
|
|
** redefined. ^The length of the name is limited to 255 bytes in a UTF-8
|
|
** representation, exclusive of the zero-terminator. ^Note that the name
|
|
-** length limit is in UTF-8 bytes, not characters nor UTF-16 bytes.
|
|
+** length limit is in UTF-8 bytes, not characters nor UTF-16 bytes.
|
|
** ^Any attempt to create a function with a longer name
|
|
** will result in [SQLITE_MISUSE] being returned.
|
|
**
|
|
@@ -5995,7 +5564,7 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
|
|
** ^The fourth parameter, eTextRep, specifies what
|
|
** [SQLITE_UTF8 | text encoding] this SQL function prefers for
|
|
** its parameters. The application should set this parameter to
|
|
-** [SQLITE_UTF16LE] if the function implementation invokes
|
|
+** [SQLITE_UTF16LE] if the function implementation invokes
|
|
** [sqlite3_value_text16le()] on an input, or [SQLITE_UTF16BE] if the
|
|
** implementation invokes [sqlite3_value_text16be()] on an input, or
|
|
** [SQLITE_UTF16] if [sqlite3_value_text16()] is used, or [SQLITE_UTF8]
|
|
@@ -6018,17 +5587,15 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
|
|
** within VIEWs, TRIGGERs, CHECK constraints, generated column expressions,
|
|
** index expressions, or the WHERE clause of partial indexes.
|
|
**
|
|
-** <span style="background-color:#ffff90;">
|
|
** For best security, the [SQLITE_DIRECTONLY] flag is recommended for
|
|
** all application-defined SQL functions that do not need to be
|
|
** used inside of triggers, view, CHECK constraints, or other elements of
|
|
-** the database schema. This flags is especially recommended for SQL
|
|
+** the database schema. This flags is especially recommended for SQL
|
|
** functions that have side effects or reveal internal application state.
|
|
** Without this flag, an attacker might be able to modify the schema of
|
|
** a database file to include invocations of the function with parameters
|
|
** chosen by the attacker, which the application will then execute when
|
|
** the database file is opened and read.
|
|
-** </span>
|
|
**
|
|
** ^(The fifth parameter is an arbitrary pointer. The implementation of the
|
|
** function can gain access to this pointer using [sqlite3_user_data()].)^
|
|
@@ -6043,21 +5610,21 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
|
|
** SQL function or aggregate, pass NULL pointers for all three function
|
|
** callbacks.
|
|
**
|
|
-** ^The sixth, seventh, eighth and ninth parameters (xStep, xFinal, xValue
|
|
+** ^The sixth, seventh, eighth and ninth parameters (xStep, xFinal, xValue
|
|
** and xInverse) passed to sqlite3_create_window_function are pointers to
|
|
** C-language callbacks that implement the new function. xStep and xFinal
|
|
** must both be non-NULL. xValue and xInverse may either both be NULL, in
|
|
-** which case a regular aggregate function is created, or must both be
|
|
+** which case a regular aggregate function is created, or must both be
|
|
** non-NULL, in which case the new function may be used as either an aggregate
|
|
** or aggregate window function. More details regarding the implementation
|
|
-** of aggregate window functions are
|
|
+** of aggregate window functions are
|
|
** [user-defined window functions|available here].
|
|
**
|
|
** ^(If the final parameter to sqlite3_create_function_v2() or
|
|
** sqlite3_create_window_function() is not NULL, then it is destructor for
|
|
-** the application data pointer. The destructor is invoked when the function
|
|
-** is deleted, either by being overloaded or when the database connection
|
|
-** closes.)^ ^The destructor is also invoked if the call to
|
|
+** the application data pointer. The destructor is invoked when the function
|
|
+** is deleted, either by being overloaded or when the database connection
|
|
+** closes.)^ ^The destructor is also invoked if the call to
|
|
** sqlite3_create_function_v2() fails. ^When the destructor callback is
|
|
** invoked, it is passed a single argument which is a copy of the application
|
|
** data pointer which was the fifth parameter to sqlite3_create_function_v2().
|
|
@@ -6070,7 +5637,7 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
|
|
** nArg parameter is a better match than a function implementation with
|
|
** a negative nArg. ^A function where the preferred text encoding
|
|
** matches the database encoding is a better
|
|
-** match than a function where the encoding is different.
|
|
+** match than a function where the encoding is different.
|
|
** ^A function where the encoding difference is between UTF16le and UTF16be
|
|
** is a closer match than a function where the encoding difference is
|
|
** between UTF8 and UTF16.
|
|
@@ -6142,7 +5709,7 @@ SQLITE_API int sqlite3_create_window_function(
|
|
/*
|
|
** CAPI3REF: Function Flags
|
|
**
|
|
-** These constants may be ORed together with the
|
|
+** These constants may be ORed together with the
|
|
** [SQLITE_UTF8 | preferred text encoding] as the fourth argument
|
|
** to [sqlite3_create_function()], [sqlite3_create_function16()], or
|
|
** [sqlite3_create_function_v2()].
|
|
@@ -6158,16 +5725,27 @@ SQLITE_API int sqlite3_create_window_function(
|
|
** SQLite might also optimize deterministic functions by factoring them
|
|
** out of inner loops.
|
|
** </dd>
|
|
-**
|
|
+**
|
|
** [[SQLITE_DIRECTONLY]] <dt>SQLITE_DIRECTONLY</dt><dd>
|
|
** The SQLITE_DIRECTONLY flag means that the function may only be invoked
|
|
-** from top-level SQL, and cannot be used in VIEWs or TRIGGERs nor in
|
|
+** from top-level SQL, and cannot be used in VIEWs or TRIGGERs nor in
|
|
** schema structures such as [CHECK constraints], [DEFAULT clauses],
|
|
** [expression indexes], [partial indexes], or [generated columns].
|
|
-** The SQLITE_DIRECTONLY flags is a security feature which is recommended
|
|
-** for all [application-defined SQL functions], and especially for functions
|
|
-** that have side-effects or that could potentially leak sensitive
|
|
-** information.
|
|
+** <p>
|
|
+** The SQLITE_DIRECTONLY flag is recommended for any
|
|
+** [application-defined SQL function]
|
|
+** that has side-effects or that could potentially leak sensitive information.
|
|
+** This will prevent attacks in which an application is tricked
|
|
+** into using a database file that has had its schema surreptiously
|
|
+** modified to invoke the application-defined function in ways that are
|
|
+** harmful.
|
|
+** <p>
|
|
+** Some people say it is good practice to set SQLITE_DIRECTONLY on all
|
|
+** [application-defined SQL functions], regardless of whether or not they
|
|
+** are security sensitive, as doing so prevents those functions from being used
|
|
+** inside of the database schema, and thus ensures that the database
|
|
+** can be inspected and modified using generic tools (such as the [CLI])
|
|
+** that do not have access to the application-defined functions.
|
|
** </dd>
|
|
**
|
|
** [[SQLITE_INNOCUOUS]] <dt>SQLITE_INNOCUOUS</dt><dd>
|
|
@@ -6214,7 +5792,7 @@ SQLITE_API int sqlite3_create_window_function(
|
|
** DEPRECATED
|
|
**
|
|
** These functions are [deprecated]. In order to maintain
|
|
-** backwards compatibility with older code, these functions continue
|
|
+** backwards compatibility with older code, these functions continue
|
|
** to be supported. However, new applications should avoid
|
|
** the use of these functions. To encourage programmers to avoid
|
|
** these functions, we will not explain what they do.
|
|
@@ -6282,11 +5860,11 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6
|
|
** sqlite3_value_text16be() and sqlite3_value_text16le() interfaces
|
|
** extract UTF-16 strings as big-endian and little-endian respectively.
|
|
**
|
|
-** ^If [sqlite3_value] object V was initialized
|
|
+** ^If [sqlite3_value] object V was initialized
|
|
** using [sqlite3_bind_pointer(S,I,P,X,D)] or [sqlite3_result_pointer(C,P,X,D)]
|
|
** and if X and Y are strings that compare equal according to strcmp(X,Y),
|
|
** then sqlite3_value_pointer(V,Y) will return the pointer P. ^Otherwise,
|
|
-** sqlite3_value_pointer(V,Y) returns a NULL. The sqlite3_bind_pointer()
|
|
+** sqlite3_value_pointer(V,Y) returns a NULL. The sqlite3_bind_pointer()
|
|
** routine is part of the [pointer passing interface] added for SQLite 3.20.0.
|
|
**
|
|
** ^(The sqlite3_value_type(V) interface returns the
|
|
@@ -6373,6 +5951,28 @@ SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*);
|
|
SQLITE_API int sqlite3_value_nochange(sqlite3_value*);
|
|
SQLITE_API int sqlite3_value_frombind(sqlite3_value*);
|
|
|
|
+/*
|
|
+** CAPI3REF: Report the internal text encoding state of an sqlite3_value object
|
|
+** METHOD: sqlite3_value
|
|
+**
|
|
+** ^(The sqlite3_value_encoding(X) interface returns one of [SQLITE_UTF8],
|
|
+** [SQLITE_UTF16BE], or [SQLITE_UTF16LE] according to the current text encoding
|
|
+** of the value X, assuming that X has type TEXT.)^ If sqlite3_value_type(X)
|
|
+** returns something other than SQLITE_TEXT, then the return value from
|
|
+** sqlite3_value_encoding(X) is meaningless. ^Calls to
|
|
+** [sqlite3_value_text(X)], [sqlite3_value_text16(X)], [sqlite3_value_text16be(X)],
|
|
+** [sqlite3_value_text16le(X)], [sqlite3_value_bytes(X)], or
|
|
+** [sqlite3_value_bytes16(X)] might change the encoding of the value X and
|
|
+** thus change the return from subsequent calls to sqlite3_value_encoding(X).
|
|
+**
|
|
+** This routine is intended for used by applications that test and validate
|
|
+** the SQLite implementation. This routine is inquiring about the opaque
|
|
+** internal state of an [sqlite3_value] object. Ordinary applications should
|
|
+** not need to know what the internal state of an sqlite3_value object is and
|
|
+** hence should not need to use this interface.
|
|
+*/
|
|
+SQLITE_API int sqlite3_value_encoding(sqlite3_value*);
|
|
+
|
|
/*
|
|
** CAPI3REF: Finding The Subtype Of SQL Values
|
|
** METHOD: sqlite3_value
|
|
@@ -6393,7 +5993,8 @@ SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value*);
|
|
** object D and returns a pointer to that copy. ^The [sqlite3_value] returned
|
|
** is a [protected sqlite3_value] object even if the input is not.
|
|
** ^The sqlite3_value_dup(V) interface returns NULL if V is NULL or if a
|
|
-** memory allocation fails.
|
|
+** memory allocation fails. ^If V is a [pointer value], then the result
|
|
+** of sqlite3_value_dup(V) is a NULL value.
|
|
**
|
|
** ^The sqlite3_value_free(V) interface frees an [sqlite3_value] object
|
|
** previously obtained from [sqlite3_value_dup()]. ^If V is a NULL pointer
|
|
@@ -6409,7 +6010,7 @@ SQLITE_API void sqlite3_value_free(sqlite3_value*);
|
|
** Implementations of aggregate SQL functions use this
|
|
** routine to allocate memory for storing their state.
|
|
**
|
|
-** ^The first time the sqlite3_aggregate_context(C,N) routine is called
|
|
+** ^The first time the sqlite3_aggregate_context(C,N) routine is called
|
|
** for a particular aggregate function, SQLite allocates
|
|
** N bytes of memory, zeroes out that memory, and returns a pointer
|
|
** to the new memory. ^On second and subsequent calls to
|
|
@@ -6422,19 +6023,19 @@ SQLITE_API void sqlite3_value_free(sqlite3_value*);
|
|
** In those cases, sqlite3_aggregate_context() might be called for the
|
|
** first time from within xFinal().)^
|
|
**
|
|
-** ^The sqlite3_aggregate_context(C,N) routine returns a NULL pointer
|
|
+** ^The sqlite3_aggregate_context(C,N) routine returns a NULL pointer
|
|
** when first called if N is less than or equal to zero or if a memory
|
|
-** allocate error occurs.
|
|
+** allocation error occurs.
|
|
**
|
|
** ^(The amount of space allocated by sqlite3_aggregate_context(C,N) is
|
|
** determined by the N parameter on first successful call. Changing the
|
|
-** value of N in any subsequents call to sqlite3_aggregate_context() within
|
|
+** value of N in any subsequent call to sqlite3_aggregate_context() within
|
|
** the same aggregate function instance will not resize the memory
|
|
** allocation.)^ Within the xFinal callback, it is customary to set
|
|
-** N=0 in calls to sqlite3_aggregate_context(C,N) so that no
|
|
+** N=0 in calls to sqlite3_aggregate_context(C,N) so that no
|
|
** pointless memory allocations occur.
|
|
**
|
|
-** ^SQLite automatically frees the memory allocated by
|
|
+** ^SQLite automatically frees the memory allocated by
|
|
** sqlite3_aggregate_context() when the aggregate query concludes.
|
|
**
|
|
** The first parameter must be a copy of the
|
|
@@ -6484,7 +6085,7 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
|
|
** 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.
|
|
+** metadata associated with the pattern string.
|
|
** Then as long as the pattern string remains the same,
|
|
** the compiled regular expression can be reused on multiple
|
|
** invocations of the same function.
|
|
@@ -6510,10 +6111,10 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
|
|
** SQL statement)^, or
|
|
** <li> ^(when sqlite3_set_auxdata() is invoked again on the same
|
|
** parameter)^, or
|
|
-** <li> ^(during the original sqlite3_set_auxdata() call when a memory
|
|
+** <li> ^(during the original sqlite3_set_auxdata() call when a memory
|
|
** allocation error occurs.)^ </ul>
|
|
**
|
|
-** Note the last bullet in particular. The destructor X in
|
|
+** Note the last bullet in particular. The destructor X in
|
|
** sqlite3_set_auxdata(C,N,P,X) might be called immediately, before the
|
|
** sqlite3_set_auxdata() interface even returns. Hence sqlite3_set_auxdata()
|
|
** should be called near the end of the function implementation and the
|
|
@@ -6585,8 +6186,9 @@ typedef void (*sqlite3_destructor_type)(void*);
|
|
** 2nd parameter of sqlite3_result_error() or sqlite3_result_error16()
|
|
** as the text of an error message. ^SQLite interprets the error
|
|
** message string from sqlite3_result_error() as UTF-8. ^SQLite
|
|
-** interprets the string from sqlite3_result_error16() as UTF-16 in native
|
|
-** byte order. ^If the third parameter to sqlite3_result_error()
|
|
+** interprets the string from sqlite3_result_error16() as UTF-16 using
|
|
+** the same [byte-order determination rules] as [sqlite3_bind_text16()].
|
|
+** ^If the third parameter to sqlite3_result_error()
|
|
** or sqlite3_result_error16() is negative then SQLite takes as the error
|
|
** message all text up through the first zero character.
|
|
** ^If the third parameter to sqlite3_result_error() or
|
|
@@ -6628,9 +6230,10 @@ typedef void (*sqlite3_destructor_type)(void*);
|
|
** of [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE].
|
|
** ^SQLite takes the text result from the application from
|
|
** the 2nd parameter of the sqlite3_result_text* interfaces.
|
|
-** ^If the 3rd parameter to the sqlite3_result_text* interfaces
|
|
-** is negative, then SQLite takes result text from the 2nd parameter
|
|
-** through the first zero character.
|
|
+** ^If the 3rd parameter to any of the sqlite3_result_text* interfaces
|
|
+** other than sqlite3_result_text64() is negative, then SQLite computes
|
|
+** the string length itself by searching the 2nd parameter for the first
|
|
+** zero character.
|
|
** ^If the 3rd parameter to the sqlite3_result_text* interfaces
|
|
** is non-negative, then as many bytes (not characters) of the text
|
|
** pointed to by the 2nd parameter are taken as the application-defined
|
|
@@ -6654,6 +6257,25 @@ typedef void (*sqlite3_destructor_type)(void*);
|
|
** then SQLite makes a copy of the result into space obtained
|
|
** from [sqlite3_malloc()] before it returns.
|
|
**
|
|
+** ^For the sqlite3_result_text16(), sqlite3_result_text16le(), and
|
|
+** sqlite3_result_text16be() routines, and for sqlite3_result_text64()
|
|
+** when the encoding is not UTF8, if the input UTF16 begins with a
|
|
+** byte-order mark (BOM, U+FEFF) then the BOM is removed from the
|
|
+** string and the rest of the string is interpreted according to the
|
|
+** byte-order specified by the BOM. ^The byte-order specified by
|
|
+** the BOM at the beginning of the text overrides the byte-order
|
|
+** specified by the interface procedure. ^So, for example, if
|
|
+** sqlite3_result_text16le() is invoked with text that begins
|
|
+** with bytes 0xfe, 0xff (a big-endian byte-order mark) then the
|
|
+** first two bytes of input are skipped and the remaining input
|
|
+** is interpreted as UTF16BE text.
|
|
+**
|
|
+** ^For UTF16 input text to the sqlite3_result_text16(),
|
|
+** sqlite3_result_text16be(), sqlite3_result_text16le(), and
|
|
+** sqlite3_result_text64() routines, if the text contains invalid
|
|
+** UTF16 characters, the invalid characters might be converted
|
|
+** into the unicode replacement character, U+FFFD.
|
|
+**
|
|
** ^The sqlite3_result_value() interface sets the result of
|
|
** the application-defined function to be a copy of the
|
|
** [unprotected sqlite3_value] object specified by the 2nd parameter. ^The
|
|
@@ -6666,7 +6288,7 @@ typedef void (*sqlite3_destructor_type)(void*);
|
|
**
|
|
** ^The sqlite3_result_pointer(C,P,T,D) interface sets the result to an
|
|
** SQL NULL value, just like [sqlite3_result_null(C)], except that it
|
|
-** also associates the host-language pointer P or type T with that
|
|
+** also associates the host-language pointer P or type T with that
|
|
** NULL value such that the pointer can be retrieved within an
|
|
** [application-defined SQL function] using [sqlite3_value_pointer()].
|
|
** ^If the D parameter is not NULL, then it is a pointer to a destructor
|
|
@@ -6708,8 +6330,8 @@ SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n);
|
|
** METHOD: sqlite3_context
|
|
**
|
|
** The sqlite3_result_subtype(C,T) function causes the subtype of
|
|
-** the result from the [application-defined SQL function] with
|
|
-** [sqlite3_context] C to be the value T. Only the lower 8 bits
|
|
+** the result from the [application-defined SQL function] with
|
|
+** [sqlite3_context] C to be the value T. Only the lower 8 bits
|
|
** of the subtype T are preserved in current versions of SQLite;
|
|
** higher order bits are discarded.
|
|
** The number of subtype bytes preserved by SQLite might increase
|
|
@@ -6756,7 +6378,7 @@ SQLITE_API void sqlite3_result_subtype(sqlite3_context*,unsigned int);
|
|
** deleted. ^When all collating functions having the same name are deleted,
|
|
** that collation is no longer usable.
|
|
**
|
|
-** ^The collating function callback is invoked with a copy of the pArg
|
|
+** ^The collating function callback is invoked with a copy of the pArg
|
|
** application data pointer and with two strings in the encoding specified
|
|
** by the eTextRep argument. The two integer parameters to the collating
|
|
** function callback are the length of the two strings, in bytes. The collating
|
|
@@ -6787,36 +6409,36 @@ SQLITE_API void sqlite3_result_subtype(sqlite3_context*,unsigned int);
|
|
** calls to the collation creation functions or when the
|
|
** [database connection] is closed using [sqlite3_close()].
|
|
**
|
|
-** ^The xDestroy callback is <u>not</u> called if the
|
|
+** ^The xDestroy callback is <u>not</u> called if the
|
|
** sqlite3_create_collation_v2() function fails. Applications that invoke
|
|
-** sqlite3_create_collation_v2() with a non-NULL xDestroy argument should
|
|
+** sqlite3_create_collation_v2() with a non-NULL xDestroy argument should
|
|
** check the return code and dispose of the application data pointer
|
|
** themselves rather than expecting SQLite to deal with it for them.
|
|
-** This is different from every other SQLite interface. The inconsistency
|
|
-** is unfortunate but cannot be changed without breaking backwards
|
|
+** This is different from every other SQLite interface. The inconsistency
|
|
+** is unfortunate but cannot be changed without breaking backwards
|
|
** compatibility.
|
|
**
|
|
** See also: [sqlite3_collation_needed()] and [sqlite3_collation_needed16()].
|
|
*/
|
|
SQLITE_API int sqlite3_create_collation(
|
|
- sqlite3*,
|
|
- const char *zName,
|
|
- int eTextRep,
|
|
+ sqlite3*,
|
|
+ const char *zName,
|
|
+ int eTextRep,
|
|
void *pArg,
|
|
int(*xCompare)(void*,int,const void*,int,const void*)
|
|
);
|
|
SQLITE_API int sqlite3_create_collation_v2(
|
|
- sqlite3*,
|
|
- const char *zName,
|
|
- int eTextRep,
|
|
+ sqlite3*,
|
|
+ const char *zName,
|
|
+ int eTextRep,
|
|
void *pArg,
|
|
int(*xCompare)(void*,int,const void*,int,const void*),
|
|
void(*xDestroy)(void*)
|
|
);
|
|
SQLITE_API int sqlite3_create_collation16(
|
|
- sqlite3*,
|
|
+ sqlite3*,
|
|
const void *zName,
|
|
- int eTextRep,
|
|
+ int eTextRep,
|
|
void *pArg,
|
|
int(*xCompare)(void*,int,const void*,int,const void*)
|
|
);
|
|
@@ -6849,64 +6471,19 @@ SQLITE_API int sqlite3_create_collation16(
|
|
** [sqlite3_create_collation_v2()].
|
|
*/
|
|
SQLITE_API int sqlite3_collation_needed(
|
|
- sqlite3*,
|
|
- void*,
|
|
+ sqlite3*,
|
|
+ void*,
|
|
void(*)(void*,sqlite3*,int eTextRep,const char*)
|
|
);
|
|
SQLITE_API int sqlite3_collation_needed16(
|
|
- sqlite3*,
|
|
+ sqlite3*,
|
|
void*,
|
|
void(*)(void*,sqlite3*,int eTextRep,const void*)
|
|
);
|
|
|
|
-#ifdef SQLITE_HAS_CODEC
|
|
-/*
|
|
-** Specify the key for an encrypted database. This routine should be
|
|
-** called right after sqlite3_open().
|
|
-**
|
|
-** The code to implement this API is not available in the public release
|
|
-** of SQLite.
|
|
-*/
|
|
-SQLITE_API int sqlite3_key(
|
|
- sqlite3 *db, /* Database to be rekeyed */
|
|
- const void *pKey, int nKey /* The key */
|
|
-);
|
|
-SQLITE_API int sqlite3_key_v2(
|
|
- sqlite3 *db, /* Database to be rekeyed */
|
|
- const char *zDbName, /* Name of the database */
|
|
- const void *pKey, int nKey /* The key */
|
|
-);
|
|
-
|
|
-/*
|
|
-** Change the key on an open database. If the current database is not
|
|
-** encrypted, this routine will encrypt it. If pNew==0 or nNew==0, the
|
|
-** database is decrypted.
|
|
-**
|
|
-** The code to implement this API is not available in the public release
|
|
-** of SQLite.
|
|
-*/
|
|
-SQLITE_API int sqlite3_rekey(
|
|
- sqlite3 *db, /* Database to be rekeyed */
|
|
- const void *pKey, int nKey /* The new key */
|
|
-);
|
|
-SQLITE_API int sqlite3_rekey_v2(
|
|
- sqlite3 *db, /* Database to be rekeyed */
|
|
- const char *zDbName, /* Name of the database */
|
|
- const void *pKey, int nKey /* The new key */
|
|
-);
|
|
-
|
|
-/*
|
|
-** Specify the activation key for a SEE database. Unless
|
|
-** activated, none of the SEE routines will work.
|
|
-*/
|
|
-SQLITE_API void sqlite3_activate_see(
|
|
- const char *zPassPhrase /* Activation phrase */
|
|
-);
|
|
-#endif
|
|
-
|
|
#ifdef SQLITE_ENABLE_CEROD
|
|
/*
|
|
-** Specify the activation key for a CEROD database. Unless
|
|
+** Specify the activation key for a CEROD database. Unless
|
|
** activated, none of the CEROD routines will work.
|
|
*/
|
|
SQLITE_API void sqlite3_activate_cerod(
|
|
@@ -6962,7 +6539,7 @@ SQLITE_API int sqlite3_sleep(int);
|
|
** ^The [temp_store_directory pragma] may modify this variable and cause
|
|
** it to point to memory obtained from [sqlite3_malloc]. ^Furthermore,
|
|
** the [temp_store_directory pragma] always assumes that any string
|
|
-** that this variable points to is held in memory obtained from
|
|
+** that this variable points to is held in memory obtained from
|
|
** [sqlite3_malloc] and the pragma may attempt to free that memory
|
|
** using [sqlite3_free].
|
|
** Hence, if this variable is modified directly, either it should be
|
|
@@ -7019,7 +6596,7 @@ SQLITE_API char *sqlite3_temp_directory;
|
|
** ^The [data_store_directory pragma] may modify this variable and cause
|
|
** it to point to memory obtained from [sqlite3_malloc]. ^Furthermore,
|
|
** the [data_store_directory pragma] always assumes that any string
|
|
-** that this variable points to is held in memory obtained from
|
|
+** that this variable points to is held in memory obtained from
|
|
** [sqlite3_malloc] and the pragma may attempt to free that memory
|
|
** using [sqlite3_free].
|
|
** Hence, if this variable is modified directly, either it should be
|
|
@@ -7100,6 +6677,28 @@ SQLITE_API int sqlite3_get_autocommit(sqlite3*);
|
|
*/
|
|
SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*);
|
|
|
|
+/*
|
|
+** CAPI3REF: Return The Schema Name For A Database Connection
|
|
+** METHOD: sqlite3
|
|
+**
|
|
+** ^The sqlite3_db_name(D,N) interface returns a pointer to the schema name
|
|
+** for the N-th database on database connection D, or a NULL pointer of N is
|
|
+** out of range. An N value of 0 means the main database file. An N of 1 is
|
|
+** the "temp" schema. Larger values of N correspond to various ATTACH-ed
|
|
+** databases.
|
|
+**
|
|
+** Space to hold the string that is returned by sqlite3_db_name() is managed
|
|
+** by SQLite itself. The string might be deallocated by any operation that
|
|
+** changes the schema, including [ATTACH] or [DETACH] or calls to
|
|
+** [sqlite3_serialize()] or [sqlite3_deserialize()], even operations that
|
|
+** occur on a different thread. Applications that need to
|
|
+** remember the string long-term should make their own copy. Applications that
|
|
+** are accessing the same database connection simultaneously on multiple
|
|
+** threads should mutex-protect calls to this API and should make their own
|
|
+** private copy of the result prior to releasing the mutex.
|
|
+*/
|
|
+SQLITE_API const char *sqlite3_db_name(sqlite3 *db, int N);
|
|
+
|
|
/*
|
|
** CAPI3REF: Return The Filename For A Database Connection
|
|
** METHOD: sqlite3
|
|
@@ -7130,7 +6729,7 @@ SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*);
|
|
** <li> [sqlite3_filename_wal()]
|
|
** </ul>
|
|
*/
|
|
-SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName);
|
|
+SQLITE_API sqlite3_filename sqlite3_db_filename(sqlite3 *db, const char *zDbName);
|
|
|
|
/*
|
|
** CAPI3REF: Determine if a database is read-only
|
|
@@ -7142,6 +6741,57 @@ SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName);
|
|
*/
|
|
SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName);
|
|
|
|
+/*
|
|
+** CAPI3REF: Determine the transaction state of a database
|
|
+** METHOD: sqlite3
|
|
+**
|
|
+** ^The sqlite3_txn_state(D,S) interface returns the current
|
|
+** [transaction state] of schema S in database connection D. ^If S is NULL,
|
|
+** then the highest transaction state of any schema on database connection D
|
|
+** is returned. Transaction states are (in order of lowest to highest):
|
|
+** <ol>
|
|
+** <li value="0"> SQLITE_TXN_NONE
|
|
+** <li value="1"> SQLITE_TXN_READ
|
|
+** <li value="2"> SQLITE_TXN_WRITE
|
|
+** </ol>
|
|
+** ^If the S argument to sqlite3_txn_state(D,S) is not the name of
|
|
+** a valid schema, then -1 is returned.
|
|
+*/
|
|
+SQLITE_API int sqlite3_txn_state(sqlite3*,const char *zSchema);
|
|
+
|
|
+/*
|
|
+** CAPI3REF: Allowed return values from [sqlite3_txn_state()]
|
|
+** KEYWORDS: {transaction state}
|
|
+**
|
|
+** These constants define the current transaction state of a database file.
|
|
+** ^The [sqlite3_txn_state(D,S)] interface returns one of these
|
|
+** constants in order to describe the transaction state of schema S
|
|
+** in [database connection] D.
|
|
+**
|
|
+** <dl>
|
|
+** [[SQLITE_TXN_NONE]] <dt>SQLITE_TXN_NONE</dt>
|
|
+** <dd>The SQLITE_TXN_NONE state means that no transaction is currently
|
|
+** pending.</dd>
|
|
+**
|
|
+** [[SQLITE_TXN_READ]] <dt>SQLITE_TXN_READ</dt>
|
|
+** <dd>The SQLITE_TXN_READ state means that the database is currently
|
|
+** in a read transaction. Content has been read from the database file
|
|
+** but nothing in the database file has changed. The transaction state
|
|
+** will advanced to SQLITE_TXN_WRITE if any changes occur and there are
|
|
+** no other conflicting concurrent write transactions. The transaction
|
|
+** state will revert to SQLITE_TXN_NONE following a [ROLLBACK] or
|
|
+** [COMMIT].</dd>
|
|
+**
|
|
+** [[SQLITE_TXN_WRITE]] <dt>SQLITE_TXN_WRITE</dt>
|
|
+** <dd>The SQLITE_TXN_WRITE state means that the database is currently
|
|
+** in a write transaction. Content has been written to the database file
|
|
+** but has not yet committed. The transaction state will change to
|
|
+** to SQLITE_TXN_NONE at the next [ROLLBACK] or [COMMIT].</dd>
|
|
+*/
|
|
+#define SQLITE_TXN_NONE 0
|
|
+#define SQLITE_TXN_READ 1
|
|
+#define SQLITE_TXN_WRITE 2
|
|
+
|
|
/*
|
|
** CAPI3REF: Find the next prepared statement
|
|
** METHOD: sqlite3
|
|
@@ -7208,6 +6858,72 @@ SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt);
|
|
SQLITE_API void *sqlite3_commit_hook(sqlite3*, int(*)(void*), void*);
|
|
SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
|
|
|
|
+/*
|
|
+** CAPI3REF: Autovacuum Compaction Amount Callback
|
|
+** METHOD: sqlite3
|
|
+**
|
|
+** ^The sqlite3_autovacuum_pages(D,C,P,X) interface registers a callback
|
|
+** function C that is invoked prior to each autovacuum of the database
|
|
+** file. ^The callback is passed a copy of the generic data pointer (P),
|
|
+** the schema-name of the attached database that is being autovacuumed,
|
|
+** the size of the database file in pages, the number of free pages,
|
|
+** and the number of bytes per page, respectively. The callback should
|
|
+** return the number of free pages that should be removed by the
|
|
+** autovacuum. ^If the callback returns zero, then no autovacuum happens.
|
|
+** ^If the value returned is greater than or equal to the number of
|
|
+** free pages, then a complete autovacuum happens.
|
|
+**
|
|
+** <p>^If there are multiple ATTACH-ed database files that are being
|
|
+** modified as part of a transaction commit, then the autovacuum pages
|
|
+** callback is invoked separately for each file.
|
|
+**
|
|
+** <p><b>The callback is not reentrant.</b> The callback function should
|
|
+** not attempt to invoke any other SQLite interface. If it does, bad
|
|
+** things may happen, including segmentation faults and corrupt database
|
|
+** files. The callback function should be a simple function that
|
|
+** does some arithmetic on its input parameters and returns a result.
|
|
+**
|
|
+** ^The X parameter to sqlite3_autovacuum_pages(D,C,P,X) is an optional
|
|
+** destructor for the P parameter. ^If X is not NULL, then X(P) is
|
|
+** invoked whenever the database connection closes or when the callback
|
|
+** is overwritten by another invocation of sqlite3_autovacuum_pages().
|
|
+**
|
|
+** <p>^There is only one autovacuum pages callback per database connection.
|
|
+** ^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
|
|
+** 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
|
|
+** return codes might be added in future releases.
|
|
+**
|
|
+** <p>If no autovacuum pages callback is specified (the usual case) or
|
|
+** a NULL pointer is provided for the callback,
|
|
+** then the default behavior is to vacuum all free pages. So, in other
|
|
+** words, the default behavior is the same as if the callback function
|
|
+** were something like this:
|
|
+**
|
|
+** <blockquote><pre>
|
|
+** unsigned int demonstration_autovac_pages_callback(
|
|
+** void *pClientData,
|
|
+** const char *zSchema,
|
|
+** unsigned int nDbPage,
|
|
+** unsigned int nFreePage,
|
|
+** unsigned int nBytePerPage
|
|
+** ){
|
|
+** return nFreePage;
|
|
+** }
|
|
+** </pre></blockquote>
|
|
+*/
|
|
+SQLITE_API int sqlite3_autovacuum_pages(
|
|
+ sqlite3 *db,
|
|
+ unsigned int(*)(void*,const char*,unsigned int,unsigned int,unsigned int),
|
|
+ void*,
|
|
+ void(*)(void*)
|
|
+);
|
|
+
|
|
+
|
|
/*
|
|
** CAPI3REF: Data Change Notification Callbacks
|
|
** METHOD: sqlite3
|
|
@@ -7232,7 +6948,7 @@ SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
|
|
** ^In the case of an update, this is the [rowid] after the update takes place.
|
|
**
|
|
** ^(The update hook is not invoked when internal system tables are
|
|
-** modified (i.e. sqlite_master and sqlite_sequence).)^
|
|
+** modified (i.e. sqlite_sequence).)^
|
|
** ^The update hook is not invoked when [WITHOUT ROWID] tables are modified.
|
|
**
|
|
** ^In the current implementation, the update hook
|
|
@@ -7258,7 +6974,7 @@ SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
|
|
** and [sqlite3_preupdate_hook()] interfaces.
|
|
*/
|
|
SQLITE_API void *sqlite3_update_hook(
|
|
- sqlite3*,
|
|
+ sqlite3*,
|
|
void(*)(void *,int ,char const *,char const *,sqlite3_int64),
|
|
void*
|
|
);
|
|
@@ -7271,8 +6987,13 @@ SQLITE_API void *sqlite3_update_hook(
|
|
** to the same database. Sharing is enabled if the argument is true
|
|
** and disabled if the argument is false.)^
|
|
**
|
|
+** This interface is omitted if SQLite is compiled with
|
|
+** [-DSQLITE_OMIT_SHARED_CACHE]. The [-DSQLITE_OMIT_SHARED_CACHE]
|
|
+** compile-time option is recommended because the
|
|
+** [use of shared cache mode is discouraged].
|
|
+**
|
|
** ^Cache sharing is enabled and disabled for an entire process.
|
|
-** This is a change as of SQLite [version 3.5.0] ([dateof:3.5.0]).
|
|
+** This is a change as of SQLite [version 3.5.0] ([dateof:3.5.0]).
|
|
** In prior versions of SQLite,
|
|
** sharing was enabled or disabled for each thread separately.
|
|
**
|
|
@@ -7293,8 +7014,8 @@ SQLITE_API void *sqlite3_update_hook(
|
|
** with the [SQLITE_OPEN_SHAREDCACHE] flag.
|
|
**
|
|
** Note: This method is disabled on MacOS X 10.7 and iOS version 5.0
|
|
-** and will always return SQLITE_MISUSE. On those systems,
|
|
-** shared cache mode should be enabled per-database connection via
|
|
+** and will always return SQLITE_MISUSE. On those systems,
|
|
+** shared cache mode should be enabled per-database connection via
|
|
** [sqlite3_open_v2()] with [SQLITE_OPEN_SHAREDCACHE].
|
|
**
|
|
** This interface is threadsafe on processors where writing a
|
|
@@ -7347,7 +7068,7 @@ SQLITE_API int sqlite3_db_release_memory(sqlite3*);
|
|
** as heap memory usages approaches the limit.
|
|
** ^The soft heap limit is "soft" because even though SQLite strives to stay
|
|
** below the limit, it will exceed the limit rather than generate
|
|
-** an [SQLITE_NOMEM] error. In other words, the soft heap limit
|
|
+** an [SQLITE_NOMEM] error. In other words, the soft heap limit
|
|
** is advisory only.
|
|
**
|
|
** ^The sqlite3_hard_heap_limit64(N) interface sets a hard upper bound of
|
|
@@ -7369,7 +7090,7 @@ SQLITE_API int sqlite3_db_release_memory(sqlite3*);
|
|
** ^The soft heap limit may not be greater than the hard heap limit.
|
|
** ^If the hard heap limit is enabled and if sqlite3_soft_heap_limit(N)
|
|
** is invoked with a value of N that is greater than the hard heap limit,
|
|
-** the the soft heap limit is set to the value of the hard heap limit.
|
|
+** the soft heap limit is set to the value of the hard heap limit.
|
|
** ^The soft heap limit is automatically enabled whenever the hard heap
|
|
** limit is enabled. ^When sqlite3_hard_heap_limit64(N) is invoked and
|
|
** the soft heap limit is outside the range of 1..N, then the soft heap
|
|
@@ -7463,7 +7184,7 @@ SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N);
|
|
**
|
|
** ^If the specified table is actually a view, an [error code] is returned.
|
|
**
|
|
-** ^If the specified column is "rowid", "oid" or "_rowid_" and the table
|
|
+** ^If the specified column is "rowid", "oid" or "_rowid_" and the table
|
|
** is not a [WITHOUT ROWID] table and an
|
|
** [INTEGER PRIMARY KEY] column has been explicitly declared, then the output
|
|
** parameters are set for the explicitly declared column. ^(If there is no
|
|
@@ -7529,7 +7250,7 @@ SQLITE_API int sqlite3_table_column_metadata(
|
|
** prior to calling this API,
|
|
** otherwise an error will be returned.
|
|
**
|
|
-** <b>Security warning:</b> It is recommended that the
|
|
+** <b>Security warning:</b> It is recommended that the
|
|
** [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method be used to enable only this
|
|
** interface. The use of the [sqlite3_enable_load_extension()] interface
|
|
** should be avoided. This will keep the SQL function [load_extension()]
|
|
@@ -7616,7 +7337,7 @@ SQLITE_API int sqlite3_auto_extension(void(*xEntryPoint)(void));
|
|
** ^The [sqlite3_cancel_auto_extension(X)] interface unregisters the
|
|
** initialization routine X that was registered using a prior call to
|
|
** [sqlite3_auto_extension(X)]. ^The [sqlite3_cancel_auto_extension(X)]
|
|
-** routine returns 1 if initialization routine X was successfully
|
|
+** routine returns 1 if initialization routine X was successfully
|
|
** unregistered and it returns 0 if X was not on the list of initialization
|
|
** routines.
|
|
*/
|
|
@@ -7630,15 +7351,6 @@ SQLITE_API int sqlite3_cancel_auto_extension(void(*xEntryPoint)(void));
|
|
*/
|
|
SQLITE_API void sqlite3_reset_auto_extension(void);
|
|
|
|
-/*
|
|
-** The interface to the virtual-table mechanism is currently considered
|
|
-** to be experimental. The interface might change in incompatible ways.
|
|
-** If this is a problem for you, do not use the interface at this time.
|
|
-**
|
|
-** When the virtual-table mechanism stabilizes, we will declare the
|
|
-** interface fixed, support it indefinitely, and remove this comment.
|
|
-*/
|
|
-
|
|
/*
|
|
** Structures used by the virtual table interface
|
|
*/
|
|
@@ -7651,8 +7363,8 @@ typedef struct sqlite3_module sqlite3_module;
|
|
** CAPI3REF: Virtual Table Object
|
|
** KEYWORDS: sqlite3_module {virtual table module}
|
|
**
|
|
-** This structure, sometimes called a "virtual table module",
|
|
-** defines the implementation of a [virtual table].
|
|
+** This structure, sometimes called a "virtual table module",
|
|
+** defines the implementation of a [virtual table].
|
|
** This structure consists mostly of methods for the module.
|
|
**
|
|
** ^A virtual table module is created by filling in a persistent
|
|
@@ -7691,7 +7403,7 @@ struct sqlite3_module {
|
|
void (**pxFunc)(sqlite3_context*,int,sqlite3_value**),
|
|
void **ppArg);
|
|
int (*xRename)(sqlite3_vtab *pVtab, const char *zNew);
|
|
- /* The methods above are in version 1 of the sqlite_module object. Those
|
|
+ /* The methods above are in version 1 of the sqlite_module object. Those
|
|
** below are for version 2 and greater. */
|
|
int (*xSavepoint)(sqlite3_vtab *pVTab, int);
|
|
int (*xRelease)(sqlite3_vtab *pVTab, int);
|
|
@@ -7741,7 +7453,7 @@ struct sqlite3_module {
|
|
** required by SQLite. If the table has at least 64 columns and any column
|
|
** to the right of the first 63 is required, then bit 63 of colUsed is also
|
|
** set. In other words, column iCol may be required if the expression
|
|
-** (colUsed & ((sqlite3_uint64)1 << (iCol>=63 ? 63 : iCol))) evaluates to
|
|
+** (colUsed & ((sqlite3_uint64)1 << (iCol>=63 ? 63 : iCol))) evaluates to
|
|
** non-zero.
|
|
**
|
|
** The [xBestIndex] method must fill aConstraintUsage[] with information
|
|
@@ -7757,10 +7469,10 @@ struct sqlite3_module {
|
|
** when the omit flag is true there is no guarantee that the constraint will
|
|
** not be checked again using byte code.)^
|
|
**
|
|
-** ^The idxNum and idxPtr values are recorded and passed into the
|
|
+** ^The idxNum and idxStr values are recorded and passed into the
|
|
** [xFilter] method.
|
|
-** ^[sqlite3_free()] is used to free idxPtr if and only if
|
|
-** needToFreeIdxPtr is true.
|
|
+** ^[sqlite3_free()] is used to free idxStr if and only if
|
|
+** needToFreeIdxStr is true.
|
|
**
|
|
** ^The orderByConsumed means that output from [xFilter]/[xNext] will occur in
|
|
** the correct order to satisfy the ORDER BY clause so that no separate
|
|
@@ -7768,17 +7480,17 @@ struct sqlite3_module {
|
|
**
|
|
** ^The estimatedCost value is an estimate of the cost of a particular
|
|
** strategy. A cost of N indicates that the cost of the strategy is similar
|
|
-** to a linear scan of an SQLite table with N rows. A cost of log(N)
|
|
+** to a linear scan of an SQLite table with N rows. A cost of log(N)
|
|
** indicates that the expense of the operation is similar to that of a
|
|
** binary search on a unique indexed field of an SQLite table with N rows.
|
|
**
|
|
** ^The estimatedRows value is an estimate of the number of rows that
|
|
** will be returned by the strategy.
|
|
**
|
|
-** The xBestIndex method may optionally populate the idxFlags field with a
|
|
+** The xBestIndex method may optionally populate the idxFlags field with a
|
|
** mask of SQLITE_INDEX_SCAN_* flags. Currently there is only one such flag -
|
|
** SQLITE_INDEX_SCAN_UNIQUE. If the xBestIndex method sets this flag, SQLite
|
|
-** assumes that the strategy may visit at most one row.
|
|
+** assumes that the strategy may visit at most one row.
|
|
**
|
|
** Additionally, if xBestIndex sets the SQLITE_INDEX_SCAN_UNIQUE flag, then
|
|
** SQLite also assumes that if a call to the xUpdate() method is made as
|
|
@@ -7791,14 +7503,14 @@ struct sqlite3_module {
|
|
** the xUpdate method are automatically rolled back by SQLite.
|
|
**
|
|
** IMPORTANT: The estimatedRows field was added to the sqlite3_index_info
|
|
-** structure for SQLite [version 3.8.2] ([dateof:3.8.2]).
|
|
+** structure for SQLite [version 3.8.2] ([dateof:3.8.2]).
|
|
** If a virtual table extension is
|
|
-** used with an SQLite version earlier than 3.8.2, the results of attempting
|
|
-** to read or write the estimatedRows field are undefined (but are likely
|
|
+** used with an SQLite version earlier than 3.8.2, the results of attempting
|
|
+** to read or write the estimatedRows field are undefined (but are likely
|
|
** to include crashing the application). The estimatedRows field should
|
|
** therefore only be used if [sqlite3_libversion_number()] returns a
|
|
** value greater than or equal to 3008002. Similarly, the idxFlags field
|
|
-** was added for [version 3.9.0] ([dateof:3.9.0]).
|
|
+** was added for [version 3.9.0] ([dateof:3.9.0]).
|
|
** It may therefore only be used if
|
|
** sqlite3_libversion_number() returns a value greater than or equal to
|
|
** 3009000.
|
|
@@ -7838,7 +7550,7 @@ struct sqlite3_index_info {
|
|
/*
|
|
** CAPI3REF: Virtual Table Scan Flags
|
|
**
|
|
-** Virtual table implementations are allowed to set the
|
|
+** Virtual table implementations are allowed to set the
|
|
** [sqlite3_index_info].idxFlags field to some combination of
|
|
** these bits.
|
|
*/
|
|
@@ -7849,24 +7561,56 @@ struct sqlite3_index_info {
|
|
**
|
|
** These macros define the allowed values for the
|
|
** [sqlite3_index_info].aConstraint[].op field. Each value represents
|
|
-** an operator that is part of a constraint term in the wHERE clause of
|
|
+** an operator that is part of a constraint term in the WHERE clause of
|
|
** a query that uses a [virtual table].
|
|
-*/
|
|
-#define SQLITE_INDEX_CONSTRAINT_EQ 2
|
|
-#define SQLITE_INDEX_CONSTRAINT_GT 4
|
|
-#define SQLITE_INDEX_CONSTRAINT_LE 8
|
|
-#define SQLITE_INDEX_CONSTRAINT_LT 16
|
|
-#define SQLITE_INDEX_CONSTRAINT_GE 32
|
|
-#define SQLITE_INDEX_CONSTRAINT_MATCH 64
|
|
-#define SQLITE_INDEX_CONSTRAINT_LIKE 65
|
|
-#define SQLITE_INDEX_CONSTRAINT_GLOB 66
|
|
-#define SQLITE_INDEX_CONSTRAINT_REGEXP 67
|
|
-#define SQLITE_INDEX_CONSTRAINT_NE 68
|
|
-#define SQLITE_INDEX_CONSTRAINT_ISNOT 69
|
|
-#define SQLITE_INDEX_CONSTRAINT_ISNOTNULL 70
|
|
-#define SQLITE_INDEX_CONSTRAINT_ISNULL 71
|
|
-#define SQLITE_INDEX_CONSTRAINT_IS 72
|
|
-#define SQLITE_INDEX_CONSTRAINT_FUNCTION 150
|
|
+**
|
|
+** ^The left-hand operand of the operator is given by the corresponding
|
|
+** aConstraint[].iColumn field. ^An iColumn of -1 indicates the left-hand
|
|
+** operand is the rowid.
|
|
+** The SQLITE_INDEX_CONSTRAINT_LIMIT and SQLITE_INDEX_CONSTRAINT_OFFSET
|
|
+** operators have no left-hand operand, and so for those operators the
|
|
+** corresponding aConstraint[].iColumn is meaningless and should not be
|
|
+** used.
|
|
+**
|
|
+** All operator values from SQLITE_INDEX_CONSTRAINT_FUNCTION through
|
|
+** value 255 are reserved to represent functions that are overloaded
|
|
+** by the [xFindFunction|xFindFunction method] of the virtual table
|
|
+** implementation.
|
|
+**
|
|
+** The right-hand operands for each constraint might be accessible using
|
|
+** the [sqlite3_vtab_rhs_value()] interface. Usually the right-hand
|
|
+** operand is only available if it appears as a single constant literal
|
|
+** in the input SQL. If the right-hand operand is another column or an
|
|
+** expression (even a constant expression) or a parameter, then the
|
|
+** sqlite3_vtab_rhs_value() probably will not be able to extract it.
|
|
+** ^The SQLITE_INDEX_CONSTRAINT_ISNULL and
|
|
+** SQLITE_INDEX_CONSTRAINT_ISNOTNULL operators have no right-hand operand
|
|
+** and hence calls to sqlite3_vtab_rhs_value() for those operators will
|
|
+** always return SQLITE_NOTFOUND.
|
|
+**
|
|
+** The collating sequence to be used for comparison can be found using
|
|
+** the [sqlite3_vtab_collation()] interface. For most real-world virtual
|
|
+** tables, the collating sequence of constraints does not matter (for example
|
|
+** because the constraints are numeric) and so the sqlite3_vtab_collation()
|
|
+** interface is not commonly needed.
|
|
+*/
|
|
+#define SQLITE_INDEX_CONSTRAINT_EQ 2
|
|
+#define SQLITE_INDEX_CONSTRAINT_GT 4
|
|
+#define SQLITE_INDEX_CONSTRAINT_LE 8
|
|
+#define SQLITE_INDEX_CONSTRAINT_LT 16
|
|
+#define SQLITE_INDEX_CONSTRAINT_GE 32
|
|
+#define SQLITE_INDEX_CONSTRAINT_MATCH 64
|
|
+#define SQLITE_INDEX_CONSTRAINT_LIKE 65
|
|
+#define SQLITE_INDEX_CONSTRAINT_GLOB 66
|
|
+#define SQLITE_INDEX_CONSTRAINT_REGEXP 67
|
|
+#define SQLITE_INDEX_CONSTRAINT_NE 68
|
|
+#define SQLITE_INDEX_CONSTRAINT_ISNOT 69
|
|
+#define SQLITE_INDEX_CONSTRAINT_ISNOTNULL 70
|
|
+#define SQLITE_INDEX_CONSTRAINT_ISNULL 71
|
|
+#define SQLITE_INDEX_CONSTRAINT_IS 72
|
|
+#define SQLITE_INDEX_CONSTRAINT_LIMIT 73
|
|
+#define SQLITE_INDEX_CONSTRAINT_OFFSET 74
|
|
+#define SQLITE_INDEX_CONSTRAINT_FUNCTION 150
|
|
|
|
/*
|
|
** CAPI3REF: Register A Virtual Table Implementation
|
|
@@ -7878,7 +7622,7 @@ struct sqlite3_index_info {
|
|
** preexisting [virtual table] for the module.
|
|
**
|
|
** ^The module name is registered on the [database connection] specified
|
|
-** by the first parameter. ^The name of the module is given by the
|
|
+** by the first parameter. ^The name of the module is given by the
|
|
** second parameter. ^The third parameter is a pointer to
|
|
** the implementation of the [virtual table module]. ^The fourth
|
|
** parameter is an arbitrary client data pointer that is passed through
|
|
@@ -7895,7 +7639,7 @@ struct sqlite3_index_info {
|
|
** destructor.
|
|
**
|
|
** ^If the third parameter (the pointer to the sqlite3_module object) is
|
|
-** NULL then no new module is create and any existing modules with the
|
|
+** NULL then no new module is created and any existing modules with the
|
|
** same name are dropped.
|
|
**
|
|
** See also: [sqlite3_drop_modules()]
|
|
@@ -7993,7 +7737,7 @@ SQLITE_API int sqlite3_declare_vtab(sqlite3*, const char *zSQL);
|
|
** METHOD: sqlite3
|
|
**
|
|
** ^(Virtual tables can provide alternative implementations of functions
|
|
-** using the [xFindFunction] method of the [virtual table module].
|
|
+** using the [xFindFunction] method of the [virtual table module].
|
|
** But global versions of those functions
|
|
** must exist in order to be overloaded.)^
|
|
**
|
|
@@ -8007,16 +7751,6 @@ SQLITE_API int sqlite3_declare_vtab(sqlite3*, const char *zSQL);
|
|
*/
|
|
SQLITE_API int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
|
|
|
|
-/*
|
|
-** The interface to the virtual-table mechanism defined above (back up
|
|
-** to a comment remarkably similar to this one) is currently considered
|
|
-** to be experimental. The interface might change in incompatible ways.
|
|
-** If this is a problem for you, do not use the interface at this time.
|
|
-**
|
|
-** When the virtual-table mechanism stabilizes, we will declare the
|
|
-** interface fixed, support it indefinitely, and remove this comment.
|
|
-*/
|
|
-
|
|
/*
|
|
** CAPI3REF: A Handle To An Open BLOB
|
|
** KEYWORDS: {BLOB handle} {BLOB handles}
|
|
@@ -8044,7 +7778,7 @@ typedef struct sqlite3_blob sqlite3_blob;
|
|
** SELECT zColumn FROM zDb.zTable WHERE [rowid] = iRow;
|
|
** </pre>)^
|
|
**
|
|
-** ^(Parameter zDb is not the filename that contains the database, but
|
|
+** ^(Parameter zDb is not the filename that contains the database, but
|
|
** rather the symbolic name of the database. For attached databases, this is
|
|
** the name that appears after the AS keyword in the [ATTACH] statement.
|
|
** For the main database file, the database name is "main". For TEMP
|
|
@@ -8057,28 +7791,28 @@ typedef struct sqlite3_blob sqlite3_blob;
|
|
** ^(On success, [SQLITE_OK] is returned and the new [BLOB handle] is stored
|
|
** in *ppBlob. Otherwise an [error code] is returned and, unless the error
|
|
** code is SQLITE_MISUSE, *ppBlob is set to NULL.)^ ^This means that, provided
|
|
-** the API is not misused, it is always safe to call [sqlite3_blob_close()]
|
|
+** the API is not misused, it is always safe to call [sqlite3_blob_close()]
|
|
** on *ppBlob after this function it returns.
|
|
**
|
|
** This function fails with SQLITE_ERROR if any of the following are true:
|
|
** <ul>
|
|
-** <li> ^(Database zDb does not exist)^,
|
|
-** <li> ^(Table zTable does not exist within database zDb)^,
|
|
-** <li> ^(Table zTable is a WITHOUT ROWID table)^,
|
|
+** <li> ^(Database zDb does not exist)^,
|
|
+** <li> ^(Table zTable does not exist within database zDb)^,
|
|
+** <li> ^(Table zTable is a WITHOUT ROWID table)^,
|
|
** <li> ^(Column zColumn does not exist)^,
|
|
** <li> ^(Row iRow is not present in the table)^,
|
|
** <li> ^(The specified column of row iRow contains a value that is not
|
|
** a TEXT or BLOB value)^,
|
|
-** <li> ^(Column zColumn is part of an index, PRIMARY KEY or UNIQUE
|
|
+** <li> ^(Column zColumn is part of an index, PRIMARY KEY or UNIQUE
|
|
** constraint and the blob is being opened for read/write access)^,
|
|
-** <li> ^([foreign key constraints | Foreign key constraints] are enabled,
|
|
+** <li> ^([foreign key constraints | Foreign key constraints] are enabled,
|
|
** column zColumn is part of a [child key] definition and the blob is
|
|
** being opened for read/write access)^.
|
|
** </ul>
|
|
**
|
|
-** ^Unless it returns SQLITE_MISUSE, this function sets the
|
|
-** [database connection] error code and message accessible via
|
|
-** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions.
|
|
+** ^Unless it returns SQLITE_MISUSE, this function sets the
|
|
+** [database connection] error code and message accessible via
|
|
+** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions.
|
|
**
|
|
** A BLOB referenced by sqlite3_blob_open() may be read using the
|
|
** [sqlite3_blob_read()] interface and modified by using
|
|
@@ -8104,7 +7838,7 @@ typedef struct sqlite3_blob sqlite3_blob;
|
|
** blob.
|
|
**
|
|
** ^The [sqlite3_bind_zeroblob()] and [sqlite3_result_zeroblob()] interfaces
|
|
-** and the built-in [zeroblob] SQL function may be used to create a
|
|
+** and the built-in [zeroblob] SQL function may be used to create a
|
|
** zero-filled blob to read or write using the incremental-blob interface.
|
|
**
|
|
** To avoid a resource leak, every open [BLOB handle] should eventually
|
|
@@ -8154,7 +7888,7 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);
|
|
** DESTRUCTOR: sqlite3_blob
|
|
**
|
|
** ^This function closes an open [BLOB handle]. ^(The BLOB handle is closed
|
|
-** unconditionally. Even if this routine returns an error code, the
|
|
+** unconditionally. Even if this routine returns an error code, the
|
|
** handle is still closed.)^
|
|
**
|
|
** ^If the blob handle being closed was opened for read-write access, and if
|
|
@@ -8164,10 +7898,10 @@ 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
|
|
-** with a null pointer (such as would be returned by a failed call to
|
|
+** open blob handle results in undefined behaviour. ^Calling this routine
|
|
+** with a null pointer (such as would be returned by a failed call to
|
|
** [sqlite3_blob_open()]) is a harmless no-op. ^Otherwise, if this function
|
|
-** is passed a valid open blob handle, the values returned by the
|
|
+** is passed a valid open blob handle, the values returned by the
|
|
** sqlite3_errcode() and sqlite3_errmsg() functions are set before returning.
|
|
*/
|
|
SQLITE_API int sqlite3_blob_close(sqlite3_blob *);
|
|
@@ -8176,7 +7910,7 @@ SQLITE_API int sqlite3_blob_close(sqlite3_blob *);
|
|
** CAPI3REF: Return The Size Of An Open BLOB
|
|
** METHOD: sqlite3_blob
|
|
**
|
|
-** ^Returns the size in bytes of the BLOB accessible via the
|
|
+** ^Returns the size in bytes of the BLOB accessible via the
|
|
** successfully opened [BLOB handle] in its only argument. ^The
|
|
** incremental blob I/O routines can only read or overwriting existing
|
|
** blob content; they cannot change the size of a blob.
|
|
@@ -8227,9 +7961,9 @@ SQLITE_API int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
|
|
**
|
|
** ^(On success, sqlite3_blob_write() returns SQLITE_OK.
|
|
** Otherwise, an [error code] or an [extended error code] is returned.)^
|
|
-** ^Unless SQLITE_MISUSE is returned, this function sets the
|
|
-** [database connection] error code and message accessible via
|
|
-** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions.
|
|
+** ^Unless SQLITE_MISUSE is returned, this function sets the
|
|
+** [database connection] error code and message accessible via
|
|
+** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions.
|
|
**
|
|
** ^If the [BLOB handle] passed as the first argument was not opened for
|
|
** writing (the flags parameter to [sqlite3_blob_open()] was zero),
|
|
@@ -8238,9 +7972,9 @@ SQLITE_API int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
|
|
** This function may only modify the contents of the BLOB; it is
|
|
** not possible to increase the size of a BLOB using this API.
|
|
** ^If offset iOffset is less than N bytes from the end of the BLOB,
|
|
-** [SQLITE_ERROR] is returned and no data is written. The size of the
|
|
-** BLOB (and hence the maximum value of N+iOffset) can be determined
|
|
-** using the [sqlite3_blob_bytes()] interface. ^If N or iOffset are less
|
|
+** [SQLITE_ERROR] is returned and no data is written. The size of the
|
|
+** BLOB (and hence the maximum value of N+iOffset) can be determined
|
|
+** using the [sqlite3_blob_bytes()] interface. ^If N or iOffset are less
|
|
** than zero [SQLITE_ERROR] is returned and no data is written.
|
|
**
|
|
** ^An attempt to write to an expired [BLOB handle] fails with an
|
|
@@ -8334,7 +8068,7 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
|
|
** <ul>
|
|
** <li> SQLITE_MUTEX_FAST
|
|
** <li> SQLITE_MUTEX_RECURSIVE
|
|
-** <li> SQLITE_MUTEX_STATIC_MASTER
|
|
+** <li> SQLITE_MUTEX_STATIC_MAIN
|
|
** <li> SQLITE_MUTEX_STATIC_MEM
|
|
** <li> SQLITE_MUTEX_STATIC_OPEN
|
|
** <li> SQLITE_MUTEX_STATIC_PRNG
|
|
@@ -8392,7 +8126,7 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
|
|
** ^(Some systems (for example, Windows 95) do not support the operation
|
|
** implemented by sqlite3_mutex_try(). On those systems, sqlite3_mutex_try()
|
|
** will always return SQLITE_BUSY. The SQLite core only ever uses
|
|
-** sqlite3_mutex_try() as an optimization so this is acceptable
|
|
+** sqlite3_mutex_try() as an optimization so this is acceptable
|
|
** behavior.)^
|
|
**
|
|
** ^The sqlite3_mutex_leave() routine exits a mutex that was
|
|
@@ -8536,7 +8270,7 @@ SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*);
|
|
*/
|
|
#define SQLITE_MUTEX_FAST 0
|
|
#define SQLITE_MUTEX_RECURSIVE 1
|
|
-#define SQLITE_MUTEX_STATIC_MASTER 2
|
|
+#define SQLITE_MUTEX_STATIC_MAIN 2
|
|
#define SQLITE_MUTEX_STATIC_MEM 3 /* sqlite3_malloc() */
|
|
#define SQLITE_MUTEX_STATIC_MEM2 4 /* NOT USED */
|
|
#define SQLITE_MUTEX_STATIC_OPEN 4 /* sqlite3BtreeOpen() */
|
|
@@ -8551,11 +8285,15 @@ SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*);
|
|
#define SQLITE_MUTEX_STATIC_VFS2 12 /* For use by extension VFS */
|
|
#define SQLITE_MUTEX_STATIC_VFS3 13 /* For use by application VFS */
|
|
|
|
+/* Legacy compatibility: */
|
|
+#define SQLITE_MUTEX_STATIC_MASTER 2
|
|
+
|
|
+
|
|
/*
|
|
** CAPI3REF: Retrieve the mutex for a database connection
|
|
** METHOD: sqlite3
|
|
**
|
|
-** ^This interface returns a pointer the [sqlite3_mutex] object that
|
|
+** ^This interface returns a pointer the [sqlite3_mutex] object that
|
|
** serializes access to the [database connection] given in the argument
|
|
** when the [threading mode] is Serialized.
|
|
** ^If the [threading mode] is Single-thread or Multi-thread then this
|
|
@@ -8582,7 +8320,7 @@ SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
|
|
** method becomes the return value of this routine.
|
|
**
|
|
** A few opcodes for [sqlite3_file_control()] are handled directly
|
|
-** by the SQLite core and never invoke the
|
|
+** by the SQLite core and never invoke the
|
|
** sqlite3_io_methods.xFileControl method.
|
|
** ^The [SQLITE_FCNTL_FILE_POINTER] value for the op parameter causes
|
|
** a pointer to the underlying [sqlite3_file] object to be written into
|
|
@@ -8646,7 +8384,7 @@ SQLITE_API int sqlite3_test_control(int op, ...);
|
|
#define SQLITE_TESTCTRL_PENDING_BYTE 11
|
|
#define SQLITE_TESTCTRL_ASSERT 12
|
|
#define SQLITE_TESTCTRL_ALWAYS 13
|
|
-#define SQLITE_TESTCTRL_RESERVE 14
|
|
+#define SQLITE_TESTCTRL_RESERVE 14 /* NOT USED */
|
|
#define SQLITE_TESTCTRL_OPTIMIZATIONS 15
|
|
#define SQLITE_TESTCTRL_ISKEYWORD 16 /* NOT USED */
|
|
#define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */
|
|
@@ -8664,12 +8402,16 @@ SQLITE_API int sqlite3_test_control(int op, ...);
|
|
#define SQLITE_TESTCTRL_RESULT_INTREAL 27
|
|
#define SQLITE_TESTCTRL_PRNG_SEED 28
|
|
#define SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS 29
|
|
-#define SQLITE_TESTCTRL_LAST 29 /* Largest TESTCTRL */
|
|
+#define SQLITE_TESTCTRL_SEEK_COUNT 30
|
|
+#define SQLITE_TESTCTRL_TRACEFLAGS 31
|
|
+#define SQLITE_TESTCTRL_TUNE 32
|
|
+#define SQLITE_TESTCTRL_LOGEST 33
|
|
+#define SQLITE_TESTCTRL_LAST 33 /* Largest TESTCTRL */
|
|
|
|
/*
|
|
** CAPI3REF: SQL Keyword Checking
|
|
**
|
|
-** These routines provide access to the set of SQL language keywords
|
|
+** These routines provide access to the set of SQL language keywords
|
|
** recognized by SQLite. Applications can uses these routines to determine
|
|
** whether or not a specific identifier needs to be escaped (for example,
|
|
** by enclosing in double-quotes) so as not to confuse the parser.
|
|
@@ -8741,14 +8483,14 @@ typedef struct sqlite3_str sqlite3_str;
|
|
**
|
|
** ^The [sqlite3_str_new(D)] interface allocates and initializes
|
|
** a new [sqlite3_str] object. To avoid memory leaks, the object returned by
|
|
-** [sqlite3_str_new()] must be freed by a subsequent call to
|
|
+** [sqlite3_str_new()] must be freed by a subsequent call to
|
|
** [sqlite3_str_finish(X)].
|
|
**
|
|
** ^The [sqlite3_str_new(D)] interface always returns a pointer to a
|
|
** valid [sqlite3_str] object, though in the event of an out-of-memory
|
|
** error the returned object might be a special singleton that will
|
|
-** silently reject new text, always return SQLITE_NOMEM from
|
|
-** [sqlite3_str_errcode()], always return 0 for
|
|
+** silently reject new text, always return SQLITE_NOMEM from
|
|
+** [sqlite3_str_errcode()], always return 0 for
|
|
** [sqlite3_str_length()], and always return NULL from
|
|
** [sqlite3_str_finish(X)]. It is always safe to use the value
|
|
** returned by [sqlite3_str_new(D)] as the sqlite3_str parameter
|
|
@@ -8784,9 +8526,9 @@ SQLITE_API char *sqlite3_str_finish(sqlite3_str*);
|
|
** These interfaces add content to an sqlite3_str object previously obtained
|
|
** from [sqlite3_str_new()].
|
|
**
|
|
-** ^The [sqlite3_str_appendf(X,F,...)] and
|
|
+** ^The [sqlite3_str_appendf(X,F,...)] and
|
|
** [sqlite3_str_vappendf(X,F,V)] interfaces uses the [built-in printf]
|
|
-** functionality of SQLite to append formatted text onto the end of
|
|
+** functionality of SQLite to append formatted text onto the end of
|
|
** [sqlite3_str] object X.
|
|
**
|
|
** ^The [sqlite3_str_append(X,S,N)] method appends exactly N bytes from string S
|
|
@@ -8803,7 +8545,7 @@ SQLITE_API char *sqlite3_str_finish(sqlite3_str*);
|
|
** ^This method can be used, for example, to add whitespace indentation.
|
|
**
|
|
** ^The [sqlite3_str_reset(X)] method resets the string under construction
|
|
-** inside [sqlite3_str] object X back to zero bytes in length.
|
|
+** inside [sqlite3_str] object X back to zero bytes in length.
|
|
**
|
|
** These methods do not return a result code. ^If an error occurs, that fact
|
|
** is recorded in the [sqlite3_str] object and can be recovered by a
|
|
@@ -8905,7 +8647,7 @@ SQLITE_API int sqlite3_status64(
|
|
** <dd>This parameter records the largest memory allocation request
|
|
** handed to [sqlite3_malloc()] or [sqlite3_realloc()] (or their
|
|
** internal equivalents). Only the value returned in the
|
|
-** *pHighwater parameter to [sqlite3_status()] is of interest.
|
|
+** *pHighwater parameter to [sqlite3_status()] is of interest.
|
|
** The value written into the *pCurrent parameter is undefined.</dd>)^
|
|
**
|
|
** [[SQLITE_STATUS_MALLOC_COUNT]] ^(<dt>SQLITE_STATUS_MALLOC_COUNT</dt>
|
|
@@ -8914,11 +8656,11 @@ SQLITE_API int sqlite3_status64(
|
|
**
|
|
** [[SQLITE_STATUS_PAGECACHE_USED]] ^(<dt>SQLITE_STATUS_PAGECACHE_USED</dt>
|
|
** <dd>This parameter returns the number of pages used out of the
|
|
-** [pagecache memory allocator] that was configured using
|
|
+** [pagecache memory allocator] that was configured using
|
|
** [SQLITE_CONFIG_PAGECACHE]. The
|
|
** value returned is in pages, not in bytes.</dd>)^
|
|
**
|
|
-** [[SQLITE_STATUS_PAGECACHE_OVERFLOW]]
|
|
+** [[SQLITE_STATUS_PAGECACHE_OVERFLOW]]
|
|
** ^(<dt>SQLITE_STATUS_PAGECACHE_OVERFLOW</dt>
|
|
** <dd>This parameter returns the number of bytes of page cache
|
|
** allocation which could not be satisfied by the [SQLITE_CONFIG_PAGECACHE]
|
|
@@ -8931,7 +8673,7 @@ SQLITE_API int sqlite3_status64(
|
|
** [[SQLITE_STATUS_PAGECACHE_SIZE]] ^(<dt>SQLITE_STATUS_PAGECACHE_SIZE</dt>
|
|
** <dd>This parameter records the largest memory allocation request
|
|
** handed to the [pagecache memory allocator]. Only the value returned in the
|
|
-** *pHighwater parameter to [sqlite3_status()] is of interest.
|
|
+** *pHighwater parameter to [sqlite3_status()] is of interest.
|
|
** The value written into the *pCurrent parameter is undefined.</dd>)^
|
|
**
|
|
** [[SQLITE_STATUS_SCRATCH_USED]] <dt>SQLITE_STATUS_SCRATCH_USED</dt>
|
|
@@ -8944,7 +8686,7 @@ SQLITE_API int sqlite3_status64(
|
|
** <dd>No longer used.</dd>
|
|
**
|
|
** [[SQLITE_STATUS_PARSER_STACK]] ^(<dt>SQLITE_STATUS_PARSER_STACK</dt>
|
|
-** <dd>The *pHighwater parameter records the deepest parser stack.
|
|
+** <dd>The *pHighwater parameter records the deepest parser stack.
|
|
** The *pCurrent value is undefined. The *pHighwater value is only
|
|
** meaningful if SQLite is compiled with [YYTRACKMAXSTACKDEPTH].</dd>)^
|
|
** </dl>
|
|
@@ -8966,12 +8708,12 @@ SQLITE_API int sqlite3_status64(
|
|
** CAPI3REF: Database Connection Status
|
|
** METHOD: sqlite3
|
|
**
|
|
-** ^This interface is used to retrieve runtime status information
|
|
+** ^This interface is used to retrieve runtime status information
|
|
** about a single [database connection]. ^The first argument is the
|
|
** database connection object to be interrogated. ^The second argument
|
|
** is an integer constant, taken from the set of
|
|
** [SQLITE_DBSTATUS options], that
|
|
-** determines the parameter to interrogate. The set of
|
|
+** determines the parameter to interrogate. The set of
|
|
** [SQLITE_DBSTATUS options] is likely
|
|
** to grow in future releases of SQLite.
|
|
**
|
|
@@ -9006,7 +8748,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
|
|
** checked out.</dd>)^
|
|
**
|
|
** [[SQLITE_DBSTATUS_LOOKASIDE_HIT]] ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_HIT</dt>
|
|
-** <dd>This parameter returns the number of malloc attempts that were
|
|
+** <dd>This parameter returns the number of malloc attempts that were
|
|
** satisfied using lookaside memory. Only the high-water value is meaningful;
|
|
** the current value is always zero.)^
|
|
**
|
|
@@ -9031,7 +8773,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
|
|
** memory used by all pager caches associated with the database connection.)^
|
|
** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0.
|
|
**
|
|
-** [[SQLITE_DBSTATUS_CACHE_USED_SHARED]]
|
|
+** [[SQLITE_DBSTATUS_CACHE_USED_SHARED]]
|
|
** ^(<dt>SQLITE_DBSTATUS_CACHE_USED_SHARED</dt>
|
|
** <dd>This parameter is similar to DBSTATUS_CACHE_USED, except that if a
|
|
** pager cache is shared between two or more connections the bytes of heap
|
|
@@ -9046,7 +8788,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
|
|
** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(<dt>SQLITE_DBSTATUS_SCHEMA_USED</dt>
|
|
** <dd>This parameter returns the approximate number of bytes of heap
|
|
** memory used to store the schema for all databases associated
|
|
-** with the connection - main, temp, and any [ATTACH]-ed databases.)^
|
|
+** with the connection - main, temp, and any [ATTACH]-ed databases.)^
|
|
** ^The full amount of memory used by the schemas is reported, even if the
|
|
** schema memory is shared with other database connections due to
|
|
** [shared cache mode] being enabled.
|
|
@@ -9061,13 +8803,13 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
|
|
**
|
|
** [[SQLITE_DBSTATUS_CACHE_HIT]] ^(<dt>SQLITE_DBSTATUS_CACHE_HIT</dt>
|
|
** <dd>This parameter returns the number of pager cache hits that have
|
|
-** occurred.)^ ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_HIT
|
|
+** occurred.)^ ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_HIT
|
|
** is always 0.
|
|
** </dd>
|
|
**
|
|
** [[SQLITE_DBSTATUS_CACHE_MISS]] ^(<dt>SQLITE_DBSTATUS_CACHE_MISS</dt>
|
|
** <dd>This parameter returns the number of pager cache misses that have
|
|
-** occurred.)^ ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_MISS
|
|
+** occurred.)^ ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_MISS
|
|
** is always 0.
|
|
** </dd>
|
|
**
|
|
@@ -9125,7 +8867,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
|
|
** statements. For example, if the number of table steps greatly exceeds
|
|
** the number of table searches or result rows, that would tend to indicate
|
|
** that the prepared statement is using a full table scan rather than
|
|
-** an index.
|
|
+** an index.
|
|
**
|
|
** ^(This interface is used to retrieve and reset counter values from
|
|
** a [prepared statement]. The first argument is the prepared statement
|
|
@@ -9152,7 +8894,7 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
|
|
** [[SQLITE_STMTSTATUS_FULLSCAN_STEP]] <dt>SQLITE_STMTSTATUS_FULLSCAN_STEP</dt>
|
|
** <dd>^This is the number of times that SQLite has stepped forward in
|
|
** a table as part of a full table scan. Large numbers for this counter
|
|
-** may indicate opportunities for performance improvement through
|
|
+** may indicate opportunities for performance improvement through
|
|
** careful use of indices.</dd>
|
|
**
|
|
** [[SQLITE_STMTSTATUS_SORT]] <dt>SQLITE_STMTSTATUS_SORT</dt>
|
|
@@ -9170,14 +8912,14 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
|
|
** [[SQLITE_STMTSTATUS_VM_STEP]] <dt>SQLITE_STMTSTATUS_VM_STEP</dt>
|
|
** <dd>^This is the number of virtual machine operations executed
|
|
** by the prepared statement if that number is less than or equal
|
|
-** to 2147483647. The number of virtual machine operations can be
|
|
+** to 2147483647. The number of virtual machine operations can be
|
|
** used as a proxy for the total work done by the prepared statement.
|
|
** If the number of virtual machine operations exceeds 2147483647
|
|
** then the value returned by this statement status code is undefined.
|
|
**
|
|
** [[SQLITE_STMTSTATUS_REPREPARE]] <dt>SQLITE_STMTSTATUS_REPREPARE</dt>
|
|
** <dd>^This is the number of times that the prepare statement has been
|
|
-** automatically regenerated due to schema changes or changes to
|
|
+** automatically regenerated due to schema changes or changes to
|
|
** [bound parameters] that might affect the query plan.
|
|
**
|
|
** [[SQLITE_STMTSTATUS_RUN]] <dt>SQLITE_STMTSTATUS_RUN</dt>
|
|
@@ -9187,6 +8929,16 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
|
|
** The counter is incremented on the first [sqlite3_step()] call of each
|
|
** cycle.
|
|
**
|
|
+** [[SQLITE_STMTSTATUS_FILTER_MISS]]
|
|
+** [[SQLITE_STMTSTATUS_FILTER HIT]]
|
|
+** <dt>SQLITE_STMTSTATUS_FILTER_HIT<br>
|
|
+** SQLITE_STMTSTATUS_FILTER_MISS</dt>
|
|
+** <dd>^SQLITE_STMTSTATUS_FILTER_HIT is the number of times that a join
|
|
+** step was bypassed because a Bloom filter returned not-found. The
|
|
+** corresponding SQLITE_STMTSTATUS_FILTER_MISS value is the number of
|
|
+** times that the Bloom filter returned a find, and thus the join step
|
|
+** had to be processed as normal.
|
|
+**
|
|
** [[SQLITE_STMTSTATUS_MEMUSED]] <dt>SQLITE_STMTSTATUS_MEMUSED</dt>
|
|
** <dd>^This is the approximate number of bytes of heap memory
|
|
** used to store the prepared statement. ^This value is not actually
|
|
@@ -9201,6 +8953,8 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
|
|
#define SQLITE_STMTSTATUS_VM_STEP 4
|
|
#define SQLITE_STMTSTATUS_REPREPARE 5
|
|
#define SQLITE_STMTSTATUS_RUN 6
|
|
+#define SQLITE_STMTSTATUS_FILTER_MISS 7
|
|
+#define SQLITE_STMTSTATUS_FILTER_HIT 8
|
|
#define SQLITE_STMTSTATUS_MEMUSED 99
|
|
|
|
/*
|
|
@@ -9237,15 +8991,15 @@ struct sqlite3_pcache_page {
|
|
** KEYWORDS: {page cache}
|
|
**
|
|
** ^(The [sqlite3_config]([SQLITE_CONFIG_PCACHE2], ...) interface can
|
|
-** register an alternative page cache implementation by passing in an
|
|
+** register an alternative page cache implementation by passing in an
|
|
** instance of the sqlite3_pcache_methods2 structure.)^
|
|
-** In many applications, most of the heap memory allocated by
|
|
+** In many applications, most of the heap memory allocated by
|
|
** SQLite is used for the page cache.
|
|
-** By implementing a
|
|
+** By implementing a
|
|
** custom page cache using this API, an application can better control
|
|
-** the amount of memory consumed by SQLite, the way in which
|
|
-** that memory is allocated and released, and the policies used to
|
|
-** determine exactly which parts of a database file are cached and for
|
|
+** the amount of memory consumed by SQLite, the way in which
|
|
+** that memory is allocated and released, and the policies used to
|
|
+** determine exactly which parts of a database file are cached and for
|
|
** how long.
|
|
**
|
|
** The alternative page cache mechanism is an
|
|
@@ -9258,19 +9012,19 @@ struct sqlite3_pcache_page {
|
|
** [sqlite3_config()] returns.)^
|
|
**
|
|
** [[the xInit() page cache method]]
|
|
-** ^(The xInit() method is called once for each effective
|
|
+** ^(The xInit() method is called once for each effective
|
|
** call to [sqlite3_initialize()])^
|
|
** (usually only once during the lifetime of the process). ^(The xInit()
|
|
** method is passed a copy of the sqlite3_pcache_methods2.pArg value.)^
|
|
-** The intent of the xInit() method is to set up global data structures
|
|
-** required by the custom page cache implementation.
|
|
-** ^(If the xInit() method is NULL, then the
|
|
+** The intent of the xInit() method is to set up global data structures
|
|
+** required by the custom page cache implementation.
|
|
+** ^(If the xInit() method is NULL, then the
|
|
** built-in default page cache is used instead of the application defined
|
|
** page cache.)^
|
|
**
|
|
** [[the xShutdown() page cache method]]
|
|
** ^The xShutdown() method is called by [sqlite3_shutdown()].
|
|
-** It can be used to clean up
|
|
+** It can be used to clean up
|
|
** any outstanding resources before process shutdown, if required.
|
|
** ^The xShutdown() method may be NULL.
|
|
**
|
|
@@ -9289,7 +9043,7 @@ struct sqlite3_pcache_page {
|
|
** though this is not guaranteed. ^The
|
|
** first parameter, szPage, is the size in bytes of the pages that must
|
|
** be allocated by the cache. ^szPage will always a power of two. ^The
|
|
-** second parameter szExtra is a number of bytes of extra storage
|
|
+** second parameter szExtra is a number of bytes of extra storage
|
|
** associated with each page cache entry. ^The szExtra parameter will
|
|
** a number less than 250. SQLite will use the
|
|
** extra szExtra bytes on each page to store metadata about the underlying
|
|
@@ -9302,7 +9056,7 @@ struct sqlite3_pcache_page {
|
|
** it is purely advisory. ^On a cache where bPurgeable is false, SQLite will
|
|
** never invoke xUnpin() except to deliberately delete a page.
|
|
** ^In other words, calls to xUnpin() on a cache with bPurgeable set to
|
|
-** false will always have the "discard" flag set to true.
|
|
+** false will always have the "discard" flag set to true.
|
|
** ^Hence, a cache created with bPurgeable false will
|
|
** never contain any unpinned pages.
|
|
**
|
|
@@ -9317,12 +9071,12 @@ struct sqlite3_pcache_page {
|
|
** [[the xPagecount() page cache methods]]
|
|
** The xPagecount() method must return the number of pages currently
|
|
** stored in the cache, both pinned and unpinned.
|
|
-**
|
|
+**
|
|
** [[the xFetch() page cache methods]]
|
|
-** The xFetch() method locates a page in the cache and returns a pointer to
|
|
+** The xFetch() method locates a page in the cache and returns a pointer to
|
|
** an sqlite3_pcache_page object associated with that page, or a NULL pointer.
|
|
** The pBuf element of the returned sqlite3_pcache_page object will be a
|
|
-** pointer to a buffer of szPage bytes used to store the content of a
|
|
+** pointer to a buffer of szPage bytes used to store the content of a
|
|
** single database page. The pExtra element of sqlite3_pcache_page will be
|
|
** a pointer to the szExtra bytes of extra storage that SQLite has requested
|
|
** for each entry in the page cache.
|
|
@@ -9361,8 +9115,8 @@ struct sqlite3_pcache_page {
|
|
** page cache implementation. ^The page cache implementation
|
|
** may choose to evict unpinned pages at any time.
|
|
**
|
|
-** The cache must not perform any reference counting. A single
|
|
-** call to xUnpin() unpins the page regardless of the number of prior calls
|
|
+** The cache must not perform any reference counting. A single
|
|
+** call to xUnpin() unpins the page regardless of the number of prior calls
|
|
** to xFetch().
|
|
**
|
|
** [[the xRekey() page cache methods]]
|
|
@@ -9402,7 +9156,7 @@ struct sqlite3_pcache_methods2 {
|
|
int (*xPagecount)(sqlite3_pcache*);
|
|
sqlite3_pcache_page *(*xFetch)(sqlite3_pcache*, unsigned key, int createFlag);
|
|
void (*xUnpin)(sqlite3_pcache*, sqlite3_pcache_page*, int discard);
|
|
- void (*xRekey)(sqlite3_pcache*, sqlite3_pcache_page*,
|
|
+ void (*xRekey)(sqlite3_pcache*, sqlite3_pcache_page*,
|
|
unsigned oldKey, unsigned newKey);
|
|
void (*xTruncate)(sqlite3_pcache*, unsigned iLimit);
|
|
void (*xDestroy)(sqlite3_pcache*);
|
|
@@ -9447,7 +9201,7 @@ typedef struct sqlite3_backup sqlite3_backup;
|
|
**
|
|
** The backup API copies the content of one database into another.
|
|
** It is useful either for creating backups of databases or
|
|
-** for copying in-memory databases to or from persistent files.
|
|
+** for copying in-memory databases to or from persistent files.
|
|
**
|
|
** See Also: [Using the SQLite Online Backup API]
|
|
**
|
|
@@ -9458,36 +9212,36 @@ typedef struct sqlite3_backup sqlite3_backup;
|
|
** ^Thus, the backup may be performed on a live source database without
|
|
** preventing other database connections from
|
|
** reading or writing to the source database while the backup is underway.
|
|
-**
|
|
-** ^(To perform a backup operation:
|
|
+**
|
|
+** ^(To perform a backup operation:
|
|
** <ol>
|
|
** <li><b>sqlite3_backup_init()</b> is called once to initialize the
|
|
-** backup,
|
|
-** <li><b>sqlite3_backup_step()</b> is called one or more times to transfer
|
|
+** backup,
|
|
+** <li><b>sqlite3_backup_step()</b> is called one or more times to transfer
|
|
** the data between the two databases, and finally
|
|
-** <li><b>sqlite3_backup_finish()</b> is called to release all resources
|
|
-** associated with the backup operation.
|
|
+** <li><b>sqlite3_backup_finish()</b> is called to release all resources
|
|
+** associated with the backup operation.
|
|
** </ol>)^
|
|
** There should be exactly one call to sqlite3_backup_finish() for each
|
|
** successful call to sqlite3_backup_init().
|
|
**
|
|
** [[sqlite3_backup_init()]] <b>sqlite3_backup_init()</b>
|
|
**
|
|
-** ^The D and N arguments to sqlite3_backup_init(D,N,S,M) are the
|
|
-** [database connection] associated with the destination database
|
|
+** ^The D and N arguments to sqlite3_backup_init(D,N,S,M) are the
|
|
+** [database connection] associated with the destination database
|
|
** and the database name, respectively.
|
|
** ^The database name is "main" for the main database, "temp" for the
|
|
** temporary database, or the name specified after the AS keyword in
|
|
** an [ATTACH] statement for an attached database.
|
|
-** ^The S and M arguments passed to
|
|
+** ^The S and M arguments passed to
|
|
** sqlite3_backup_init(D,N,S,M) identify the [database connection]
|
|
** and database name of the source database, respectively.
|
|
** ^The source and destination [database connections] (parameters S and D)
|
|
** must be different or else sqlite3_backup_init(D,N,S,M) will fail with
|
|
** an error.
|
|
**
|
|
-** ^A call to sqlite3_backup_init() will fail, returning NULL, if
|
|
-** there is already a read or read-write transaction open on the
|
|
+** ^A call to sqlite3_backup_init() will fail, returning NULL, if
|
|
+** there is already a read or read-write transaction open on the
|
|
** destination database.
|
|
**
|
|
** ^If an error occurs within sqlite3_backup_init(D,N,S,M), then NULL is
|
|
@@ -9499,14 +9253,14 @@ typedef struct sqlite3_backup sqlite3_backup;
|
|
** ^A successful call to sqlite3_backup_init() returns a pointer to an
|
|
** [sqlite3_backup] object.
|
|
** ^The [sqlite3_backup] object may be used with the sqlite3_backup_step() and
|
|
-** sqlite3_backup_finish() functions to perform the specified backup
|
|
+** sqlite3_backup_finish() functions to perform the specified backup
|
|
** operation.
|
|
**
|
|
** [[sqlite3_backup_step()]] <b>sqlite3_backup_step()</b>
|
|
**
|
|
-** ^Function sqlite3_backup_step(B,N) will copy up to N pages between
|
|
+** ^Function sqlite3_backup_step(B,N) will copy up to N pages between
|
|
** the source and destination databases specified by [sqlite3_backup] object B.
|
|
-** ^If N is negative, all remaining source pages are copied.
|
|
+** ^If N is negative, all remaining source pages are copied.
|
|
** ^If sqlite3_backup_step(B,N) successfully copies N pages and there
|
|
** are still more pages to be copied, then the function returns [SQLITE_OK].
|
|
** ^If sqlite3_backup_step(B,N) successfully finishes copying all pages
|
|
@@ -9528,8 +9282,8 @@ typedef struct sqlite3_backup sqlite3_backup;
|
|
**
|
|
** ^If sqlite3_backup_step() cannot obtain a required file-system lock, then
|
|
** the [sqlite3_busy_handler | busy-handler function]
|
|
-** is invoked (if one is specified). ^If the
|
|
-** busy-handler returns non-zero before the lock is available, then
|
|
+** is invoked (if one is specified). ^If the
|
|
+** busy-handler returns non-zero before the lock is available, then
|
|
** [SQLITE_BUSY] is returned to the caller. ^In this case the call to
|
|
** sqlite3_backup_step() can be retried later. ^If the source
|
|
** [database connection]
|
|
@@ -9537,15 +9291,15 @@ typedef struct sqlite3_backup sqlite3_backup;
|
|
** is called, then [SQLITE_LOCKED] is returned immediately. ^Again, in this
|
|
** case the call to sqlite3_backup_step() can be retried later on. ^(If
|
|
** [SQLITE_IOERR_ACCESS | SQLITE_IOERR_XXX], [SQLITE_NOMEM], or
|
|
-** [SQLITE_READONLY] is returned, then
|
|
-** there is no point in retrying the call to sqlite3_backup_step(). These
|
|
-** errors are considered fatal.)^ The application must accept
|
|
-** that the backup operation has failed and pass the backup operation handle
|
|
+** [SQLITE_READONLY] is returned, then
|
|
+** there is no point in retrying the call to sqlite3_backup_step(). These
|
|
+** errors are considered fatal.)^ The application must accept
|
|
+** that the backup operation has failed and pass the backup operation handle
|
|
** to the sqlite3_backup_finish() to release associated resources.
|
|
**
|
|
** ^The first call to sqlite3_backup_step() obtains an exclusive lock
|
|
-** on the destination file. ^The exclusive lock is not released until either
|
|
-** sqlite3_backup_finish() is called or the backup operation is complete
|
|
+** on the destination file. ^The exclusive lock is not released until either
|
|
+** sqlite3_backup_finish() is called or the backup operation is complete
|
|
** and sqlite3_backup_step() returns [SQLITE_DONE]. ^Every call to
|
|
** sqlite3_backup_step() obtains a [shared lock] on the source database that
|
|
** lasts for the duration of the sqlite3_backup_step() call.
|
|
@@ -9554,18 +9308,18 @@ typedef struct sqlite3_backup sqlite3_backup;
|
|
** through the backup process. ^If the source database is modified by an
|
|
** external process or via a database connection other than the one being
|
|
** used by the backup operation, then the backup will be automatically
|
|
-** restarted by the next call to sqlite3_backup_step(). ^If the source
|
|
+** restarted by the next call to sqlite3_backup_step(). ^If the source
|
|
** database is modified by the using the same database connection as is used
|
|
** by the backup operation, then the backup database is automatically
|
|
** updated at the same time.
|
|
**
|
|
** [[sqlite3_backup_finish()]] <b>sqlite3_backup_finish()</b>
|
|
**
|
|
-** When sqlite3_backup_step() has returned [SQLITE_DONE], or when the
|
|
+** When sqlite3_backup_step() has returned [SQLITE_DONE], or when the
|
|
** application wishes to abandon the backup operation, the application
|
|
** should destroy the [sqlite3_backup] by passing it to sqlite3_backup_finish().
|
|
** ^The sqlite3_backup_finish() interfaces releases all
|
|
-** resources associated with the [sqlite3_backup] object.
|
|
+** resources associated with the [sqlite3_backup] object.
|
|
** ^If sqlite3_backup_step() has not yet returned [SQLITE_DONE], then any
|
|
** active write-transaction on the destination database is rolled back.
|
|
** The [sqlite3_backup] object is invalid
|
|
@@ -9605,23 +9359,23 @@ typedef struct sqlite3_backup sqlite3_backup;
|
|
** connections, then the source database connection may be used concurrently
|
|
** from within other threads.
|
|
**
|
|
-** However, the application must guarantee that the destination
|
|
-** [database connection] is not passed to any other API (by any thread) after
|
|
+** However, the application must guarantee that the destination
|
|
+** [database connection] is not passed to any other API (by any thread) after
|
|
** sqlite3_backup_init() is called and before the corresponding call to
|
|
** sqlite3_backup_finish(). SQLite does not currently check to see
|
|
** if the application incorrectly accesses the destination [database connection]
|
|
** and so no error code is reported, but the operations may malfunction
|
|
** nevertheless. Use of the destination database connection while a
|
|
-** backup is in progress might also also cause a mutex deadlock.
|
|
+** backup is in progress might also cause a mutex deadlock.
|
|
**
|
|
** If running in [shared cache mode], the application must
|
|
** guarantee that the shared cache used by the destination database
|
|
** is not accessed while the backup is running. In practice this means
|
|
-** that the application must guarantee that the disk file being
|
|
+** that the application must guarantee that the disk file being
|
|
** backed up to is not accessed by any connection within the process,
|
|
** not just the specific connection that was passed to sqlite3_backup_init().
|
|
**
|
|
-** The [sqlite3_backup] object itself is partially threadsafe. Multiple
|
|
+** The [sqlite3_backup] object itself is partially threadsafe. Multiple
|
|
** threads may safely make multiple concurrent calls to sqlite3_backup_step().
|
|
** However, the sqlite3_backup_remaining() and sqlite3_backup_pagecount()
|
|
** APIs are not strictly speaking threadsafe. If they are invoked at the
|
|
@@ -9646,8 +9400,8 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
|
|
** ^When running in shared-cache mode, a database operation may fail with
|
|
** an [SQLITE_LOCKED] error if the required locks on the shared-cache or
|
|
** individual tables within the shared-cache cannot be obtained. See
|
|
-** [SQLite Shared-Cache Mode] for a description of shared-cache locking.
|
|
-** ^This API may be used to register a callback that SQLite will invoke
|
|
+** [SQLite Shared-Cache Mode] for a description of shared-cache locking.
|
|
+** ^This API may be used to register a callback that SQLite will invoke
|
|
** when the connection currently holding the required lock relinquishes it.
|
|
** ^This API is only available if the library was compiled with the
|
|
** [SQLITE_ENABLE_UNLOCK_NOTIFY] C-preprocessor symbol defined.
|
|
@@ -9655,14 +9409,14 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
|
|
** See Also: [Using the SQLite Unlock Notification Feature].
|
|
**
|
|
** ^Shared-cache locks are released when a database connection concludes
|
|
-** its current transaction, either by committing it or rolling it back.
|
|
+** its current transaction, either by committing it or rolling it back.
|
|
**
|
|
** ^When a connection (known as the blocked connection) fails to obtain a
|
|
** shared-cache lock and SQLITE_LOCKED is returned to the caller, the
|
|
** identity of the database connection (the blocking connection) that
|
|
-** has locked the required resource is stored internally. ^After an
|
|
+** has locked the required resource is stored internally. ^After an
|
|
** application receives an SQLITE_LOCKED error, it may call the
|
|
-** sqlite3_unlock_notify() method with the blocked connection handle as
|
|
+** sqlite3_unlock_notify() method with the blocked connection handle as
|
|
** the first argument to register for a callback that will be invoked
|
|
** when the blocking connections current transaction is concluded. ^The
|
|
** callback is invoked from within the [sqlite3_step] or [sqlite3_close]
|
|
@@ -9676,15 +9430,15 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
|
|
**
|
|
** ^If the blocked connection is attempting to obtain a write-lock on a
|
|
** shared-cache table, and more than one other connection currently holds
|
|
-** a read-lock on the same table, then SQLite arbitrarily selects one of
|
|
+** a read-lock on the same table, then SQLite arbitrarily selects one of
|
|
** the other connections to use as the blocking connection.
|
|
**
|
|
-** ^(There may be at most one unlock-notify callback registered by a
|
|
+** ^(There may be at most one unlock-notify callback registered by a
|
|
** blocked connection. If sqlite3_unlock_notify() is called when the
|
|
** blocked connection already has a registered unlock-notify callback,
|
|
** then the new callback replaces the old.)^ ^If sqlite3_unlock_notify() is
|
|
** called with a NULL pointer as its second argument, then any existing
|
|
-** unlock-notify callback is canceled. ^The blocked connections
|
|
+** unlock-notify callback is canceled. ^The blocked connections
|
|
** unlock-notify callback may also be canceled by closing the blocked
|
|
** connection using [sqlite3_close()].
|
|
**
|
|
@@ -9697,7 +9451,7 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
|
|
**
|
|
** <b>Callback Invocation Details</b>
|
|
**
|
|
-** When an unlock-notify callback is registered, the application provides a
|
|
+** When an unlock-notify callback is registered, the application provides a
|
|
** single void* pointer that is passed to the callback when it is invoked.
|
|
** However, the signature of the callback function allows SQLite to pass
|
|
** it an array of void* context pointers. The first argument passed to
|
|
@@ -9710,12 +9464,12 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
|
|
** same callback function, then instead of invoking the callback function
|
|
** multiple times, it is invoked once with the set of void* context pointers
|
|
** specified by the blocked connections bundled together into an array.
|
|
-** This gives the application an opportunity to prioritize any actions
|
|
+** This gives the application an opportunity to prioritize any actions
|
|
** related to the set of unblocked database connections.
|
|
**
|
|
** <b>Deadlock Detection</b>
|
|
**
|
|
-** Assuming that after registering for an unlock-notify callback a
|
|
+** Assuming that after registering for an unlock-notify callback a
|
|
** database waits for the callback to be issued before taking any further
|
|
** action (a reasonable assumption), then using this API may cause the
|
|
** application to deadlock. For example, if connection X is waiting for
|
|
@@ -9738,7 +9492,7 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
|
|
**
|
|
** <b>The "DROP TABLE" Exception</b>
|
|
**
|
|
-** When a call to [sqlite3_step()] returns SQLITE_LOCKED, it is almost
|
|
+** When a call to [sqlite3_step()] returns SQLITE_LOCKED, it is almost
|
|
** always appropriate to call sqlite3_unlock_notify(). There is however,
|
|
** one exception. When executing a "DROP TABLE" or "DROP INDEX" statement,
|
|
** SQLite checks if there are any currently executing SELECT statements
|
|
@@ -9751,7 +9505,7 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
|
|
** One way around this problem is to check the extended error code returned
|
|
** by an sqlite3_step() call. ^(If there is a blocking connection, then the
|
|
** extended error code is set to SQLITE_LOCKED_SHAREDCACHE. Otherwise, in
|
|
-** the special "DROP TABLE/INDEX" case, the extended error code is just
|
|
+** the special "DROP TABLE/INDEX" case, the extended error code is just
|
|
** SQLITE_LOCKED.)^
|
|
*/
|
|
SQLITE_API int sqlite3_unlock_notify(
|
|
@@ -9842,8 +9596,8 @@ SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...);
|
|
** ^The [sqlite3_wal_hook()] function is used to register a callback that
|
|
** is invoked each time data is committed to a database in wal mode.
|
|
**
|
|
-** ^(The callback is invoked by SQLite after the commit has taken place and
|
|
-** the associated write-lock on the database released)^, so the implementation
|
|
+** ^(The callback is invoked by SQLite after the commit has taken place and
|
|
+** the associated write-lock on the database released)^, so the implementation
|
|
** may read, write or [checkpoint] the database as required.
|
|
**
|
|
** ^The first parameter passed to the callback function when it is invoked
|
|
@@ -9862,15 +9616,16 @@ SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...);
|
|
** that does not correspond to any valid SQLite error code, the results
|
|
** are undefined.
|
|
**
|
|
-** A single database handle may have at most a single write-ahead log callback
|
|
+** A single database handle may have at most a single write-ahead log callback
|
|
** registered at one time. ^Calling [sqlite3_wal_hook()] replaces any
|
|
-** previously registered write-ahead log callback. ^Note that the
|
|
-** [sqlite3_wal_autocheckpoint()] interface and the
|
|
+** previously registered write-ahead log callback. ^The return value is
|
|
+** a copy of the third parameter from the previous call, if any, or 0.
|
|
+** ^Note that the [sqlite3_wal_autocheckpoint()] interface and the
|
|
** [wal_autocheckpoint pragma] both invoke [sqlite3_wal_hook()] and will
|
|
** overwrite any prior [sqlite3_wal_hook()] settings.
|
|
*/
|
|
SQLITE_API void *sqlite3_wal_hook(
|
|
- sqlite3*,
|
|
+ sqlite3*,
|
|
int(*)(void *,sqlite3*,const char*,int),
|
|
void*
|
|
);
|
|
@@ -9883,7 +9638,7 @@ SQLITE_API void *sqlite3_wal_hook(
|
|
** [sqlite3_wal_hook()] that causes any database on [database connection] D
|
|
** to automatically [checkpoint]
|
|
** after committing a transaction if there are N or
|
|
-** more frames in the [write-ahead log] file. ^Passing zero or
|
|
+** more frames in the [write-ahead log] file. ^Passing zero or
|
|
** a negative value as the nFrame parameter disables automatic
|
|
** checkpoints entirely.
|
|
**
|
|
@@ -9913,7 +9668,7 @@ SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int N);
|
|
** ^(The sqlite3_wal_checkpoint(D,X) is equivalent to
|
|
** [sqlite3_wal_checkpoint_v2](D,X,[SQLITE_CHECKPOINT_PASSIVE],0,0).)^
|
|
**
|
|
-** In brief, sqlite3_wal_checkpoint(D,X) causes the content in the
|
|
+** In brief, sqlite3_wal_checkpoint(D,X) causes the content in the
|
|
** [write-ahead log] for database X on [database connection] D to be
|
|
** transferred into the database file and for the write-ahead log to
|
|
** be reset. See the [checkpointing] documentation for addition
|
|
@@ -9939,10 +9694,10 @@ SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
|
|
**
|
|
** <dl>
|
|
** <dt>SQLITE_CHECKPOINT_PASSIVE<dd>
|
|
-** ^Checkpoint as many frames as possible without waiting for any database
|
|
-** readers or writers to finish, then sync the database file if all frames
|
|
+** ^Checkpoint as many frames as possible without waiting for any database
|
|
+** readers or writers to finish, then sync the database file if all frames
|
|
** in the log were checkpointed. ^The [busy-handler callback]
|
|
-** is never invoked in the SQLITE_CHECKPOINT_PASSIVE mode.
|
|
+** is never invoked in the SQLITE_CHECKPOINT_PASSIVE mode.
|
|
** ^On the other hand, passive mode might leave the checkpoint unfinished
|
|
** if there are concurrent readers or writers.
|
|
**
|
|
@@ -9956,9 +9711,9 @@ SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
|
|
**
|
|
** <dt>SQLITE_CHECKPOINT_RESTART<dd>
|
|
** ^This mode works the same way as SQLITE_CHECKPOINT_FULL with the addition
|
|
-** that after checkpointing the log file it blocks (calls the
|
|
+** that after checkpointing the log file it blocks (calls the
|
|
** [busy-handler callback])
|
|
-** until all readers are reading from the database file only. ^This ensures
|
|
+** until all readers are reading from the database file only. ^This ensures
|
|
** that the next writer will restart the log file from the beginning.
|
|
** ^Like SQLITE_CHECKPOINT_FULL, this mode blocks new
|
|
** database writer attempts while it is pending, but does not impede readers.
|
|
@@ -9980,31 +9735,31 @@ SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
|
|
** truncated to zero bytes and so both *pnLog and *pnCkpt will be set to zero.
|
|
**
|
|
** ^All calls obtain an exclusive "checkpoint" lock on the database file. ^If
|
|
-** any other process is running a checkpoint operation at the same time, the
|
|
-** lock cannot be obtained and SQLITE_BUSY is returned. ^Even if there is a
|
|
+** any other process is running a checkpoint operation at the same time, the
|
|
+** lock cannot be obtained and SQLITE_BUSY is returned. ^Even if there is a
|
|
** busy-handler configured, it will not be invoked in this case.
|
|
**
|
|
-** ^The SQLITE_CHECKPOINT_FULL, RESTART and TRUNCATE modes also obtain the
|
|
+** ^The SQLITE_CHECKPOINT_FULL, RESTART and TRUNCATE modes also obtain the
|
|
** exclusive "writer" lock on the database file. ^If the writer lock cannot be
|
|
** obtained immediately, and a busy-handler is configured, it is invoked and
|
|
** the writer lock retried until either the busy-handler returns 0 or the lock
|
|
** is successfully obtained. ^The busy-handler is also invoked while waiting for
|
|
** database readers as described above. ^If the busy-handler returns 0 before
|
|
** the writer lock is obtained or while waiting for database readers, the
|
|
-** checkpoint operation proceeds from that point in the same way as
|
|
-** SQLITE_CHECKPOINT_PASSIVE - checkpointing as many frames as possible
|
|
+** checkpoint operation proceeds from that point in the same way as
|
|
+** SQLITE_CHECKPOINT_PASSIVE - checkpointing as many frames as possible
|
|
** without blocking any further. ^SQLITE_BUSY is returned in this case.
|
|
**
|
|
** ^If parameter zDb is NULL or points to a zero length string, then the
|
|
-** specified operation is attempted on all WAL databases [attached] to
|
|
+** specified operation is attempted on all WAL databases [attached] to
|
|
** [database connection] db. In this case the
|
|
-** values written to output parameters *pnLog and *pnCkpt are undefined. ^If
|
|
-** an SQLITE_BUSY error is encountered when processing one or more of the
|
|
-** attached WAL databases, the operation is still attempted on any remaining
|
|
-** attached databases and SQLITE_BUSY is returned at the end. ^If any other
|
|
-** error occurs while processing an attached database, processing is abandoned
|
|
-** and the error code is returned to the caller immediately. ^If no error
|
|
-** (SQLITE_BUSY or otherwise) is encountered while processing the attached
|
|
+** values written to output parameters *pnLog and *pnCkpt are undefined. ^If
|
|
+** an SQLITE_BUSY error is encountered when processing one or more of the
|
|
+** attached WAL databases, the operation is still attempted on any remaining
|
|
+** attached databases and SQLITE_BUSY is returned at the end. ^If any other
|
|
+** error occurs while processing an attached database, processing is abandoned
|
|
+** and the error code is returned to the caller immediately. ^If no error
|
|
+** (SQLITE_BUSY or otherwise) is encountered while processing the attached
|
|
** databases, SQLITE_OK is returned.
|
|
**
|
|
** ^If database zDb is the name of an attached database that is not in WAL
|
|
@@ -10039,7 +9794,7 @@ SQLITE_API int sqlite3_wal_checkpoint_v2(
|
|
*/
|
|
#define SQLITE_CHECKPOINT_PASSIVE 0 /* Do as much as possible w/o blocking */
|
|
#define SQLITE_CHECKPOINT_FULL 1 /* Wait for writers, then checkpoint */
|
|
-#define SQLITE_CHECKPOINT_RESTART 2 /* Like FULL but wait for for readers */
|
|
+#define SQLITE_CHECKPOINT_RESTART 2 /* Like FULL but wait for readers */
|
|
#define SQLITE_CHECKPOINT_TRUNCATE 3 /* Like RESTART but also truncate WAL */
|
|
|
|
/*
|
|
@@ -10064,7 +9819,7 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...);
|
|
|
|
/*
|
|
** CAPI3REF: Virtual Table Configuration Options
|
|
-** KEYWORDS: {virtual table configuration options}
|
|
+** KEYWORDS: {virtual table configuration options}
|
|
** KEYWORDS: {virtual table configuration option}
|
|
**
|
|
** These macros define the various options to the
|
|
@@ -10087,20 +9842,20 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...);
|
|
** If X is non-zero, then the virtual table implementation guarantees
|
|
** that if [xUpdate] returns [SQLITE_CONSTRAINT], it will do so before
|
|
** any modifications to internal or persistent data structures have been made.
|
|
-** If the [ON CONFLICT] mode is ABORT, FAIL, IGNORE or ROLLBACK, SQLite
|
|
+** If the [ON CONFLICT] mode is ABORT, FAIL, IGNORE or ROLLBACK, SQLite
|
|
** is able to roll back a statement or database transaction, and abandon
|
|
-** or continue processing the current SQL statement as appropriate.
|
|
+** or continue processing the current SQL statement as appropriate.
|
|
** If the ON CONFLICT mode is REPLACE and the [xUpdate] method returns
|
|
** [SQLITE_CONSTRAINT], SQLite handles this as if the ON CONFLICT mode
|
|
** had been ABORT.
|
|
**
|
|
** Virtual table implementations that are required to handle OR REPLACE
|
|
-** must do so within the [xUpdate] method. If a call to the
|
|
-** [sqlite3_vtab_on_conflict()] function indicates that the current ON
|
|
-** CONFLICT policy is REPLACE, the virtual table implementation should
|
|
+** must do so within the [xUpdate] method. If a call to the
|
|
+** [sqlite3_vtab_on_conflict()] function indicates that the current ON
|
|
+** CONFLICT policy is REPLACE, the virtual table implementation should
|
|
** silently replace the appropriate rows within the xUpdate callback and
|
|
** return SQLITE_OK. Or, if this is not possible, it may return
|
|
-** SQLITE_CONSTRAINT, in which case SQLite falls back to OR ABORT
|
|
+** SQLITE_CONSTRAINT, in which case SQLite falls back to OR ABORT
|
|
** constraint handling.
|
|
** </dd>
|
|
**
|
|
@@ -10144,10 +9899,11 @@ SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *);
|
|
** CAPI3REF: Determine If Virtual Table Column Access Is For UPDATE
|
|
**
|
|
** If the sqlite3_vtab_nochange(X) routine is called within the [xColumn]
|
|
-** method of a [virtual table], then it returns true if and only if the
|
|
+** method of a [virtual table], then it might return true if the
|
|
** column is being fetched as part of an UPDATE operation during which the
|
|
-** column value will not change. Applications might use this to substitute
|
|
-** a return value that is less expensive to compute and that the corresponding
|
|
+** column value will not change. The virtual table implementation can use
|
|
+** this hint as permission to substitute a return value that is less
|
|
+** expensive to compute and that the corresponding
|
|
** [xUpdate] method understands as a "no-change" value.
|
|
**
|
|
** If the [xColumn] method calls sqlite3_vtab_nochange() and finds that
|
|
@@ -10156,23 +9912,285 @@ SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *);
|
|
** any of the [sqlite3_result_int|sqlite3_result_xxxxx() interfaces].
|
|
** In that case, [sqlite3_value_nochange(X)] will return true for the
|
|
** same column in the [xUpdate] method.
|
|
+**
|
|
+** The sqlite3_vtab_nochange() routine is an optimization. Virtual table
|
|
+** implementations should continue to give a correct answer even if the
|
|
+** sqlite3_vtab_nochange() interface were to always return false. In the
|
|
+** current implementation, the sqlite3_vtab_nochange() interface does always
|
|
+** returns false for the enhanced [UPDATE FROM] statement.
|
|
*/
|
|
SQLITE_API int sqlite3_vtab_nochange(sqlite3_context*);
|
|
|
|
/*
|
|
** CAPI3REF: Determine The Collation For a Virtual Table Constraint
|
|
+** METHOD: sqlite3_index_info
|
|
**
|
|
** This function may only be called from within a call to the [xBestIndex]
|
|
-** method of a [virtual table].
|
|
+** method of a [virtual table]. This function returns a pointer to a string
|
|
+** that is the name of the appropriate collation sequence to use for text
|
|
+** comparisons on the constraint identified by its arguments.
|
|
+**
|
|
+** The first argument must be the pointer to the [sqlite3_index_info] object
|
|
+** that is the first parameter to the xBestIndex() method. The second argument
|
|
+** must be an index into the aConstraint[] array belonging to the
|
|
+** sqlite3_index_info structure passed to xBestIndex.
|
|
+**
|
|
+** Important:
|
|
+** The first parameter must be the same pointer that is passed into the
|
|
+** xBestMethod() method. The first parameter may not be a pointer to a
|
|
+** different [sqlite3_index_info] object, even an exact copy.
|
|
+**
|
|
+** The return value is computed as follows:
|
|
+**
|
|
+** <ol>
|
|
+** <li><p> If the constraint comes from a WHERE clause expression that contains
|
|
+** a [COLLATE operator], then the name of the collation specified by
|
|
+** that COLLATE operator is returned.
|
|
+** <li><p> If there is no COLLATE operator, but the column that is the subject
|
|
+** of the constraint specifies an alternative collating sequence via
|
|
+** a [COLLATE clause] on the column definition within the CREATE TABLE
|
|
+** statement that was passed into [sqlite3_declare_vtab()], then the
|
|
+** name of that alternative collating sequence is returned.
|
|
+** <li><p> Otherwise, "BINARY" is returned.
|
|
+** </ol>
|
|
+*/
|
|
+SQLITE_API const char *sqlite3_vtab_collation(sqlite3_index_info*,int);
|
|
+
|
|
+/*
|
|
+** CAPI3REF: Determine if a virtual table query is DISTINCT
|
|
+** METHOD: sqlite3_index_info
|
|
+**
|
|
+** This API may only be used from within an [xBestIndex|xBestIndex method]
|
|
+** of a [virtual table] implementation. The result of calling this
|
|
+** interface from outside of xBestIndex() is undefined and probably harmful.
|
|
+**
|
|
+** ^The sqlite3_vtab_distinct() interface returns an integer between 0 and
|
|
+** 3. The integer returned by sqlite3_vtab_distinct()
|
|
+** gives the virtual table additional information about how the query
|
|
+** planner wants the output to be ordered. As long as the virtual table
|
|
+** can meet the ordering requirements of the query planner, it may set
|
|
+** the "orderByConsumed" flag.
|
|
+**
|
|
+** <ol><li value="0"><p>
|
|
+** ^If the sqlite3_vtab_distinct() interface returns 0, that means
|
|
+** that the query planner needs the virtual table to return all rows in the
|
|
+** sort order defined by the "nOrderBy" and "aOrderBy" fields of the
|
|
+** [sqlite3_index_info] object. This is the default expectation. If the
|
|
+** virtual table outputs all rows in sorted order, then it is always safe for
|
|
+** the xBestIndex method to set the "orderByConsumed" flag, regardless of
|
|
+** the return value from sqlite3_vtab_distinct().
|
|
+** <li value="1"><p>
|
|
+** ^(If the sqlite3_vtab_distinct() interface returns 1, that means
|
|
+** that the query planner does not need the rows to be returned in sorted order
|
|
+** as long as all rows with the same values in all columns identified by the
|
|
+** "aOrderBy" field are adjacent.)^ This mode is used when the query planner
|
|
+** is doing a GROUP BY.
|
|
+** <li value="2"><p>
|
|
+** ^(If the sqlite3_vtab_distinct() interface returns 2, that means
|
|
+** that the query planner does not need the rows returned in any particular
|
|
+** order, as long as rows with the same values in all "aOrderBy" columns
|
|
+** are adjacent.)^ ^(Furthermore, only a single row for each particular
|
|
+** combination of values in the columns identified by the "aOrderBy" field
|
|
+** needs to be returned.)^ ^It is always ok for two or more rows with the same
|
|
+** values in all "aOrderBy" columns to be returned, as long as all such rows
|
|
+** are adjacent. ^The virtual table may, if it chooses, omit extra rows
|
|
+** that have the same value for all columns identified by "aOrderBy".
|
|
+** ^However omitting the extra rows is optional.
|
|
+** This mode is used for a DISTINCT query.
|
|
+** <li value="3"><p>
|
|
+** ^(If the sqlite3_vtab_distinct() interface returns 3, that means
|
|
+** that the query planner needs only distinct rows but it does need the
|
|
+** rows to be sorted.)^ ^The virtual table implementation is free to omit
|
|
+** rows that are identical in all aOrderBy columns, if it wants to, but
|
|
+** it is not required to omit any rows. This mode is used for queries
|
|
+** that have both DISTINCT and ORDER BY clauses.
|
|
+** </ol>
|
|
+**
|
|
+** ^For the purposes of comparing virtual table output values to see if the
|
|
+** values are same value for sorting purposes, two NULL values are considered
|
|
+** to be the same. In other words, the comparison operator is "IS"
|
|
+** (or "IS NOT DISTINCT FROM") and not "==".
|
|
+**
|
|
+** If a virtual table implementation is unable to meet the requirements
|
|
+** specified above, then it must not set the "orderByConsumed" flag in the
|
|
+** [sqlite3_index_info] object or an incorrect answer may result.
|
|
+**
|
|
+** ^A virtual table implementation is always free to return rows in any order
|
|
+** it wants, as long as the "orderByConsumed" flag is not set. ^When the
|
|
+** the "orderByConsumed" flag is unset, the query planner will add extra
|
|
+** [bytecode] to ensure that the final results returned by the SQL query are
|
|
+** ordered correctly. The use of the "orderByConsumed" flag and the
|
|
+** sqlite3_vtab_distinct() interface is merely an optimization. ^Careful
|
|
+** use of the sqlite3_vtab_distinct() interface and the "orderByConsumed"
|
|
+** flag might help queries against a virtual table to run faster. Being
|
|
+** overly aggressive and setting the "orderByConsumed" flag when it is not
|
|
+** valid to do so, on the other hand, might cause SQLite to return incorrect
|
|
+** results.
|
|
+*/
|
|
+SQLITE_API int sqlite3_vtab_distinct(sqlite3_index_info*);
|
|
+
|
|
+/*
|
|
+** CAPI3REF: Identify and handle IN constraints in xBestIndex
|
|
+**
|
|
+** This interface may only be used from within an
|
|
+** [xBestIndex|xBestIndex() method] of a [virtual table] implementation.
|
|
+** The result of invoking this interface from any other context is
|
|
+** undefined and probably harmful.
|
|
+**
|
|
+** ^(A constraint on a virtual table of the form
|
|
+** "[IN operator|column IN (...)]" is
|
|
+** 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
|
|
+** 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
|
|
+** only sees a single value from the right-hand side of the IN operator
|
|
+** at a time.
|
|
+**
|
|
+** In some cases, however, it would be advantageous for the virtual
|
|
+** table to see all values on the right-hand of the IN operator all at
|
|
+** once. The sqlite3_vtab_in() interfaces facilitates this in two ways:
|
|
+**
|
|
+** <ol>
|
|
+** <li><p>
|
|
+** ^A call to sqlite3_vtab_in(P,N,-1) will return true (non-zero)
|
|
+** if and only if the [sqlite3_index_info|P->aConstraint][N] constraint
|
|
+** is an [IN operator] that can be processed all at once. ^In other words,
|
|
+** sqlite3_vtab_in() with -1 in the third argument is a mechanism
|
|
+** by which the virtual table can ask SQLite if all-at-once processing
|
|
+** of the IN operator is even possible.
|
|
+**
|
|
+** <li><p>
|
|
+** ^A call to sqlite3_vtab_in(P,N,F) with F==1 or F==0 indicates
|
|
+** to SQLite that the virtual table does or does not want to process
|
|
+** the IN operator all-at-once, respectively. ^Thus when the third
|
|
+** parameter (F) is non-negative, this interface is the mechanism by
|
|
+** which the virtual table tells SQLite how it wants to process the
|
|
+** IN operator.
|
|
+** </ol>
|
|
+**
|
|
+** ^The sqlite3_vtab_in(P,N,F) interface can be invoked multiple times
|
|
+** within the same xBestIndex method call. ^For any given P,N pair,
|
|
+** the return value from sqlite3_vtab_in(P,N,F) will always be the same
|
|
+** within the same xBestIndex call. ^If the interface returns true
|
|
+** (non-zero), that means that the constraint is an IN operator
|
|
+** that can be processed all-at-once. ^If the constraint is not an IN
|
|
+** operator or cannot be processed all-at-once, then the interface returns
|
|
+** false.
|
|
+**
|
|
+** ^(All-at-once processing of the IN operator is selected if both of the
|
|
+** following conditions are met:
|
|
+**
|
|
+** <ol>
|
|
+** <li><p> The P->aConstraintUsage[N].argvIndex value is set to a positive
|
|
+** integer. This is how the virtual table tells SQLite that it wants to
|
|
+** use the N-th constraint.
|
|
+**
|
|
+** <li><p> The last call to sqlite3_vtab_in(P,N,F) for which F was
|
|
+** non-negative had F>=1.
|
|
+** </ol>)^
|
|
**
|
|
-** The first argument must be the sqlite3_index_info object that is the
|
|
-** first parameter to the xBestIndex() method. The second argument must be
|
|
-** an index into the aConstraint[] array belonging to the sqlite3_index_info
|
|
-** structure passed to xBestIndex. This function returns a pointer to a buffer
|
|
-** containing the name of the collation sequence for the corresponding
|
|
-** constraint.
|
|
+** ^If either or both of the conditions above are false, then SQLite uses
|
|
+** the traditional one-at-a-time processing strategy for the IN constraint.
|
|
+** ^If both conditions are true, then the argvIndex-th parameter to the
|
|
+** xFilter method will be an [sqlite3_value] that appears to be NULL,
|
|
+** but which can be passed to [sqlite3_vtab_in_first()] and
|
|
+** [sqlite3_vtab_in_next()] to find all values on the right-hand side
|
|
+** of the IN constraint.
|
|
*/
|
|
-SQLITE_API SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_info*,int);
|
|
+SQLITE_API int sqlite3_vtab_in(sqlite3_index_info*, int iCons, int bHandle);
|
|
+
|
|
+/*
|
|
+** CAPI3REF: Find all elements on the right-hand side of an IN constraint.
|
|
+**
|
|
+** These interfaces are only useful from within the
|
|
+** [xFilter|xFilter() method] of a [virtual table] implementation.
|
|
+** The result of invoking these interfaces from any other context
|
|
+** is undefined and probably harmful.
|
|
+**
|
|
+** The X parameter in a call to sqlite3_vtab_in_first(X,P) or
|
|
+** sqlite3_vtab_in_next(X,P) should be one of the parameters to the
|
|
+** xFilter method which invokes these routines, and specifically
|
|
+** a parameter that was previously selected for all-at-once IN constraint
|
|
+** processing use the [sqlite3_vtab_in()] interface in the
|
|
+** [xBestIndex|xBestIndex method]. ^(If the X parameter is not
|
|
+** an xFilter argument that was selected for all-at-once IN constraint
|
|
+** processing, then these routines return [SQLITE_ERROR].)^
|
|
+**
|
|
+** ^(Use these routines to access all values on the right-hand side
|
|
+** of the IN constraint using code like the following:
|
|
+**
|
|
+** <blockquote><pre>
|
|
+** for(rc=sqlite3_vtab_in_first(pList, &pVal);
|
|
+** rc==SQLITE_OK && pVal;
|
|
+** rc=sqlite3_vtab_in_next(pList, &pVal)
|
|
+** ){
|
|
+** // do something with pVal
|
|
+** }
|
|
+** if( rc!=SQLITE_OK ){
|
|
+** // an error has occurred
|
|
+** }
|
|
+** </pre></blockquote>)^
|
|
+**
|
|
+** ^On success, the sqlite3_vtab_in_first(X,P) and sqlite3_vtab_in_next(X,P)
|
|
+** routines return SQLITE_OK and set *P to point to the first or next value
|
|
+** on the RHS of the IN constraint. ^If there are no more values on the
|
|
+** right hand side of the IN constraint, then *P is set to NULL and these
|
|
+** routines return [SQLITE_DONE]. ^The return value might be
|
|
+** some other value, such as SQLITE_NOMEM, in the event of a malfunction.
|
|
+**
|
|
+** The *ppOut values returned by these routines are only valid until the
|
|
+** next call to either of these routines or until the end of the xFilter
|
|
+** method from which these routines were called. If the virtual table
|
|
+** implementation needs to retain the *ppOut values for longer, it must make
|
|
+** copies. The *ppOut values are [protected sqlite3_value|protected].
|
|
+*/
|
|
+SQLITE_API int sqlite3_vtab_in_first(sqlite3_value *pVal, sqlite3_value **ppOut);
|
|
+SQLITE_API int sqlite3_vtab_in_next(sqlite3_value *pVal, sqlite3_value **ppOut);
|
|
+
|
|
+/*
|
|
+** CAPI3REF: Constraint values in xBestIndex()
|
|
+** METHOD: sqlite3_index_info
|
|
+**
|
|
+** This API may only be used from within the [xBestIndex|xBestIndex method]
|
|
+** of a [virtual table] implementation. The result of calling this interface
|
|
+** from outside of an xBestIndex method are undefined and probably harmful.
|
|
+**
|
|
+** ^When the sqlite3_vtab_rhs_value(P,J,V) interface is invoked from within
|
|
+** the [xBestIndex] method of a [virtual table] implementation, with P being
|
|
+** a copy of the [sqlite3_index_info] object pointer passed into xBestIndex and
|
|
+** J being a 0-based index into P->aConstraint[], then this routine
|
|
+** attempts to set *V to the value of the right-hand operand of
|
|
+** that constraint if the right-hand operand is known. ^If the
|
|
+** right-hand operand is not known, then *V is set to a NULL pointer.
|
|
+** ^The sqlite3_vtab_rhs_value(P,J,V) interface returns SQLITE_OK if
|
|
+** and only if *V is set to a value. ^The sqlite3_vtab_rhs_value(P,J,V)
|
|
+** inteface returns SQLITE_NOTFOUND if the right-hand side of the J-th
|
|
+** constraint is not available. ^The sqlite3_vtab_rhs_value() interface
|
|
+** can return an result code other than SQLITE_OK or SQLITE_NOTFOUND if
|
|
+** something goes wrong.
|
|
+**
|
|
+** The sqlite3_vtab_rhs_value() interface is usually only successful if
|
|
+** the right-hand operand of a constraint is a literal value in the original
|
|
+** SQL statement. If the right-hand operand is an expression or a reference
|
|
+** to some other column or a [host parameter], then sqlite3_vtab_rhs_value()
|
|
+** will probably return [SQLITE_NOTFOUND].
|
|
+**
|
|
+** ^(Some constraints, such as [SQLITE_INDEX_CONSTRAINT_ISNULL] and
|
|
+** [SQLITE_INDEX_CONSTRAINT_ISNOTNULL], have no right-hand operand. For such
|
|
+** constraints, sqlite3_vtab_rhs_value() always returns SQLITE_NOTFOUND.)^
|
|
+**
|
|
+** ^The [sqlite3_value] object returned in *V is a protected sqlite3_value
|
|
+** and remains valid for the duration of the xBestIndex method call.
|
|
+** ^When xBestIndex returns, the sqlite3_value object returned by
|
|
+** sqlite3_vtab_rhs_value() is automatically deallocated.
|
|
+**
|
|
+** The "_rhs_" in the name of this routine is an abbreviation for
|
|
+** "Right-Hand Side".
|
|
+*/
|
|
+SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value **ppVal);
|
|
|
|
/*
|
|
** CAPI3REF: Conflict resolution modes
|
|
@@ -10204,6 +10222,10 @@ SQLITE_API SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_
|
|
** managed by the prepared statement S and will be automatically freed when
|
|
** S is finalized.
|
|
**
|
|
+** Not all values are available for all query elements. When a value is
|
|
+** not available, the output variable is set to -1 if the value is numeric,
|
|
+** or to NULL if it is a string (SQLITE_SCANSTAT_NAME).
|
|
+**
|
|
** <dl>
|
|
** [[SQLITE_SCANSTAT_NLOOP]] <dt>SQLITE_SCANSTAT_NLOOP</dt>
|
|
** <dd>^The [sqlite3_int64] variable pointed to by the V parameter will be
|
|
@@ -10231,12 +10253,24 @@ SQLITE_API SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_
|
|
** to a zero-terminated UTF-8 string containing the [EXPLAIN QUERY PLAN]
|
|
** description for the X-th loop.
|
|
**
|
|
-** [[SQLITE_SCANSTAT_SELECTID]] <dt>SQLITE_SCANSTAT_SELECT</dt>
|
|
+** [[SQLITE_SCANSTAT_SELECTID]] <dt>SQLITE_SCANSTAT_SELECTID</dt>
|
|
** <dd>^The "int" variable pointed to by the V parameter will be set to the
|
|
-** "select-id" for the X-th loop. The select-id identifies which query or
|
|
-** subquery the loop is part of. The main query has a select-id of zero.
|
|
-** The select-id is the same value as is output in the first column
|
|
-** of an [EXPLAIN QUERY PLAN] query.
|
|
+** id for the X-th query plan element. The id value is unique within the
|
|
+** statement. The select-id is the same value as is output in the first
|
|
+** column of an [EXPLAIN QUERY PLAN] query.
|
|
+**
|
|
+** [[SQLITE_SCANSTAT_PARENTID]] <dt>SQLITE_SCANSTAT_PARENTID</dt>
|
|
+** <dd>The "int" variable pointed to by the V parameter will be set to the
|
|
+** the id of the parent of the current query element, if applicable, or
|
|
+** to zero if the query element has no parent. This is the same value as
|
|
+** returned in the second column of an [EXPLAIN QUERY PLAN] query.
|
|
+**
|
|
+** [[SQLITE_SCANSTAT_NCYCLE]] <dt>SQLITE_SCANSTAT_NCYCLE</dt>
|
|
+** <dd>The sqlite3_int64 output value is set to the number of cycles,
|
|
+** according to the processor time-stamp counter, that elapsed while the
|
|
+** query element was being processed. This value is not available for
|
|
+** all query elements - if it is unavailable the output variable is
|
|
+** set to -1.
|
|
** </dl>
|
|
*/
|
|
#define SQLITE_SCANSTAT_NLOOP 0
|
|
@@ -10245,12 +10279,14 @@ SQLITE_API SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_
|
|
#define SQLITE_SCANSTAT_NAME 3
|
|
#define SQLITE_SCANSTAT_EXPLAIN 4
|
|
#define SQLITE_SCANSTAT_SELECTID 5
|
|
+#define SQLITE_SCANSTAT_PARENTID 6
|
|
+#define SQLITE_SCANSTAT_NCYCLE 7
|
|
|
|
/*
|
|
** CAPI3REF: Prepared Statement Scan Status
|
|
** METHOD: sqlite3_stmt
|
|
**
|
|
-** This interface returns information about the predicted and measured
|
|
+** These interfaces return information about the predicted and measured
|
|
** performance for pStmt. Advanced applications can use this
|
|
** interface to compare the predicted and the measured performance and
|
|
** issue warnings and/or rerun [ANALYZE] if discrepancies are found.
|
|
@@ -10261,19 +10297,25 @@ SQLITE_API SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_
|
|
**
|
|
** The "iScanStatusOp" parameter determines which status information to return.
|
|
** The "iScanStatusOp" must be one of the [scanstatus options] or the behavior
|
|
-** of this interface is undefined.
|
|
-** ^The requested measurement is written into a variable pointed to by
|
|
-** the "pOut" parameter.
|
|
-** Parameter "idx" identifies the specific loop to retrieve statistics for.
|
|
-** Loops are numbered starting from zero. ^If idx is out of range - less than
|
|
-** zero or greater than or equal to the total number of loops used to implement
|
|
-** the statement - a non-zero value is returned and the variable that pOut
|
|
-** points to is unchanged.
|
|
-**
|
|
-** ^Statistics might not be available for all loops in all statements. ^In cases
|
|
-** where there exist loops with no available statistics, this function behaves
|
|
-** as if the loop did not exist - it returns non-zero and leave the variable
|
|
-** that pOut points to unchanged.
|
|
+** of this interface is undefined. ^The requested measurement is written into
|
|
+** a variable pointed to by the "pOut" parameter.
|
|
+**
|
|
+** The "flags" parameter must be passed a mask of flags. At present only
|
|
+** one flag is defined - SQLITE_SCANSTAT_COMPLEX. If SQLITE_SCANSTAT_COMPLEX
|
|
+** is specified, then status information is available for all elements
|
|
+** of a query plan that are reported by "EXPLAIN QUERY PLAN" output. If
|
|
+** SQLITE_SCANSTAT_COMPLEX is not specified, then only query plan elements
|
|
+** that correspond to query loops (the "SCAN..." and "SEARCH..." elements of
|
|
+** the EXPLAIN QUERY PLAN output) are available. Invoking API
|
|
+** sqlite3_stmt_scanstatus() is equivalent to calling
|
|
+** sqlite3_stmt_scanstatus_v2() with a zeroed flags parameter.
|
|
+**
|
|
+** Parameter "idx" identifies the specific query element to retrieve statistics
|
|
+** for. Query elements are numbered starting from zero. A value of -1 may be
|
|
+** to query for statistics regarding the entire query. ^If idx is out of range
|
|
+** - less than -1 or greater than or equal to the total number of query
|
|
+** elements used to implement the statement - a non-zero value is returned and
|
|
+** the variable that pOut points to is unchanged.
|
|
**
|
|
** See also: [sqlite3_stmt_scanstatus_reset()]
|
|
*/
|
|
@@ -10282,7 +10324,20 @@ SQLITE_API int sqlite3_stmt_scanstatus(
|
|
int idx, /* Index of loop to report on */
|
|
int iScanStatusOp, /* Information desired. SQLITE_SCANSTAT_* */
|
|
void *pOut /* Result written here */
|
|
-);
|
|
+);
|
|
+SQLITE_API int sqlite3_stmt_scanstatus_v2(
|
|
+ sqlite3_stmt *pStmt, /* Prepared statement for which info desired */
|
|
+ int idx, /* Index of loop to report on */
|
|
+ int iScanStatusOp, /* Information desired. SQLITE_SCANSTAT_* */
|
|
+ int flags, /* Mask of flags defined below */
|
|
+ void *pOut /* Result written here */
|
|
+);
|
|
+
|
|
+/*
|
|
+** CAPI3REF: Prepared Statement Scan Status
|
|
+** KEYWORDS: {scan status flags}
|
|
+*/
|
|
+#define SQLITE_SCANSTAT_COMPLEX 0x0001
|
|
|
|
/*
|
|
** CAPI3REF: Zero Scan-Status Counters
|
|
@@ -10297,18 +10352,19 @@ SQLITE_API void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*);
|
|
|
|
/*
|
|
** CAPI3REF: Flush caches to disk mid-transaction
|
|
+** METHOD: sqlite3
|
|
**
|
|
** ^If a write-transaction is open on [database connection] D when the
|
|
** [sqlite3_db_cacheflush(D)] interface invoked, any dirty
|
|
-** pages in the pager-cache that are not currently in use are written out
|
|
+** pages in the pager-cache that are not currently in use are written out
|
|
** to disk. A dirty page may be in use if a database cursor created by an
|
|
** active SQL statement is reading from it, or if it is page 1 of a database
|
|
** file (page 1 is always "in use"). ^The [sqlite3_db_cacheflush(D)]
|
|
** interface flushes caches for all schemas - "main", "temp", and
|
|
** any [attached] databases.
|
|
**
|
|
-** ^If this function needs to obtain extra database locks before dirty pages
|
|
-** can be flushed to disk, it does so. ^If those locks cannot be obtained
|
|
+** ^If this function needs to obtain extra database locks before dirty pages
|
|
+** can be flushed to disk, it does so. ^If those locks cannot be obtained
|
|
** immediately and there is a busy-handler callback configured, it is invoked
|
|
** in the usual manner. ^If the required lock still cannot be obtained, then
|
|
** the database is skipped and an attempt made to flush any dirty pages
|
|
@@ -10329,6 +10385,7 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*);
|
|
|
|
/*
|
|
** CAPI3REF: The pre-update hook.
|
|
+** METHOD: sqlite3
|
|
**
|
|
** ^These interfaces are only available if SQLite is compiled using the
|
|
** [SQLITE_ENABLE_PREUPDATE_HOOK] compile-time option.
|
|
@@ -10346,7 +10403,7 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*);
|
|
**
|
|
** ^The preupdate hook only fires for changes to real database tables; the
|
|
** preupdate hook is not invoked for changes to [virtual tables] or to
|
|
-** system tables like sqlite_master or sqlite_stat1.
|
|
+** system tables like sqlite_sequence or sqlite_stat1.
|
|
**
|
|
** ^The second parameter to the preupdate callback is a pointer to
|
|
** the [database connection] that registered the preupdate hook.
|
|
@@ -10355,21 +10412,25 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*);
|
|
** kind of update operation that is about to occur.
|
|
** ^(The fourth parameter to the preupdate callback is the name of the
|
|
** database within the database connection that is being modified. This
|
|
-** will be "main" for the main database or "temp" for TEMP tables or
|
|
+** will be "main" for the main database or "temp" for TEMP tables or
|
|
** the name given after the AS keyword in the [ATTACH] statement for attached
|
|
** databases.)^
|
|
** ^The fifth parameter to the preupdate callback is the name of the
|
|
** table that is being modified.
|
|
**
|
|
** For an UPDATE or DELETE operation on a [rowid table], the sixth
|
|
-** parameter passed to the preupdate callback is the initial [rowid] of the
|
|
+** parameter passed to the preupdate callback is the initial [rowid] of the
|
|
** row being modified or deleted. For an INSERT operation on a rowid table,
|
|
-** or any operation on a WITHOUT ROWID table, the value of the sixth
|
|
+** or any operation on a WITHOUT ROWID table, the value of the sixth
|
|
** parameter is undefined. For an INSERT or UPDATE on a rowid table the
|
|
** seventh parameter is the final rowid value of the row being inserted
|
|
** or updated. The value of the seventh parameter passed to the callback
|
|
** function is not defined for operations on WITHOUT ROWID tables, or for
|
|
-** INSERT operations on rowid tables.
|
|
+** DELETE operations on rowid tables.
|
|
+**
|
|
+** ^The sqlite3_preupdate_hook(D,C,P) function returns the P argument from
|
|
+** the previous call on the same [database connection] D, or NULL for
|
|
+** the first call on D.
|
|
**
|
|
** The [sqlite3_preupdate_old()], [sqlite3_preupdate_new()],
|
|
** [sqlite3_preupdate_count()], and [sqlite3_preupdate_depth()] interfaces
|
|
@@ -10403,10 +10464,19 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*);
|
|
**
|
|
** ^The [sqlite3_preupdate_depth(D)] interface returns 0 if the preupdate
|
|
** callback was invoked as a result of a direct insert, update, or delete
|
|
-** operation; or 1 for inserts, updates, or deletes invoked by top-level
|
|
+** operation; or 1 for inserts, updates, or deletes invoked by top-level
|
|
** triggers; or 2 for changes resulting from triggers called by top-level
|
|
** triggers; and so forth.
|
|
**
|
|
+** When the [sqlite3_blob_write()] API is used to update a blob column,
|
|
+** the pre-update hook is invoked with SQLITE_DELETE. This is because the
|
|
+** in this case the new values are not available. In this case, when a
|
|
+** callback made with op==SQLITE_DELETE is actuall a write using the
|
|
+** sqlite3_blob_write() API, the [sqlite3_preupdate_blobwrite()] returns
|
|
+** the index of the column being written. In other cases, where the
|
|
+** pre-update hook is being invoked for some other reason, including a
|
|
+** regular DELETE, sqlite3_preupdate_blobwrite() returns -1.
|
|
+**
|
|
** See also: [sqlite3_update_hook()]
|
|
*/
|
|
#if defined(SQLITE_ENABLE_PREUPDATE_HOOK)
|
|
@@ -10427,17 +10497,19 @@ SQLITE_API int sqlite3_preupdate_old(sqlite3 *, int, sqlite3_value **);
|
|
SQLITE_API int sqlite3_preupdate_count(sqlite3 *);
|
|
SQLITE_API int sqlite3_preupdate_depth(sqlite3 *);
|
|
SQLITE_API int sqlite3_preupdate_new(sqlite3 *, int, sqlite3_value **);
|
|
+SQLITE_API int sqlite3_preupdate_blobwrite(sqlite3 *);
|
|
#endif
|
|
|
|
/*
|
|
** CAPI3REF: Low-level system error code
|
|
+** METHOD: sqlite3
|
|
**
|
|
** ^Attempt to return the underlying operating system error code or error
|
|
** number that caused the most recent I/O error or failure to open a file.
|
|
** The return value is OS-dependent. For example, on unix systems, after
|
|
** [sqlite3_open_v2()] returns [SQLITE_CANTOPEN], this interface could be
|
|
** called to get back the underlying "errno" that caused the problem, such
|
|
-** as ENOSPC, EAUTH, EISDIR, and so forth.
|
|
+** as ENOSPC, EAUTH, EISDIR, and so forth.
|
|
*/
|
|
SQLITE_API int sqlite3_system_errno(sqlite3*);
|
|
|
|
@@ -10475,12 +10547,12 @@ typedef struct sqlite3_snapshot {
|
|
** [sqlite3_snapshot_get(D,S,P)] interface writes a pointer to the newly
|
|
** created [sqlite3_snapshot] object into *P and returns SQLITE_OK.
|
|
** If there is not already a read-transaction open on schema S when
|
|
-** this function is called, one is opened automatically.
|
|
+** this function is called, one is opened automatically.
|
|
**
|
|
** The following must be true for this function to succeed. If any of
|
|
** the following statements are false when sqlite3_snapshot_get() is
|
|
** called, SQLITE_ERROR is returned. The final value of *P is undefined
|
|
-** in this case.
|
|
+** in this case.
|
|
**
|
|
** <ul>
|
|
** <li> The database handle must not be in [autocommit mode].
|
|
@@ -10492,13 +10564,13 @@ typedef struct sqlite3_snapshot {
|
|
**
|
|
** <li> One or more transactions must have been written to the current wal
|
|
** file since it was created on disk (by any connection). This means
|
|
-** that a snapshot cannot be taken on a wal mode database with no wal
|
|
+** that a snapshot cannot be taken on a wal mode database with no wal
|
|
** file immediately after it is first opened. At least one transaction
|
|
** must be written to it first.
|
|
** </ul>
|
|
**
|
|
** This function may also return SQLITE_NOMEM. If it is called with the
|
|
-** database handle in autocommit mode but fails for some other reason,
|
|
+** database handle in autocommit mode but fails for some other reason,
|
|
** whether or not a read transaction is opened on schema S is undefined.
|
|
**
|
|
** The [sqlite3_snapshot] object returned from a successful call to
|
|
@@ -10518,38 +10590,38 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get(
|
|
** CAPI3REF: Start a read transaction on an historical snapshot
|
|
** METHOD: sqlite3_snapshot
|
|
**
|
|
-** ^The [sqlite3_snapshot_open(D,S,P)] interface either starts a new read
|
|
-** transaction or upgrades an existing one for schema S of
|
|
-** [database connection] D such that the read transaction refers to
|
|
-** historical [snapshot] P, rather than the most recent change to the
|
|
-** database. ^The [sqlite3_snapshot_open()] interface returns SQLITE_OK
|
|
+** ^The [sqlite3_snapshot_open(D,S,P)] interface either starts a new read
|
|
+** transaction or upgrades an existing one for schema S of
|
|
+** [database connection] D such that the read transaction refers to
|
|
+** historical [snapshot] P, rather than the most recent change to the
|
|
+** database. ^The [sqlite3_snapshot_open()] interface returns SQLITE_OK
|
|
** on success or an appropriate [error code] if it fails.
|
|
**
|
|
-** ^In order to succeed, the database connection must not be in
|
|
+** ^In order to succeed, the database connection must not be in
|
|
** [autocommit mode] when [sqlite3_snapshot_open(D,S,P)] is called. If there
|
|
** is already a read transaction open on schema S, then the database handle
|
|
** must have no active statements (SELECT statements that have been passed
|
|
-** to sqlite3_step() but not sqlite3_reset() or sqlite3_finalize()).
|
|
+** to sqlite3_step() but not sqlite3_reset() or sqlite3_finalize()).
|
|
** SQLITE_ERROR is returned if either of these conditions is violated, or
|
|
** if schema S does not exist, or if the snapshot object is invalid.
|
|
**
|
|
** ^A call to sqlite3_snapshot_open() will fail to open if the specified
|
|
-** snapshot has been overwritten by a [checkpoint]. In this case
|
|
+** snapshot has been overwritten by a [checkpoint]. In this case
|
|
** SQLITE_ERROR_SNAPSHOT is returned.
|
|
**
|
|
-** If there is already a read transaction open when this function is
|
|
+** If there is already a read transaction open when this function is
|
|
** invoked, then the same read transaction remains open (on the same
|
|
** database snapshot) if SQLITE_ERROR, SQLITE_BUSY or SQLITE_ERROR_SNAPSHOT
|
|
** is returned. If another error code - for example SQLITE_PROTOCOL or an
|
|
** SQLITE_IOERR error code - is returned, then the final state of the
|
|
-** read transaction is undefined. If SQLITE_OK is returned, then the
|
|
+** read transaction is undefined. If SQLITE_OK is returned, then the
|
|
** read transaction is now open on database snapshot P.
|
|
**
|
|
** ^(A call to [sqlite3_snapshot_open(D,S,P)] will fail if the
|
|
** database connection D does not know that the database file for
|
|
** schema S is in [WAL mode]. A database connection might not know
|
|
** that the database file is in [WAL mode] if there has been no prior
|
|
-** I/O on that database connection, or if the database entered [WAL mode]
|
|
+** I/O on that database connection, or if the database entered [WAL mode]
|
|
** after the most recent I/O on the database connection.)^
|
|
** (Hint: Run "[PRAGMA application_id]" against a newly opened
|
|
** database connection in order to make it ready to use snapshots.)
|
|
@@ -10581,17 +10653,17 @@ SQLITE_API SQLITE_EXPERIMENTAL void sqlite3_snapshot_free(sqlite3_snapshot*);
|
|
** METHOD: sqlite3_snapshot
|
|
**
|
|
** The sqlite3_snapshot_cmp(P1, P2) interface is used to compare the ages
|
|
-** of two valid snapshot handles.
|
|
+** of two valid snapshot handles.
|
|
**
|
|
-** If the two snapshot handles are not associated with the same database
|
|
-** file, the result of the comparison is undefined.
|
|
+** If the two snapshot handles are not associated with the same database
|
|
+** file, the result of the comparison is undefined.
|
|
**
|
|
** Additionally, the result of the comparison is only valid if both of the
|
|
** snapshot handles were obtained by calling sqlite3_snapshot_get() since the
|
|
** last time the wal file was deleted. The wal file is deleted when the
|
|
** database is changed back to rollback mode or when the number of database
|
|
-** clients drops to zero. If either snapshot handle was obtained before the
|
|
-** wal file was last deleted, the value returned by this function
|
|
+** clients drops to zero. If either snapshot handle was obtained before the
|
|
+** wal file was last deleted, the value returned by this function
|
|
** is undefined.
|
|
**
|
|
** Otherwise, this API returns a negative value if P1 refers to an older
|
|
@@ -10656,7 +10728,7 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const c
|
|
** representation of the database will usually only exist if there has
|
|
** been a prior call to [sqlite3_deserialize(D,S,...)] with the same
|
|
** values of D and S.
|
|
-** The size of the database is written into *P even if the
|
|
+** The size of the database is written into *P even if the
|
|
** SQLITE_SERIALIZE_NOCOPY bit is set but no contiguous copy
|
|
** of the database exists.
|
|
**
|
|
@@ -10664,8 +10736,8 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const c
|
|
** SQLITE_SERIALIZE_NOCOPY bit is omitted from argument F if a memory
|
|
** allocation error occurs.
|
|
**
|
|
-** This interface is only available if SQLite is compiled with the
|
|
-** [SQLITE_ENABLE_DESERIALIZE] option.
|
|
+** This interface is omitted if SQLite is compiled with the
|
|
+** [SQLITE_OMIT_DESERIALIZE] option.
|
|
*/
|
|
SQLITE_API unsigned char *sqlite3_serialize(
|
|
sqlite3 *db, /* The database connection */
|
|
@@ -10693,7 +10765,7 @@ SQLITE_API unsigned char *sqlite3_serialize(
|
|
/*
|
|
** CAPI3REF: Deserialize a database
|
|
**
|
|
-** The sqlite3_deserialize(D,S,P,N,M,F) interface causes the
|
|
+** The sqlite3_deserialize(D,S,P,N,M,F) interface causes the
|
|
** [database connection] D to disconnect from database S and then
|
|
** reopen S as an in-memory database based on the serialization contained
|
|
** in P. The serialized database P is N bytes in size. M is the size of
|
|
@@ -10712,12 +10784,16 @@ SQLITE_API unsigned char *sqlite3_serialize(
|
|
** database is currently in a read transaction or is involved in a backup
|
|
** operation.
|
|
**
|
|
-** If sqlite3_deserialize(D,S,P,N,M,F) fails for any reason and if the
|
|
+** It is not possible to deserialized into the TEMP database. If the
|
|
+** S argument to sqlite3_deserialize(D,S,P,N,M,F) is "temp" then the
|
|
+** function returns SQLITE_ERROR.
|
|
+**
|
|
+** 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.
|
|
**
|
|
-** This interface is only available if SQLite is compiled with the
|
|
-** [SQLITE_ENABLE_DESERIALIZE] option.
|
|
+** This interface is omitted if SQLite is compiled with the
|
|
+** [SQLITE_OMIT_DESERIALIZE] option.
|
|
*/
|
|
SQLITE_API int sqlite3_deserialize(
|
|
sqlite3 *db, /* The database connection */
|
|
@@ -10761,6 +10837,19 @@ SQLITE_API int sqlite3_deserialize(
|
|
# undef double
|
|
#endif
|
|
|
|
+#if defined(__wasi__)
|
|
+# undef SQLITE_WASI
|
|
+# define SQLITE_WASI 1
|
|
+# undef SQLITE_OMIT_WAL
|
|
+# define SQLITE_OMIT_WAL 1/* because it requires shared memory APIs */
|
|
+# ifndef SQLITE_OMIT_LOAD_EXTENSION
|
|
+# define SQLITE_OMIT_LOAD_EXTENSION
|
|
+# endif
|
|
+# ifndef SQLITE_THREADSAFE
|
|
+# define SQLITE_THREADSAFE 0
|
|
+# endif
|
|
+#endif
|
|
+
|
|
#if 0
|
|
} /* End of the 'extern "C"' block */
|
|
#endif
|
|
@@ -10827,7 +10916,7 @@ struct sqlite3_rtree_geometry {
|
|
};
|
|
|
|
/*
|
|
-** Register a 2nd-generation geometry callback named zScore that can be
|
|
+** Register a 2nd-generation geometry callback named zScore that can be
|
|
** used as part of an R-Tree geometry query as follows:
|
|
**
|
|
** SELECT ... FROM <rtree> WHERE <rtree col> MATCH $zQueryFunc(... params ...)
|
|
@@ -10842,7 +10931,7 @@ SQLITE_API int sqlite3_rtree_query_callback(
|
|
|
|
|
|
/*
|
|
-** A pointer to a structure of the following type is passed as the
|
|
+** A pointer to a structure of the following type is passed as the
|
|
** argument to scored geometry callback registered using
|
|
** sqlite3_rtree_query_callback().
|
|
**
|
|
@@ -10937,7 +11026,7 @@ typedef struct sqlite3_changeset_iter sqlite3_changeset_iter;
|
|
** is not possible for an application to register a pre-update hook on a
|
|
** database handle that has one or more session objects attached. Nor is
|
|
** it possible to create a session object attached to a database handle for
|
|
-** which a pre-update hook is already defined. The results of attempting
|
|
+** which a pre-update hook is already defined. The results of attempting
|
|
** either of these things are undefined.
|
|
**
|
|
** The session object will be used to create changesets for tables in
|
|
@@ -10955,17 +11044,49 @@ SQLITE_API int sqlite3session_create(
|
|
** CAPI3REF: Delete A Session Object
|
|
** DESTRUCTOR: sqlite3_session
|
|
**
|
|
-** Delete a session object previously allocated using
|
|
+** Delete a session object previously allocated using
|
|
** [sqlite3session_create()]. Once a session object has been deleted, the
|
|
** results of attempting to use pSession with any other session module
|
|
** function are undefined.
|
|
**
|
|
** Session objects must be deleted before the database handle to which they
|
|
-** are attached is closed. Refer to the documentation for
|
|
+** are attached is closed. Refer to the documentation for
|
|
** [sqlite3session_create()] for details.
|
|
*/
|
|
SQLITE_API void sqlite3session_delete(sqlite3_session *pSession);
|
|
|
|
+/*
|
|
+** CAPIREF: Conigure a Session Object
|
|
+** METHOD: sqlite3_session
|
|
+**
|
|
+** This method is used to configure a session object after it has been
|
|
+** created. At present the only valid value for the second parameter is
|
|
+** [SQLITE_SESSION_OBJCONFIG_SIZE].
|
|
+**
|
|
+** Arguments for sqlite3session_object_config()
|
|
+**
|
|
+** The following values may passed as the the 4th parameter to
|
|
+** sqlite3session_object_config().
|
|
+**
|
|
+** <dt>SQLITE_SESSION_OBJCONFIG_SIZE <dd>
|
|
+** This option is used to set, clear or query the flag that enables
|
|
+** the [sqlite3session_changeset_size()] API. Because it imposes some
|
|
+** computational overhead, this API is disabled by default. Argument
|
|
+** pArg must point to a value of type (int). If the value is initially
|
|
+** 0, then the sqlite3session_changeset_size() API is disabled. If it
|
|
+** is greater than 0, then the same API is enabled. Or, if the initial
|
|
+** value is less than zero, no change is made. In all cases the (int)
|
|
+** variable is set to 1 if the sqlite3session_changeset_size() API is
|
|
+** enabled following the current call, or 0 otherwise.
|
|
+**
|
|
+** 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
|
|
|
|
/*
|
|
** CAPI3REF: Enable Or Disable A Session Object
|
|
@@ -10979,10 +11100,10 @@ SQLITE_API void sqlite3session_delete(sqlite3_session *pSession);
|
|
** the eventual changesets.
|
|
**
|
|
** Passing zero to this function disables the session. Passing a value
|
|
-** greater than zero enables it. Passing a value less than zero is a
|
|
+** greater than zero enables it. Passing a value less than zero is a
|
|
** no-op, and may be used to query the current state of the session.
|
|
**
|
|
-** The return value indicates the final state of the session object: 0 if
|
|
+** The return value indicates the final state of the session object: 0 if
|
|
** the session is disabled, or 1 if it is enabled.
|
|
*/
|
|
SQLITE_API int sqlite3session_enable(sqlite3_session *pSession, int bEnable);
|
|
@@ -10997,7 +11118,7 @@ SQLITE_API int sqlite3session_enable(sqlite3_session *pSession, int bEnable);
|
|
** <ul>
|
|
** <li> The session object "indirect" flag is set when the change is
|
|
** made, or
|
|
-** <li> The change is made by an SQL trigger or foreign key action
|
|
+** <li> The change is made by an SQL trigger or foreign key action
|
|
** instead of directly as a result of a users SQL statement.
|
|
** </ul>
|
|
**
|
|
@@ -11009,10 +11130,10 @@ SQLITE_API int sqlite3session_enable(sqlite3_session *pSession, int bEnable);
|
|
** flag. If the second argument passed to this function is zero, then the
|
|
** indirect flag is cleared. If it is greater than zero, the indirect flag
|
|
** is set. Passing a value less than zero does not modify the current value
|
|
-** of the indirect flag, and may be used to query the current state of the
|
|
+** of the indirect flag, and may be used to query the current state of the
|
|
** indirect flag for the specified session object.
|
|
**
|
|
-** The return value indicates the final state of the indirect flag: 0 if
|
|
+** The return value indicates the final state of the indirect flag: 0 if
|
|
** it is clear, or 1 if it is set.
|
|
*/
|
|
SQLITE_API int sqlite3session_indirect(sqlite3_session *pSession, int bIndirect);
|
|
@@ -11022,20 +11143,20 @@ SQLITE_API int sqlite3session_indirect(sqlite3_session *pSession, int bIndirect)
|
|
** METHOD: sqlite3_session
|
|
**
|
|
** If argument zTab is not NULL, then it is the name of a table to attach
|
|
-** to the session object passed as the first argument. All subsequent changes
|
|
-** made to the table while the session object is enabled will be recorded. See
|
|
+** to the session object passed as the first argument. All subsequent changes
|
|
+** made to the table while the session object is enabled will be recorded. See
|
|
** documentation for [sqlite3session_changeset()] for further details.
|
|
**
|
|
** Or, if argument zTab is NULL, then changes are recorded for all tables
|
|
-** in the database. If additional tables are added to the database (by
|
|
-** executing "CREATE TABLE" statements) after this call is made, changes for
|
|
+** in the database. If additional tables are added to the database (by
|
|
+** executing "CREATE TABLE" statements) after this call is made, changes for
|
|
** the new tables are also recorded.
|
|
**
|
|
** Changes can only be recorded for tables that have a PRIMARY KEY explicitly
|
|
-** defined as part of their CREATE TABLE statement. It does not matter if the
|
|
+** defined as part of their CREATE TABLE statement. It does not matter if the
|
|
** PRIMARY KEY is an "INTEGER PRIMARY KEY" (rowid alias) or not. The PRIMARY
|
|
** KEY may consist of a single column, or may be a composite key.
|
|
-**
|
|
+**
|
|
** It is not an error if the named table does not exist in the database. Nor
|
|
** is it an error if the named table does not have a PRIMARY KEY. However,
|
|
** no changes will be recorded in either of these scenarios.
|
|
@@ -11043,29 +11164,29 @@ SQLITE_API int sqlite3session_indirect(sqlite3_session *pSession, int bIndirect)
|
|
** Changes are not recorded for individual rows that have NULL values stored
|
|
** in one or more of their PRIMARY KEY columns.
|
|
**
|
|
-** SQLITE_OK is returned if the call completes without error. Or, if an error
|
|
+** SQLITE_OK is returned if the call completes without error. Or, if an error
|
|
** occurs, an SQLite error code (e.g. SQLITE_NOMEM) is returned.
|
|
**
|
|
** <h3>Special sqlite_stat1 Handling</h3>
|
|
**
|
|
-** As of SQLite version 3.22.0, the "sqlite_stat1" table is an exception to
|
|
+** As of SQLite version 3.22.0, the "sqlite_stat1" table is an exception to
|
|
** some of the rules above. In SQLite, the schema of sqlite_stat1 is:
|
|
** <pre>
|
|
-** CREATE TABLE sqlite_stat1(tbl,idx,stat)
|
|
+** CREATE TABLE sqlite_stat1(tbl,idx,stat)
|
|
** </pre>
|
|
**
|
|
-** Even though sqlite_stat1 does not have a PRIMARY KEY, changes are
|
|
-** recorded for it as if the PRIMARY KEY is (tbl,idx). Additionally, changes
|
|
+** Even though sqlite_stat1 does not have a PRIMARY KEY, changes are
|
|
+** recorded for it as if the PRIMARY KEY is (tbl,idx). Additionally, changes
|
|
** are recorded for rows for which (idx IS NULL) is true. However, for such
|
|
** rows a zero-length blob (SQL value X'') is stored in the changeset or
|
|
** patchset instead of a NULL value. This allows such changesets to be
|
|
** manipulated by legacy implementations of sqlite3changeset_invert(),
|
|
** concat() and similar.
|
|
**
|
|
-** The sqlite3changeset_apply() function automatically converts the
|
|
+** The sqlite3changeset_apply() function automatically converts the
|
|
** zero-length blob back to a NULL value when updating the sqlite_stat1
|
|
** table. However, if the application calls sqlite3changeset_new(),
|
|
-** sqlite3changeset_old() or sqlite3changeset_conflict on a changeset
|
|
+** sqlite3changeset_old() or sqlite3changeset_conflict on a changeset
|
|
** iterator directly (including on a changeset iterator passed to a
|
|
** conflict-handler callback) then the X'' value is returned. The application
|
|
** must translate X'' to NULL itself if required.
|
|
@@ -11084,10 +11205,10 @@ SQLITE_API int sqlite3session_attach(
|
|
** CAPI3REF: Set a table filter on a Session Object.
|
|
** METHOD: sqlite3_session
|
|
**
|
|
-** The second argument (xFilter) is the "filter callback". For changes to rows
|
|
+** The second argument (xFilter) is the "filter callback". For changes to rows
|
|
** in tables that are not attached to the Session object, the filter is called
|
|
-** to determine whether changes to the table's rows should be tracked or not.
|
|
-** If xFilter returns 0, changes are not tracked. Note that once a table is
|
|
+** to determine whether changes to the table's rows should be tracked or not.
|
|
+** If xFilter returns 0, changes are not tracked. Note that once a table is
|
|
** attached, xFilter will not be called again.
|
|
*/
|
|
SQLITE_API void sqlite3session_table_filter(
|
|
@@ -11103,9 +11224,9 @@ SQLITE_API void sqlite3session_table_filter(
|
|
** CAPI3REF: Generate A Changeset From A Session Object
|
|
** METHOD: sqlite3_session
|
|
**
|
|
-** Obtain a changeset containing changes to the tables attached to the
|
|
-** session object passed as the first argument. If successful,
|
|
-** set *ppChangeset to point to a buffer containing the changeset
|
|
+** Obtain a changeset containing changes to the tables attached to the
|
|
+** session object passed as the first argument. If successful,
|
|
+** set *ppChangeset to point to a buffer containing the changeset
|
|
** and *pnChangeset to the size of the changeset in bytes before returning
|
|
** SQLITE_OK. If an error occurs, set both *ppChangeset and *pnChangeset to
|
|
** zero and return an SQLite error code.
|
|
@@ -11120,7 +11241,7 @@ SQLITE_API void sqlite3session_table_filter(
|
|
** modifies the values of primary key columns. If such a change is made, it
|
|
** is represented in a changeset as a DELETE followed by an INSERT.
|
|
**
|
|
-** Changes are not recorded for rows that have NULL values stored in one or
|
|
+** Changes are not recorded for rows that have NULL values stored in one or
|
|
** more of their PRIMARY KEY columns. If such a row is inserted or deleted,
|
|
** no corresponding change is present in the changesets returned by this
|
|
** function. If an existing row with one or more NULL values stored in
|
|
@@ -11173,14 +11294,14 @@ SQLITE_API void sqlite3session_table_filter(
|
|
** <ul>
|
|
** <li> For each record generated by an insert, the database is queried
|
|
** for a row with a matching primary key. If one is found, an INSERT
|
|
-** change is added to the changeset. If no such row is found, no change
|
|
+** change is added to the changeset. If no such row is found, no change
|
|
** is added to the changeset.
|
|
**
|
|
-** <li> For each record generated by an update or delete, the database is
|
|
+** <li> For each record generated by an update or delete, the database is
|
|
** queried for a row with a matching primary key. If such a row is
|
|
** found and one or more of the non-primary key fields have been
|
|
-** modified from their original values, an UPDATE change is added to
|
|
-** the changeset. Or, if no such row is found in the table, a DELETE
|
|
+** modified from their original values, an UPDATE change is added to
|
|
+** the changeset. Or, if no such row is found in the table, a DELETE
|
|
** change is added to the changeset. If there is a row with a matching
|
|
** primary key in the database, but all fields contain their original
|
|
** values, no change is added to the changeset.
|
|
@@ -11188,7 +11309,7 @@ SQLITE_API void sqlite3session_table_filter(
|
|
**
|
|
** This means, amongst other things, that if a row is inserted and then later
|
|
** deleted while a session object is active, neither the insert nor the delete
|
|
-** will be present in the changeset. Or if a row is deleted and then later a
|
|
+** will be present in the changeset. Or if a row is deleted and then later a
|
|
** row with the same primary key values inserted while a session object is
|
|
** active, the resulting changeset will contain an UPDATE change instead of
|
|
** a DELETE and an INSERT.
|
|
@@ -11197,10 +11318,10 @@ SQLITE_API void sqlite3session_table_filter(
|
|
** it does not accumulate records when rows are inserted, updated or deleted.
|
|
** This may appear to have some counter-intuitive effects if a single row
|
|
** is written to more than once during a session. For example, if a row
|
|
-** is inserted while a session object is enabled, then later deleted while
|
|
+** is inserted while a session object is enabled, then later deleted while
|
|
** the same session object is disabled, no INSERT record will appear in the
|
|
** changeset, even though the delete took place while the session was disabled.
|
|
-** Or, if one field of a row is updated while a session is disabled, and
|
|
+** Or, if one field of a row is updated while a session is disabled, and
|
|
** another field of the same row is updated while the session is enabled, the
|
|
** resulting changeset will contain an UPDATE change that updates both fields.
|
|
*/
|
|
@@ -11210,6 +11331,22 @@ SQLITE_API int sqlite3session_changeset(
|
|
void **ppChangeset /* OUT: Buffer containing changeset */
|
|
);
|
|
|
|
+/*
|
|
+** CAPI3REF: Return An Upper-limit For The Size Of The Changeset
|
|
+** METHOD: sqlite3_session
|
|
+**
|
|
+** By default, this function always returns 0. For it to return
|
|
+** a useful result, the sqlite3_session object must have been configured
|
|
+** to enable this API using sqlite3session_object_config() with the
|
|
+** SQLITE_SESSION_OBJCONFIG_SIZE verb.
|
|
+**
|
|
+** When enabled, this function returns an upper limit, in bytes, for the size
|
|
+** of the changeset that might be produced if sqlite3session_changeset() were
|
|
+** called. The final changeset size might be equal to or smaller than the
|
|
+** size in bytes returned by this function.
|
|
+*/
|
|
+SQLITE_API sqlite3_int64 sqlite3session_changeset_size(sqlite3_session *pSession);
|
|
+
|
|
/*
|
|
** CAPI3REF: Load The Difference Between Tables Into A Session
|
|
** METHOD: sqlite3_session
|
|
@@ -11221,7 +11358,7 @@ SQLITE_API int sqlite3session_changeset(
|
|
** an error).
|
|
**
|
|
** Argument zFromDb must be the name of a database ("main", "temp" etc.)
|
|
-** attached to the same database handle as the session object that contains
|
|
+** attached to the same database handle as the session object that contains
|
|
** a table compatible with the table attached to the session by this function.
|
|
** A table is considered compatible if it:
|
|
**
|
|
@@ -11237,25 +11374,25 @@ SQLITE_API int sqlite3session_changeset(
|
|
** APIs, tables without PRIMARY KEYs are simply ignored.
|
|
**
|
|
** This function adds a set of changes to the session object that could be
|
|
-** used to update the table in database zFrom (call this the "from-table")
|
|
-** so that its content is the same as the table attached to the session
|
|
+** used to update the table in database zFrom (call this the "from-table")
|
|
+** so that its content is the same as the table attached to the session
|
|
** object (call this the "to-table"). Specifically:
|
|
**
|
|
** <ul>
|
|
-** <li> For each row (primary key) that exists in the to-table but not in
|
|
+** <li> For each row (primary key) that exists in the to-table but not in
|
|
** the from-table, an INSERT record is added to the session object.
|
|
**
|
|
-** <li> For each row (primary key) that exists in the to-table but not in
|
|
+** <li> For each row (primary key) that exists in the to-table but not in
|
|
** the from-table, a DELETE record is added to the session object.
|
|
**
|
|
-** <li> For each row (primary key) that exists in both tables, but features
|
|
+** <li> For each row (primary key) that exists in both tables, but features
|
|
** different non-PK values in each, an UPDATE record is added to the
|
|
-** session.
|
|
+** session.
|
|
** </ul>
|
|
**
|
|
** To clarify, if this function is called and then a changeset constructed
|
|
-** using [sqlite3session_changeset()], then after applying that changeset to
|
|
-** database zFrom the contents of the two compatible tables would be
|
|
+** using [sqlite3session_changeset()], then after applying that changeset to
|
|
+** database zFrom the contents of the two compatible tables would be
|
|
** identical.
|
|
**
|
|
** It an error if database zFrom does not exist or does not contain the
|
|
@@ -11263,7 +11400,7 @@ SQLITE_API int sqlite3session_changeset(
|
|
**
|
|
** If the operation is successful, SQLITE_OK is returned. Otherwise, an SQLite
|
|
** error code. In this case, if argument pzErrMsg is not NULL, *pzErrMsg
|
|
-** may be set to point to a buffer containing an English language error
|
|
+** may be set to point to a buffer containing an English language error
|
|
** message. It is the responsibility of the caller to free this buffer using
|
|
** sqlite3_free().
|
|
*/
|
|
@@ -11282,19 +11419,19 @@ SQLITE_API int sqlite3session_diff(
|
|
** The differences between a patchset and a changeset are that:
|
|
**
|
|
** <ul>
|
|
-** <li> DELETE records consist of the primary key fields only. The
|
|
+** <li> DELETE records consist of the primary key fields only. The
|
|
** original values of other fields are omitted.
|
|
-** <li> The original values of any modified fields are omitted from
|
|
+** <li> The original values of any modified fields are omitted from
|
|
** UPDATE records.
|
|
** </ul>
|
|
**
|
|
-** A patchset blob may be used with up to date versions of all
|
|
-** sqlite3changeset_xxx API functions except for sqlite3changeset_invert(),
|
|
+** A patchset blob may be used with up to date versions of all
|
|
+** sqlite3changeset_xxx API functions except for sqlite3changeset_invert(),
|
|
** which returns SQLITE_CORRUPT if it is passed a patchset. Similarly,
|
|
** attempting to use a patchset blob with old versions of the
|
|
-** sqlite3changeset_xxx APIs also provokes an SQLITE_CORRUPT error.
|
|
+** sqlite3changeset_xxx APIs also provokes an SQLITE_CORRUPT error.
|
|
**
|
|
-** Because the non-primary key "old.*" fields are omitted, no
|
|
+** Because the non-primary key "old.*" fields are omitted, no
|
|
** SQLITE_CHANGESET_DATA conflicts can be detected or reported if a patchset
|
|
** is passed to the sqlite3changeset_apply() API. Other conflict types work
|
|
** in the same way as for changesets.
|
|
@@ -11313,22 +11450,30 @@ SQLITE_API int sqlite3session_patchset(
|
|
/*
|
|
** CAPI3REF: Test if a changeset has recorded any changes.
|
|
**
|
|
-** Return non-zero if no changes to attached tables have been recorded by
|
|
-** the session object passed as the first argument. Otherwise, if one or
|
|
+** Return non-zero if no changes to attached tables have been recorded by
|
|
+** the session object passed as the first argument. Otherwise, if one or
|
|
** more changes have been recorded, return zero.
|
|
**
|
|
** Even if this function returns zero, it is possible that calling
|
|
** [sqlite3session_changeset()] on the session handle may still return a
|
|
-** changeset that contains no changes. This can happen when a row in
|
|
-** an attached table is modified and then later on the original values
|
|
+** changeset that contains no changes. This can happen when a row in
|
|
+** an attached table is modified and then later on the original values
|
|
** are restored. However, if this function returns non-zero, then it is
|
|
-** guaranteed that a call to sqlite3session_changeset() will return a
|
|
+** guaranteed that a call to sqlite3session_changeset() will return a
|
|
** changeset containing zero changes.
|
|
*/
|
|
SQLITE_API int sqlite3session_isempty(sqlite3_session *pSession);
|
|
|
|
/*
|
|
-** CAPI3REF: Create An Iterator To Traverse A Changeset
|
|
+** CAPI3REF: Query for the amount of heap memory used by a session object.
|
|
+**
|
|
+** This API returns the total amount of heap memory in bytes currently
|
|
+** used by the session object passed as the only argument.
|
|
+*/
|
|
+SQLITE_API sqlite3_int64 sqlite3session_memory_used(sqlite3_session *pSession);
|
|
+
|
|
+/*
|
|
+** CAPI3REF: Create An Iterator To Traverse A Changeset
|
|
** CONSTRUCTOR: sqlite3_changeset_iter
|
|
**
|
|
** Create an iterator used to iterate through the contents of a changeset.
|
|
@@ -11336,7 +11481,7 @@ SQLITE_API int sqlite3session_isempty(sqlite3_session *pSession);
|
|
** is returned. Otherwise, if an error occurs, *pp is set to zero and an
|
|
** SQLite error code is returned.
|
|
**
|
|
-** The following functions can be used to advance and query a changeset
|
|
+** The following functions can be used to advance and query a changeset
|
|
** iterator created by this function:
|
|
**
|
|
** <ul>
|
|
@@ -11353,12 +11498,12 @@ SQLITE_API int sqlite3session_isempty(sqlite3_session *pSession);
|
|
**
|
|
** Assuming the changeset blob was created by one of the
|
|
** [sqlite3session_changeset()], [sqlite3changeset_concat()] or
|
|
-** [sqlite3changeset_invert()] functions, all changes within the changeset
|
|
-** that apply to a single table are grouped together. This means that when
|
|
-** an application iterates through a changeset using an iterator created by
|
|
-** this function, all changes that relate to a single table are visited
|
|
-** consecutively. There is no chance that the iterator will visit a change
|
|
-** the applies to table X, then one for table Y, and then later on visit
|
|
+** [sqlite3changeset_invert()] functions, all changes within the changeset
|
|
+** that apply to a single table are grouped together. This means that when
|
|
+** an application iterates through a changeset using an iterator created by
|
|
+** this function, all changes that relate to a single table are visited
|
|
+** consecutively. There is no chance that the iterator will visit a change
|
|
+** the applies to table X, then one for table Y, and then later on visit
|
|
** another change for table X.
|
|
**
|
|
** The behavior of sqlite3changeset_start_v2() and its streaming equivalent
|
|
@@ -11409,12 +11554,12 @@ SQLITE_API int sqlite3changeset_start_v2(
|
|
** point to the first change in the changeset. Each subsequent call advances
|
|
** the iterator to point to the next change in the changeset (if any). If
|
|
** no error occurs and the iterator points to a valid change after a call
|
|
-** to sqlite3changeset_next() has advanced it, SQLITE_ROW is returned.
|
|
+** to sqlite3changeset_next() has advanced it, SQLITE_ROW is returned.
|
|
** Otherwise, if all changes in the changeset have already been visited,
|
|
** SQLITE_DONE is returned.
|
|
**
|
|
-** If an error occurs, an SQLite error code is returned. Possible error
|
|
-** codes include SQLITE_CORRUPT (if the changeset buffer is corrupt) or
|
|
+** If an error occurs, an SQLite error code is returned. Possible error
|
|
+** codes include SQLITE_CORRUPT (if the changeset buffer is corrupt) or
|
|
** SQLITE_NOMEM.
|
|
*/
|
|
SQLITE_API int sqlite3changeset_next(sqlite3_changeset_iter *pIter);
|
|
@@ -11429,18 +11574,23 @@ SQLITE_API int sqlite3changeset_next(sqlite3_changeset_iter *pIter);
|
|
** call to [sqlite3changeset_next()] must have returned [SQLITE_ROW]. If this
|
|
** is not the case, this function returns [SQLITE_MISUSE].
|
|
**
|
|
-** If argument pzTab is not NULL, then *pzTab is set to point to a
|
|
-** nul-terminated utf-8 encoded string containing the name of the table
|
|
-** affected by the current change. The buffer remains valid until either
|
|
-** sqlite3changeset_next() is called on the iterator or until the
|
|
-** conflict-handler function returns. If pnCol is not NULL, then *pnCol is
|
|
-** set to the number of columns in the table affected by the change. If
|
|
-** pbIndirect is not NULL, then *pbIndirect is set to true (1) if the change
|
|
+** Arguments pOp, pnCol and pzTab may not be NULL. Upon return, three
|
|
+** outputs are set through these pointers:
|
|
+**
|
|
+** *pOp is set to one of [SQLITE_INSERT], [SQLITE_DELETE] or [SQLITE_UPDATE],
|
|
+** depending on the type of change that the iterator currently points to;
|
|
+**
|
|
+** *pnCol is set to the number of columns in the table affected by the change; and
|
|
+**
|
|
+** *pzTab is set to point to a nul-terminated utf-8 encoded string containing
|
|
+** the name of the table affected by the current change. The buffer remains
|
|
+** valid until either sqlite3changeset_next() is called on the iterator
|
|
+** or until the conflict-handler function returns.
|
|
+**
|
|
+** If pbIndirect is not NULL, then *pbIndirect is set to true (1) if the change
|
|
** is an indirect change, or false (0) otherwise. See the documentation for
|
|
** [sqlite3session_indirect()] for a description of direct and indirect
|
|
-** changes. Finally, if pOp is not NULL, then *pOp is set to one of
|
|
-** [SQLITE_INSERT], [SQLITE_DELETE] or [SQLITE_UPDATE], depending on the
|
|
-** type of change that the iterator currently points to.
|
|
+** changes.
|
|
**
|
|
** If no error occurs, SQLITE_OK is returned. If an error does occur, an
|
|
** SQLite error code is returned. The values of the output variables may not
|
|
@@ -11493,7 +11643,7 @@ SQLITE_API int sqlite3changeset_pk(
|
|
** The pIter argument passed to this function may either be an iterator
|
|
** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator
|
|
** created by [sqlite3changeset_start()]. In the latter case, the most recent
|
|
-** call to [sqlite3changeset_next()] must have returned SQLITE_ROW.
|
|
+** call to [sqlite3changeset_next()] must have returned SQLITE_ROW.
|
|
** Furthermore, it may only be called if the type of change that the iterator
|
|
** currently points to is either [SQLITE_DELETE] or [SQLITE_UPDATE]. Otherwise,
|
|
** this function returns [SQLITE_MISUSE] and sets *ppValue to NULL.
|
|
@@ -11503,9 +11653,9 @@ SQLITE_API int sqlite3changeset_pk(
|
|
** [SQLITE_RANGE] is returned and *ppValue is set to NULL.
|
|
**
|
|
** If successful, this function sets *ppValue to point to a protected
|
|
-** sqlite3_value object containing the iVal'th value from the vector of
|
|
+** sqlite3_value object containing the iVal'th value from the vector of
|
|
** original row values stored as part of the UPDATE or DELETE change and
|
|
-** returns SQLITE_OK. The name of the function comes from the fact that this
|
|
+** returns SQLITE_OK. The name of the function comes from the fact that this
|
|
** is similar to the "old.*" columns available to update or delete triggers.
|
|
**
|
|
** If some other error occurs (e.g. an OOM condition), an SQLite error code
|
|
@@ -11524,7 +11674,7 @@ SQLITE_API int sqlite3changeset_old(
|
|
** The pIter argument passed to this function may either be an iterator
|
|
** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator
|
|
** created by [sqlite3changeset_start()]. In the latter case, the most recent
|
|
-** call to [sqlite3changeset_next()] must have returned SQLITE_ROW.
|
|
+** call to [sqlite3changeset_next()] must have returned SQLITE_ROW.
|
|
** Furthermore, it may only be called if the type of change that the iterator
|
|
** currently points to is either [SQLITE_UPDATE] or [SQLITE_INSERT]. Otherwise,
|
|
** this function returns [SQLITE_MISUSE] and sets *ppValue to NULL.
|
|
@@ -11534,12 +11684,12 @@ SQLITE_API int sqlite3changeset_old(
|
|
** [SQLITE_RANGE] is returned and *ppValue is set to NULL.
|
|
**
|
|
** If successful, this function sets *ppValue to point to a protected
|
|
-** sqlite3_value object containing the iVal'th value from the vector of
|
|
+** sqlite3_value object containing the iVal'th value from the vector of
|
|
** new row values stored as part of the UPDATE or INSERT change and
|
|
** returns SQLITE_OK. If the change is an UPDATE and does not include
|
|
-** a new value for the requested column, *ppValue is set to NULL and
|
|
-** SQLITE_OK returned. The name of the function comes from the fact that
|
|
-** this is similar to the "new.*" columns available to update or delete
|
|
+** a new value for the requested column, *ppValue is set to NULL and
|
|
+** SQLITE_OK returned. The name of the function comes from the fact that
|
|
+** this is similar to the "new.*" columns available to update or delete
|
|
** triggers.
|
|
**
|
|
** If some other error occurs (e.g. an OOM condition), an SQLite error code
|
|
@@ -11566,7 +11716,7 @@ SQLITE_API int sqlite3changeset_new(
|
|
** [SQLITE_RANGE] is returned and *ppValue is set to NULL.
|
|
**
|
|
** If successful, this function sets *ppValue to point to a protected
|
|
-** sqlite3_value object containing the iVal'th value from the
|
|
+** sqlite3_value object containing the iVal'th value from the
|
|
** "conflicting row" associated with the current conflict-handler callback
|
|
** and returns SQLITE_OK.
|
|
**
|
|
@@ -11610,7 +11760,7 @@ SQLITE_API int sqlite3changeset_fk_conflicts(
|
|
** call has no effect.
|
|
**
|
|
** If an error was encountered within a call to an sqlite3changeset_xxx()
|
|
-** function (for example an [SQLITE_CORRUPT] in [sqlite3changeset_next()] or an
|
|
+** function (for example an [SQLITE_CORRUPT] in [sqlite3changeset_next()] or an
|
|
** [SQLITE_NOMEM] in [sqlite3changeset_new()]) then an error code corresponding
|
|
** to that error is returned by this function. Otherwise, SQLITE_OK is
|
|
** returned. This is to allow the following pattern (pseudo-code):
|
|
@@ -11622,7 +11772,7 @@ SQLITE_API int sqlite3changeset_fk_conflicts(
|
|
** }
|
|
** rc = sqlite3changeset_finalize();
|
|
** if( rc!=SQLITE_OK ){
|
|
-** // An error has occurred
|
|
+** // An error has occurred
|
|
** }
|
|
** </pre>
|
|
*/
|
|
@@ -11650,7 +11800,7 @@ SQLITE_API int sqlite3changeset_finalize(sqlite3_changeset_iter *pIter);
|
|
** zeroed and an SQLite error code returned.
|
|
**
|
|
** It is the responsibility of the caller to eventually call sqlite3_free()
|
|
-** on the *ppOut pointer to free the buffer allocation following a successful
|
|
+** on the *ppOut pointer to free the buffer allocation following a successful
|
|
** call to this function.
|
|
**
|
|
** WARNING/TODO: This function currently assumes that the input is a valid
|
|
@@ -11664,11 +11814,11 @@ SQLITE_API int sqlite3changeset_invert(
|
|
/*
|
|
** CAPI3REF: Concatenate Two Changeset Objects
|
|
**
|
|
-** This function is used to concatenate two changesets, A and B, into a
|
|
+** This function is used to concatenate two changesets, A and B, into a
|
|
** single changeset. The result is a changeset equivalent to applying
|
|
-** changeset A followed by changeset B.
|
|
+** changeset A followed by changeset B.
|
|
**
|
|
-** This function combines the two input changesets using an
|
|
+** This function combines the two input changesets using an
|
|
** sqlite3_changegroup object. Calling it produces similar results as the
|
|
** following code fragment:
|
|
**
|
|
@@ -11700,7 +11850,7 @@ SQLITE_API int sqlite3changeset_concat(
|
|
/*
|
|
** CAPI3REF: Changegroup Handle
|
|
**
|
|
-** A changegroup is an object used to combine two or more
|
|
+** A changegroup is an object used to combine two or more
|
|
** [changesets] or [patchsets]
|
|
*/
|
|
typedef struct sqlite3_changegroup sqlite3_changegroup;
|
|
@@ -11716,7 +11866,7 @@ typedef struct sqlite3_changegroup sqlite3_changegroup;
|
|
**
|
|
** If successful, this function returns SQLITE_OK and populates (*pp) with
|
|
** a pointer to a new sqlite3_changegroup object before returning. The caller
|
|
-** should eventually free the returned object using a call to
|
|
+** should eventually free the returned object using a call to
|
|
** sqlite3changegroup_delete(). If an error occurs, an SQLite error code
|
|
** (i.e. SQLITE_NOMEM) is returned and *pp is set to NULL.
|
|
**
|
|
@@ -11728,7 +11878,7 @@ typedef struct sqlite3_changegroup sqlite3_changegroup;
|
|
** <li> Zero or more changesets (or patchsets) are added to the object
|
|
** by calling sqlite3changegroup_add().
|
|
**
|
|
-** <li> The result of combining all input changesets together is obtained
|
|
+** <li> The result of combining all input changesets together is obtained
|
|
** by the application via a call to sqlite3changegroup_output().
|
|
**
|
|
** <li> The object is deleted using a call to sqlite3changegroup_delete().
|
|
@@ -11737,7 +11887,7 @@ typedef struct sqlite3_changegroup sqlite3_changegroup;
|
|
** Any number of calls to add() and output() may be made between the calls to
|
|
** new() and delete(), and in any order.
|
|
**
|
|
-** As well as the regular sqlite3changegroup_add() and
|
|
+** As well as the regular sqlite3changegroup_add() and
|
|
** sqlite3changegroup_output() functions, also available are the streaming
|
|
** versions sqlite3changegroup_add_strm() and sqlite3changegroup_output_strm().
|
|
*/
|
|
@@ -11748,7 +11898,7 @@ SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp);
|
|
** METHOD: sqlite3_changegroup
|
|
**
|
|
** Add all changes within the changeset (or patchset) in buffer pData (size
|
|
-** nData bytes) to the changegroup.
|
|
+** nData bytes) to the changegroup.
|
|
**
|
|
** If the buffer contains a patchset, then all prior calls to this function
|
|
** on the same changegroup object must also have specified patchsets. Or, if
|
|
@@ -11775,7 +11925,7 @@ SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp);
|
|
** changeset was recorded immediately after the changesets already
|
|
** added to the changegroup.
|
|
** <tr><td>INSERT <td>UPDATE <td>
|
|
-** The INSERT change remains in the changegroup. The values in the
|
|
+** The INSERT change remains in the changegroup. The values in the
|
|
** INSERT change are modified as if the row was inserted by the
|
|
** existing change and then updated according to the new change.
|
|
** <tr><td>INSERT <td>DELETE <td>
|
|
@@ -11786,17 +11936,17 @@ SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp);
|
|
** changeset was recorded immediately after the changesets already
|
|
** added to the changegroup.
|
|
** <tr><td>UPDATE <td>UPDATE <td>
|
|
-** The existing UPDATE remains within the changegroup. It is amended
|
|
-** so that the accompanying values are as if the row was updated once
|
|
+** The existing UPDATE remains within the changegroup. It is amended
|
|
+** so that the accompanying values are as if the row was updated once
|
|
** by the existing change and then again by the new change.
|
|
** <tr><td>UPDATE <td>DELETE <td>
|
|
** The existing UPDATE is replaced by the new DELETE within the
|
|
** changegroup.
|
|
** <tr><td>DELETE <td>INSERT <td>
|
|
** If one or more of the column values in the row inserted by the
|
|
-** new change differ from those in the row deleted by the existing
|
|
+** new change differ from those in the row deleted by the existing
|
|
** change, the existing DELETE is replaced by an UPDATE within the
|
|
-** changegroup. Otherwise, if the inserted row is exactly the same
|
|
+** changegroup. Otherwise, if the inserted row is exactly the same
|
|
** as the deleted row, the existing DELETE is simply discarded.
|
|
** <tr><td>DELETE <td>UPDATE <td>
|
|
** The new change is ignored. This case does not occur if the new
|
|
@@ -11841,7 +11991,7 @@ SQLITE_API int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pDa
|
|
**
|
|
** If an error occurs, an SQLite error code is returned and the output
|
|
** variables (*pnData) and (*ppData) are set to 0. Otherwise, SQLITE_OK
|
|
-** is returned and the output variables are set to the size of and a
|
|
+** is returned and the output variables are set to the size of and a
|
|
** pointer to the output buffer, respectively. In this case it is the
|
|
** responsibility of the caller to eventually free the buffer using a
|
|
** call to sqlite3_free().
|
|
@@ -11863,7 +12013,7 @@ SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup*);
|
|
**
|
|
** Apply a changeset or patchset to a database. These functions attempt to
|
|
** update the "main" database attached to handle db with the changes found in
|
|
-** the changeset passed via the second and third arguments.
|
|
+** the changeset passed via the second and third arguments.
|
|
**
|
|
** The fourth argument (xFilter) passed to these functions is the "filter
|
|
** callback". If it is not NULL, then for each table affected by at least one
|
|
@@ -11874,16 +12024,16 @@ SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup*);
|
|
** Otherwise, if the return value is non-zero or the xFilter argument to
|
|
** is NULL, all changes related to the table are attempted.
|
|
**
|
|
-** For each table that is not excluded by the filter callback, this function
|
|
-** tests that the target database contains a compatible table. A table is
|
|
+** For each table that is not excluded by the filter callback, this function
|
|
+** tests that the target database contains a compatible table. A table is
|
|
** considered compatible if all of the following are true:
|
|
**
|
|
** <ul>
|
|
-** <li> The table has the same name as the name recorded in the
|
|
+** <li> The table has the same name as the name recorded in the
|
|
** changeset, and
|
|
-** <li> The table has at least as many columns as recorded in the
|
|
+** <li> The table has at least as many columns as recorded in the
|
|
** changeset, and
|
|
-** <li> The table has primary key columns in the same position as
|
|
+** <li> The table has primary key columns in the same position as
|
|
** recorded in the changeset.
|
|
** </ul>
|
|
**
|
|
@@ -11892,11 +12042,11 @@ SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup*);
|
|
** via the sqlite3_log() mechanism with the error code SQLITE_SCHEMA. At most
|
|
** one such warning is issued for each table in the changeset.
|
|
**
|
|
-** For each change for which there is a compatible table, an attempt is made
|
|
-** to modify the table contents according to the UPDATE, INSERT or DELETE
|
|
-** change. If a change cannot be applied cleanly, the conflict handler
|
|
-** function passed as the fifth argument to sqlite3changeset_apply() may be
|
|
-** invoked. A description of exactly when the conflict handler is invoked for
|
|
+** For each change for which there is a compatible table, an attempt is made
|
|
+** to modify the table contents according to the UPDATE, INSERT or DELETE
|
|
+** change. If a change cannot be applied cleanly, the conflict handler
|
|
+** function passed as the fifth argument to sqlite3changeset_apply() may be
|
|
+** invoked. A description of exactly when the conflict handler is invoked for
|
|
** each type of change is below.
|
|
**
|
|
** Unlike the xFilter argument, xConflict may not be passed NULL. The results
|
|
@@ -11904,23 +12054,23 @@ SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup*);
|
|
** argument are undefined.
|
|
**
|
|
** Each time the conflict handler function is invoked, it must return one
|
|
-** of [SQLITE_CHANGESET_OMIT], [SQLITE_CHANGESET_ABORT] or
|
|
+** of [SQLITE_CHANGESET_OMIT], [SQLITE_CHANGESET_ABORT] or
|
|
** [SQLITE_CHANGESET_REPLACE]. SQLITE_CHANGESET_REPLACE may only be returned
|
|
** if the second argument passed to the conflict handler is either
|
|
** SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT. If the conflict-handler
|
|
** returns an illegal value, any changes already made are rolled back and
|
|
-** the call to sqlite3changeset_apply() returns SQLITE_MISUSE. Different
|
|
+** the call to sqlite3changeset_apply() returns SQLITE_MISUSE. Different
|
|
** actions are taken by sqlite3changeset_apply() depending on the value
|
|
** returned by each invocation of the conflict-handler function. Refer to
|
|
-** the documentation for the three
|
|
+** the documentation for the three
|
|
** [SQLITE_CHANGESET_OMIT|available return values] for details.
|
|
**
|
|
** <dl>
|
|
** <dt>DELETE Changes<dd>
|
|
-** For each DELETE change, the function checks if the target database
|
|
-** contains a row with the same primary key value (or values) as the
|
|
-** original row values stored in the changeset. If it does, and the values
|
|
-** stored in all non-primary key columns also match the values stored in
|
|
+** For each DELETE change, the function checks if the target database
|
|
+** contains a row with the same primary key value (or values) as the
|
|
+** original row values stored in the changeset. If it does, and the values
|
|
+** stored in all non-primary key columns also match the values stored in
|
|
** the changeset the row is deleted from the target database.
|
|
**
|
|
** If a row with matching primary key values is found, but one or more of
|
|
@@ -11949,22 +12099,22 @@ SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup*);
|
|
** database table, the trailing fields are populated with their default
|
|
** values.
|
|
**
|
|
-** If the attempt to insert the row fails because the database already
|
|
+** If the attempt to insert the row fails because the database already
|
|
** contains a row with the same primary key values, the conflict handler
|
|
-** function is invoked with the second argument set to
|
|
+** function is invoked with the second argument set to
|
|
** [SQLITE_CHANGESET_CONFLICT].
|
|
**
|
|
** If the attempt to insert the row fails because of some other constraint
|
|
-** violation (e.g. NOT NULL or UNIQUE), the conflict handler function is
|
|
+** violation (e.g. NOT NULL or UNIQUE), the conflict handler function is
|
|
** invoked with the second argument set to [SQLITE_CHANGESET_CONSTRAINT].
|
|
-** This includes the case where the INSERT operation is re-attempted because
|
|
-** an earlier call to the conflict handler function returned
|
|
+** This includes the case where the INSERT operation is re-attempted because
|
|
+** an earlier call to the conflict handler function returned
|
|
** [SQLITE_CHANGESET_REPLACE].
|
|
**
|
|
** <dt>UPDATE Changes<dd>
|
|
-** For each UPDATE change, the function checks if the target database
|
|
-** contains a row with the same primary key value (or values) as the
|
|
-** original row values stored in the changeset. If it does, and the values
|
|
+** For each UPDATE change, the function checks if the target database
|
|
+** contains a row with the same primary key value (or values) as the
|
|
+** original row values stored in the changeset. If it does, and the values
|
|
** stored in all modified non-primary key columns also match the values
|
|
** stored in the changeset the row is updated within the target database.
|
|
**
|
|
@@ -11980,12 +12130,12 @@ SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup*);
|
|
** the conflict-handler function is invoked with [SQLITE_CHANGESET_NOTFOUND]
|
|
** passed as the second argument.
|
|
**
|
|
-** If the UPDATE operation is attempted, but SQLite returns
|
|
-** SQLITE_CONSTRAINT, the conflict-handler function is invoked with
|
|
+** If the UPDATE operation is attempted, but SQLite returns
|
|
+** SQLITE_CONSTRAINT, the conflict-handler function is invoked with
|
|
** [SQLITE_CHANGESET_CONSTRAINT] passed as the second argument.
|
|
-** This includes the case where the UPDATE operation is attempted after
|
|
+** This includes the case where the UPDATE operation is attempted after
|
|
** an earlier call to the conflict handler function returned
|
|
-** [SQLITE_CHANGESET_REPLACE].
|
|
+** [SQLITE_CHANGESET_REPLACE].
|
|
** </dl>
|
|
**
|
|
** It is safe to execute SQL statements, including those that write to the
|
|
@@ -11996,12 +12146,12 @@ SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup*);
|
|
** All changes made by these functions are enclosed in a savepoint transaction.
|
|
** If any other error (aside from a constraint failure when attempting to
|
|
** write to the target database) occurs, then the savepoint transaction is
|
|
-** rolled back, restoring the target database to its original state, and an
|
|
+** rolled back, restoring the target database to its original state, and an
|
|
** SQLite error code returned.
|
|
**
|
|
** If the output parameters (ppRebase) and (pnRebase) are non-NULL and
|
|
** the input is a changeset (not a patchset), then sqlite3changeset_apply_v2()
|
|
-** may set (*ppRebase) to point to a "rebase" that may be used with the
|
|
+** may set (*ppRebase) to point to a "rebase" that may be used with the
|
|
** sqlite3_rebaser APIs buffer before returning. In this case (*pnRebase)
|
|
** is set to the size of the buffer in bytes. It is the responsibility of the
|
|
** caller to eventually free any such buffer using sqlite3_free(). The buffer
|
|
@@ -12062,7 +12212,7 @@ SQLITE_API int sqlite3changeset_apply_v2(
|
|
** SAVEPOINT is committed if the changeset or patchset is successfully
|
|
** applied, or rolled back if an error occurs. Specifying this flag
|
|
** causes the sessions module to omit this savepoint. In this case, if the
|
|
-** caller has an open transaction or savepoint when apply_v2() is called,
|
|
+** caller has an open transaction or savepoint when apply_v2() is called,
|
|
** it may revert the partially applied changeset by rolling it back.
|
|
**
|
|
** <dt>SQLITE_CHANGESETAPPLY_INVERT <dd>
|
|
@@ -12073,7 +12223,7 @@ SQLITE_API int sqlite3changeset_apply_v2(
|
|
#define SQLITE_CHANGESETAPPLY_NOSAVEPOINT 0x0001
|
|
#define SQLITE_CHANGESETAPPLY_INVERT 0x0002
|
|
|
|
-/*
|
|
+/*
|
|
** CAPI3REF: Constants Passed To The Conflict Handler
|
|
**
|
|
** Values that may be passed as the second argument to a conflict-handler.
|
|
@@ -12082,32 +12232,32 @@ SQLITE_API int sqlite3changeset_apply_v2(
|
|
** <dt>SQLITE_CHANGESET_DATA<dd>
|
|
** The conflict handler is invoked with CHANGESET_DATA as the second argument
|
|
** when processing a DELETE or UPDATE change if a row with the required
|
|
-** PRIMARY KEY fields is present in the database, but one or more other
|
|
-** (non primary-key) fields modified by the update do not contain the
|
|
+** PRIMARY KEY fields is present in the database, but one or more other
|
|
+** (non primary-key) fields modified by the update do not contain the
|
|
** expected "before" values.
|
|
-**
|
|
+**
|
|
** The conflicting row, in this case, is the database row with the matching
|
|
** primary key.
|
|
-**
|
|
+**
|
|
** <dt>SQLITE_CHANGESET_NOTFOUND<dd>
|
|
** The conflict handler is invoked with CHANGESET_NOTFOUND as the second
|
|
** argument when processing a DELETE or UPDATE change if a row with the
|
|
** required PRIMARY KEY fields is not present in the database.
|
|
-**
|
|
+**
|
|
** There is no conflicting row in this case. The results of invoking the
|
|
** sqlite3changeset_conflict() API are undefined.
|
|
-**
|
|
+**
|
|
** <dt>SQLITE_CHANGESET_CONFLICT<dd>
|
|
** CHANGESET_CONFLICT is passed as the second argument to the conflict
|
|
-** handler while processing an INSERT change if the operation would result
|
|
+** handler while processing an INSERT change if the operation would result
|
|
** in duplicate primary key values.
|
|
-**
|
|
+**
|
|
** The conflicting row in this case is the database row with the matching
|
|
** primary key.
|
|
**
|
|
** <dt>SQLITE_CHANGESET_FOREIGN_KEY<dd>
|
|
** If foreign key handling is enabled, and applying a changeset leaves the
|
|
-** database in a state containing foreign key violations, the conflict
|
|
+** database in a state containing foreign key violations, the conflict
|
|
** handler is invoked with CHANGESET_FOREIGN_KEY as the second argument
|
|
** exactly once before the changeset is committed. If the conflict handler
|
|
** returns CHANGESET_OMIT, the changes, including those that caused the
|
|
@@ -12117,12 +12267,12 @@ SQLITE_API int sqlite3changeset_apply_v2(
|
|
** No current or conflicting row information is provided. The only function
|
|
** it is possible to call on the supplied sqlite3_changeset_iter handle
|
|
** is sqlite3changeset_fk_conflicts().
|
|
-**
|
|
+**
|
|
** <dt>SQLITE_CHANGESET_CONSTRAINT<dd>
|
|
-** If any other constraint violation occurs while applying a change (i.e.
|
|
-** a UNIQUE, CHECK or NOT NULL constraint), the conflict handler is
|
|
+** If any other constraint violation occurs while applying a change (i.e.
|
|
+** a UNIQUE, CHECK or NOT NULL constraint), the conflict handler is
|
|
** invoked with CHANGESET_CONSTRAINT as the second argument.
|
|
-**
|
|
+**
|
|
** There is no conflicting row in this case. The results of invoking the
|
|
** sqlite3changeset_conflict() API are undefined.
|
|
**
|
|
@@ -12134,7 +12284,7 @@ SQLITE_API int sqlite3changeset_apply_v2(
|
|
#define SQLITE_CHANGESET_CONSTRAINT 4
|
|
#define SQLITE_CHANGESET_FOREIGN_KEY 5
|
|
|
|
-/*
|
|
+/*
|
|
** CAPI3REF: Constants Returned By The Conflict Handler
|
|
**
|
|
** A conflict handler callback must return one of the following three values.
|
|
@@ -12142,13 +12292,13 @@ SQLITE_API int sqlite3changeset_apply_v2(
|
|
** <dl>
|
|
** <dt>SQLITE_CHANGESET_OMIT<dd>
|
|
** If a conflict handler returns this value no special action is taken. The
|
|
-** change that caused the conflict is not applied. The session module
|
|
+** change that caused the conflict is not applied. The session module
|
|
** continues to the next change in the changeset.
|
|
**
|
|
** <dt>SQLITE_CHANGESET_REPLACE<dd>
|
|
** This value may only be returned if the second argument to the conflict
|
|
** handler was SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT. If this
|
|
-** is not the case, any changes applied so far are rolled back and the
|
|
+** is not the case, any changes applied so far are rolled back and the
|
|
** call to sqlite3changeset_apply() returns SQLITE_MISUSE.
|
|
**
|
|
** If CHANGESET_REPLACE is returned by an SQLITE_CHANGESET_DATA conflict
|
|
@@ -12161,7 +12311,7 @@ SQLITE_API int sqlite3changeset_apply_v2(
|
|
** the original row is restored to the database before continuing.
|
|
**
|
|
** <dt>SQLITE_CHANGESET_ABORT<dd>
|
|
-** If this value is returned, any changes applied so far are rolled back
|
|
+** If this value is returned, any changes applied so far are rolled back
|
|
** and the call to sqlite3changeset_apply() returns SQLITE_ABORT.
|
|
** </dl>
|
|
*/
|
|
@@ -12169,20 +12319,20 @@ SQLITE_API int sqlite3changeset_apply_v2(
|
|
#define SQLITE_CHANGESET_REPLACE 1
|
|
#define SQLITE_CHANGESET_ABORT 2
|
|
|
|
-/*
|
|
+/*
|
|
** CAPI3REF: Rebasing changesets
|
|
** EXPERIMENTAL
|
|
**
|
|
** Suppose there is a site hosting a database in state S0. And that
|
|
** modifications are made that move that database to state S1 and a
|
|
** changeset recorded (the "local" changeset). Then, a changeset based
|
|
-** on S0 is received from another site (the "remote" changeset) and
|
|
-** applied to the database. The database is then in state
|
|
+** on S0 is received from another site (the "remote" changeset) and
|
|
+** applied to the database. The database is then in state
|
|
** (S1+"remote"), where the exact state depends on any conflict
|
|
** resolution decisions (OMIT or REPLACE) made while applying "remote".
|
|
-** Rebasing a changeset is to update it to take those conflict
|
|
+** Rebasing a changeset is to update it to take those conflict
|
|
** resolution decisions into account, so that the same conflicts
|
|
-** do not have to be resolved elsewhere in the network.
|
|
+** do not have to be resolved elsewhere in the network.
|
|
**
|
|
** For example, if both the local and remote changesets contain an
|
|
** INSERT of the same key on "CREATE TABLE t1(a PRIMARY KEY, b)":
|
|
@@ -12201,7 +12351,7 @@ SQLITE_API int sqlite3changeset_apply_v2(
|
|
**
|
|
** <dl>
|
|
** <dt>Local INSERT<dd>
|
|
-** This may only conflict with a remote INSERT. If the conflict
|
|
+** This may only conflict with a remote INSERT. If the conflict
|
|
** resolution was OMIT, then add an UPDATE change to the rebased
|
|
** changeset. Or, if the conflict resolution was REPLACE, add
|
|
** nothing to the rebased changeset.
|
|
@@ -12225,12 +12375,12 @@ SQLITE_API int sqlite3changeset_apply_v2(
|
|
** the old.* values are rebased using the new.* values in the remote
|
|
** change. Or, if the resolution is REPLACE, then the change is copied
|
|
** into the rebased changeset with updates to columns also updated by
|
|
-** the conflicting remote UPDATE removed. If this means no columns would
|
|
+** the conflicting remote UPDATE removed. If this means no columns would
|
|
** be updated, the change is omitted.
|
|
** </dl>
|
|
**
|
|
-** A local change may be rebased against multiple remote changes
|
|
-** simultaneously. If a single key is modified by multiple remote
|
|
+** A local change may be rebased against multiple remote changes
|
|
+** simultaneously. If a single key is modified by multiple remote
|
|
** changesets, they are combined as follows before the local changeset
|
|
** is rebased:
|
|
**
|
|
@@ -12243,10 +12393,10 @@ SQLITE_API int sqlite3changeset_apply_v2(
|
|
** of the OMIT resolutions.
|
|
** </ul>
|
|
**
|
|
-** Note that conflict resolutions from multiple remote changesets are
|
|
-** combined on a per-field basis, not per-row. This means that in the
|
|
-** case of multiple remote UPDATE operations, some fields of a single
|
|
-** local change may be rebased for REPLACE while others are rebased for
|
|
+** Note that conflict resolutions from multiple remote changesets are
|
|
+** combined on a per-field basis, not per-row. This means that in the
|
|
+** case of multiple remote UPDATE operations, some fields of a single
|
|
+** local change may be rebased for REPLACE while others are rebased for
|
|
** OMIT.
|
|
**
|
|
** In order to rebase a local changeset, the remote changeset must first
|
|
@@ -12254,7 +12404,7 @@ SQLITE_API int sqlite3changeset_apply_v2(
|
|
** the buffer of rebase information captured. Then:
|
|
**
|
|
** <ol>
|
|
-** <li> An sqlite3_rebaser object is created by calling
|
|
+** <li> An sqlite3_rebaser object is created by calling
|
|
** sqlite3rebaser_create().
|
|
** <li> The new object is configured with the rebase buffer obtained from
|
|
** sqlite3changeset_apply_v2() by calling sqlite3rebaser_configure().
|
|
@@ -12275,8 +12425,8 @@ typedef struct sqlite3_rebaser sqlite3_rebaser;
|
|
**
|
|
** Allocate a new changeset rebaser object. If successful, set (*ppNew) to
|
|
** point to the new object and return SQLITE_OK. Otherwise, if an error
|
|
-** occurs, return an SQLite error code (e.g. SQLITE_NOMEM) and set (*ppNew)
|
|
-** to NULL.
|
|
+** occurs, return an SQLite error code (e.g. SQLITE_NOMEM) and set (*ppNew)
|
|
+** to NULL.
|
|
*/
|
|
SQLITE_API int sqlite3rebaser_create(sqlite3_rebaser **ppNew);
|
|
|
|
@@ -12290,9 +12440,9 @@ SQLITE_API int sqlite3rebaser_create(sqlite3_rebaser **ppNew);
|
|
** sqlite3changeset_apply_v2().
|
|
*/
|
|
SQLITE_API int sqlite3rebaser_configure(
|
|
- sqlite3_rebaser*,
|
|
+ sqlite3_rebaser*,
|
|
int nRebase, const void *pRebase
|
|
-);
|
|
+);
|
|
|
|
/*
|
|
** CAPI3REF: Rebase a changeset
|
|
@@ -12302,7 +12452,7 @@ SQLITE_API int sqlite3rebaser_configure(
|
|
** in size. This function allocates and populates a buffer with a copy
|
|
** of the changeset rebased according to the configuration of the
|
|
** rebaser object passed as the first argument. If successful, (*ppOut)
|
|
-** is set to point to the new buffer containing the rebased changeset and
|
|
+** is set to point to the new buffer containing the rebased changeset and
|
|
** (*pnOut) to its size in bytes and SQLITE_OK returned. It is the
|
|
** responsibility of the caller to eventually free the new buffer using
|
|
** sqlite3_free(). Otherwise, if an error occurs, (*ppOut) and (*pnOut)
|
|
@@ -12310,8 +12460,8 @@ SQLITE_API int sqlite3rebaser_configure(
|
|
*/
|
|
SQLITE_API int sqlite3rebaser_rebase(
|
|
sqlite3_rebaser*,
|
|
- int nIn, const void *pIn,
|
|
- int *pnOut, void **ppOut
|
|
+ int nIn, const void *pIn,
|
|
+ int *pnOut, void **ppOut
|
|
);
|
|
|
|
/*
|
|
@@ -12322,30 +12472,30 @@ SQLITE_API int sqlite3rebaser_rebase(
|
|
** should be one call to this function for each successful invocation
|
|
** of sqlite3rebaser_create().
|
|
*/
|
|
-SQLITE_API void sqlite3rebaser_delete(sqlite3_rebaser *p);
|
|
+SQLITE_API void sqlite3rebaser_delete(sqlite3_rebaser *p);
|
|
|
|
/*
|
|
** CAPI3REF: Streaming Versions of API functions.
|
|
**
|
|
-** The six streaming API xxx_strm() functions serve similar purposes to the
|
|
+** The six streaming API xxx_strm() functions serve similar purposes to the
|
|
** corresponding non-streaming API functions:
|
|
**
|
|
** <table border=1 style="margin-left:8ex;margin-right:8ex">
|
|
** <tr><th>Streaming function<th>Non-streaming equivalent</th>
|
|
-** <tr><td>sqlite3changeset_apply_strm<td>[sqlite3changeset_apply]
|
|
-** <tr><td>sqlite3changeset_apply_strm_v2<td>[sqlite3changeset_apply_v2]
|
|
-** <tr><td>sqlite3changeset_concat_strm<td>[sqlite3changeset_concat]
|
|
-** <tr><td>sqlite3changeset_invert_strm<td>[sqlite3changeset_invert]
|
|
-** <tr><td>sqlite3changeset_start_strm<td>[sqlite3changeset_start]
|
|
-** <tr><td>sqlite3session_changeset_strm<td>[sqlite3session_changeset]
|
|
-** <tr><td>sqlite3session_patchset_strm<td>[sqlite3session_patchset]
|
|
+** <tr><td>sqlite3changeset_apply_strm<td>[sqlite3changeset_apply]
|
|
+** <tr><td>sqlite3changeset_apply_strm_v2<td>[sqlite3changeset_apply_v2]
|
|
+** <tr><td>sqlite3changeset_concat_strm<td>[sqlite3changeset_concat]
|
|
+** <tr><td>sqlite3changeset_invert_strm<td>[sqlite3changeset_invert]
|
|
+** <tr><td>sqlite3changeset_start_strm<td>[sqlite3changeset_start]
|
|
+** <tr><td>sqlite3session_changeset_strm<td>[sqlite3session_changeset]
|
|
+** <tr><td>sqlite3session_patchset_strm<td>[sqlite3session_patchset]
|
|
** </table>
|
|
**
|
|
** Non-streaming functions that accept changesets (or patchsets) as input
|
|
-** require that the entire changeset be stored in a single buffer in memory.
|
|
-** Similarly, those that return a changeset or patchset do so by returning
|
|
-** a pointer to a single large buffer allocated using sqlite3_malloc().
|
|
-** Normally this is convenient. However, if an application running in a
|
|
+** require that the entire changeset be stored in a single buffer in memory.
|
|
+** Similarly, those that return a changeset or patchset do so by returning
|
|
+** a pointer to a single large buffer allocated using sqlite3_malloc().
|
|
+** Normally this is convenient. However, if an application running in a
|
|
** low-memory environment is required to handle very large changesets, the
|
|
** large contiguous memory allocations required can become onerous.
|
|
**
|
|
@@ -12367,12 +12517,12 @@ SQLITE_API void sqlite3rebaser_delete(sqlite3_rebaser *p);
|
|
** </pre>
|
|
**
|
|
** Each time the xInput callback is invoked by the sessions module, the first
|
|
-** argument passed is a copy of the supplied pIn context pointer. The second
|
|
-** argument, pData, points to a buffer (*pnData) bytes in size. Assuming no
|
|
-** error occurs the xInput method should copy up to (*pnData) bytes of data
|
|
-** into the buffer and set (*pnData) to the actual number of bytes copied
|
|
-** before returning SQLITE_OK. If the input is completely exhausted, (*pnData)
|
|
-** should be set to zero to indicate this. Or, if an error occurs, an SQLite
|
|
+** argument passed is a copy of the supplied pIn context pointer. The second
|
|
+** argument, pData, points to a buffer (*pnData) bytes in size. Assuming no
|
|
+** error occurs the xInput method should copy up to (*pnData) bytes of data
|
|
+** into the buffer and set (*pnData) to the actual number of bytes copied
|
|
+** before returning SQLITE_OK. If the input is completely exhausted, (*pnData)
|
|
+** should be set to zero to indicate this. Or, if an error occurs, an SQLite
|
|
** error code should be returned. In all cases, if an xInput callback returns
|
|
** an error, all processing is abandoned and the streaming API function
|
|
** returns a copy of the error code to the caller.
|
|
@@ -12380,7 +12530,7 @@ SQLITE_API void sqlite3rebaser_delete(sqlite3_rebaser *p);
|
|
** In the case of sqlite3changeset_start_strm(), the xInput callback may be
|
|
** invoked by the sessions module at any point during the lifetime of the
|
|
** iterator. If such an xInput callback returns an error, the iterator enters
|
|
-** an error state, whereby all subsequent calls to iterator functions
|
|
+** an error state, whereby all subsequent calls to iterator functions
|
|
** immediately fail with the same error code as returned by xInput.
|
|
**
|
|
** Similarly, streaming API functions that return changesets (or patchsets)
|
|
@@ -12410,7 +12560,7 @@ SQLITE_API void sqlite3rebaser_delete(sqlite3_rebaser *p);
|
|
** is immediately abandoned and the streaming API function returns a copy
|
|
** of the xOutput error code to the application.
|
|
**
|
|
-** The sessions module never invokes an xOutput callback with the third
|
|
+** The sessions module never invokes an xOutput callback with the third
|
|
** parameter set to a value less than or equal to zero. Other than this,
|
|
** no guarantees are made as to the size of the chunks of data returned.
|
|
*/
|
|
@@ -12481,12 +12631,12 @@ SQLITE_API int sqlite3session_patchset_strm(
|
|
int (*xOutput)(void *pOut, const void *pData, int nData),
|
|
void *pOut
|
|
);
|
|
-SQLITE_API int sqlite3changegroup_add_strm(sqlite3_changegroup*,
|
|
+SQLITE_API int sqlite3changegroup_add_strm(sqlite3_changegroup*,
|
|
int (*xInput)(void *pIn, void *pData, int *pnData),
|
|
void *pIn
|
|
);
|
|
SQLITE_API int sqlite3changegroup_output_strm(sqlite3_changegroup*,
|
|
- int (*xOutput)(void *pOut, const void *pData, int nData),
|
|
+ int (*xOutput)(void *pOut, const void *pData, int nData),
|
|
void *pOut
|
|
);
|
|
SQLITE_API int sqlite3rebaser_rebase_strm(
|
|
@@ -12501,16 +12651,16 @@ SQLITE_API int sqlite3rebaser_rebase_strm(
|
|
** CAPI3REF: Configure global parameters
|
|
**
|
|
** The sqlite3session_config() interface is used to make global configuration
|
|
-** changes to the sessions module in order to tune it to the specific needs
|
|
+** changes to the sessions module in order to tune it to the specific needs
|
|
** of the application.
|
|
**
|
|
** The sqlite3session_config() interface is not threadsafe. If it is invoked
|
|
** while any other thread is inside any other sessions method then the
|
|
** results are undefined. Furthermore, if it is invoked after any sessions
|
|
-** related objects have been created, the results are also undefined.
|
|
+** related objects have been created, the results are also undefined.
|
|
**
|
|
** The first argument to the sqlite3session_config() function must be one
|
|
-** of the SQLITE_SESSION_CONFIG_XXX constants defined below. The
|
|
+** of the SQLITE_SESSION_CONFIG_XXX constants defined below. The
|
|
** interpretation of the (void*) value passed as the second parameter and
|
|
** the effect of calling this function depends on the value of the first
|
|
** parameter.
|
|
@@ -12560,7 +12710,7 @@ SQLITE_API int sqlite3session_config(int op, void *pArg);
|
|
**
|
|
******************************************************************************
|
|
**
|
|
-** Interfaces to extend FTS5. Using the interfaces defined in this file,
|
|
+** Interfaces to extend FTS5. Using the interfaces defined in this file,
|
|
** FTS5 may be extended with:
|
|
**
|
|
** * custom tokenizers, and
|
|
@@ -12604,19 +12754,19 @@ struct Fts5PhraseIter {
|
|
** EXTENSION API FUNCTIONS
|
|
**
|
|
** xUserData(pFts):
|
|
-** Return a copy of the context pointer the extension function was
|
|
+** Return a copy of the context pointer the extension function was
|
|
** registered with.
|
|
**
|
|
** xColumnTotalSize(pFts, iCol, pnToken):
|
|
** If parameter iCol is less than zero, set output variable *pnToken
|
|
** to the total number of tokens in the FTS5 table. Or, if iCol is
|
|
** non-negative but less than the number of columns in the table, return
|
|
-** the total number of tokens in column iCol, considering all rows in
|
|
+** the total number of tokens in column iCol, considering all rows in
|
|
** the FTS5 table.
|
|
**
|
|
** If parameter iCol is greater than or equal to the number of columns
|
|
** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g.
|
|
-** an OOM condition or IO error), an appropriate SQLite error code is
|
|
+** an OOM condition or IO error), an appropriate SQLite error code is
|
|
** returned.
|
|
**
|
|
** xColumnCount(pFts):
|
|
@@ -12630,7 +12780,7 @@ struct Fts5PhraseIter {
|
|
**
|
|
** If parameter iCol is greater than or equal to the number of columns
|
|
** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g.
|
|
-** an OOM condition or IO error), an appropriate SQLite error code is
|
|
+** an OOM condition or IO error), an appropriate SQLite error code is
|
|
** returned.
|
|
**
|
|
** This function may be quite inefficient if used with an FTS5 table
|
|
@@ -12657,8 +12807,8 @@ struct Fts5PhraseIter {
|
|
** an error code (i.e. SQLITE_NOMEM) if an error occurs.
|
|
**
|
|
** This API can be quite slow if used with an FTS5 table created with the
|
|
-** "detail=none" or "detail=column" option. If the FTS5 table is created
|
|
-** with either "detail=none" or "detail=column" and "content=" option
|
|
+** "detail=none" or "detail=column" option. If the FTS5 table is created
|
|
+** with either "detail=none" or "detail=column" and "content=" option
|
|
** (i.e. if it is a contentless table), then this API always returns 0.
|
|
**
|
|
** xInst:
|
|
@@ -12673,7 +12823,7 @@ struct Fts5PhraseIter {
|
|
** code (i.e. SQLITE_NOMEM) if an error occurs.
|
|
**
|
|
** This API can be quite slow if used with an FTS5 table created with the
|
|
-** "detail=none" or "detail=column" option.
|
|
+** "detail=none" or "detail=column" option.
|
|
**
|
|
** xRowid:
|
|
** Returns the rowid of the current row.
|
|
@@ -12689,11 +12839,11 @@ struct Fts5PhraseIter {
|
|
**
|
|
** with $p set to a phrase equivalent to the phrase iPhrase of the
|
|
** current query is executed. Any column filter that applies to
|
|
-** phrase iPhrase of the current query is included in $p. For each
|
|
-** row visited, the callback function passed as the fourth argument
|
|
-** is invoked. The context and API objects passed to the callback
|
|
+** phrase iPhrase of the current query is included in $p. For each
|
|
+** row visited, the callback function passed as the fourth argument
|
|
+** is invoked. The context and API objects passed to the callback
|
|
** function may be used to access the properties of each matched row.
|
|
-** Invoking Api.xUserData() returns a copy of the pointer passed as
|
|
+** Invoking Api.xUserData() returns a copy of the pointer passed as
|
|
** the third argument to pUserData.
|
|
**
|
|
** If the callback function returns any value other than SQLITE_OK, the
|
|
@@ -12708,14 +12858,14 @@ struct Fts5PhraseIter {
|
|
**
|
|
** xSetAuxdata(pFts5, pAux, xDelete)
|
|
**
|
|
-** Save the pointer passed as the second argument as the extension function's
|
|
+** Save the pointer passed as the second argument as the extension function's
|
|
** "auxiliary data". The pointer may then be retrieved by the current or any
|
|
** future invocation of the same fts5 extension function made as part of
|
|
** the same MATCH query using the xGetAuxdata() API.
|
|
**
|
|
** Each extension function is allocated a single auxiliary data slot for
|
|
-** each FTS query (MATCH expression). If the extension function is invoked
|
|
-** more than once for a single FTS query, then all invocations share a
|
|
+** each FTS query (MATCH expression). If the extension function is invoked
|
|
+** more than once for a single FTS query, then all invocations share a
|
|
** single auxiliary data context.
|
|
**
|
|
** If there is already an auxiliary data pointer when this function is
|
|
@@ -12734,7 +12884,7 @@ struct Fts5PhraseIter {
|
|
**
|
|
** xGetAuxdata(pFts5, bClear)
|
|
**
|
|
-** Returns the current auxiliary data pointer for the fts5 extension
|
|
+** Returns the current auxiliary data pointer for the fts5 extension
|
|
** function. See the xSetAuxdata() method for details.
|
|
**
|
|
** If the bClear argument is non-zero, then the auxiliary data is cleared
|
|
@@ -12754,7 +12904,7 @@ struct Fts5PhraseIter {
|
|
** method, to iterate through all instances of a single query phrase within
|
|
** the current row. This is the same information as is accessible via the
|
|
** xInstCount/xInst APIs. While the xInstCount/xInst APIs are more convenient
|
|
-** to use, this API may be faster under some circumstances. To iterate
|
|
+** to use, this API may be faster under some circumstances. To iterate
|
|
** through instances of phrase iPhrase, use the following code:
|
|
**
|
|
** Fts5PhraseIter iter;
|
|
@@ -12772,8 +12922,8 @@ struct Fts5PhraseIter {
|
|
** xPhraseFirstColumn() and xPhraseNextColumn() as illustrated below).
|
|
**
|
|
** This API can be quite slow if used with an FTS5 table created with the
|
|
-** "detail=none" or "detail=column" option. If the FTS5 table is created
|
|
-** with either "detail=none" or "detail=column" and "content=" option
|
|
+** "detail=none" or "detail=column" option. If the FTS5 table is created
|
|
+** with either "detail=none" or "detail=column" and "content=" option
|
|
** (i.e. if it is a contentless table), then this API always iterates
|
|
** through an empty set (all calls to xPhraseFirst() set iCol to -1).
|
|
**
|
|
@@ -12797,16 +12947,16 @@ struct Fts5PhraseIter {
|
|
** }
|
|
**
|
|
** This API can be quite slow if used with an FTS5 table created with the
|
|
-** "detail=none" option. If the FTS5 table is created with either
|
|
-** "detail=none" "content=" option (i.e. if it is a contentless table),
|
|
-** then this API always iterates through an empty set (all calls to
|
|
+** "detail=none" option. If the FTS5 table is created with either
|
|
+** "detail=none" "content=" option (i.e. if it is a contentless table),
|
|
+** then this API always iterates through an empty set (all calls to
|
|
** xPhraseFirstColumn() set iCol to -1).
|
|
**
|
|
** The information accessed using this API and its companion
|
|
** xPhraseFirstColumn() may also be obtained using xPhraseFirst/xPhraseNext
|
|
** (or xInst/xInstCount). The chief advantage of this API is that it is
|
|
** significantly more efficient than those alternatives when used with
|
|
-** "detail=column" tables.
|
|
+** "detail=column" tables.
|
|
**
|
|
** xPhraseNextColumn()
|
|
** See xPhraseFirstColumn above.
|
|
@@ -12820,7 +12970,7 @@ struct Fts5ExtensionApi {
|
|
int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow);
|
|
int (*xColumnTotalSize)(Fts5Context*, int iCol, sqlite3_int64 *pnToken);
|
|
|
|
- int (*xTokenize)(Fts5Context*,
|
|
+ int (*xTokenize)(Fts5Context*,
|
|
const char *pText, int nText, /* Text to tokenize */
|
|
void *pCtx, /* Context passed to xToken() */
|
|
int (*xToken)(void*, int, const char*, int, int, int) /* Callback */
|
|
@@ -12849,15 +12999,15 @@ struct Fts5ExtensionApi {
|
|
void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol);
|
|
};
|
|
|
|
-/*
|
|
+/*
|
|
** CUSTOM AUXILIARY FUNCTIONS
|
|
*************************************************************************/
|
|
|
|
/*************************************************************************
|
|
** CUSTOM TOKENIZERS
|
|
**
|
|
-** Applications may also register custom tokenizer types. A tokenizer
|
|
-** is registered by providing fts5 with a populated instance of the
|
|
+** Applications may also register custom tokenizer types. A tokenizer
|
|
+** is registered by providing fts5 with a populated instance of the
|
|
** following structure. All structure methods must be defined, setting
|
|
** any member of the fts5_tokenizer struct to NULL leads to undefined
|
|
** behaviour. The structure methods are expected to function as follows:
|
|
@@ -12868,16 +13018,16 @@ struct Fts5ExtensionApi {
|
|
**
|
|
** The first argument passed to this function is a copy of the (void*)
|
|
** pointer provided by the application when the fts5_tokenizer object
|
|
-** was registered with FTS5 (the third argument to xCreateTokenizer()).
|
|
+** was registered with FTS5 (the third argument to xCreateTokenizer()).
|
|
** The second and third arguments are an array of nul-terminated strings
|
|
** containing the tokenizer arguments, if any, specified following the
|
|
** tokenizer name as part of the CREATE VIRTUAL TABLE statement used
|
|
** to create the FTS5 table.
|
|
**
|
|
-** The final argument is an output variable. If successful, (*ppOut)
|
|
+** The final argument is an output variable. If successful, (*ppOut)
|
|
** should be set to point to the new tokenizer handle and SQLITE_OK
|
|
** returned. If an error occurs, some value other than SQLITE_OK should
|
|
-** be returned. In this case, fts5 assumes that the final value of *ppOut
|
|
+** be returned. In this case, fts5 assumes that the final value of *ppOut
|
|
** is undefined.
|
|
**
|
|
** xDelete:
|
|
@@ -12886,7 +13036,7 @@ struct Fts5ExtensionApi {
|
|
** be invoked exactly once for each successful call to xCreate().
|
|
**
|
|
** xTokenize:
|
|
-** This function is expected to tokenize the nText byte string indicated
|
|
+** This function is expected to tokenize the nText byte string indicated
|
|
** by argument pText. pText may or may not be nul-terminated. The first
|
|
** argument passed to this function is a pointer to an Fts5Tokenizer object
|
|
** returned by an earlier call to xCreate().
|
|
@@ -12900,8 +13050,8 @@ struct Fts5ExtensionApi {
|
|
** determine the set of tokens to add to (or delete from) the
|
|
** FTS index.
|
|
**
|
|
-** <li> <b>FTS5_TOKENIZE_QUERY</b> - A MATCH query is being executed
|
|
-** against the FTS index. The tokenizer is being called to tokenize
|
|
+** <li> <b>FTS5_TOKENIZE_QUERY</b> - A MATCH query is being executed
|
|
+** against the FTS index. The tokenizer is being called to tokenize
|
|
** a bareword or quoted string specified as part of the query.
|
|
**
|
|
** <li> <b>(FTS5_TOKENIZE_QUERY | FTS5_TOKENIZE_PREFIX)</b> - Same as
|
|
@@ -12909,10 +13059,10 @@ struct Fts5ExtensionApi {
|
|
** followed by a "*" character, indicating that the last token
|
|
** returned by the tokenizer will be treated as a token prefix.
|
|
**
|
|
-** <li> <b>FTS5_TOKENIZE_AUX</b> - The tokenizer is being invoked to
|
|
+** <li> <b>FTS5_TOKENIZE_AUX</b> - The tokenizer is being invoked to
|
|
** satisfy an fts5_api.xTokenize() request made by an auxiliary
|
|
** function. Or an fts5_api.xColumnSize() request made by the same
|
|
-** on a columnsize=0 database.
|
|
+** on a columnsize=0 database.
|
|
** </ul>
|
|
**
|
|
** For each token in the input string, the supplied callback xToken() must
|
|
@@ -12924,10 +13074,10 @@ struct Fts5ExtensionApi {
|
|
** which the token is derived within the input.
|
|
**
|
|
** The second argument passed to the xToken() callback ("tflags") should
|
|
-** normally be set to 0. The exception is if the tokenizer supports
|
|
+** normally be set to 0. The exception is if the tokenizer supports
|
|
** synonyms. In this case see the discussion below for details.
|
|
**
|
|
-** FTS5 assumes the xToken() callback is invoked for each token in the
|
|
+** FTS5 assumes the xToken() callback is invoked for each token in the
|
|
** order that they occur within the input text.
|
|
**
|
|
** If an xToken() callback returns any value other than SQLITE_OK, then
|
|
@@ -12941,7 +13091,7 @@ struct Fts5ExtensionApi {
|
|
** SYNONYM SUPPORT
|
|
**
|
|
** Custom tokenizers may also support synonyms. Consider a case in which a
|
|
-** user wishes to query for a phrase such as "first place". Using the
|
|
+** user wishes to query for a phrase such as "first place". Using the
|
|
** built-in tokenizers, the FTS5 query 'first + place' will match instances
|
|
** of "first place" within the document set, but not alternative forms
|
|
** such as "1st place". In some applications, it would be better to match
|
|
@@ -12961,34 +13111,34 @@ struct Fts5ExtensionApi {
|
|
**
|
|
** <li> By querying the index for all synonyms of each query term
|
|
** separately. In this case, when tokenizing query text, the
|
|
-** tokenizer may provide multiple synonyms for a single term
|
|
-** within the document. FTS5 then queries the index for each
|
|
+** tokenizer may provide multiple synonyms for a single term
|
|
+** within the document. FTS5 then queries the index for each
|
|
** synonym individually. For example, faced with the query:
|
|
**
|
|
** <codeblock>
|
|
** ... MATCH 'first place'</codeblock>
|
|
**
|
|
** the tokenizer offers both "1st" and "first" as synonyms for the
|
|
-** first token in the MATCH query and FTS5 effectively runs a query
|
|
+** first token in the MATCH query and FTS5 effectively runs a query
|
|
** similar to:
|
|
**
|
|
** <codeblock>
|
|
** ... MATCH '(first OR 1st) place'</codeblock>
|
|
**
|
|
** except that, for the purposes of auxiliary functions, the query
|
|
-** still appears to contain just two phrases - "(first OR 1st)"
|
|
+** still appears to contain just two phrases - "(first OR 1st)"
|
|
** being treated as a single phrase.
|
|
**
|
|
** <li> By adding multiple synonyms for a single term to the FTS index.
|
|
** Using this method, when tokenizing document text, the tokenizer
|
|
-** provides multiple synonyms for each token. So that when a
|
|
+** provides multiple synonyms for each token. So that when a
|
|
** document such as "I won first place" is tokenized, entries are
|
|
** added to the FTS index for "i", "won", "first", "1st" and
|
|
** "place".
|
|
**
|
|
** This way, even if the tokenizer does not provide synonyms
|
|
** when tokenizing query text (it should not - to do so would be
|
|
-** inefficient), it doesn't matter if the user queries for
|
|
+** inefficient), it doesn't matter if the user queries for
|
|
** 'first + place' or '1st + place', as there are entries in the
|
|
** FTS index corresponding to both forms of the first token.
|
|
** </ol>
|
|
@@ -13009,11 +13159,11 @@ struct Fts5ExtensionApi {
|
|
**
|
|
** It is an error to specify the FTS5_TOKEN_COLOCATED flag the first time
|
|
** xToken() is called. Multiple synonyms may be specified for a single token
|
|
-** by making multiple calls to xToken(FTS5_TOKEN_COLOCATED) in sequence.
|
|
+** by making multiple calls to xToken(FTS5_TOKEN_COLOCATED) in sequence.
|
|
** There is no limit to the number of synonyms that may be provided for a
|
|
** single token.
|
|
**
|
|
-** In many cases, method (1) above is the best approach. It does not add
|
|
+** In many cases, method (1) above is the best approach. It does not add
|
|
** extra data to the FTS index or require FTS5 to query for multiple terms,
|
|
** so it is efficient in terms of disk space and query speed. However, it
|
|
** does not support prefix queries very well. If, as suggested above, the
|
|
@@ -13025,18 +13175,18 @@ struct Fts5ExtensionApi {
|
|
** will not match documents that contain the token "1st" (as the tokenizer
|
|
** will probably not map "1s" to any prefix of "first").
|
|
**
|
|
-** For full prefix support, method (3) may be preferred. In this case,
|
|
+** For full prefix support, method (3) may be preferred. In this case,
|
|
** because the index contains entries for both "first" and "1st", prefix
|
|
** queries such as 'fi*' or '1s*' will match correctly. However, because
|
|
** extra entries are added to the FTS index, this method uses more space
|
|
** within the database.
|
|
**
|
|
** Method (2) offers a midpoint between (1) and (3). Using this method,
|
|
-** a query such as '1s*' will match documents that contain the literal
|
|
+** a query such as '1s*' will match documents that contain the literal
|
|
** token "1st", but not "first" (assuming the tokenizer is not able to
|
|
** provide synonyms for prefixes). However, a non-prefix query like '1st'
|
|
** will match against "1st" and "first". This method does not require
|
|
-** extra disk space, as no extra entries are added to the FTS index.
|
|
+** extra disk space, as no extra entries are added to the FTS index.
|
|
** On the other hand, it may require more CPU cycles to run MATCH queries,
|
|
** as separate queries of the FTS index are required for each synonym.
|
|
**
|
|
@@ -13050,10 +13200,10 @@ typedef struct fts5_tokenizer fts5_tokenizer;
|
|
struct fts5_tokenizer {
|
|
int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
|
|
void (*xDelete)(Fts5Tokenizer*);
|
|
- int (*xTokenize)(Fts5Tokenizer*,
|
|
+ int (*xTokenize)(Fts5Tokenizer*,
|
|
void *pCtx,
|
|
int flags, /* Mask of FTS5_TOKENIZE_* flags */
|
|
- const char *pText, int nText,
|
|
+ const char *pText, int nText,
|
|
int (*xToken)(
|
|
void *pCtx, /* Copy of 2nd argument to xTokenize() */
|
|
int tflags, /* Mask of FTS5_TOKEN_* flags */
|
|
@@ -13128,12 +13278,17 @@ struct fts5_api {
|
|
/************** End of sqlite3.h *********************************************/
|
|
/************** Continuing where we left off in sqliteInt.h ******************/
|
|
|
|
+/*
|
|
+** Reuse the STATIC_LRU for mutex access to sqlite3_temp_directory.
|
|
+*/
|
|
+#define SQLITE_MUTEX_STATIC_TEMPDIR SQLITE_MUTEX_STATIC_VFS1
|
|
+
|
|
/*
|
|
** Include the configuration header output by 'configure' if we're using the
|
|
** autoconf-based build
|
|
*/
|
|
#if defined(_HAVE_SQLITE_CONFIG_H) && !defined(SQLITECONFIG_H)
|
|
-/* #include "config.h" */
|
|
+#include "sqlite_cfg.h"
|
|
#define SQLITECONFIG_H 1
|
|
#endif
|
|
|
|
@@ -13150,7 +13305,7 @@ struct fts5_api {
|
|
** May you share freely, never taking more than you give.
|
|
**
|
|
*************************************************************************
|
|
-**
|
|
+**
|
|
** This file defines various limits of what SQLite can process.
|
|
*/
|
|
|
|
@@ -13198,14 +13353,10 @@ struct fts5_api {
|
|
#endif
|
|
|
|
/*
|
|
-** The maximum depth of an expression tree. This is limited to
|
|
-** some extent by SQLITE_MAX_SQL_LENGTH. But sometime you might
|
|
-** want to place more severe limits on the complexity of an
|
|
-** expression.
|
|
-**
|
|
-** A value of 0 used to mean that the limit was not enforced.
|
|
-** But that is no longer true. The limit is now strictly enforced
|
|
-** at all times.
|
|
+** The maximum depth of an expression tree. This is limited to
|
|
+** some extent by SQLITE_MAX_SQL_LENGTH. But sometime you might
|
|
+** want to place more severe limits on the complexity of an
|
|
+** expression. A value of 0 means that there is no limit.
|
|
*/
|
|
#ifndef SQLITE_MAX_EXPR_DEPTH
|
|
# define SQLITE_MAX_EXPR_DEPTH 1000
|
|
@@ -13272,9 +13423,12 @@ struct fts5_api {
|
|
|
|
/*
|
|
** The maximum value of a ?nnn wildcard that the parser will accept.
|
|
+** If the value exceeds 32767 then extra space is required for the Expr
|
|
+** structure. But otherwise, we believe that the number can be as large
|
|
+** as a signed 32-bit integer can hold.
|
|
*/
|
|
#ifndef SQLITE_MAX_VARIABLE_NUMBER
|
|
-# define SQLITE_MAX_VARIABLE_NUMBER 999
|
|
+# define SQLITE_MAX_VARIABLE_NUMBER 32766
|
|
#endif
|
|
|
|
/* Maximum page size. The upper bound on this value is 65536. This a limit
|
|
@@ -13282,10 +13436,10 @@ struct fts5_api {
|
|
**
|
|
** Earlier versions of SQLite allowed the user to change this value at
|
|
** compile time. This is no longer permitted, on the grounds that it creates
|
|
-** a library that is technically incompatible with an SQLite library
|
|
-** compiled with a different limit. If a process operating on a database
|
|
-** with a page-size of 65536 bytes crashes, then an instance of SQLite
|
|
-** compiled with the default page-size limit will not be able to rollback
|
|
+** a library that is technically incompatible with an SQLite library
|
|
+** compiled with a different limit. If a process operating on a database
|
|
+** with a page-size of 65536 bytes crashes, then an instance of SQLite
|
|
+** compiled with the default page-size limit will not be able to rollback
|
|
** the aborted transaction. This could lead to database corruption.
|
|
*/
|
|
#ifdef SQLITE_MAX_PAGE_SIZE
|
|
@@ -13344,7 +13498,7 @@ struct fts5_api {
|
|
** Maximum depth of recursion for triggers.
|
|
**
|
|
** A value of 1 means that a trigger program will not be able to itself
|
|
-** fire any triggers. A value of 0 means that no trigger programs at all
|
|
+** fire any triggers. A value of 0 means that no trigger programs at all
|
|
** may be executed.
|
|
*/
|
|
#ifndef SQLITE_MAX_TRIGGER_DEPTH
|
|
@@ -13363,6 +13517,23 @@ struct fts5_api {
|
|
#pragma warn -spa /* Suspicious pointer arithmetic */
|
|
#endif
|
|
|
|
+/*
|
|
+** WAL mode depends on atomic aligned 32-bit loads and stores in a few
|
|
+** places. The following macros try to make this explicit.
|
|
+*/
|
|
+#ifndef __has_extension
|
|
+# define __has_extension(x) 0 /* compatibility with non-clang compilers */
|
|
+#endif
|
|
+#if GCC_VERSION>=4007000 || __has_extension(c_atomic)
|
|
+# define SQLITE_ATOMIC_INTRINSICS 1
|
|
+# define AtomicLoad(PTR) __atomic_load_n((PTR),__ATOMIC_RELAXED)
|
|
+# define AtomicStore(PTR,VAL) __atomic_store_n((PTR),(VAL),__ATOMIC_RELAXED)
|
|
+#else
|
|
+# define SQLITE_ATOMIC_INTRINSICS 0
|
|
+# define AtomicLoad(PTR) (*(PTR))
|
|
+# define AtomicStore(PTR,VAL) (*(PTR) = (VAL))
|
|
+#endif
|
|
+
|
|
/*
|
|
** Include standard header files as necessary
|
|
*/
|
|
@@ -13563,11 +13734,12 @@ struct fts5_api {
|
|
** is significant and used at least once. On switch statements
|
|
** where multiple cases go to the same block of code, testcase()
|
|
** can insure that all cases are evaluated.
|
|
-**
|
|
*/
|
|
-#ifdef SQLITE_COVERAGE_TEST
|
|
-SQLITE_PRIVATE void sqlite3Coverage(int);
|
|
-# define testcase(X) if( X ){ sqlite3Coverage(__LINE__); }
|
|
+#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_DEBUG)
|
|
+# ifndef SQLITE_AMALGAMATION
|
|
+ extern unsigned int sqlite3CoverageCounter;
|
|
+# endif
|
|
+# define testcase(X) if( X ){ sqlite3CoverageCounter += (unsigned)__LINE__; }
|
|
#else
|
|
# define testcase(X)
|
|
#endif
|
|
@@ -13597,6 +13769,14 @@ SQLITE_PRIVATE void sqlite3Coverage(int);
|
|
# define VVA_ONLY(X)
|
|
#endif
|
|
|
|
+/*
|
|
+** Disable ALWAYS() and NEVER() (make them pass-throughs) for coverage
|
|
+** and mutation testing
|
|
+*/
|
|
+#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST)
|
|
+# define SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS 1
|
|
+#endif
|
|
+
|
|
/*
|
|
** The ALWAYS and NEVER macros surround boolean expressions which
|
|
** are intended to always be true or false, respectively. Such
|
|
@@ -13612,7 +13792,7 @@ SQLITE_PRIVATE void sqlite3Coverage(int);
|
|
** be true and false so that the unreachable code they specify will
|
|
** not be counted as untested code.
|
|
*/
|
|
-#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST)
|
|
+#if defined(SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS)
|
|
# define ALWAYS(X) (1)
|
|
# define NEVER(X) (0)
|
|
#elif !defined(NDEBUG)
|
|
@@ -13623,26 +13803,6 @@ SQLITE_PRIVATE void sqlite3Coverage(int);
|
|
# define NEVER(X) (X)
|
|
#endif
|
|
|
|
-/*
|
|
-** The harmless(X) macro indicates that expression X is usually false
|
|
-** but can be true without causing any problems, but we don't know of
|
|
-** any way to cause X to be true.
|
|
-**
|
|
-** In debugging and testing builds, this macro will abort if X is ever
|
|
-** true. In this way, developers are alerted to a possible test case
|
|
-** that causes X to be true. If a harmless macro ever fails, that is
|
|
-** an opportunity to change the macro into a testcase() and add a new
|
|
-** test case to the test suite.
|
|
-**
|
|
-** For normal production builds, harmless(X) is a no-op, since it does
|
|
-** not matter whether expression X is true or false.
|
|
-*/
|
|
-#ifdef SQLITE_DEBUG
|
|
-# define harmless(X) assert(!(X));
|
|
-#else
|
|
-# define harmless(X)
|
|
-#endif
|
|
-
|
|
/*
|
|
** Some conditionals are optimizations only. In other words, if the
|
|
** conditionals are replaced with a constant 1 (true) or 0 (false) then
|
|
@@ -13706,6 +13866,13 @@ SQLITE_PRIVATE void sqlite3Coverage(int);
|
|
# undef SQLITE_ENABLE_EXPLAIN_COMMENTS
|
|
#endif
|
|
|
|
+/*
|
|
+** SQLITE_OMIT_VIRTUALTABLE implies SQLITE_OMIT_ALTERTABLE
|
|
+*/
|
|
+#if defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_ALTERTABLE)
|
|
+# define SQLITE_OMIT_ALTERTABLE
|
|
+#endif
|
|
+
|
|
/*
|
|
** Return true (non-zero) if the input is an integer that is too large
|
|
** to fit in 32-bits. This macro is used inside of various testcase()
|
|
@@ -13762,7 +13929,7 @@ typedef struct HashElem HashElem;
|
|
** element pointed to plus the next _ht.count-1 elements in the list.
|
|
**
|
|
** Hash.htsize and Hash.ht may be zero. In that case lookup is done
|
|
-** by a linear search of the global list. For small tables, the
|
|
+** by a linear search of the global list. For small tables, the
|
|
** Hash.ht table is never allocated because if there are few elements
|
|
** in the table, it is faster to do a linear search than to manage
|
|
** the hash table.
|
|
@@ -13777,7 +13944,7 @@ struct Hash {
|
|
} *ht;
|
|
};
|
|
|
|
-/* Each element in the hash table is an instance of the following
|
|
+/* Each element in the hash table is an instance of the following
|
|
** structure. All elements are stored on a single doubly-linked list.
|
|
**
|
|
** Again, this structure is intended to be opaque, but it can't really
|
|
@@ -13818,7 +13985,7 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
|
|
/*
|
|
** Number of entries in a hash table
|
|
*/
|
|
-/* #define sqliteHashCount(H) ((H)->count) // NOT USED */
|
|
+#define sqliteHashCount(H) ((H)->count)
|
|
|
|
#endif /* SQLITE_HASH_H */
|
|
|
|
@@ -13850,8 +14017,8 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
|
|
#define TK_LP 22
|
|
#define TK_RP 23
|
|
#define TK_AS 24
|
|
-#define TK_WITHOUT 25
|
|
-#define TK_COMMA 26
|
|
+#define TK_COMMA 25
|
|
+#define TK_WITHOUT 26
|
|
#define TK_ABORT 27
|
|
#define TK_ACTION 28
|
|
#define TK_AFTER 29
|
|
@@ -13922,90 +14089,94 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
|
|
#define TK_TIES 94
|
|
#define TK_GENERATED 95
|
|
#define TK_ALWAYS 96
|
|
-#define TK_REINDEX 97
|
|
-#define TK_RENAME 98
|
|
-#define TK_CTIME_KW 99
|
|
-#define TK_ANY 100
|
|
-#define TK_BITAND 101
|
|
-#define TK_BITOR 102
|
|
-#define TK_LSHIFT 103
|
|
-#define TK_RSHIFT 104
|
|
-#define TK_PLUS 105
|
|
-#define TK_MINUS 106
|
|
-#define TK_STAR 107
|
|
-#define TK_SLASH 108
|
|
-#define TK_REM 109
|
|
-#define TK_CONCAT 110
|
|
-#define TK_COLLATE 111
|
|
-#define TK_BITNOT 112
|
|
-#define TK_ON 113
|
|
-#define TK_INDEXED 114
|
|
-#define TK_STRING 115
|
|
-#define TK_JOIN_KW 116
|
|
-#define TK_CONSTRAINT 117
|
|
-#define TK_DEFAULT 118
|
|
-#define TK_NULL 119
|
|
-#define TK_PRIMARY 120
|
|
-#define TK_UNIQUE 121
|
|
-#define TK_CHECK 122
|
|
-#define TK_REFERENCES 123
|
|
-#define TK_AUTOINCR 124
|
|
-#define TK_INSERT 125
|
|
-#define TK_DELETE 126
|
|
-#define TK_UPDATE 127
|
|
-#define TK_SET 128
|
|
-#define TK_DEFERRABLE 129
|
|
-#define TK_FOREIGN 130
|
|
-#define TK_DROP 131
|
|
-#define TK_UNION 132
|
|
-#define TK_ALL 133
|
|
-#define TK_EXCEPT 134
|
|
-#define TK_INTERSECT 135
|
|
-#define TK_SELECT 136
|
|
-#define TK_VALUES 137
|
|
-#define TK_DISTINCT 138
|
|
-#define TK_DOT 139
|
|
-#define TK_FROM 140
|
|
-#define TK_JOIN 141
|
|
-#define TK_USING 142
|
|
-#define TK_ORDER 143
|
|
-#define TK_GROUP 144
|
|
-#define TK_HAVING 145
|
|
-#define TK_LIMIT 146
|
|
-#define TK_WHERE 147
|
|
-#define TK_INTO 148
|
|
-#define TK_NOTHING 149
|
|
-#define TK_FLOAT 150
|
|
-#define TK_BLOB 151
|
|
-#define TK_INTEGER 152
|
|
-#define TK_VARIABLE 153
|
|
-#define TK_CASE 154
|
|
-#define TK_WHEN 155
|
|
-#define TK_THEN 156
|
|
-#define TK_ELSE 157
|
|
-#define TK_INDEX 158
|
|
-#define TK_ALTER 159
|
|
-#define TK_ADD 160
|
|
-#define TK_WINDOW 161
|
|
-#define TK_OVER 162
|
|
-#define TK_FILTER 163
|
|
-#define TK_COLUMN 164
|
|
-#define TK_AGG_FUNCTION 165
|
|
-#define TK_AGG_COLUMN 166
|
|
-#define TK_TRUEFALSE 167
|
|
-#define TK_ISNOT 168
|
|
-#define TK_FUNCTION 169
|
|
-#define TK_UMINUS 170
|
|
-#define TK_UPLUS 171
|
|
-#define TK_TRUTH 172
|
|
-#define TK_REGISTER 173
|
|
-#define TK_VECTOR 174
|
|
-#define TK_SELECT_COLUMN 175
|
|
-#define TK_IF_NULL_ROW 176
|
|
-#define TK_ASTERISK 177
|
|
-#define TK_SPAN 178
|
|
-#define TK_SPACE 179
|
|
-#define TK_ILLEGAL 180
|
|
+#define TK_MATERIALIZED 97
|
|
+#define TK_REINDEX 98
|
|
+#define TK_RENAME 99
|
|
+#define TK_CTIME_KW 100
|
|
+#define TK_ANY 101
|
|
+#define TK_BITAND 102
|
|
+#define TK_BITOR 103
|
|
+#define TK_LSHIFT 104
|
|
+#define TK_RSHIFT 105
|
|
+#define TK_PLUS 106
|
|
+#define TK_MINUS 107
|
|
+#define TK_STAR 108
|
|
+#define TK_SLASH 109
|
|
+#define TK_REM 110
|
|
+#define TK_CONCAT 111
|
|
+#define TK_PTR 112
|
|
+#define TK_COLLATE 113
|
|
+#define TK_BITNOT 114
|
|
+#define TK_ON 115
|
|
+#define TK_INDEXED 116
|
|
+#define TK_STRING 117
|
|
+#define TK_JOIN_KW 118
|
|
+#define TK_CONSTRAINT 119
|
|
+#define TK_DEFAULT 120
|
|
+#define TK_NULL 121
|
|
+#define TK_PRIMARY 122
|
|
+#define TK_UNIQUE 123
|
|
+#define TK_CHECK 124
|
|
+#define TK_REFERENCES 125
|
|
+#define TK_AUTOINCR 126
|
|
+#define TK_INSERT 127
|
|
+#define TK_DELETE 128
|
|
+#define TK_UPDATE 129
|
|
+#define TK_SET 130
|
|
+#define TK_DEFERRABLE 131
|
|
+#define TK_FOREIGN 132
|
|
+#define TK_DROP 133
|
|
+#define TK_UNION 134
|
|
+#define TK_ALL 135
|
|
+#define TK_EXCEPT 136
|
|
+#define TK_INTERSECT 137
|
|
+#define TK_SELECT 138
|
|
+#define TK_VALUES 139
|
|
+#define TK_DISTINCT 140
|
|
+#define TK_DOT 141
|
|
+#define TK_FROM 142
|
|
+#define TK_JOIN 143
|
|
+#define TK_USING 144
|
|
+#define TK_ORDER 145
|
|
+#define TK_GROUP 146
|
|
+#define TK_HAVING 147
|
|
+#define TK_LIMIT 148
|
|
+#define TK_WHERE 149
|
|
+#define TK_RETURNING 150
|
|
+#define TK_INTO 151
|
|
+#define TK_NOTHING 152
|
|
+#define TK_FLOAT 153
|
|
+#define TK_BLOB 154
|
|
+#define TK_INTEGER 155
|
|
+#define TK_VARIABLE 156
|
|
+#define TK_CASE 157
|
|
+#define TK_WHEN 158
|
|
+#define TK_THEN 159
|
|
+#define TK_ELSE 160
|
|
+#define TK_INDEX 161
|
|
+#define TK_ALTER 162
|
|
+#define TK_ADD 163
|
|
+#define TK_WINDOW 164
|
|
+#define TK_OVER 165
|
|
+#define TK_FILTER 166
|
|
+#define TK_COLUMN 167
|
|
+#define TK_AGG_FUNCTION 168
|
|
+#define TK_AGG_COLUMN 169
|
|
+#define TK_TRUEFALSE 170
|
|
+#define TK_ISNOT 171
|
|
+#define TK_FUNCTION 172
|
|
+#define TK_UMINUS 173
|
|
+#define TK_UPLUS 174
|
|
+#define TK_TRUTH 175
|
|
+#define TK_REGISTER 176
|
|
+#define TK_VECTOR 177
|
|
+#define TK_SELECT_COLUMN 178
|
|
+#define TK_IF_NULL_ROW 179
|
|
+#define TK_ASTERISK 180
|
|
+#define TK_SPAN 181
|
|
+#define TK_ERROR 182
|
|
+#define TK_SPACE 183
|
|
+#define TK_ILLEGAL 184
|
|
|
|
/************** End of parse.h ***********************************************/
|
|
/************** Continuing where we left off in sqliteInt.h ******************/
|
|
@@ -14111,7 +14282,7 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
|
|
** number of pages. A negative number N translations means that a buffer
|
|
** of -1024*N bytes is allocated and used for as many pages as it will hold.
|
|
**
|
|
-** The default value of "20" was choosen to minimize the run-time of the
|
|
+** The default value of "20" was chosen to minimize the run-time of the
|
|
** speedtest1 test program with options: --shrink-memory --reprepare
|
|
*/
|
|
#ifndef SQLITE_DEFAULT_PCACHE_INITSZ
|
|
@@ -14126,7 +14297,7 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*);
|
|
#endif
|
|
|
|
/*
|
|
-** The compile-time options SQLITE_MMAP_READWRITE and
|
|
+** The compile-time options SQLITE_MMAP_READWRITE and
|
|
** SQLITE_ENABLE_BATCH_ATOMIC_WRITE are not compatible with one another.
|
|
** You must choose one or the other (or neither) but not both.
|
|
*/
|
|
@@ -14230,15 +14401,9 @@ typedef INT8_TYPE i8; /* 1-byte signed integer */
|
|
|
|
/*
|
|
** The datatype used to store estimates of the number of rows in a
|
|
-** table or index. This is an unsigned integer type. For 99.9% of
|
|
-** the world, a 32-bit integer is sufficient. But a 64-bit integer
|
|
-** can be used at compile-time if desired.
|
|
+** table or index.
|
|
*/
|
|
-#ifdef SQLITE_64BIT_STATS
|
|
- typedef u64 tRowcnt; /* 64-bit only if requested at compile-time */
|
|
-#else
|
|
- typedef u32 tRowcnt; /* 32-bit is the default */
|
|
-#endif
|
|
+typedef u64 tRowcnt;
|
|
|
|
/*
|
|
** Estimated quantities used for query planning are stored as 16-bit
|
|
@@ -14273,6 +14438,7 @@ typedef INT16_TYPE LogEst;
|
|
# define SQLITE_PTRSIZE __SIZEOF_POINTER__
|
|
# elif defined(i386) || defined(__i386__) || defined(_M_IX86) || \
|
|
defined(_M_ARM) || defined(__arm__) || defined(__x86) || \
|
|
+ (defined(__APPLE__) && defined(__POWERPC__)) || \
|
|
(defined(__TOS_AIX__) && !defined(__64BIT__))
|
|
# define SQLITE_PTRSIZE 4
|
|
# else
|
|
@@ -14348,13 +14514,25 @@ typedef INT16_TYPE LogEst;
|
|
** compilers.
|
|
*/
|
|
#define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32))
|
|
+#define LARGEST_UINT64 (0xffffffff|(((u64)0xffffffff)<<32))
|
|
#define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64)
|
|
|
|
/*
|
|
** Round up a number to the next larger multiple of 8. This is used
|
|
** to force 8-byte alignment on 64-bit architectures.
|
|
+**
|
|
+** ROUND8() always does the rounding, for any argument.
|
|
+**
|
|
+** ROUND8P() assumes that the argument is already an integer number of
|
|
+** pointers in size, and so it is a no-op on systems where the pointer
|
|
+** size is 8.
|
|
*/
|
|
#define ROUND8(x) (((x)+7)&~7)
|
|
+#if SQLITE_PTRSIZE==8
|
|
+# define ROUND8P(x) (x)
|
|
+#else
|
|
+# define ROUND8P(x) (((x)+7)&~7)
|
|
+#endif
|
|
|
|
/*
|
|
** Round down to the nearest multiple of 8
|
|
@@ -14371,9 +14549,9 @@ typedef INT16_TYPE LogEst;
|
|
** pointers. In that case, only verify 4-byte alignment.
|
|
*/
|
|
#ifdef SQLITE_4_BYTE_ALIGNED_MALLOC
|
|
-# define EIGHT_BYTE_ALIGNMENT(X) ((((char*)(X) - (char*)0)&3)==0)
|
|
+# define EIGHT_BYTE_ALIGNMENT(X) ((((uptr)(X) - (uptr)0)&3)==0)
|
|
#else
|
|
-# define EIGHT_BYTE_ALIGNMENT(X) ((((char*)(X) - (char*)0)&7)==0)
|
|
+# define EIGHT_BYTE_ALIGNMENT(X) ((((uptr)(X) - (uptr)0)&7)==0)
|
|
#endif
|
|
|
|
/*
|
|
@@ -14417,15 +14595,91 @@ typedef INT16_TYPE LogEst;
|
|
#endif
|
|
|
|
/*
|
|
-** SELECTTRACE_ENABLED will be either 1 or 0 depending on whether or not
|
|
-** the Select query generator tracing logic is turned on.
|
|
+** TREETRACE_ENABLED will be either 1 or 0 depending on whether or not
|
|
+** the Abstract Syntax Tree tracing logic is turned on.
|
|
*/
|
|
-#if defined(SQLITE_ENABLE_SELECTTRACE)
|
|
-# define SELECTTRACE_ENABLED 1
|
|
+#if !defined(SQLITE_AMALGAMATION)
|
|
+SQLITE_PRIVATE u32 sqlite3TreeTrace;
|
|
+#endif
|
|
+#if defined(SQLITE_DEBUG) \
|
|
+ && (defined(SQLITE_TEST) || defined(SQLITE_ENABLE_SELECTTRACE) \
|
|
+ || defined(SQLITE_ENABLE_TREETRACE))
|
|
+# define TREETRACE_ENABLED 1
|
|
+# define TREETRACE(K,P,S,X) \
|
|
+ if(sqlite3TreeTrace&(K)) \
|
|
+ sqlite3DebugPrintf("%u/%d/%p: ",(S)->selId,(P)->addrExplain,(S)),\
|
|
+ sqlite3DebugPrintf X
|
|
#else
|
|
-# define SELECTTRACE_ENABLED 0
|
|
+# define TREETRACE(K,P,S,X)
|
|
+# define TREETRACE_ENABLED 0
|
|
#endif
|
|
|
|
+/* TREETRACE flag meanings:
|
|
+**
|
|
+** 0x00000001 Beginning and end of SELECT processing
|
|
+** 0x00000002 WHERE clause processing
|
|
+** 0x00000004 Query flattener
|
|
+** 0x00000008 Result-set wildcard expansion
|
|
+** 0x00000010 Query name resolution
|
|
+** 0x00000020 Aggregate analysis
|
|
+** 0x00000040 Window functions
|
|
+** 0x00000080 Generated column names
|
|
+** 0x00000100 Move HAVING terms into WHERE
|
|
+** 0x00000200 Count-of-view optimization
|
|
+** 0x00000400 Compound SELECT processing
|
|
+** 0x00000800 Drop superfluous ORDER BY
|
|
+** 0x00001000 LEFT JOIN simplifies to JOIN
|
|
+** 0x00002000 Constant propagation
|
|
+** 0x00004000 Push-down optimization
|
|
+** 0x00008000 After all FROM-clause analysis
|
|
+** 0x00010000 Beginning of DELETE/INSERT/UPDATE processing
|
|
+** 0x00020000 Transform DISTINCT into GROUP BY
|
|
+** 0x00040000 SELECT tree dump after all code has been generated
|
|
+*/
|
|
+
|
|
+/*
|
|
+** Macros for "wheretrace"
|
|
+*/
|
|
+SQLITE_PRIVATE u32 sqlite3WhereTrace;
|
|
+#if defined(SQLITE_DEBUG) \
|
|
+ && (defined(SQLITE_TEST) || defined(SQLITE_ENABLE_WHERETRACE))
|
|
+# define WHERETRACE(K,X) if(sqlite3WhereTrace&(K)) sqlite3DebugPrintf X
|
|
+# define WHERETRACE_ENABLED 1
|
|
+#else
|
|
+# define WHERETRACE(K,X)
|
|
+#endif
|
|
+
|
|
+/*
|
|
+** Bits for the sqlite3WhereTrace mask:
|
|
+**
|
|
+** (---any--) Top-level block structure
|
|
+** 0x-------F High-level debug messages
|
|
+** 0x----FFF- More detail
|
|
+** 0xFFFF---- Low-level debug messages
|
|
+**
|
|
+** 0x00000001 Code generation
|
|
+** 0x00000002 Solver
|
|
+** 0x00000004 Solver costs
|
|
+** 0x00000008 WhereLoop inserts
|
|
+**
|
|
+** 0x00000010 Display sqlite3_index_info xBestIndex calls
|
|
+** 0x00000020 Range an equality scan metrics
|
|
+** 0x00000040 IN operator decisions
|
|
+** 0x00000080 WhereLoop cost adjustements
|
|
+** 0x00000100
|
|
+** 0x00000200 Covering index decisions
|
|
+** 0x00000400 OR optimization
|
|
+** 0x00000800 Index scanner
|
|
+** 0x00001000 More details associated with code generation
|
|
+** 0x00002000
|
|
+** 0x00004000 Show all WHERE terms at key points
|
|
+** 0x00008000 Show the full SELECT statement at key places
|
|
+**
|
|
+** 0x00010000 Show more detail when printing WHERE terms
|
|
+** 0x00020000 Show WHERE terms returned from whereScanNext()
|
|
+*/
|
|
+
|
|
+
|
|
/*
|
|
** An instance of the following structure is used to store the busy-handler
|
|
** callback for a given sqlite handle.
|
|
@@ -14440,26 +14694,41 @@ struct BusyHandler {
|
|
int (*xBusyHandler)(void *,int); /* The busy callback */
|
|
void *pBusyArg; /* First arg to busy callback */
|
|
int nBusy; /* Incremented with each busy call */
|
|
- u8 bExtraFileArg; /* Include sqlite3_file as callback arg */
|
|
};
|
|
|
|
/*
|
|
-** Name of the master database table. The master database table
|
|
-** is a special table that holds the names and attributes of all
|
|
-** user tables and indices.
|
|
+** Name of table that holds the database schema.
|
|
+**
|
|
+** The PREFERRED names are used whereever possible. But LEGACY is also
|
|
+** used for backwards compatibility.
|
|
+**
|
|
+** 1. Queries can use either the PREFERRED or the LEGACY names
|
|
+** 2. The sqlite3_set_authorizer() callback uses the LEGACY name
|
|
+** 3. The PRAGMA table_list statement uses the PREFERRED name
|
|
+**
|
|
+** The LEGACY names are stored in the internal symbol hash table
|
|
+** in support of (2). Names are translated using sqlite3PreferredTableName()
|
|
+** for (3). The sqlite3FindTable() function takes care of translating
|
|
+** names for (1).
|
|
+**
|
|
+** Note that "sqlite_temp_schema" can also be called "temp.sqlite_schema".
|
|
*/
|
|
-#define MASTER_NAME "sqlite_master"
|
|
-#define TEMP_MASTER_NAME "sqlite_temp_master"
|
|
+#define LEGACY_SCHEMA_TABLE "sqlite_master"
|
|
+#define LEGACY_TEMP_SCHEMA_TABLE "sqlite_temp_master"
|
|
+#define PREFERRED_SCHEMA_TABLE "sqlite_schema"
|
|
+#define PREFERRED_TEMP_SCHEMA_TABLE "sqlite_temp_schema"
|
|
+
|
|
|
|
/*
|
|
-** The root-page of the master database table.
|
|
+** The root-page of the schema table.
|
|
*/
|
|
-#define MASTER_ROOT 1
|
|
+#define SCHEMA_ROOT 1
|
|
|
|
/*
|
|
-** The name of the schema table.
|
|
+** The name of the schema table. The name is different for TEMP.
|
|
*/
|
|
-#define SCHEMA_TABLE(x) ((!OMIT_TEMPDB)&&(x==1)?TEMP_MASTER_NAME:MASTER_NAME)
|
|
+#define SCHEMA_TABLE(x) \
|
|
+ ((!OMIT_TEMPDB)&&(x==1)?LEGACY_TEMP_SCHEMA_TABLE:LEGACY_SCHEMA_TABLE)
|
|
|
|
/*
|
|
** A convenience macro that returns the number of elements in
|
|
@@ -14480,7 +14749,7 @@ struct BusyHandler {
|
|
** pointer will work here as long as it is distinct from SQLITE_STATIC
|
|
** and SQLITE_TRANSIENT.
|
|
*/
|
|
-#define SQLITE_DYNAMIC ((sqlite3_destructor_type)sqlite3MallocSize)
|
|
+#define SQLITE_DYNAMIC ((sqlite3_destructor_type)sqlite3OomClear)
|
|
|
|
/*
|
|
** When SQLITE_OMIT_WSD is defined, it means that the target platform does
|
|
@@ -14536,7 +14805,10 @@ typedef struct AutoincInfo AutoincInfo;
|
|
typedef struct Bitvec Bitvec;
|
|
typedef struct CollSeq CollSeq;
|
|
typedef struct Column Column;
|
|
+typedef struct Cte Cte;
|
|
+typedef struct CteUse CteUse;
|
|
typedef struct Db Db;
|
|
+typedef struct DbFixer DbFixer;
|
|
typedef struct Schema Schema;
|
|
typedef struct Expr Expr;
|
|
typedef struct ExprList ExprList;
|
|
@@ -14546,6 +14818,7 @@ typedef struct FuncDef FuncDef;
|
|
typedef struct FuncDefHash FuncDefHash;
|
|
typedef struct IdList IdList;
|
|
typedef struct Index Index;
|
|
+typedef struct IndexedExpr IndexedExpr;
|
|
typedef struct IndexSample IndexSample;
|
|
typedef struct KeyClass KeyClass;
|
|
typedef struct KeyInfo KeyInfo;
|
|
@@ -14553,15 +14826,19 @@ typedef struct Lookaside Lookaside;
|
|
typedef struct LookasideSlot LookasideSlot;
|
|
typedef struct Module Module;
|
|
typedef struct NameContext NameContext;
|
|
+typedef struct OnOrUsing OnOrUsing;
|
|
typedef struct Parse Parse;
|
|
+typedef struct ParseCleanup ParseCleanup;
|
|
typedef struct PreUpdate PreUpdate;
|
|
typedef struct PrintfArguments PrintfArguments;
|
|
typedef struct RenameToken RenameToken;
|
|
+typedef struct Returning Returning;
|
|
typedef struct RowSet RowSet;
|
|
typedef struct Savepoint Savepoint;
|
|
typedef struct Select Select;
|
|
typedef struct SQLiteThread SQLiteThread;
|
|
typedef struct SelectDest SelectDest;
|
|
+typedef struct SrcItem SrcItem;
|
|
typedef struct SrcList SrcList;
|
|
typedef struct sqlite3_str StrAccum; /* Internal alias for sqlite3_str */
|
|
typedef struct Table Table;
|
|
@@ -14602,10 +14879,12 @@ typedef struct With With;
|
|
/*
|
|
** A bit in a Bitmask
|
|
*/
|
|
-#define MASKBIT(n) (((Bitmask)1)<<(n))
|
|
-#define MASKBIT64(n) (((u64)1)<<(n))
|
|
-#define MASKBIT32(n) (((unsigned int)1)<<(n))
|
|
-#define ALLBITS ((Bitmask)-1)
|
|
+#define MASKBIT(n) (((Bitmask)1)<<(n))
|
|
+#define MASKBIT64(n) (((u64)1)<<(n))
|
|
+#define MASKBIT32(n) (((unsigned int)1)<<(n))
|
|
+#define SMASKBIT32(n) ((n)<=31?((unsigned int)1)<<(n):0)
|
|
+#define ALLBITS ((Bitmask)-1)
|
|
+#define TOPBIT (((Bitmask)1)<<(BMS-1))
|
|
|
|
/* A VList object records a mapping between parameters/variables/wildcards
|
|
** in the SQL statement (such as $abc, @pqr, or :xyz) and the integer
|
|
@@ -14620,6 +14899,579 @@ typedef int VList;
|
|
** "BusyHandler" typedefs. vdbe.h also requires a few of the opaque
|
|
** pointer types (i.e. FuncDef) defined above.
|
|
*/
|
|
+/************** Include os.h in the middle of sqliteInt.h ********************/
|
|
+/************** Begin file os.h **********************************************/
|
|
+/*
|
|
+** 2001 September 16
|
|
+**
|
|
+** The author disclaims copyright to this source code. In place of
|
|
+** a legal notice, here is a blessing:
|
|
+**
|
|
+** May you do good and not evil.
|
|
+** May you find forgiveness for yourself and forgive others.
|
|
+** May you share freely, never taking more than you give.
|
|
+**
|
|
+******************************************************************************
|
|
+**
|
|
+** This header file (together with is companion C source-code file
|
|
+** "os.c") attempt to abstract the underlying operating system so that
|
|
+** the SQLite library will work on both POSIX and windows systems.
|
|
+**
|
|
+** This header file is #include-ed by sqliteInt.h and thus ends up
|
|
+** being included by every source file.
|
|
+*/
|
|
+#ifndef _SQLITE_OS_H_
|
|
+#define _SQLITE_OS_H_
|
|
+
|
|
+/*
|
|
+** Attempt to automatically detect the operating system and setup the
|
|
+** necessary pre-processor macros for it.
|
|
+*/
|
|
+/************** Include os_setup.h in the middle of os.h *********************/
|
|
+/************** Begin file os_setup.h ****************************************/
|
|
+/*
|
|
+** 2013 November 25
|
|
+**
|
|
+** The author disclaims copyright to this source code. In place of
|
|
+** a legal notice, here is a blessing:
|
|
+**
|
|
+** May you do good and not evil.
|
|
+** May you find forgiveness for yourself and forgive others.
|
|
+** May you share freely, never taking more than you give.
|
|
+**
|
|
+******************************************************************************
|
|
+**
|
|
+** This file contains pre-processor directives related to operating system
|
|
+** detection and/or setup.
|
|
+*/
|
|
+#ifndef SQLITE_OS_SETUP_H
|
|
+#define SQLITE_OS_SETUP_H
|
|
+
|
|
+/*
|
|
+** Figure out if we are dealing with Unix, Windows, or some other operating
|
|
+** system.
|
|
+**
|
|
+** After the following block of preprocess macros, all of
|
|
+**
|
|
+** SQLITE_OS_KV
|
|
+** SQLITE_OS_OTHER
|
|
+** SQLITE_OS_UNIX
|
|
+** SQLITE_OS_WIN
|
|
+**
|
|
+** will defined to either 1 or 0. One of them will be 1. The others will be 0.
|
|
+** If none of the macros are initially defined, then select either
|
|
+** SQLITE_OS_UNIX or SQLITE_OS_WIN depending on the target platform.
|
|
+**
|
|
+** If SQLITE_OS_OTHER=1 is specified at compile-time, then the application
|
|
+** must provide its own VFS implementation together with sqlite3_os_init()
|
|
+** and sqlite3_os_end() routines.
|
|
+*/
|
|
+#if !defined(SQLITE_OS_KV) && !defined(SQLITE_OS_OTHER) && \
|
|
+ !defined(SQLITE_OS_UNIX) && !defined(SQLITE_OS_WIN)
|
|
+# if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || \
|
|
+ defined(__MINGW32__) || defined(__BORLANDC__)
|
|
+# define SQLITE_OS_WIN 1
|
|
+# define SQLITE_OS_UNIX 0
|
|
+# else
|
|
+# define SQLITE_OS_WIN 0
|
|
+# define SQLITE_OS_UNIX 1
|
|
+# endif
|
|
+#endif
|
|
+#if SQLITE_OS_OTHER+1>1
|
|
+# undef SQLITE_OS_KV
|
|
+# define SQLITE_OS_KV 0
|
|
+# undef SQLITE_OS_UNIX
|
|
+# define SQLITE_OS_UNIX 0
|
|
+# undef SQLITE_OS_WIN
|
|
+# define SQLITE_OS_WIN 0
|
|
+#endif
|
|
+#if SQLITE_OS_KV+1>1
|
|
+# undef SQLITE_OS_OTHER
|
|
+# define SQLITE_OS_OTHER 0
|
|
+# undef SQLITE_OS_UNIX
|
|
+# define SQLITE_OS_UNIX 0
|
|
+# undef SQLITE_OS_WIN
|
|
+# define SQLITE_OS_WIN 0
|
|
+# define SQLITE_OMIT_LOAD_EXTENSION 1
|
|
+# define SQLITE_OMIT_WAL 1
|
|
+# define SQLITE_OMIT_DEPRECATED 1
|
|
+# undef SQLITE_TEMP_STORE
|
|
+# define SQLITE_TEMP_STORE 3 /* Always use memory for temporary storage */
|
|
+# define SQLITE_DQS 0
|
|
+# define SQLITE_OMIT_SHARED_CACHE 1
|
|
+# define SQLITE_OMIT_AUTOINIT 1
|
|
+#endif
|
|
+#if SQLITE_OS_UNIX+1>1
|
|
+# undef SQLITE_OS_KV
|
|
+# define SQLITE_OS_KV 0
|
|
+# undef SQLITE_OS_OTHER
|
|
+# define SQLITE_OS_OTHER 0
|
|
+# undef SQLITE_OS_WIN
|
|
+# define SQLITE_OS_WIN 0
|
|
+#endif
|
|
+#if SQLITE_OS_WIN+1>1
|
|
+# undef SQLITE_OS_KV
|
|
+# define SQLITE_OS_KV 0
|
|
+# undef SQLITE_OS_OTHER
|
|
+# define SQLITE_OS_OTHER 0
|
|
+# undef SQLITE_OS_UNIX
|
|
+# define SQLITE_OS_UNIX 0
|
|
+#endif
|
|
+
|
|
+
|
|
+#endif /* SQLITE_OS_SETUP_H */
|
|
+
|
|
+/************** End of os_setup.h ********************************************/
|
|
+/************** Continuing where we left off in os.h *************************/
|
|
+
|
|
+/* If the SET_FULLSYNC macro is not defined above, then make it
|
|
+** a no-op
|
|
+*/
|
|
+#ifndef SET_FULLSYNC
|
|
+# define SET_FULLSYNC(x,y)
|
|
+#endif
|
|
+
|
|
+/* Maximum pathname length. Note: FILENAME_MAX defined by stdio.h
|
|
+*/
|
|
+#ifndef SQLITE_MAX_PATHLEN
|
|
+# define SQLITE_MAX_PATHLEN FILENAME_MAX
|
|
+#endif
|
|
+
|
|
+/* Maximum number of symlinks that will be resolved while trying to
|
|
+** expand a filename in xFullPathname() in the VFS.
|
|
+*/
|
|
+#ifndef SQLITE_MAX_SYMLINK
|
|
+# define SQLITE_MAX_SYMLINK 200
|
|
+#endif
|
|
+
|
|
+/*
|
|
+** The default size of a disk sector
|
|
+*/
|
|
+#ifndef SQLITE_DEFAULT_SECTOR_SIZE
|
|
+# define SQLITE_DEFAULT_SECTOR_SIZE 4096
|
|
+#endif
|
|
+
|
|
+/*
|
|
+** Temporary files are named starting with this prefix followed by 16 random
|
|
+** alphanumeric characters, and no file extension. They are stored in the
|
|
+** OS's standard temporary file directory, and are deleted prior to exit.
|
|
+** If sqlite is being embedded in another program, you may wish to change the
|
|
+** prefix to reflect your program's name, so that if your program exits
|
|
+** prematurely, old temporary files can be easily identified. This can be done
|
|
+** using -DSQLITE_TEMP_FILE_PREFIX=myprefix_ on the compiler command line.
|
|
+**
|
|
+** 2006-10-31: The default prefix used to be "sqlite_". But then
|
|
+** Mcafee started using SQLite in their anti-virus product and it
|
|
+** started putting files with the "sqlite" name in the c:/temp folder.
|
|
+** This annoyed many windows users. Those users would then do a
|
|
+** Google search for "sqlite", find the telephone numbers of the
|
|
+** developers and call to wake them up at night and complain.
|
|
+** For this reason, the default name prefix is changed to be "sqlite"
|
|
+** spelled backwards. So the temp files are still identified, but
|
|
+** anybody smart enough to figure out the code is also likely smart
|
|
+** enough to know that calling the developer will not help get rid
|
|
+** of the file.
|
|
+*/
|
|
+#ifndef SQLITE_TEMP_FILE_PREFIX
|
|
+# define SQLITE_TEMP_FILE_PREFIX "etilqs_"
|
|
+#endif
|
|
+
|
|
+/*
|
|
+** The following values may be passed as the second argument to
|
|
+** sqlite3OsLock(). The various locks exhibit the following semantics:
|
|
+**
|
|
+** SHARED: Any number of processes may hold a SHARED lock simultaneously.
|
|
+** RESERVED: A single process may hold a RESERVED lock on a file at
|
|
+** any time. Other processes may hold and obtain new SHARED locks.
|
|
+** PENDING: A single process may hold a PENDING lock on a file at
|
|
+** any one time. Existing SHARED locks may persist, but no new
|
|
+** SHARED locks may be obtained by other processes.
|
|
+** EXCLUSIVE: An EXCLUSIVE lock precludes all other locks.
|
|
+**
|
|
+** PENDING_LOCK may not be passed directly to sqlite3OsLock(). Instead, a
|
|
+** process that requests an EXCLUSIVE lock may actually obtain a PENDING
|
|
+** lock. This can be upgraded to an EXCLUSIVE lock by a subsequent call to
|
|
+** sqlite3OsLock().
|
|
+*/
|
|
+#define NO_LOCK 0
|
|
+#define SHARED_LOCK 1
|
|
+#define RESERVED_LOCK 2
|
|
+#define PENDING_LOCK 3
|
|
+#define EXCLUSIVE_LOCK 4
|
|
+
|
|
+/*
|
|
+** File Locking Notes: (Mostly about windows but also some info for Unix)
|
|
+**
|
|
+** We cannot use LockFileEx() or UnlockFileEx() on Win95/98/ME because
|
|
+** those functions are not available. So we use only LockFile() and
|
|
+** UnlockFile().
|
|
+**
|
|
+** LockFile() prevents not just writing but also reading by other processes.
|
|
+** A SHARED_LOCK is obtained by locking a single randomly-chosen
|
|
+** byte out of a specific range of bytes. The lock byte is obtained at
|
|
+** random so two separate readers can probably access the file at the
|
|
+** same time, unless they are unlucky and choose the same lock byte.
|
|
+** An EXCLUSIVE_LOCK is obtained by locking all bytes in the range.
|
|
+** There can only be one writer. A RESERVED_LOCK is obtained by locking
|
|
+** a single byte of the file that is designated as the reserved lock byte.
|
|
+** A PENDING_LOCK is obtained by locking a designated byte different from
|
|
+** the RESERVED_LOCK byte.
|
|
+**
|
|
+** On WinNT/2K/XP systems, LockFileEx() and UnlockFileEx() are available,
|
|
+** which means we can use reader/writer locks. When reader/writer locks
|
|
+** are used, the lock is placed on the same range of bytes that is used
|
|
+** for probabilistic locking in Win95/98/ME. Hence, the locking scheme
|
|
+** will support two or more Win95 readers or two or more WinNT readers.
|
|
+** But a single Win95 reader will lock out all WinNT readers and a single
|
|
+** WinNT reader will lock out all other Win95 readers.
|
|
+**
|
|
+** The following #defines specify the range of bytes used for locking.
|
|
+** SHARED_SIZE is the number of bytes available in the pool from which
|
|
+** a random byte is selected for a shared lock. The pool of bytes for
|
|
+** shared locks begins at SHARED_FIRST.
|
|
+**
|
|
+** The same locking strategy and
|
|
+** byte ranges are used for Unix. This leaves open the possibility of having
|
|
+** clients on win95, winNT, and unix all talking to the same shared file
|
|
+** and all locking correctly. To do so would require that samba (or whatever
|
|
+** tool is being used for file sharing) implements locks correctly between
|
|
+** windows and unix. I'm guessing that isn't likely to happen, but by
|
|
+** using the same locking range we are at least open to the possibility.
|
|
+**
|
|
+** Locking in windows is manditory. For this reason, we cannot store
|
|
+** actual data in the bytes used for locking. The pager never allocates
|
|
+** the pages involved in locking therefore. SHARED_SIZE is selected so
|
|
+** that all locks will fit on a single page even at the minimum page size.
|
|
+** PENDING_BYTE defines the beginning of the locks. By default PENDING_BYTE
|
|
+** is set high so that we don't have to allocate an unused page except
|
|
+** for very large databases. But one should test the page skipping logic
|
|
+** by setting PENDING_BYTE low and running the entire regression suite.
|
|
+**
|
|
+** Changing the value of PENDING_BYTE results in a subtly incompatible
|
|
+** file format. Depending on how it is changed, you might not notice
|
|
+** the incompatibility right away, even running a full regression test.
|
|
+** The default location of PENDING_BYTE is the first byte past the
|
|
+** 1GB boundary.
|
|
+**
|
|
+*/
|
|
+#ifdef SQLITE_OMIT_WSD
|
|
+# define PENDING_BYTE (0x40000000)
|
|
+#else
|
|
+# define PENDING_BYTE sqlite3PendingByte
|
|
+#endif
|
|
+#define RESERVED_BYTE (PENDING_BYTE+1)
|
|
+#define SHARED_FIRST (PENDING_BYTE+2)
|
|
+#define SHARED_SIZE 510
|
|
+
|
|
+/*
|
|
+** Wrapper around OS specific sqlite3_os_init() function.
|
|
+*/
|
|
+SQLITE_PRIVATE int sqlite3OsInit(void);
|
|
+
|
|
+/*
|
|
+** Functions for accessing sqlite3_file methods
|
|
+*/
|
|
+SQLITE_PRIVATE void sqlite3OsClose(sqlite3_file*);
|
|
+SQLITE_PRIVATE int sqlite3OsRead(sqlite3_file*, void*, int amt, i64 offset);
|
|
+SQLITE_PRIVATE int sqlite3OsWrite(sqlite3_file*, const void*, int amt, i64 offset);
|
|
+SQLITE_PRIVATE int sqlite3OsTruncate(sqlite3_file*, i64 size);
|
|
+SQLITE_PRIVATE int sqlite3OsSync(sqlite3_file*, int);
|
|
+SQLITE_PRIVATE int sqlite3OsFileSize(sqlite3_file*, i64 *pSize);
|
|
+SQLITE_PRIVATE int sqlite3OsLock(sqlite3_file*, int);
|
|
+SQLITE_PRIVATE int sqlite3OsUnlock(sqlite3_file*, int);
|
|
+SQLITE_PRIVATE int sqlite3OsCheckReservedLock(sqlite3_file *id, int *pResOut);
|
|
+SQLITE_PRIVATE int sqlite3OsFileControl(sqlite3_file*,int,void*);
|
|
+SQLITE_PRIVATE void sqlite3OsFileControlHint(sqlite3_file*,int,void*);
|
|
+#define SQLITE_FCNTL_DB_UNCHANGED 0xca093fa0
|
|
+SQLITE_PRIVATE int sqlite3OsSectorSize(sqlite3_file *id);
|
|
+SQLITE_PRIVATE int sqlite3OsDeviceCharacteristics(sqlite3_file *id);
|
|
+#ifndef SQLITE_OMIT_WAL
|
|
+SQLITE_PRIVATE int sqlite3OsShmMap(sqlite3_file *,int,int,int,void volatile **);
|
|
+SQLITE_PRIVATE int sqlite3OsShmLock(sqlite3_file *id, int, int, int);
|
|
+SQLITE_PRIVATE void sqlite3OsShmBarrier(sqlite3_file *id);
|
|
+SQLITE_PRIVATE int sqlite3OsShmUnmap(sqlite3_file *id, int);
|
|
+#endif /* SQLITE_OMIT_WAL */
|
|
+SQLITE_PRIVATE int sqlite3OsFetch(sqlite3_file *id, i64, int, void **);
|
|
+SQLITE_PRIVATE int sqlite3OsUnfetch(sqlite3_file *, i64, void *);
|
|
+
|
|
+
|
|
+/*
|
|
+** Functions for accessing sqlite3_vfs methods
|
|
+*/
|
|
+SQLITE_PRIVATE int sqlite3OsOpen(sqlite3_vfs *, const char *, sqlite3_file*, int, int *);
|
|
+SQLITE_PRIVATE int sqlite3OsDelete(sqlite3_vfs *, const char *, int);
|
|
+SQLITE_PRIVATE int sqlite3OsAccess(sqlite3_vfs *, const char *, int, int *pResOut);
|
|
+SQLITE_PRIVATE int sqlite3OsFullPathname(sqlite3_vfs *, const char *, int, char *);
|
|
+#ifndef SQLITE_OMIT_LOAD_EXTENSION
|
|
+SQLITE_PRIVATE void *sqlite3OsDlOpen(sqlite3_vfs *, const char *);
|
|
+SQLITE_PRIVATE void sqlite3OsDlError(sqlite3_vfs *, int, char *);
|
|
+SQLITE_PRIVATE void (*sqlite3OsDlSym(sqlite3_vfs *, void *, const char *))(void);
|
|
+SQLITE_PRIVATE void sqlite3OsDlClose(sqlite3_vfs *, void *);
|
|
+#endif /* SQLITE_OMIT_LOAD_EXTENSION */
|
|
+SQLITE_PRIVATE int sqlite3OsRandomness(sqlite3_vfs *, int, char *);
|
|
+SQLITE_PRIVATE int sqlite3OsSleep(sqlite3_vfs *, int);
|
|
+SQLITE_PRIVATE int sqlite3OsGetLastError(sqlite3_vfs*);
|
|
+SQLITE_PRIVATE int sqlite3OsCurrentTimeInt64(sqlite3_vfs *, sqlite3_int64*);
|
|
+
|
|
+/*
|
|
+** Convenience functions for opening and closing files using
|
|
+** sqlite3_malloc() to obtain space for the file-handle structure.
|
|
+*/
|
|
+SQLITE_PRIVATE int sqlite3OsOpenMalloc(sqlite3_vfs *, const char *, sqlite3_file **, int,int*);
|
|
+SQLITE_PRIVATE void sqlite3OsCloseFree(sqlite3_file *);
|
|
+
|
|
+#endif /* _SQLITE_OS_H_ */
|
|
+
|
|
+/************** End of os.h **************************************************/
|
|
+/************** Continuing where we left off in sqliteInt.h ******************/
|
|
+/************** Include pager.h in the middle of sqliteInt.h *****************/
|
|
+/************** Begin file pager.h *******************************************/
|
|
+/*
|
|
+** 2001 September 15
|
|
+**
|
|
+** The author disclaims copyright to this source code. In place of
|
|
+** a legal notice, here is a blessing:
|
|
+**
|
|
+** May you do good and not evil.
|
|
+** May you find forgiveness for yourself and forgive others.
|
|
+** May you share freely, never taking more than you give.
|
|
+**
|
|
+*************************************************************************
|
|
+** This header file defines the interface that the sqlite page cache
|
|
+** subsystem. The page cache subsystem reads and writes a file a page
|
|
+** at a time and provides a journal for rollback.
|
|
+*/
|
|
+
|
|
+#ifndef SQLITE_PAGER_H
|
|
+#define SQLITE_PAGER_H
|
|
+
|
|
+/*
|
|
+** Default maximum size for persistent journal files. A negative
|
|
+** value means no limit. This value may be overridden using the
|
|
+** sqlite3PagerJournalSizeLimit() API. See also "PRAGMA journal_size_limit".
|
|
+*/
|
|
+#ifndef SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT
|
|
+ #define SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT -1
|
|
+#endif
|
|
+
|
|
+/*
|
|
+** The type used to represent a page number. The first page in a file
|
|
+** is called page 1. 0 is used to represent "not a page".
|
|
+*/
|
|
+typedef u32 Pgno;
|
|
+
|
|
+/*
|
|
+** Each open file is managed by a separate instance of the "Pager" structure.
|
|
+*/
|
|
+typedef struct Pager Pager;
|
|
+
|
|
+/*
|
|
+** Handle type for pages.
|
|
+*/
|
|
+typedef struct PgHdr DbPage;
|
|
+
|
|
+/*
|
|
+** Page number PAGER_SJ_PGNO is never used in an SQLite database (it is
|
|
+** reserved for working around a windows/posix incompatibility). It is
|
|
+** used in the journal to signify that the remainder of the journal file
|
|
+** is devoted to storing a super-journal name - there are no more pages to
|
|
+** roll back. See comments for function writeSuperJournal() in pager.c
|
|
+** for details.
|
|
+*/
|
|
+#define PAGER_SJ_PGNO_COMPUTED(x) ((Pgno)((PENDING_BYTE/((x)->pageSize))+1))
|
|
+#define PAGER_SJ_PGNO(x) ((x)->lckPgno)
|
|
+
|
|
+/*
|
|
+** Allowed values for the flags parameter to sqlite3PagerOpen().
|
|
+**
|
|
+** NOTE: These values must match the corresponding BTREE_ values in btree.h.
|
|
+*/
|
|
+#define PAGER_OMIT_JOURNAL 0x0001 /* Do not use a rollback journal */
|
|
+#define PAGER_MEMORY 0x0002 /* In-memory database */
|
|
+
|
|
+/*
|
|
+** Valid values for the second argument to sqlite3PagerLockingMode().
|
|
+*/
|
|
+#define PAGER_LOCKINGMODE_QUERY -1
|
|
+#define PAGER_LOCKINGMODE_NORMAL 0
|
|
+#define PAGER_LOCKINGMODE_EXCLUSIVE 1
|
|
+
|
|
+/*
|
|
+** Numeric constants that encode the journalmode.
|
|
+**
|
|
+** The numeric values encoded here (other than PAGER_JOURNALMODE_QUERY)
|
|
+** are exposed in the API via the "PRAGMA journal_mode" command and
|
|
+** therefore cannot be changed without a compatibility break.
|
|
+*/
|
|
+#define PAGER_JOURNALMODE_QUERY (-1) /* Query the value of journalmode */
|
|
+#define PAGER_JOURNALMODE_DELETE 0 /* Commit by deleting journal file */
|
|
+#define PAGER_JOURNALMODE_PERSIST 1 /* Commit by zeroing journal header */
|
|
+#define PAGER_JOURNALMODE_OFF 2 /* Journal omitted. */
|
|
+#define PAGER_JOURNALMODE_TRUNCATE 3 /* Commit by truncating journal */
|
|
+#define PAGER_JOURNALMODE_MEMORY 4 /* In-memory journal file */
|
|
+#define PAGER_JOURNALMODE_WAL 5 /* Use write-ahead logging */
|
|
+
|
|
+/*
|
|
+** Flags that make up the mask passed to sqlite3PagerGet().
|
|
+*/
|
|
+#define PAGER_GET_NOCONTENT 0x01 /* Do not load data from disk */
|
|
+#define PAGER_GET_READONLY 0x02 /* Read-only page is acceptable */
|
|
+
|
|
+/*
|
|
+** Flags for sqlite3PagerSetFlags()
|
|
+**
|
|
+** Value constraints (enforced via assert()):
|
|
+** PAGER_FULLFSYNC == SQLITE_FullFSync
|
|
+** PAGER_CKPT_FULLFSYNC == SQLITE_CkptFullFSync
|
|
+** PAGER_CACHE_SPILL == SQLITE_CacheSpill
|
|
+*/
|
|
+#define PAGER_SYNCHRONOUS_OFF 0x01 /* PRAGMA synchronous=OFF */
|
|
+#define PAGER_SYNCHRONOUS_NORMAL 0x02 /* PRAGMA synchronous=NORMAL */
|
|
+#define PAGER_SYNCHRONOUS_FULL 0x03 /* PRAGMA synchronous=FULL */
|
|
+#define PAGER_SYNCHRONOUS_EXTRA 0x04 /* PRAGMA synchronous=EXTRA */
|
|
+#define PAGER_SYNCHRONOUS_MASK 0x07 /* Mask for four values above */
|
|
+#define PAGER_FULLFSYNC 0x08 /* PRAGMA fullfsync=ON */
|
|
+#define PAGER_CKPT_FULLFSYNC 0x10 /* PRAGMA checkpoint_fullfsync=ON */
|
|
+#define PAGER_CACHESPILL 0x20 /* PRAGMA cache_spill=ON */
|
|
+#define PAGER_FLAGS_MASK 0x38 /* All above except SYNCHRONOUS */
|
|
+
|
|
+/*
|
|
+** The remainder of this file contains the declarations of the functions
|
|
+** that make up the Pager sub-system API. See source code comments for
|
|
+** a detailed description of each routine.
|
|
+*/
|
|
+
|
|
+/* Open and close a Pager connection. */
|
|
+SQLITE_PRIVATE int sqlite3PagerOpen(
|
|
+ sqlite3_vfs*,
|
|
+ Pager **ppPager,
|
|
+ const char*,
|
|
+ int,
|
|
+ int,
|
|
+ int,
|
|
+ void(*)(DbPage*)
|
|
+);
|
|
+SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3*);
|
|
+SQLITE_PRIVATE int sqlite3PagerReadFileheader(Pager*, int, unsigned char*);
|
|
+
|
|
+/* Functions used to configure a Pager object. */
|
|
+SQLITE_PRIVATE void sqlite3PagerSetBusyHandler(Pager*, int(*)(void *), void *);
|
|
+SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager*, u32*, int);
|
|
+SQLITE_PRIVATE Pgno sqlite3PagerMaxPageCount(Pager*, Pgno);
|
|
+SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager*, int);
|
|
+SQLITE_PRIVATE int sqlite3PagerSetSpillsize(Pager*, int);
|
|
+SQLITE_PRIVATE void sqlite3PagerSetMmapLimit(Pager *, sqlite3_int64);
|
|
+SQLITE_PRIVATE void sqlite3PagerShrink(Pager*);
|
|
+SQLITE_PRIVATE void sqlite3PagerSetFlags(Pager*,unsigned);
|
|
+SQLITE_PRIVATE int sqlite3PagerLockingMode(Pager *, int);
|
|
+SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *, int);
|
|
+SQLITE_PRIVATE int sqlite3PagerGetJournalMode(Pager*);
|
|
+SQLITE_PRIVATE int sqlite3PagerOkToChangeJournalMode(Pager*);
|
|
+SQLITE_PRIVATE i64 sqlite3PagerJournalSizeLimit(Pager *, i64);
|
|
+SQLITE_PRIVATE sqlite3_backup **sqlite3PagerBackupPtr(Pager*);
|
|
+SQLITE_PRIVATE int sqlite3PagerFlush(Pager*);
|
|
+
|
|
+/* Functions used to obtain and release page references. */
|
|
+SQLITE_PRIVATE int sqlite3PagerGet(Pager *pPager, Pgno pgno, DbPage **ppPage, int clrFlag);
|
|
+SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno);
|
|
+SQLITE_PRIVATE void sqlite3PagerRef(DbPage*);
|
|
+SQLITE_PRIVATE void sqlite3PagerUnref(DbPage*);
|
|
+SQLITE_PRIVATE void sqlite3PagerUnrefNotNull(DbPage*);
|
|
+SQLITE_PRIVATE void sqlite3PagerUnrefPageOne(DbPage*);
|
|
+
|
|
+/* Operations on page references. */
|
|
+SQLITE_PRIVATE int sqlite3PagerWrite(DbPage*);
|
|
+SQLITE_PRIVATE void sqlite3PagerDontWrite(DbPage*);
|
|
+SQLITE_PRIVATE int sqlite3PagerMovepage(Pager*,DbPage*,Pgno,int);
|
|
+SQLITE_PRIVATE int sqlite3PagerPageRefcount(DbPage*);
|
|
+SQLITE_PRIVATE void *sqlite3PagerGetData(DbPage *);
|
|
+SQLITE_PRIVATE void *sqlite3PagerGetExtra(DbPage *);
|
|
+
|
|
+/* Functions used to manage pager transactions and savepoints. */
|
|
+SQLITE_PRIVATE void sqlite3PagerPagecount(Pager*, int*);
|
|
+SQLITE_PRIVATE int sqlite3PagerBegin(Pager*, int exFlag, int);
|
|
+SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(Pager*,const char *zSuper, int);
|
|
+SQLITE_PRIVATE int sqlite3PagerExclusiveLock(Pager*);
|
|
+SQLITE_PRIVATE int sqlite3PagerSync(Pager *pPager, const char *zSuper);
|
|
+SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager*);
|
|
+SQLITE_PRIVATE int sqlite3PagerRollback(Pager*);
|
|
+SQLITE_PRIVATE int sqlite3PagerOpenSavepoint(Pager *pPager, int n);
|
|
+SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint);
|
|
+SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager);
|
|
+
|
|
+#ifndef SQLITE_OMIT_WAL
|
|
+SQLITE_PRIVATE int sqlite3PagerCheckpoint(Pager *pPager, sqlite3*, int, int*, int*);
|
|
+SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager);
|
|
+SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager);
|
|
+SQLITE_PRIVATE int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen);
|
|
+SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager, sqlite3*);
|
|
+# ifdef SQLITE_ENABLE_SNAPSHOT
|
|
+SQLITE_PRIVATE int sqlite3PagerSnapshotGet(Pager*, sqlite3_snapshot **ppSnapshot);
|
|
+SQLITE_PRIVATE int sqlite3PagerSnapshotOpen(Pager*, sqlite3_snapshot *pSnapshot);
|
|
+SQLITE_PRIVATE int sqlite3PagerSnapshotRecover(Pager *pPager);
|
|
+SQLITE_PRIVATE int sqlite3PagerSnapshotCheck(Pager *pPager, sqlite3_snapshot *pSnapshot);
|
|
+SQLITE_PRIVATE void sqlite3PagerSnapshotUnlock(Pager *pPager);
|
|
+# endif
|
|
+#endif
|
|
+
|
|
+#if !defined(SQLITE_OMIT_WAL) && defined(SQLITE_ENABLE_SETLK_TIMEOUT)
|
|
+SQLITE_PRIVATE int sqlite3PagerWalWriteLock(Pager*, int);
|
|
+SQLITE_PRIVATE void sqlite3PagerWalDb(Pager*, sqlite3*);
|
|
+#else
|
|
+# define sqlite3PagerWalWriteLock(y,z) SQLITE_OK
|
|
+# define sqlite3PagerWalDb(x,y)
|
|
+#endif
|
|
+
|
|
+#ifdef SQLITE_DIRECT_OVERFLOW_READ
|
|
+SQLITE_PRIVATE int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno);
|
|
+#endif
|
|
+
|
|
+#ifdef SQLITE_ENABLE_ZIPVFS
|
|
+SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager);
|
|
+#endif
|
|
+
|
|
+/* Functions used to query pager state and configuration. */
|
|
+SQLITE_PRIVATE u8 sqlite3PagerIsreadonly(Pager*);
|
|
+SQLITE_PRIVATE u32 sqlite3PagerDataVersion(Pager*);
|
|
+#ifdef SQLITE_DEBUG
|
|
+SQLITE_PRIVATE int sqlite3PagerRefcount(Pager*);
|
|
+#endif
|
|
+SQLITE_PRIVATE int sqlite3PagerMemUsed(Pager*);
|
|
+SQLITE_PRIVATE const char *sqlite3PagerFilename(const Pager*, int);
|
|
+SQLITE_PRIVATE sqlite3_vfs *sqlite3PagerVfs(Pager*);
|
|
+SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager*);
|
|
+SQLITE_PRIVATE sqlite3_file *sqlite3PagerJrnlFile(Pager*);
|
|
+SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager*);
|
|
+SQLITE_PRIVATE void *sqlite3PagerTempSpace(Pager*);
|
|
+SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager*);
|
|
+SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *, int, int, int *);
|
|
+SQLITE_PRIVATE void sqlite3PagerClearCache(Pager*);
|
|
+SQLITE_PRIVATE int sqlite3SectorSize(sqlite3_file *);
|
|
+
|
|
+/* Functions used to truncate the database file. */
|
|
+SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager*,Pgno);
|
|
+
|
|
+SQLITE_PRIVATE void sqlite3PagerRekey(DbPage*, Pgno, u16);
|
|
+
|
|
+/* Functions to support testing and debugging. */
|
|
+#if !defined(NDEBUG) || defined(SQLITE_TEST)
|
|
+SQLITE_PRIVATE Pgno sqlite3PagerPagenumber(DbPage*);
|
|
+SQLITE_PRIVATE int sqlite3PagerIswriteable(DbPage*);
|
|
+#endif
|
|
+#ifdef SQLITE_TEST
|
|
+SQLITE_PRIVATE int *sqlite3PagerStats(Pager*);
|
|
+SQLITE_PRIVATE void sqlite3PagerRefdump(Pager*);
|
|
+ void disable_simulated_io_errors(void);
|
|
+ void enable_simulated_io_errors(void);
|
|
+#else
|
|
+# define disable_simulated_io_errors()
|
|
+# define enable_simulated_io_errors()
|
|
+#endif
|
|
+
|
|
+#endif /* SQLITE_PAGER_H */
|
|
+
|
|
+/************** End of pager.h ***********************************************/
|
|
+/************** Continuing where we left off in sqliteInt.h ******************/
|
|
/************** Include btree.h in the middle of sqliteInt.h *****************/
|
|
/************** Begin file btree.h *******************************************/
|
|
/*
|
|
@@ -14695,30 +15547,38 @@ SQLITE_PRIVATE int sqlite3BtreeSetMmapLimit(Btree*,sqlite3_int64);
|
|
SQLITE_PRIVATE int sqlite3BtreeSetPagerFlags(Btree*,unsigned);
|
|
SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix);
|
|
SQLITE_PRIVATE int sqlite3BtreeGetPageSize(Btree*);
|
|
-SQLITE_PRIVATE int sqlite3BtreeMaxPageCount(Btree*,int);
|
|
-SQLITE_PRIVATE u32 sqlite3BtreeLastPage(Btree*);
|
|
+SQLITE_PRIVATE Pgno sqlite3BtreeMaxPageCount(Btree*,Pgno);
|
|
+SQLITE_PRIVATE Pgno sqlite3BtreeLastPage(Btree*);
|
|
SQLITE_PRIVATE int sqlite3BtreeSecureDelete(Btree*,int);
|
|
-SQLITE_PRIVATE int sqlite3BtreeGetOptimalReserve(Btree*);
|
|
+SQLITE_PRIVATE int sqlite3BtreeGetRequestedReserve(Btree*);
|
|
SQLITE_PRIVATE int sqlite3BtreeGetReserveNoMutex(Btree *p);
|
|
SQLITE_PRIVATE int sqlite3BtreeSetAutoVacuum(Btree *, int);
|
|
SQLITE_PRIVATE int sqlite3BtreeGetAutoVacuum(Btree *);
|
|
SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree*,int,int*);
|
|
-SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree*, const char *zMaster);
|
|
+SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree*, const char*);
|
|
SQLITE_PRIVATE int sqlite3BtreeCommitPhaseTwo(Btree*, int);
|
|
SQLITE_PRIVATE int sqlite3BtreeCommit(Btree*);
|
|
SQLITE_PRIVATE int sqlite3BtreeRollback(Btree*,int,int);
|
|
SQLITE_PRIVATE int sqlite3BtreeBeginStmt(Btree*,int);
|
|
-SQLITE_PRIVATE int sqlite3BtreeCreateTable(Btree*, int*, int flags);
|
|
-SQLITE_PRIVATE int sqlite3BtreeIsInTrans(Btree*);
|
|
-SQLITE_PRIVATE int sqlite3BtreeIsInReadTrans(Btree*);
|
|
+SQLITE_PRIVATE int sqlite3BtreeCreateTable(Btree*, Pgno*, int flags);
|
|
+SQLITE_PRIVATE int sqlite3BtreeTxnState(Btree*);
|
|
SQLITE_PRIVATE int sqlite3BtreeIsInBackup(Btree*);
|
|
+
|
|
SQLITE_PRIVATE void *sqlite3BtreeSchema(Btree *, int, void(*)(void *));
|
|
SQLITE_PRIVATE int sqlite3BtreeSchemaLocked(Btree *pBtree);
|
|
#ifndef SQLITE_OMIT_SHARED_CACHE
|
|
SQLITE_PRIVATE int sqlite3BtreeLockTable(Btree *pBtree, int iTab, u8 isWriteLock);
|
|
#endif
|
|
+
|
|
+/* Savepoints are named, nestable SQL transactions mostly implemented */
|
|
+/* in vdbe.c and pager.c See https://sqlite.org/lang_savepoint.html */
|
|
SQLITE_PRIVATE int sqlite3BtreeSavepoint(Btree *, int, int);
|
|
|
|
+/* "Checkpoint" only refers to WAL. See https://sqlite.org/wal.html#ckpt */
|
|
+#ifndef SQLITE_OMIT_WAL
|
|
+SQLITE_PRIVATE int sqlite3BtreeCheckpoint(Btree*, int, int *, int *);
|
|
+#endif
|
|
+
|
|
SQLITE_PRIVATE const char *sqlite3BtreeGetFilename(Btree *);
|
|
SQLITE_PRIVATE const char *sqlite3BtreeGetJournalname(Btree *);
|
|
SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *, Btree *);
|
|
@@ -14739,7 +15599,7 @@ SQLITE_PRIVATE int sqlite3BtreeIncrVacuum(Btree *);
|
|
#define BTREE_BLOBKEY 2 /* Table has keys only - no data */
|
|
|
|
SQLITE_PRIVATE int sqlite3BtreeDropTable(Btree*, int, int*);
|
|
-SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree*, int, int*);
|
|
+SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree*, int, i64*);
|
|
SQLITE_PRIVATE int sqlite3BtreeClearTableOfCursor(BtCursor*);
|
|
SQLITE_PRIVATE int sqlite3BtreeTripAllCursors(Btree*, int, int);
|
|
|
|
@@ -14750,7 +15610,7 @@ SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p);
|
|
|
|
/*
|
|
** The second parameter to sqlite3BtreeGetMeta or sqlite3BtreeUpdateMeta
|
|
-** should be one of the following values. The integer values are assigned
|
|
+** should be one of the following values. The integer values are assigned
|
|
** to constants so that the offset of the corresponding field in an
|
|
** SQLite database header may be found using the following formula:
|
|
**
|
|
@@ -14799,7 +15659,7 @@ SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p);
|
|
** reduce network bandwidth.
|
|
**
|
|
** Note that BTREE_HINT_FLAGS with BTREE_BULKLOAD is the only hint used by
|
|
-** standard SQLite. The other hints are provided for extentions that use
|
|
+** standard SQLite. The other hints are provided for extensions that use
|
|
** the SQLite parser and code generator but substitute their own storage
|
|
** engine.
|
|
*/
|
|
@@ -14821,7 +15681,7 @@ SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p);
|
|
#define BTREE_BULKLOAD 0x00000001 /* Used to full index in sorted order */
|
|
#define BTREE_SEEK_EQ 0x00000002 /* EQ seeks only - no range seeks */
|
|
|
|
-/*
|
|
+/*
|
|
** Flags passed as the third argument to sqlite3BtreeCursor().
|
|
**
|
|
** For read-only cursors the wrFlag argument is always zero. For read-write
|
|
@@ -14849,7 +15709,7 @@ SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p);
|
|
|
|
SQLITE_PRIVATE int sqlite3BtreeCursor(
|
|
Btree*, /* BTree containing table to open */
|
|
- int iTable, /* Index of root page */
|
|
+ Pgno iTable, /* Index of root page */
|
|
int wrFlag, /* 1 for writing. 0 for read-only */
|
|
struct KeyInfo*, /* First argument to compare function */
|
|
BtCursor *pCursor /* Space to write cursor structure */
|
|
@@ -14863,13 +15723,17 @@ SQLITE_PRIVATE void sqlite3BtreeCursorHint(BtCursor*, int, ...);
|
|
#endif
|
|
|
|
SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor*);
|
|
-SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
|
|
+SQLITE_PRIVATE int sqlite3BtreeTableMoveto(
|
|
BtCursor*,
|
|
- UnpackedRecord *pUnKey,
|
|
i64 intKey,
|
|
int bias,
|
|
int *pRes
|
|
);
|
|
+SQLITE_PRIVATE int sqlite3BtreeIndexMoveto(
|
|
+ BtCursor*,
|
|
+ UnpackedRecord *pUnKey,
|
|
+ int *pRes
|
|
+);
|
|
SQLITE_PRIVATE int sqlite3BtreeCursorHasMoved(BtCursor*);
|
|
SQLITE_PRIVATE int sqlite3BtreeCursorRestore(BtCursor*, int*);
|
|
SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor*, u8 flags);
|
|
@@ -14878,6 +15742,7 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor*, u8 flags);
|
|
#define BTREE_SAVEPOSITION 0x02 /* Leave cursor pointing at NEXT or PREV */
|
|
#define BTREE_AUXDELETE 0x04 /* not the primary delete operation */
|
|
#define BTREE_APPEND 0x08 /* Insert is likely an append */
|
|
+#define BTREE_PREFORMAT 0x80 /* Inserted data is a preformated cell */
|
|
|
|
/* An instance of the BtreePayload object describes the content of a single
|
|
** entry in either an index or table btree.
|
|
@@ -14889,7 +15754,7 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor*, u8 flags);
|
|
** The nMem field might be zero, indicating that no decomposition is available.
|
|
**
|
|
** Table btrees (used for rowid tables) contain an integer rowid used as
|
|
-** the key and passed in the nKey field. The pKey field is zero.
|
|
+** the key and passed in the nKey field. The pKey field is zero.
|
|
** pData,nData hold the content of the new entry. nZero extra zero bytes
|
|
** are appended to the end of the content when constructing the entry.
|
|
** The aMem,nMem fields are uninitialized for table btrees.
|
|
@@ -14908,7 +15773,7 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor*, u8 flags);
|
|
**
|
|
** This object is used to pass information into sqlite3BtreeInsert(). The
|
|
** same information used to be passed as five separate parameters. But placing
|
|
-** the information into this object helps to keep the interface more
|
|
+** the information into this object helps to keep the interface more
|
|
** organized and understandable, and it also helps the resulting code to
|
|
** run a little faster by using fewer registers for parameter passing.
|
|
*/
|
|
@@ -14940,7 +15805,15 @@ SQLITE_PRIVATE const void *sqlite3BtreePayloadFetch(BtCursor*, u32 *pAmt);
|
|
SQLITE_PRIVATE u32 sqlite3BtreePayloadSize(BtCursor*);
|
|
SQLITE_PRIVATE sqlite3_int64 sqlite3BtreeMaxRecordSize(BtCursor*);
|
|
|
|
-SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(sqlite3*,Btree*,int*aRoot,int nRoot,int,int*);
|
|
+SQLITE_PRIVATE int sqlite3BtreeIntegrityCheck(
|
|
+ sqlite3 *db, /* Database connection that is running the check */
|
|
+ Btree *p, /* The btree to be checked */
|
|
+ Pgno *aRoot, /* An array of root pages numbers for individual trees */
|
|
+ int nRoot, /* Number of entries in aRoot[] */
|
|
+ int mxErr, /* Stop reporting errors after this many */
|
|
+ int *pnErr, /* OUT: Write number of errors seen to this variable */
|
|
+ char **pzOut /* OUT: Write the error message string here */
|
|
+);
|
|
SQLITE_PRIVATE struct Pager *sqlite3BtreePager(Btree*);
|
|
SQLITE_PRIVATE i64 sqlite3BtreeRowCountEst(BtCursor*);
|
|
|
|
@@ -14955,14 +15828,18 @@ SQLITE_PRIVATE int sqlite3BtreeCursorHasHint(BtCursor*, unsigned int mask);
|
|
SQLITE_PRIVATE int sqlite3BtreeIsReadonly(Btree *pBt);
|
|
SQLITE_PRIVATE int sqlite3HeaderSizeBtree(void);
|
|
|
|
+#ifdef SQLITE_DEBUG
|
|
+SQLITE_PRIVATE sqlite3_uint64 sqlite3BtreeSeekCount(Btree*);
|
|
+#else
|
|
+# define sqlite3BtreeSeekCount(X) 0
|
|
+#endif
|
|
+
|
|
#ifndef NDEBUG
|
|
SQLITE_PRIVATE int sqlite3BtreeCursorIsValid(BtCursor*);
|
|
#endif
|
|
SQLITE_PRIVATE int sqlite3BtreeCursorIsValidNN(BtCursor*);
|
|
|
|
-#ifndef SQLITE_OMIT_BTREECOUNT
|
|
SQLITE_PRIVATE int sqlite3BtreeCount(sqlite3*, BtCursor*, i64*);
|
|
-#endif
|
|
|
|
#ifdef SQLITE_TEST
|
|
SQLITE_PRIVATE int sqlite3BtreeCursorInfo(BtCursor*, int*, int);
|
|
@@ -14973,6 +15850,10 @@ SQLITE_PRIVATE void sqlite3BtreeCursorList(Btree*);
|
|
SQLITE_PRIVATE int sqlite3BtreeCheckpoint(Btree*, int, int *, int *);
|
|
#endif
|
|
|
|
+SQLITE_PRIVATE int sqlite3BtreeTransferRow(BtCursor*, BtCursor*, i64);
|
|
+
|
|
+SQLITE_PRIVATE void sqlite3BtreeClearCache(Btree*);
|
|
+
|
|
/*
|
|
** If we are not using shared cache, then there is no need to
|
|
** use mutexes to access the BtShared structures. So make the
|
|
@@ -14985,7 +15866,7 @@ SQLITE_PRIVATE int sqlite3BtreeSharable(Btree*);
|
|
SQLITE_PRIVATE void sqlite3BtreeEnterCursor(BtCursor*);
|
|
SQLITE_PRIVATE int sqlite3BtreeConnectionCount(Btree*);
|
|
#else
|
|
-# define sqlite3BtreeEnter(X)
|
|
+# define sqlite3BtreeEnter(X)
|
|
# define sqlite3BtreeEnterAll(X)
|
|
# define sqlite3BtreeSharable(X) 0
|
|
# define sqlite3BtreeEnterCursor(X)
|
|
@@ -15079,25 +15960,24 @@ struct VdbeOp {
|
|
Mem *pMem; /* Used when p4type is P4_MEM */
|
|
VTable *pVtab; /* Used when p4type is P4_VTAB */
|
|
KeyInfo *pKeyInfo; /* Used when p4type is P4_KEYINFO */
|
|
- int *ai; /* Used when p4type is P4_INTARRAY */
|
|
+ u32 *ai; /* Used when p4type is P4_INTARRAY */
|
|
SubProgram *pProgram; /* Used when p4type is P4_SUBPROGRAM */
|
|
Table *pTab; /* Used when p4type is P4_TABLE */
|
|
#ifdef SQLITE_ENABLE_CURSOR_HINTS
|
|
Expr *pExpr; /* Used when p4type is P4_EXPR */
|
|
#endif
|
|
- int (*xAdvance)(BtCursor *, int);
|
|
} p4;
|
|
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
|
|
char *zComment; /* Comment to improve readability */
|
|
#endif
|
|
-#ifdef VDBE_PROFILE
|
|
- u32 cnt; /* Number of times this instruction was executed */
|
|
- u64 cycles; /* Total time spent executing this instruction */
|
|
-#endif
|
|
#ifdef SQLITE_VDBE_COVERAGE
|
|
u32 iSrcLine; /* Source-code line that generated this opcode
|
|
** with flags in the upper 8 bits */
|
|
#endif
|
|
+#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || defined(VDBE_PROFILE)
|
|
+ u64 nExec;
|
|
+ u64 nCycle;
|
|
+#endif
|
|
};
|
|
typedef struct VdbeOp VdbeOp;
|
|
|
|
@@ -15136,21 +16016,19 @@ typedef struct VdbeOpList VdbeOpList;
|
|
#define P4_COLLSEQ (-2) /* P4 is a pointer to a CollSeq structure */
|
|
#define P4_INT32 (-3) /* P4 is a 32-bit signed integer */
|
|
#define P4_SUBPROGRAM (-4) /* P4 is a pointer to a SubProgram structure */
|
|
-#define P4_ADVANCE (-5) /* P4 is a pointer to BtreeNext() or BtreePrev() */
|
|
-#define P4_TABLE (-6) /* P4 is a pointer to a Table structure */
|
|
+#define P4_TABLE (-5) /* P4 is a pointer to a Table structure */
|
|
/* Above do not own any resources. Must free those below */
|
|
-#define P4_FREE_IF_LE (-7)
|
|
-#define P4_DYNAMIC (-7) /* Pointer to memory from sqliteMalloc() */
|
|
-#define P4_FUNCDEF (-8) /* P4 is a pointer to a FuncDef structure */
|
|
-#define P4_KEYINFO (-9) /* P4 is a pointer to a KeyInfo structure */
|
|
-#define P4_EXPR (-10) /* P4 is a pointer to an Expr tree */
|
|
-#define P4_MEM (-11) /* P4 is a pointer to a Mem* structure */
|
|
-#define P4_VTAB (-12) /* P4 is a pointer to an sqlite3_vtab structure */
|
|
-#define P4_REAL (-13) /* P4 is a 64-bit floating point value */
|
|
-#define P4_INT64 (-14) /* P4 is a 64-bit signed integer */
|
|
-#define P4_INTARRAY (-15) /* P4 is a vector of 32-bit integers */
|
|
-#define P4_FUNCCTX (-16) /* P4 is a pointer to an sqlite3_context object */
|
|
-#define P4_DYNBLOB (-17) /* Pointer to memory from sqliteMalloc() */
|
|
+#define P4_FREE_IF_LE (-6)
|
|
+#define P4_DYNAMIC (-6) /* Pointer to memory from sqliteMalloc() */
|
|
+#define P4_FUNCDEF (-7) /* P4 is a pointer to a FuncDef structure */
|
|
+#define P4_KEYINFO (-8) /* P4 is a pointer to a KeyInfo structure */
|
|
+#define P4_EXPR (-9) /* P4 is a pointer to an Expr tree */
|
|
+#define P4_MEM (-10) /* P4 is a pointer to a Mem* structure */
|
|
+#define P4_VTAB (-11) /* P4 is a pointer to an sqlite3_vtab structure */
|
|
+#define P4_REAL (-12) /* P4 is a 64-bit floating point value */
|
|
+#define P4_INT64 (-13) /* P4 is a 64-bit signed integer */
|
|
+#define P4_INTARRAY (-14) /* P4 is a vector of 32-bit integers */
|
|
+#define P4_FUNCCTX (-15) /* P4 is a pointer to an sqlite3_context object */
|
|
|
|
/* Error message codes for OP_Halt */
|
|
#define P5_ConstraintNotNull 1
|
|
@@ -15159,7 +16037,7 @@ typedef struct VdbeOpList VdbeOpList;
|
|
#define P5_ConstraintFK 4
|
|
|
|
/*
|
|
-** The Vdbe.aColName array contains 5n Mem structures, where n is the
|
|
+** The Vdbe.aColName array contains 5n Mem structures, where n is the
|
|
** number of columns of data returned by the statement.
|
|
*/
|
|
#define COLNAME_NAME 0
|
|
@@ -15195,53 +16073,53 @@ typedef struct VdbeOpList VdbeOpList;
|
|
#define OP_Savepoint 0
|
|
#define OP_AutoCommit 1
|
|
#define OP_Transaction 2
|
|
-#define OP_SorterNext 3 /* jump */
|
|
-#define OP_Prev 4 /* jump */
|
|
-#define OP_Next 5 /* jump */
|
|
-#define OP_Checkpoint 6
|
|
-#define OP_JournalMode 7
|
|
-#define OP_Vacuum 8
|
|
-#define OP_VFilter 9 /* jump, synopsis: iplan=r[P3] zplan='P4' */
|
|
-#define OP_VUpdate 10 /* synopsis: data=r[P3@P2] */
|
|
-#define OP_Goto 11 /* jump */
|
|
-#define OP_Gosub 12 /* jump */
|
|
-#define OP_InitCoroutine 13 /* jump */
|
|
-#define OP_Yield 14 /* jump */
|
|
-#define OP_MustBeInt 15 /* jump */
|
|
-#define OP_Jump 16 /* jump */
|
|
-#define OP_Once 17 /* jump */
|
|
-#define OP_If 18 /* jump */
|
|
+#define OP_Checkpoint 3
|
|
+#define OP_JournalMode 4
|
|
+#define OP_Vacuum 5
|
|
+#define OP_VFilter 6 /* jump, synopsis: iplan=r[P3] zplan='P4' */
|
|
+#define OP_VUpdate 7 /* synopsis: data=r[P3@P2] */
|
|
+#define OP_Init 8 /* jump, synopsis: Start at P2 */
|
|
+#define OP_Goto 9 /* jump */
|
|
+#define OP_Gosub 10 /* jump */
|
|
+#define OP_InitCoroutine 11 /* jump */
|
|
+#define OP_Yield 12 /* jump */
|
|
+#define OP_MustBeInt 13 /* jump */
|
|
+#define OP_Jump 14 /* jump */
|
|
+#define OP_Once 15 /* jump */
|
|
+#define OP_If 16 /* jump */
|
|
+#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_IfNot 20 /* jump */
|
|
-#define OP_IfNullRow 21 /* jump, synopsis: if P1.nullRow then r[P3]=NULL, goto P2 */
|
|
-#define OP_SeekLT 22 /* jump, synopsis: key=r[P3@P4] */
|
|
-#define OP_SeekLE 23 /* jump, synopsis: key=r[P3@P4] */
|
|
-#define OP_SeekGE 24 /* jump, synopsis: key=r[P3@P4] */
|
|
-#define OP_SeekGT 25 /* jump, synopsis: key=r[P3@P4] */
|
|
-#define OP_IfNotOpen 26 /* jump, synopsis: if( !csr[P1] ) goto P2 */
|
|
-#define OP_IfNoHope 27 /* jump, synopsis: key=r[P3@P4] */
|
|
-#define OP_NoConflict 28 /* jump, synopsis: key=r[P3@P4] */
|
|
-#define OP_NotFound 29 /* jump, synopsis: key=r[P3@P4] */
|
|
-#define OP_Found 30 /* jump, synopsis: key=r[P3@P4] */
|
|
-#define OP_SeekRowid 31 /* jump, synopsis: intkey=r[P3] */
|
|
-#define OP_NotExists 32 /* jump, synopsis: intkey=r[P3] */
|
|
-#define OP_Last 33 /* jump */
|
|
-#define OP_IfSmaller 34 /* jump */
|
|
-#define OP_SorterSort 35 /* jump */
|
|
-#define OP_Sort 36 /* jump */
|
|
-#define OP_Rewind 37 /* jump */
|
|
-#define OP_IdxLE 38 /* jump, synopsis: key=r[P3@P4] */
|
|
-#define OP_IdxGT 39 /* jump, synopsis: key=r[P3@P4] */
|
|
-#define OP_IdxLT 40 /* jump, synopsis: key=r[P3@P4] */
|
|
-#define OP_IdxGE 41 /* jump, synopsis: key=r[P3@P4] */
|
|
-#define OP_RowSetRead 42 /* jump, synopsis: r[P3]=rowset(P1) */
|
|
+#define OP_IfNullRow 20 /* jump, synopsis: if P1.nullRow then r[P3]=NULL, goto P2 */
|
|
+#define OP_SeekLT 21 /* jump, synopsis: key=r[P3@P4] */
|
|
+#define OP_SeekLE 22 /* jump, synopsis: key=r[P3@P4] */
|
|
+#define OP_SeekGE 23 /* jump, synopsis: key=r[P3@P4] */
|
|
+#define OP_SeekGT 24 /* jump, synopsis: key=r[P3@P4] */
|
|
+#define OP_IfNotOpen 25 /* jump, synopsis: if( !csr[P1] ) goto P2 */
|
|
+#define OP_IfNoHope 26 /* jump, synopsis: key=r[P3@P4] */
|
|
+#define OP_NoConflict 27 /* jump, synopsis: key=r[P3@P4] */
|
|
+#define OP_NotFound 28 /* jump, synopsis: key=r[P3@P4] */
|
|
+#define OP_Found 29 /* jump, synopsis: key=r[P3@P4] */
|
|
+#define OP_SeekRowid 30 /* jump, synopsis: intkey=r[P3] */
|
|
+#define OP_NotExists 31 /* jump, synopsis: intkey=r[P3] */
|
|
+#define OP_Last 32 /* jump */
|
|
+#define OP_IfSmaller 33 /* jump */
|
|
+#define OP_SorterSort 34 /* jump */
|
|
+#define OP_Sort 35 /* jump */
|
|
+#define OP_Rewind 36 /* jump */
|
|
+#define OP_SorterNext 37 /* jump */
|
|
+#define OP_Prev 38 /* jump */
|
|
+#define OP_Next 39 /* jump */
|
|
+#define OP_IdxLE 40 /* jump, synopsis: key=r[P3@P4] */
|
|
+#define OP_IdxGT 41 /* jump, synopsis: key=r[P3@P4] */
|
|
+#define OP_IdxLT 42 /* jump, synopsis: key=r[P3@P4] */
|
|
#define OP_Or 43 /* same as TK_OR, synopsis: r[P3]=(r[P1] || r[P2]) */
|
|
#define OP_And 44 /* same as TK_AND, synopsis: r[P3]=(r[P1] && r[P2]) */
|
|
-#define OP_RowSetTest 45 /* jump, synopsis: if r[P3] in rowset(P1) goto P2 */
|
|
-#define OP_Program 46 /* jump */
|
|
-#define OP_FkIfZero 47 /* jump, synopsis: if fkctr[P1]==0 goto P2 */
|
|
-#define OP_IfPos 48 /* jump, synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */
|
|
-#define OP_IfNotZero 49 /* jump, synopsis: if r[P1]!=0 then r[P1]--, goto P2 */
|
|
+#define OP_IdxGE 45 /* jump, synopsis: key=r[P3@P4] */
|
|
+#define OP_RowSetRead 46 /* jump, synopsis: r[P3]=rowset(P1) */
|
|
+#define OP_RowSetTest 47 /* jump, synopsis: if r[P3] in rowset(P1) goto P2 */
|
|
+#define OP_Program 48 /* jump */
|
|
+#define OP_FkIfZero 49 /* jump, synopsis: if fkctr[P1]==0 goto P2 */
|
|
#define OP_IsNull 50 /* jump, same as TK_ISNULL, synopsis: if r[P1]==NULL goto P2 */
|
|
#define OP_NotNull 51 /* jump, same as TK_NOTNULL, synopsis: if r[P1]!=NULL goto P2 */
|
|
#define OP_Ne 52 /* jump, same as TK_NE, synopsis: IF r[P3]!=r[P1] */
|
|
@@ -15250,124 +16128,135 @@ typedef struct VdbeOpList VdbeOpList;
|
|
#define OP_Le 55 /* jump, same as TK_LE, synopsis: IF r[P3]<=r[P1] */
|
|
#define OP_Lt 56 /* jump, same as TK_LT, synopsis: IF r[P3]<r[P1] */
|
|
#define OP_Ge 57 /* jump, same as TK_GE, synopsis: IF r[P3]>=r[P1] */
|
|
-#define OP_ElseNotEq 58 /* jump, same as TK_ESCAPE */
|
|
-#define OP_DecrJumpZero 59 /* jump, synopsis: if (--r[P1])==0 goto P2 */
|
|
-#define OP_IncrVacuum 60 /* jump */
|
|
-#define OP_VNext 61 /* jump */
|
|
-#define OP_Init 62 /* jump, synopsis: Start at P2 */
|
|
-#define OP_PureFunc 63 /* synopsis: r[P3]=func(r[P2@P5]) */
|
|
-#define OP_Function 64 /* synopsis: r[P3]=func(r[P2@P5]) */
|
|
-#define OP_Return 65
|
|
-#define OP_EndCoroutine 66
|
|
-#define OP_HaltIfNull 67 /* synopsis: if r[P3]=null halt */
|
|
-#define OP_Halt 68
|
|
-#define OP_Integer 69 /* synopsis: r[P2]=P1 */
|
|
-#define OP_Int64 70 /* synopsis: r[P2]=P4 */
|
|
-#define OP_String 71 /* synopsis: r[P2]='P4' (len=P1) */
|
|
-#define OP_Null 72 /* synopsis: r[P2..P3]=NULL */
|
|
-#define OP_SoftNull 73 /* synopsis: r[P1]=NULL */
|
|
-#define OP_Blob 74 /* synopsis: r[P2]=P4 (len=P1) */
|
|
-#define OP_Variable 75 /* synopsis: r[P2]=parameter(P1,P4) */
|
|
-#define OP_Move 76 /* synopsis: r[P2@P3]=r[P1@P3] */
|
|
-#define OP_Copy 77 /* synopsis: r[P2@P3+1]=r[P1@P3+1] */
|
|
-#define OP_SCopy 78 /* synopsis: r[P2]=r[P1] */
|
|
-#define OP_IntCopy 79 /* synopsis: r[P2]=r[P1] */
|
|
-#define OP_ResultRow 80 /* synopsis: output=r[P1@P2] */
|
|
-#define OP_CollSeq 81
|
|
-#define OP_AddImm 82 /* synopsis: r[P1]=r[P1]+P2 */
|
|
-#define OP_RealAffinity 83
|
|
-#define OP_Cast 84 /* synopsis: affinity(r[P1]) */
|
|
-#define OP_Permutation 85
|
|
-#define OP_Compare 86 /* synopsis: r[P1@P3] <-> r[P2@P3] */
|
|
-#define OP_IsTrue 87 /* synopsis: r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4 */
|
|
-#define OP_Offset 88 /* synopsis: r[P3] = sqlite_offset(P1) */
|
|
-#define OP_Column 89 /* synopsis: r[P3]=PX */
|
|
-#define OP_Affinity 90 /* synopsis: affinity(r[P1@P2]) */
|
|
-#define OP_MakeRecord 91 /* synopsis: r[P3]=mkrec(r[P1@P2]) */
|
|
-#define OP_Count 92 /* synopsis: r[P2]=count() */
|
|
-#define OP_ReadCookie 93
|
|
-#define OP_SetCookie 94
|
|
-#define OP_ReopenIdx 95 /* synopsis: root=P2 iDb=P3 */
|
|
-#define OP_OpenRead 96 /* synopsis: root=P2 iDb=P3 */
|
|
-#define OP_OpenWrite 97 /* synopsis: root=P2 iDb=P3 */
|
|
-#define OP_OpenDup 98
|
|
-#define OP_OpenAutoindex 99 /* synopsis: nColumn=P2 */
|
|
-#define OP_OpenEphemeral 100 /* synopsis: nColumn=P2 */
|
|
-#define OP_BitAnd 101 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */
|
|
-#define OP_BitOr 102 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */
|
|
-#define OP_ShiftLeft 103 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<<r[P1] */
|
|
-#define OP_ShiftRight 104 /* same as TK_RSHIFT, synopsis: r[P3]=r[P2]>>r[P1] */
|
|
-#define OP_Add 105 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */
|
|
-#define OP_Subtract 106 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */
|
|
-#define OP_Multiply 107 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */
|
|
-#define OP_Divide 108 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */
|
|
-#define OP_Remainder 109 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */
|
|
-#define OP_Concat 110 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */
|
|
-#define OP_SorterOpen 111
|
|
-#define OP_BitNot 112 /* same as TK_BITNOT, synopsis: r[P2]= ~r[P1] */
|
|
-#define OP_SequenceTest 113 /* synopsis: if( cursor[P1].ctr++ ) pc = P2 */
|
|
-#define OP_OpenPseudo 114 /* synopsis: P3 columns in r[P2] */
|
|
-#define OP_String8 115 /* same as TK_STRING, synopsis: r[P2]='P4' */
|
|
-#define OP_Close 116
|
|
-#define OP_ColumnsUsed 117
|
|
-#define OP_SeekHit 118 /* synopsis: seekHit=P2 */
|
|
-#define OP_Sequence 119 /* synopsis: r[P2]=cursor[P1].ctr++ */
|
|
-#define OP_NewRowid 120 /* synopsis: r[P2]=rowid */
|
|
-#define OP_Insert 121 /* synopsis: intkey=r[P3] data=r[P2] */
|
|
-#define OP_Delete 122
|
|
-#define OP_ResetCount 123
|
|
-#define OP_SorterCompare 124 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */
|
|
-#define OP_SorterData 125 /* synopsis: r[P2]=data */
|
|
-#define OP_RowData 126 /* synopsis: r[P2]=data */
|
|
-#define OP_Rowid 127 /* synopsis: r[P2]=rowid */
|
|
-#define OP_NullRow 128
|
|
-#define OP_SeekEnd 129
|
|
-#define OP_SorterInsert 130 /* synopsis: key=r[P2] */
|
|
-#define OP_IdxInsert 131 /* synopsis: key=r[P2] */
|
|
-#define OP_IdxDelete 132 /* synopsis: key=r[P2@P3] */
|
|
-#define OP_DeferredSeek 133 /* synopsis: Move P3 to P1.rowid if needed */
|
|
-#define OP_IdxRowid 134 /* synopsis: r[P2]=rowid */
|
|
-#define OP_FinishSeek 135
|
|
-#define OP_Destroy 136
|
|
-#define OP_Clear 137
|
|
-#define OP_ResetSorter 138
|
|
-#define OP_CreateBtree 139 /* synopsis: r[P2]=root iDb=P1 flags=P3 */
|
|
-#define OP_SqlExec 140
|
|
-#define OP_ParseSchema 141
|
|
-#define OP_LoadAnalysis 142
|
|
-#define OP_DropTable 143
|
|
-#define OP_DropIndex 144
|
|
-#define OP_DropTrigger 145
|
|
-#define OP_IntegrityCk 146
|
|
-#define OP_RowSetAdd 147 /* synopsis: rowset(P1)=r[P2] */
|
|
-#define OP_Param 148
|
|
-#define OP_FkCounter 149 /* synopsis: fkctr[P1]+=P2 */
|
|
-#define OP_Real 150 /* same as TK_FLOAT, synopsis: r[P2]=P4 */
|
|
-#define OP_MemMax 151 /* synopsis: r[P1]=max(r[P1],r[P2]) */
|
|
-#define OP_OffsetLimit 152 /* synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */
|
|
-#define OP_AggInverse 153 /* synopsis: accum=r[P3] inverse(r[P2@P5]) */
|
|
-#define OP_AggStep 154 /* synopsis: accum=r[P3] step(r[P2@P5]) */
|
|
-#define OP_AggStep1 155 /* synopsis: accum=r[P3] step(r[P2@P5]) */
|
|
-#define OP_AggValue 156 /* synopsis: r[P3]=value N=P2 */
|
|
-#define OP_AggFinal 157 /* synopsis: accum=r[P1] N=P2 */
|
|
-#define OP_Expire 158
|
|
-#define OP_CursorLock 159
|
|
-#define OP_CursorUnlock 160
|
|
-#define OP_TableLock 161 /* synopsis: iDb=P1 root=P2 write=P3 */
|
|
-#define OP_VBegin 162
|
|
-#define OP_VCreate 163
|
|
-#define OP_VDestroy 164
|
|
-#define OP_VOpen 165
|
|
-#define OP_VColumn 166 /* synopsis: r[P3]=vcolumn(P2) */
|
|
-#define OP_VRename 167
|
|
-#define OP_Pagecount 168
|
|
-#define OP_MaxPgcnt 169
|
|
-#define OP_Trace 170
|
|
-#define OP_CursorHint 171
|
|
-#define OP_ReleaseReg 172 /* synopsis: release r[P1@P2] mask P3 */
|
|
-#define OP_Noop 173
|
|
-#define OP_Explain 174
|
|
-#define OP_Abortable 175
|
|
+#define OP_ElseEq 58 /* jump, same as TK_ESCAPE */
|
|
+#define OP_IfPos 59 /* jump, synopsis: if r[P1]>0 then r[P1]-=P3, goto P2 */
|
|
+#define OP_IfNotZero 60 /* jump, synopsis: if r[P1]!=0 then r[P1]--, goto P2 */
|
|
+#define OP_DecrJumpZero 61 /* jump, synopsis: if (--r[P1])==0 goto P2 */
|
|
+#define OP_IncrVacuum 62 /* jump */
|
|
+#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]) */
|
|
+#define OP_Function 66 /* synopsis: r[P3]=func(r[P2@NP]) */
|
|
+#define OP_Return 67
|
|
+#define OP_EndCoroutine 68
|
|
+#define OP_HaltIfNull 69 /* synopsis: if r[P3]=null halt */
|
|
+#define OP_Halt 70
|
|
+#define OP_Integer 71 /* synopsis: r[P2]=P1 */
|
|
+#define OP_Int64 72 /* synopsis: r[P2]=P4 */
|
|
+#define OP_String 73 /* synopsis: r[P2]='P4' (len=P1) */
|
|
+#define OP_BeginSubrtn 74 /* synopsis: r[P2]=NULL */
|
|
+#define OP_Null 75 /* synopsis: r[P2..P3]=NULL */
|
|
+#define OP_SoftNull 76 /* synopsis: r[P1]=NULL */
|
|
+#define OP_Blob 77 /* synopsis: r[P2]=P4 (len=P1) */
|
|
+#define OP_Variable 78 /* synopsis: r[P2]=parameter(P1,P4) */
|
|
+#define OP_Move 79 /* synopsis: r[P2@P3]=r[P1@P3] */
|
|
+#define OP_Copy 80 /* synopsis: r[P2@P3+1]=r[P1@P3+1] */
|
|
+#define OP_SCopy 81 /* synopsis: r[P2]=r[P1] */
|
|
+#define OP_IntCopy 82 /* synopsis: r[P2]=r[P1] */
|
|
+#define OP_FkCheck 83
|
|
+#define OP_ResultRow 84 /* synopsis: output=r[P1@P2] */
|
|
+#define OP_CollSeq 85
|
|
+#define OP_AddImm 86 /* synopsis: r[P1]=r[P1]+P2 */
|
|
+#define OP_RealAffinity 87
|
|
+#define OP_Cast 88 /* synopsis: affinity(r[P1]) */
|
|
+#define OP_Permutation 89
|
|
+#define OP_Compare 90 /* synopsis: r[P1@P3] <-> r[P2@P3] */
|
|
+#define OP_IsTrue 91 /* synopsis: r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4 */
|
|
+#define OP_ZeroOrNull 92 /* synopsis: r[P2] = 0 OR NULL */
|
|
+#define OP_Offset 93 /* synopsis: r[P3] = sqlite_offset(P1) */
|
|
+#define OP_Column 94 /* synopsis: r[P3]=PX cursor P1 column P2 */
|
|
+#define OP_TypeCheck 95 /* synopsis: typecheck(r[P1@P2]) */
|
|
+#define OP_Affinity 96 /* synopsis: affinity(r[P1@P2]) */
|
|
+#define OP_MakeRecord 97 /* synopsis: r[P3]=mkrec(r[P1@P2]) */
|
|
+#define OP_Count 98 /* synopsis: r[P2]=count() */
|
|
+#define OP_ReadCookie 99
|
|
+#define OP_SetCookie 100
|
|
+#define OP_ReopenIdx 101 /* synopsis: root=P2 iDb=P3 */
|
|
+#define OP_BitAnd 102 /* same as TK_BITAND, synopsis: r[P3]=r[P1]&r[P2] */
|
|
+#define OP_BitOr 103 /* same as TK_BITOR, synopsis: r[P3]=r[P1]|r[P2] */
|
|
+#define OP_ShiftLeft 104 /* same as TK_LSHIFT, synopsis: r[P3]=r[P2]<<r[P1] */
|
|
+#define OP_ShiftRight 105 /* same as TK_RSHIFT, synopsis: r[P3]=r[P2]>>r[P1] */
|
|
+#define OP_Add 106 /* same as TK_PLUS, synopsis: r[P3]=r[P1]+r[P2] */
|
|
+#define OP_Subtract 107 /* same as TK_MINUS, synopsis: r[P3]=r[P2]-r[P1] */
|
|
+#define OP_Multiply 108 /* same as TK_STAR, synopsis: r[P3]=r[P1]*r[P2] */
|
|
+#define OP_Divide 109 /* same as TK_SLASH, synopsis: r[P3]=r[P2]/r[P1] */
|
|
+#define OP_Remainder 110 /* same as TK_REM, synopsis: r[P3]=r[P2]%r[P1] */
|
|
+#define OP_Concat 111 /* same as TK_CONCAT, synopsis: r[P3]=r[P2]+r[P1] */
|
|
+#define OP_OpenRead 112 /* synopsis: root=P2 iDb=P3 */
|
|
+#define OP_OpenWrite 113 /* synopsis: root=P2 iDb=P3 */
|
|
+#define OP_BitNot 114 /* same as TK_BITNOT, synopsis: r[P2]= ~r[P1] */
|
|
+#define OP_OpenDup 115
|
|
+#define OP_OpenAutoindex 116 /* synopsis: nColumn=P2 */
|
|
+#define OP_String8 117 /* same as TK_STRING, synopsis: r[P2]='P4' */
|
|
+#define OP_OpenEphemeral 118 /* synopsis: nColumn=P2 */
|
|
+#define OP_SorterOpen 119
|
|
+#define OP_SequenceTest 120 /* synopsis: if( cursor[P1].ctr++ ) pc = P2 */
|
|
+#define OP_OpenPseudo 121 /* synopsis: P3 columns in r[P2] */
|
|
+#define OP_Close 122
|
|
+#define OP_ColumnsUsed 123
|
|
+#define OP_SeekScan 124 /* synopsis: Scan-ahead up to P1 rows */
|
|
+#define OP_SeekHit 125 /* synopsis: set P2<=seekHit<=P3 */
|
|
+#define OP_Sequence 126 /* synopsis: r[P2]=cursor[P1].ctr++ */
|
|
+#define OP_NewRowid 127 /* synopsis: r[P2]=rowid */
|
|
+#define OP_Insert 128 /* synopsis: intkey=r[P3] data=r[P2] */
|
|
+#define OP_RowCell 129
|
|
+#define OP_Delete 130
|
|
+#define OP_ResetCount 131
|
|
+#define OP_SorterCompare 132 /* synopsis: if key(P1)!=trim(r[P3],P4) goto P2 */
|
|
+#define OP_SorterData 133 /* synopsis: r[P2]=data */
|
|
+#define OP_RowData 134 /* synopsis: r[P2]=data */
|
|
+#define OP_Rowid 135 /* synopsis: r[P2]=PX rowid of P1 */
|
|
+#define OP_NullRow 136
|
|
+#define OP_SeekEnd 137
|
|
+#define OP_IdxInsert 138 /* synopsis: key=r[P2] */
|
|
+#define OP_SorterInsert 139 /* synopsis: key=r[P2] */
|
|
+#define OP_IdxDelete 140 /* synopsis: key=r[P2@P3] */
|
|
+#define OP_DeferredSeek 141 /* synopsis: Move P3 to P1.rowid if needed */
|
|
+#define OP_IdxRowid 142 /* synopsis: r[P2]=rowid */
|
|
+#define OP_FinishSeek 143
|
|
+#define OP_Destroy 144
|
|
+#define OP_Clear 145
|
|
+#define OP_ResetSorter 146
|
|
+#define OP_CreateBtree 147 /* synopsis: r[P2]=root iDb=P1 flags=P3 */
|
|
+#define OP_SqlExec 148
|
|
+#define OP_ParseSchema 149
|
|
+#define OP_LoadAnalysis 150
|
|
+#define OP_DropTable 151
|
|
+#define OP_DropIndex 152
|
|
+#define OP_Real 153 /* same as TK_FLOAT, synopsis: r[P2]=P4 */
|
|
+#define OP_DropTrigger 154
|
|
+#define OP_IntegrityCk 155
|
|
+#define OP_RowSetAdd 156 /* synopsis: rowset(P1)=r[P2] */
|
|
+#define OP_Param 157
|
|
+#define OP_FkCounter 158 /* synopsis: fkctr[P1]+=P2 */
|
|
+#define OP_MemMax 159 /* synopsis: r[P1]=max(r[P1],r[P2]) */
|
|
+#define OP_OffsetLimit 160 /* synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1) */
|
|
+#define OP_AggInverse 161 /* synopsis: accum=r[P3] inverse(r[P2@P5]) */
|
|
+#define OP_AggStep 162 /* synopsis: accum=r[P3] step(r[P2@P5]) */
|
|
+#define OP_AggStep1 163 /* synopsis: accum=r[P3] step(r[P2@P5]) */
|
|
+#define OP_AggValue 164 /* synopsis: r[P3]=value N=P2 */
|
|
+#define OP_AggFinal 165 /* synopsis: accum=r[P1] N=P2 */
|
|
+#define OP_Expire 166
|
|
+#define OP_CursorLock 167
|
|
+#define OP_CursorUnlock 168
|
|
+#define OP_TableLock 169 /* synopsis: iDb=P1 root=P2 write=P3 */
|
|
+#define OP_VBegin 170
|
|
+#define OP_VCreate 171
|
|
+#define OP_VDestroy 172
|
|
+#define OP_VOpen 173
|
|
+#define OP_VInitIn 174 /* synopsis: r[P2]=ValueList(P1,P3) */
|
|
+#define OP_VColumn 175 /* synopsis: r[P3]=vcolumn(P2) */
|
|
+#define OP_VRename 176
|
|
+#define OP_Pagecount 177
|
|
+#define OP_MaxPgcnt 178
|
|
+#define OP_ClrSubtype 179 /* synopsis: r[P1].subtype = 0 */
|
|
+#define OP_FilterAdd 180 /* synopsis: filter(P1) += key(P3@P4) */
|
|
+#define OP_Trace 181
|
|
+#define OP_CursorHint 182
|
|
+#define OP_ReleaseReg 183 /* synopsis: release r[P1@P2] mask P3 */
|
|
+#define OP_Noop 184
|
|
+#define OP_Explain 185
|
|
+#define OP_Abortable 186
|
|
|
|
/* Properties such as "out2" or "jump" that are specified in
|
|
** comments following the "case" for each opcode in the vdbe.c
|
|
@@ -15379,38 +16268,40 @@ typedef struct VdbeOpList VdbeOpList;
|
|
#define OPFLG_IN3 0x08 /* in3: P3 is an input */
|
|
#define OPFLG_OUT2 0x10 /* out2: P2 is an output */
|
|
#define OPFLG_OUT3 0x20 /* out3: P3 is an output */
|
|
+#define OPFLG_NCYCLE 0x40 /* ncycle:Cycles count against P1 */
|
|
#define OPFLG_INITIALIZER {\
|
|
-/* 0 */ 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x10,\
|
|
-/* 8 */ 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x03, 0x03,\
|
|
-/* 16 */ 0x01, 0x01, 0x03, 0x12, 0x03, 0x01, 0x09, 0x09,\
|
|
-/* 24 */ 0x09, 0x09, 0x01, 0x09, 0x09, 0x09, 0x09, 0x09,\
|
|
-/* 32 */ 0x09, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,\
|
|
-/* 40 */ 0x01, 0x01, 0x23, 0x26, 0x26, 0x0b, 0x01, 0x01,\
|
|
-/* 48 */ 0x03, 0x03, 0x03, 0x03, 0x0b, 0x0b, 0x0b, 0x0b,\
|
|
-/* 56 */ 0x0b, 0x0b, 0x01, 0x03, 0x01, 0x01, 0x01, 0x00,\
|
|
-/* 64 */ 0x00, 0x02, 0x02, 0x08, 0x00, 0x10, 0x10, 0x10,\
|
|
-/* 72 */ 0x10, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10,\
|
|
-/* 80 */ 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x12,\
|
|
-/* 88 */ 0x20, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00,\
|
|
-/* 96 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x26, 0x26,\
|
|
-/* 104 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x00,\
|
|
-/* 112 */ 0x12, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,\
|
|
-/* 120 */ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,\
|
|
-/* 128 */ 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x10, 0x00,\
|
|
-/* 136 */ 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,\
|
|
-/* 144 */ 0x00, 0x00, 0x00, 0x06, 0x10, 0x00, 0x10, 0x04,\
|
|
-/* 152 */ 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
|
|
-/* 160 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
|
|
-/* 168 */ 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
|
|
-}
|
|
-
|
|
-/* The sqlite3P2Values() routine is able to run faster if it knows
|
|
+/* 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,\
|
|
+/* 24 */ 0x49, 0x01, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49,\
|
|
+/* 32 */ 0x41, 0x01, 0x01, 0x01, 0x41, 0x01, 0x41, 0x41,\
|
|
+/* 40 */ 0x41, 0x41, 0x41, 0x26, 0x26, 0x41, 0x23, 0x0b,\
|
|
+/* 48 */ 0x01, 0x01, 0x03, 0x03, 0x0b, 0x0b, 0x0b, 0x0b,\
|
|
+/* 56 */ 0x0b, 0x0b, 0x01, 0x03, 0x03, 0x03, 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, 0x26, 0x26,\
|
|
+/* 104 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26,\
|
|
+/* 112 */ 0x40, 0x00, 0x12, 0x40, 0x40, 0x10, 0x40, 0x00,\
|
|
+/* 120 */ 0x00, 0x00, 0x40, 0x00, 0x40, 0x40, 0x10, 0x10,\
|
|
+/* 128 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50,\
|
|
+/* 136 */ 0x00, 0x40, 0x04, 0x04, 0x00, 0x40, 0x50, 0x40,\
|
|
+/* 144 */ 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,\
|
|
+/* 152 */ 0x00, 0x10, 0x00, 0x00, 0x06, 0x10, 0x00, 0x04,\
|
|
+/* 160 */ 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
|
|
+/* 168 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x50, 0x40,\
|
|
+/* 176 */ 0x00, 0x10, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00,\
|
|
+/* 184 */ 0x00, 0x00, 0x00,}
|
|
+
|
|
+/* The resolve3P2Values() routine is able to run faster if it knows
|
|
** the value of the largest JUMP opcode. The smaller the maximum
|
|
** JUMP opcode the better, so the mkopcodeh.tcl script that
|
|
** generated this include file strives to group all JUMP opcodes
|
|
** together near the beginning of the list.
|
|
*/
|
|
-#define SQLITE_MX_JUMP_OPCODE 62 /* Maximum JUMP opcode */
|
|
+#define SQLITE_MX_JUMP_OPCODE 64 /* Maximum JUMP opcode */
|
|
|
|
/************** End of opcodes.h *********************************************/
|
|
/************** Continuing where we left off in vdbe.h ***********************/
|
|
@@ -15448,19 +16339,27 @@ SQLITE_PRIVATE void sqlite3VdbeVerifyNoResultRow(Vdbe *p);
|
|
#endif
|
|
#if defined(SQLITE_DEBUG)
|
|
SQLITE_PRIVATE void sqlite3VdbeVerifyAbortable(Vdbe *p, int);
|
|
+SQLITE_PRIVATE void sqlite3VdbeNoJumpsOutsideSubrtn(Vdbe*,int,int,int);
|
|
#else
|
|
# define sqlite3VdbeVerifyAbortable(A,B)
|
|
+# define sqlite3VdbeNoJumpsOutsideSubrtn(A,B,C,D)
|
|
#endif
|
|
SQLITE_PRIVATE VdbeOp *sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp,int iLineno);
|
|
#ifndef SQLITE_OMIT_EXPLAIN
|
|
-SQLITE_PRIVATE void sqlite3VdbeExplain(Parse*,u8,const char*,...);
|
|
+SQLITE_PRIVATE int sqlite3VdbeExplain(Parse*,u8,const char*,...);
|
|
SQLITE_PRIVATE void sqlite3VdbeExplainPop(Parse*);
|
|
SQLITE_PRIVATE int sqlite3VdbeExplainParent(Parse*);
|
|
# define ExplainQueryPlan(P) sqlite3VdbeExplain P
|
|
+# ifdef SQLITE_ENABLE_STMT_SCANSTATUS
|
|
+# define ExplainQueryPlan2(V,P) (V = sqlite3VdbeExplain P)
|
|
+# else
|
|
+# define ExplainQueryPlan2(V,P) ExplainQueryPlan(P)
|
|
+# endif
|
|
# define ExplainQueryPlanPop(P) sqlite3VdbeExplainPop(P)
|
|
# define ExplainQueryPlanParent(P) sqlite3VdbeExplainParent(P)
|
|
#else
|
|
# define ExplainQueryPlan(P)
|
|
+# define ExplainQueryPlan2(V,P)
|
|
# define ExplainQueryPlanPop(P)
|
|
# define ExplainQueryPlanParent(P) 0
|
|
# define sqlite3ExplainBreakpoint(A,B) /*no-op*/
|
|
@@ -15470,13 +16369,15 @@ SQLITE_PRIVATE void sqlite3ExplainBreakpoint(const char*,const char*);
|
|
#else
|
|
# define sqlite3ExplainBreakpoint(A,B) /*no-op*/
|
|
#endif
|
|
-SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*);
|
|
+SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe*, int, char*, u16);
|
|
SQLITE_PRIVATE void sqlite3VdbeChangeOpcode(Vdbe*, int addr, u8);
|
|
SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe*, int addr, int P1);
|
|
SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2);
|
|
SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe*, int addr, int P3);
|
|
SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe*, u16 P5);
|
|
+SQLITE_PRIVATE void sqlite3VdbeTypeofColumn(Vdbe*, int);
|
|
SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe*, int addr);
|
|
+SQLITE_PRIVATE void sqlite3VdbeJumpHereOrPopInst(Vdbe*, int addr);
|
|
SQLITE_PRIVATE int sqlite3VdbeChangeToNoop(Vdbe*, int addr);
|
|
SQLITE_PRIVATE int sqlite3VdbeDeletePriorOpcode(Vdbe*, u8 op);
|
|
#ifdef SQLITE_DEBUG
|
|
@@ -15489,11 +16390,11 @@ SQLITE_PRIVATE void sqlite3VdbeAppendP4(Vdbe*, void *pP4, int p4type);
|
|
SQLITE_PRIVATE void sqlite3VdbeSetP4KeyInfo(Parse*, Index*);
|
|
SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe*, int);
|
|
SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe*, int);
|
|
+SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetLastOp(Vdbe*);
|
|
SQLITE_PRIVATE int sqlite3VdbeMakeLabel(Parse*);
|
|
SQLITE_PRIVATE void sqlite3VdbeRunOnlyOnce(Vdbe*);
|
|
SQLITE_PRIVATE void sqlite3VdbeReusable(Vdbe*);
|
|
SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe*);
|
|
-SQLITE_PRIVATE void sqlite3VdbeClearObject(sqlite3*,Vdbe*);
|
|
SQLITE_PRIVATE void sqlite3VdbeMakeReady(Vdbe*,Parse*);
|
|
SQLITE_PRIVATE int sqlite3VdbeFinalize(Vdbe*);
|
|
SQLITE_PRIVATE void sqlite3VdbeResolveLabel(Vdbe*, int);
|
|
@@ -15536,6 +16437,9 @@ SQLITE_PRIVATE void sqlite3VdbeLinkSubProgram(Vdbe *, SubProgram *);
|
|
SQLITE_PRIVATE int sqlite3VdbeHasSubProgram(Vdbe*);
|
|
|
|
SQLITE_PRIVATE int sqlite3NotPureFunc(sqlite3_context*);
|
|
+#ifdef SQLITE_ENABLE_BYTECODE_VTAB
|
|
+SQLITE_PRIVATE int sqlite3VdbeBytecodeVtabInit(sqlite3*);
|
|
+#endif
|
|
|
|
/* Use SQLITE_ENABLE_COMMENTS to enable generation of extra comments on
|
|
** each VDBE opcode.
|
|
@@ -15628,8 +16532,12 @@ SQLITE_PRIVATE void sqlite3VdbeSetLineNumber(Vdbe*,int);
|
|
|
|
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
|
|
SQLITE_PRIVATE void sqlite3VdbeScanStatus(Vdbe*, int, int, int, LogEst, const char*);
|
|
+SQLITE_PRIVATE void sqlite3VdbeScanStatusRange(Vdbe*, int, int, int);
|
|
+SQLITE_PRIVATE void sqlite3VdbeScanStatusCounters(Vdbe*, int, int, int);
|
|
#else
|
|
-# define sqlite3VdbeScanStatus(a,b,c,d,e)
|
|
+# define sqlite3VdbeScanStatus(a,b,c,d,e,f)
|
|
+# define sqlite3VdbeScanStatusRange(a,b,c,d)
|
|
+# define sqlite3VdbeScanStatusCounters(a,b,c,d)
|
|
#endif
|
|
|
|
#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
|
|
@@ -15640,257 +16548,6 @@ SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE*, int, VdbeOp*);
|
|
|
|
/************** End of vdbe.h ************************************************/
|
|
/************** Continuing where we left off in sqliteInt.h ******************/
|
|
-/************** Include pager.h in the middle of sqliteInt.h *****************/
|
|
-/************** Begin file pager.h *******************************************/
|
|
-/*
|
|
-** 2001 September 15
|
|
-**
|
|
-** The author disclaims copyright to this source code. In place of
|
|
-** a legal notice, here is a blessing:
|
|
-**
|
|
-** May you do good and not evil.
|
|
-** May you find forgiveness for yourself and forgive others.
|
|
-** May you share freely, never taking more than you give.
|
|
-**
|
|
-*************************************************************************
|
|
-** This header file defines the interface that the sqlite page cache
|
|
-** subsystem. The page cache subsystem reads and writes a file a page
|
|
-** at a time and provides a journal for rollback.
|
|
-*/
|
|
-
|
|
-#ifndef SQLITE_PAGER_H
|
|
-#define SQLITE_PAGER_H
|
|
-
|
|
-/*
|
|
-** Default maximum size for persistent journal files. A negative
|
|
-** value means no limit. This value may be overridden using the
|
|
-** sqlite3PagerJournalSizeLimit() API. See also "PRAGMA journal_size_limit".
|
|
-*/
|
|
-#ifndef SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT
|
|
- #define SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT -1
|
|
-#endif
|
|
-
|
|
-/*
|
|
-** The type used to represent a page number. The first page in a file
|
|
-** is called page 1. 0 is used to represent "not a page".
|
|
-*/
|
|
-typedef u32 Pgno;
|
|
-
|
|
-/*
|
|
-** Each open file is managed by a separate instance of the "Pager" structure.
|
|
-*/
|
|
-typedef struct Pager Pager;
|
|
-
|
|
-/*
|
|
-** Handle type for pages.
|
|
-*/
|
|
-typedef struct PgHdr DbPage;
|
|
-
|
|
-/*
|
|
-** Page number PAGER_MJ_PGNO is never used in an SQLite database (it is
|
|
-** reserved for working around a windows/posix incompatibility). It is
|
|
-** used in the journal to signify that the remainder of the journal file
|
|
-** is devoted to storing a master journal name - there are no more pages to
|
|
-** roll back. See comments for function writeMasterJournal() in pager.c
|
|
-** for details.
|
|
-*/
|
|
-#define PAGER_MJ_PGNO(x) ((Pgno)((PENDING_BYTE/((x)->pageSize))+1))
|
|
-
|
|
-/*
|
|
-** Allowed values for the flags parameter to sqlite3PagerOpen().
|
|
-**
|
|
-** NOTE: These values must match the corresponding BTREE_ values in btree.h.
|
|
-*/
|
|
-#define PAGER_OMIT_JOURNAL 0x0001 /* Do not use a rollback journal */
|
|
-#define PAGER_MEMORY 0x0002 /* In-memory database */
|
|
-
|
|
-/*
|
|
-** Valid values for the second argument to sqlite3PagerLockingMode().
|
|
-*/
|
|
-#define PAGER_LOCKINGMODE_QUERY -1
|
|
-#define PAGER_LOCKINGMODE_NORMAL 0
|
|
-#define PAGER_LOCKINGMODE_EXCLUSIVE 1
|
|
-
|
|
-/*
|
|
-** Numeric constants that encode the journalmode.
|
|
-**
|
|
-** The numeric values encoded here (other than PAGER_JOURNALMODE_QUERY)
|
|
-** are exposed in the API via the "PRAGMA journal_mode" command and
|
|
-** therefore cannot be changed without a compatibility break.
|
|
-*/
|
|
-#define PAGER_JOURNALMODE_QUERY (-1) /* Query the value of journalmode */
|
|
-#define PAGER_JOURNALMODE_DELETE 0 /* Commit by deleting journal file */
|
|
-#define PAGER_JOURNALMODE_PERSIST 1 /* Commit by zeroing journal header */
|
|
-#define PAGER_JOURNALMODE_OFF 2 /* Journal omitted. */
|
|
-#define PAGER_JOURNALMODE_TRUNCATE 3 /* Commit by truncating journal */
|
|
-#define PAGER_JOURNALMODE_MEMORY 4 /* In-memory journal file */
|
|
-#define PAGER_JOURNALMODE_WAL 5 /* Use write-ahead logging */
|
|
-
|
|
-/*
|
|
-** Flags that make up the mask passed to sqlite3PagerGet().
|
|
-*/
|
|
-#define PAGER_GET_NOCONTENT 0x01 /* Do not load data from disk */
|
|
-#define PAGER_GET_READONLY 0x02 /* Read-only page is acceptable */
|
|
-
|
|
-/*
|
|
-** Flags for sqlite3PagerSetFlags()
|
|
-**
|
|
-** Value constraints (enforced via assert()):
|
|
-** PAGER_FULLFSYNC == SQLITE_FullFSync
|
|
-** PAGER_CKPT_FULLFSYNC == SQLITE_CkptFullFSync
|
|
-** PAGER_CACHE_SPILL == SQLITE_CacheSpill
|
|
-*/
|
|
-#define PAGER_SYNCHRONOUS_OFF 0x01 /* PRAGMA synchronous=OFF */
|
|
-#define PAGER_SYNCHRONOUS_NORMAL 0x02 /* PRAGMA synchronous=NORMAL */
|
|
-#define PAGER_SYNCHRONOUS_FULL 0x03 /* PRAGMA synchronous=FULL */
|
|
-#define PAGER_SYNCHRONOUS_EXTRA 0x04 /* PRAGMA synchronous=EXTRA */
|
|
-#define PAGER_SYNCHRONOUS_MASK 0x07 /* Mask for four values above */
|
|
-#define PAGER_FULLFSYNC 0x08 /* PRAGMA fullfsync=ON */
|
|
-#define PAGER_CKPT_FULLFSYNC 0x10 /* PRAGMA checkpoint_fullfsync=ON */
|
|
-#define PAGER_CACHESPILL 0x20 /* PRAGMA cache_spill=ON */
|
|
-#define PAGER_FLAGS_MASK 0x38 /* All above except SYNCHRONOUS */
|
|
-
|
|
-/*
|
|
-** The remainder of this file contains the declarations of the functions
|
|
-** that make up the Pager sub-system API. See source code comments for
|
|
-** a detailed description of each routine.
|
|
-*/
|
|
-
|
|
-/* Open and close a Pager connection. */
|
|
-SQLITE_PRIVATE int sqlite3PagerOpen(
|
|
- sqlite3_vfs*,
|
|
- Pager **ppPager,
|
|
- const char*,
|
|
- int,
|
|
- int,
|
|
- int,
|
|
- void(*)(DbPage*)
|
|
-);
|
|
-SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3*);
|
|
-SQLITE_PRIVATE int sqlite3PagerReadFileheader(Pager*, int, unsigned char*);
|
|
-
|
|
-/* Functions used to configure a Pager object. */
|
|
-SQLITE_PRIVATE void sqlite3PagerSetBusyHandler(Pager*, int(*)(void *), void *);
|
|
-SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager*, u32*, int);
|
|
-#ifdef SQLITE_HAS_CODEC
|
|
-SQLITE_PRIVATE void sqlite3PagerAlignReserve(Pager*,Pager*);
|
|
-#endif
|
|
-SQLITE_PRIVATE int sqlite3PagerMaxPageCount(Pager*, int);
|
|
-SQLITE_PRIVATE void sqlite3PagerSetCachesize(Pager*, int);
|
|
-SQLITE_PRIVATE int sqlite3PagerSetSpillsize(Pager*, int);
|
|
-SQLITE_PRIVATE void sqlite3PagerSetMmapLimit(Pager *, sqlite3_int64);
|
|
-SQLITE_PRIVATE void sqlite3PagerShrink(Pager*);
|
|
-SQLITE_PRIVATE void sqlite3PagerSetFlags(Pager*,unsigned);
|
|
-SQLITE_PRIVATE int sqlite3PagerLockingMode(Pager *, int);
|
|
-SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *, int);
|
|
-SQLITE_PRIVATE int sqlite3PagerGetJournalMode(Pager*);
|
|
-SQLITE_PRIVATE int sqlite3PagerOkToChangeJournalMode(Pager*);
|
|
-SQLITE_PRIVATE i64 sqlite3PagerJournalSizeLimit(Pager *, i64);
|
|
-SQLITE_PRIVATE sqlite3_backup **sqlite3PagerBackupPtr(Pager*);
|
|
-SQLITE_PRIVATE int sqlite3PagerFlush(Pager*);
|
|
-
|
|
-/* Functions used to obtain and release page references. */
|
|
-SQLITE_PRIVATE int sqlite3PagerGet(Pager *pPager, Pgno pgno, DbPage **ppPage, int clrFlag);
|
|
-SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno);
|
|
-SQLITE_PRIVATE void sqlite3PagerRef(DbPage*);
|
|
-SQLITE_PRIVATE void sqlite3PagerUnref(DbPage*);
|
|
-SQLITE_PRIVATE void sqlite3PagerUnrefNotNull(DbPage*);
|
|
-SQLITE_PRIVATE void sqlite3PagerUnrefPageOne(DbPage*);
|
|
-
|
|
-/* Operations on page references. */
|
|
-SQLITE_PRIVATE int sqlite3PagerWrite(DbPage*);
|
|
-SQLITE_PRIVATE void sqlite3PagerDontWrite(DbPage*);
|
|
-SQLITE_PRIVATE int sqlite3PagerMovepage(Pager*,DbPage*,Pgno,int);
|
|
-SQLITE_PRIVATE int sqlite3PagerPageRefcount(DbPage*);
|
|
-SQLITE_PRIVATE void *sqlite3PagerGetData(DbPage *);
|
|
-SQLITE_PRIVATE void *sqlite3PagerGetExtra(DbPage *);
|
|
-
|
|
-/* Functions used to manage pager transactions and savepoints. */
|
|
-SQLITE_PRIVATE void sqlite3PagerPagecount(Pager*, int*);
|
|
-SQLITE_PRIVATE int sqlite3PagerBegin(Pager*, int exFlag, int);
|
|
-SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(Pager*,const char *zMaster, int);
|
|
-SQLITE_PRIVATE int sqlite3PagerExclusiveLock(Pager*);
|
|
-SQLITE_PRIVATE int sqlite3PagerSync(Pager *pPager, const char *zMaster);
|
|
-SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager*);
|
|
-SQLITE_PRIVATE int sqlite3PagerRollback(Pager*);
|
|
-SQLITE_PRIVATE int sqlite3PagerOpenSavepoint(Pager *pPager, int n);
|
|
-SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint);
|
|
-SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager);
|
|
-
|
|
-#ifndef SQLITE_OMIT_WAL
|
|
-SQLITE_PRIVATE int sqlite3PagerCheckpoint(Pager *pPager, sqlite3*, int, int*, int*);
|
|
-SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager);
|
|
-SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager);
|
|
-SQLITE_PRIVATE int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen);
|
|
-SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager, sqlite3*);
|
|
-# ifdef SQLITE_ENABLE_SNAPSHOT
|
|
-SQLITE_PRIVATE int sqlite3PagerSnapshotGet(Pager *pPager, sqlite3_snapshot **ppSnapshot);
|
|
-SQLITE_PRIVATE int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSnapshot);
|
|
-SQLITE_PRIVATE int sqlite3PagerSnapshotRecover(Pager *pPager);
|
|
-SQLITE_PRIVATE int sqlite3PagerSnapshotCheck(Pager *pPager, sqlite3_snapshot *pSnapshot);
|
|
-SQLITE_PRIVATE void sqlite3PagerSnapshotUnlock(Pager *pPager);
|
|
-# endif
|
|
-#endif
|
|
-
|
|
-#ifdef SQLITE_DIRECT_OVERFLOW_READ
|
|
-SQLITE_PRIVATE int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno);
|
|
-#endif
|
|
-
|
|
-#ifdef SQLITE_ENABLE_ZIPVFS
|
|
-SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager);
|
|
-#endif
|
|
-
|
|
-/* Functions used to query pager state and configuration. */
|
|
-SQLITE_PRIVATE u8 sqlite3PagerIsreadonly(Pager*);
|
|
-SQLITE_PRIVATE u32 sqlite3PagerDataVersion(Pager*);
|
|
-#ifdef SQLITE_DEBUG
|
|
-SQLITE_PRIVATE int sqlite3PagerRefcount(Pager*);
|
|
-#endif
|
|
-SQLITE_PRIVATE int sqlite3PagerMemUsed(Pager*);
|
|
-SQLITE_PRIVATE const char *sqlite3PagerFilename(const Pager*, int);
|
|
-SQLITE_PRIVATE sqlite3_vfs *sqlite3PagerVfs(Pager*);
|
|
-SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager*);
|
|
-SQLITE_PRIVATE sqlite3_file *sqlite3PagerJrnlFile(Pager*);
|
|
-SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager*);
|
|
-SQLITE_PRIVATE void *sqlite3PagerTempSpace(Pager*);
|
|
-SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager*);
|
|
-SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *, int, int, int *);
|
|
-SQLITE_PRIVATE void sqlite3PagerClearCache(Pager*);
|
|
-SQLITE_PRIVATE int sqlite3SectorSize(sqlite3_file *);
|
|
-#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
|
-SQLITE_PRIVATE void sqlite3PagerResetLockTimeout(Pager *pPager);
|
|
-#else
|
|
-# define sqlite3PagerResetLockTimeout(X)
|
|
-#endif
|
|
-
|
|
-/* Functions used to truncate the database file. */
|
|
-SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager*,Pgno);
|
|
-
|
|
-SQLITE_PRIVATE void sqlite3PagerRekey(DbPage*, Pgno, u16);
|
|
-
|
|
-#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_WAL)
|
|
-SQLITE_PRIVATE void *sqlite3PagerCodec(DbPage *);
|
|
-#endif
|
|
-
|
|
-/* Functions to support testing and debugging. */
|
|
-#if !defined(NDEBUG) || defined(SQLITE_TEST)
|
|
-SQLITE_PRIVATE Pgno sqlite3PagerPagenumber(DbPage*);
|
|
-SQLITE_PRIVATE int sqlite3PagerIswriteable(DbPage*);
|
|
-#endif
|
|
-#ifdef SQLITE_TEST
|
|
-SQLITE_PRIVATE int *sqlite3PagerStats(Pager*);
|
|
-SQLITE_PRIVATE void sqlite3PagerRefdump(Pager*);
|
|
- void disable_simulated_io_errors(void);
|
|
- void enable_simulated_io_errors(void);
|
|
-#else
|
|
-# define disable_simulated_io_errors()
|
|
-# define enable_simulated_io_errors()
|
|
-#endif
|
|
-
|
|
-#endif /* SQLITE_PAGER_H */
|
|
-
|
|
-/************** End of pager.h ***********************************************/
|
|
-/************** Continuing where we left off in sqliteInt.h ******************/
|
|
/************** Include pcache.h in the middle of sqliteInt.h ****************/
|
|
/************** Begin file pcache.h ******************************************/
|
|
/*
|
|
@@ -15905,7 +16562,7 @@ SQLITE_PRIVATE void sqlite3PagerRefdump(Pager*);
|
|
**
|
|
*************************************************************************
|
|
** This header file defines the interface that the sqlite page cache
|
|
-** subsystem.
|
|
+** subsystem.
|
|
*/
|
|
|
|
#ifndef _PCACHE_H_
|
|
@@ -15931,11 +16588,11 @@ struct PgHdr {
|
|
u16 flags; /* PGHDR flags defined below */
|
|
|
|
/**********************************************************************
|
|
- ** Elements above, except pCache, are public. All that follow are
|
|
+ ** Elements above, except pCache, are public. All that follow are
|
|
** private to pcache.c and should not be accessed by other modules.
|
|
** pCache is grouped with the public elements for efficiency.
|
|
*/
|
|
- i16 nRef; /* Number of users of this page */
|
|
+ i64 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
|
|
@@ -15984,7 +16641,7 @@ SQLITE_PRIVATE int sqlite3PcacheSetPageSize(PCache *, int);
|
|
SQLITE_PRIVATE int sqlite3PcacheSize(void);
|
|
|
|
/* One release per successful fetch. Page is pinned until released.
|
|
-** Reference counted.
|
|
+** Reference counted.
|
|
*/
|
|
SQLITE_PRIVATE sqlite3_pcache_page *sqlite3PcacheFetch(PCache*, Pgno, int createFlag);
|
|
SQLITE_PRIVATE int sqlite3PcacheFetchStress(PCache*, Pgno, sqlite3_pcache_page**);
|
|
@@ -16016,19 +16673,19 @@ 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*);
|
|
|
|
#if defined(SQLITE_CHECK_PAGES) || defined(SQLITE_DEBUG)
|
|
/* Iterate through all dirty pages currently stored in the cache. This
|
|
-** interface is only available if SQLITE_CHECK_PAGES is defined when the
|
|
+** interface is only available if SQLITE_CHECK_PAGES is defined when the
|
|
** library is built.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHdr *));
|
|
@@ -16086,284 +16743,6 @@ SQLITE_PRIVATE int sqlite3PCacheIsDirty(PCache *pCache);
|
|
|
|
/************** End of pcache.h **********************************************/
|
|
/************** Continuing where we left off in sqliteInt.h ******************/
|
|
-/************** Include os.h in the middle of sqliteInt.h ********************/
|
|
-/************** Begin file os.h **********************************************/
|
|
-/*
|
|
-** 2001 September 16
|
|
-**
|
|
-** The author disclaims copyright to this source code. In place of
|
|
-** a legal notice, here is a blessing:
|
|
-**
|
|
-** May you do good and not evil.
|
|
-** May you find forgiveness for yourself and forgive others.
|
|
-** May you share freely, never taking more than you give.
|
|
-**
|
|
-******************************************************************************
|
|
-**
|
|
-** This header file (together with is companion C source-code file
|
|
-** "os.c") attempt to abstract the underlying operating system so that
|
|
-** the SQLite library will work on both POSIX and windows systems.
|
|
-**
|
|
-** This header file is #include-ed by sqliteInt.h and thus ends up
|
|
-** being included by every source file.
|
|
-*/
|
|
-#ifndef _SQLITE_OS_H_
|
|
-#define _SQLITE_OS_H_
|
|
-
|
|
-/*
|
|
-** Attempt to automatically detect the operating system and setup the
|
|
-** necessary pre-processor macros for it.
|
|
-*/
|
|
-/************** Include os_setup.h in the middle of os.h *********************/
|
|
-/************** Begin file os_setup.h ****************************************/
|
|
-/*
|
|
-** 2013 November 25
|
|
-**
|
|
-** The author disclaims copyright to this source code. In place of
|
|
-** a legal notice, here is a blessing:
|
|
-**
|
|
-** May you do good and not evil.
|
|
-** May you find forgiveness for yourself and forgive others.
|
|
-** May you share freely, never taking more than you give.
|
|
-**
|
|
-******************************************************************************
|
|
-**
|
|
-** This file contains pre-processor directives related to operating system
|
|
-** detection and/or setup.
|
|
-*/
|
|
-#ifndef SQLITE_OS_SETUP_H
|
|
-#define SQLITE_OS_SETUP_H
|
|
-
|
|
-/*
|
|
-** Figure out if we are dealing with Unix, Windows, or some other operating
|
|
-** system.
|
|
-**
|
|
-** After the following block of preprocess macros, all of SQLITE_OS_UNIX,
|
|
-** SQLITE_OS_WIN, and SQLITE_OS_OTHER will defined to either 1 or 0. One of
|
|
-** the three will be 1. The other two will be 0.
|
|
-*/
|
|
-#if defined(SQLITE_OS_OTHER)
|
|
-# if SQLITE_OS_OTHER==1
|
|
-# undef SQLITE_OS_UNIX
|
|
-# define SQLITE_OS_UNIX 0
|
|
-# undef SQLITE_OS_WIN
|
|
-# define SQLITE_OS_WIN 0
|
|
-# else
|
|
-# undef SQLITE_OS_OTHER
|
|
-# endif
|
|
-#endif
|
|
-#if !defined(SQLITE_OS_UNIX) && !defined(SQLITE_OS_OTHER)
|
|
-# define SQLITE_OS_OTHER 0
|
|
-# ifndef SQLITE_OS_WIN
|
|
-# if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || \
|
|
- defined(__MINGW32__) || defined(__BORLANDC__)
|
|
-# define SQLITE_OS_WIN 1
|
|
-# define SQLITE_OS_UNIX 0
|
|
-# else
|
|
-# define SQLITE_OS_WIN 0
|
|
-# define SQLITE_OS_UNIX 1
|
|
-# endif
|
|
-# else
|
|
-# define SQLITE_OS_UNIX 0
|
|
-# endif
|
|
-#else
|
|
-# ifndef SQLITE_OS_WIN
|
|
-# define SQLITE_OS_WIN 0
|
|
-# endif
|
|
-#endif
|
|
-
|
|
-#endif /* SQLITE_OS_SETUP_H */
|
|
-
|
|
-/************** End of os_setup.h ********************************************/
|
|
-/************** Continuing where we left off in os.h *************************/
|
|
-
|
|
-/* If the SET_FULLSYNC macro is not defined above, then make it
|
|
-** a no-op
|
|
-*/
|
|
-#ifndef SET_FULLSYNC
|
|
-# define SET_FULLSYNC(x,y)
|
|
-#endif
|
|
-
|
|
-/*
|
|
-** The default size of a disk sector
|
|
-*/
|
|
-#ifndef SQLITE_DEFAULT_SECTOR_SIZE
|
|
-# define SQLITE_DEFAULT_SECTOR_SIZE 4096
|
|
-#endif
|
|
-
|
|
-/*
|
|
-** Temporary files are named starting with this prefix followed by 16 random
|
|
-** alphanumeric characters, and no file extension. They are stored in the
|
|
-** OS's standard temporary file directory, and are deleted prior to exit.
|
|
-** If sqlite is being embedded in another program, you may wish to change the
|
|
-** prefix to reflect your program's name, so that if your program exits
|
|
-** prematurely, old temporary files can be easily identified. This can be done
|
|
-** using -DSQLITE_TEMP_FILE_PREFIX=myprefix_ on the compiler command line.
|
|
-**
|
|
-** 2006-10-31: The default prefix used to be "sqlite_". But then
|
|
-** Mcafee started using SQLite in their anti-virus product and it
|
|
-** started putting files with the "sqlite" name in the c:/temp folder.
|
|
-** This annoyed many windows users. Those users would then do a
|
|
-** Google search for "sqlite", find the telephone numbers of the
|
|
-** developers and call to wake them up at night and complain.
|
|
-** For this reason, the default name prefix is changed to be "sqlite"
|
|
-** spelled backwards. So the temp files are still identified, but
|
|
-** anybody smart enough to figure out the code is also likely smart
|
|
-** enough to know that calling the developer will not help get rid
|
|
-** of the file.
|
|
-*/
|
|
-#ifndef SQLITE_TEMP_FILE_PREFIX
|
|
-# define SQLITE_TEMP_FILE_PREFIX "etilqs_"
|
|
-#endif
|
|
-
|
|
-/*
|
|
-** The following values may be passed as the second argument to
|
|
-** sqlite3OsLock(). The various locks exhibit the following semantics:
|
|
-**
|
|
-** SHARED: Any number of processes may hold a SHARED lock simultaneously.
|
|
-** RESERVED: A single process may hold a RESERVED lock on a file at
|
|
-** any time. Other processes may hold and obtain new SHARED locks.
|
|
-** PENDING: A single process may hold a PENDING lock on a file at
|
|
-** any one time. Existing SHARED locks may persist, but no new
|
|
-** SHARED locks may be obtained by other processes.
|
|
-** EXCLUSIVE: An EXCLUSIVE lock precludes all other locks.
|
|
-**
|
|
-** PENDING_LOCK may not be passed directly to sqlite3OsLock(). Instead, a
|
|
-** process that requests an EXCLUSIVE lock may actually obtain a PENDING
|
|
-** lock. This can be upgraded to an EXCLUSIVE lock by a subsequent call to
|
|
-** sqlite3OsLock().
|
|
-*/
|
|
-#define NO_LOCK 0
|
|
-#define SHARED_LOCK 1
|
|
-#define RESERVED_LOCK 2
|
|
-#define PENDING_LOCK 3
|
|
-#define EXCLUSIVE_LOCK 4
|
|
-
|
|
-/*
|
|
-** File Locking Notes: (Mostly about windows but also some info for Unix)
|
|
-**
|
|
-** We cannot use LockFileEx() or UnlockFileEx() on Win95/98/ME because
|
|
-** those functions are not available. So we use only LockFile() and
|
|
-** UnlockFile().
|
|
-**
|
|
-** LockFile() prevents not just writing but also reading by other processes.
|
|
-** A SHARED_LOCK is obtained by locking a single randomly-chosen
|
|
-** byte out of a specific range of bytes. The lock byte is obtained at
|
|
-** random so two separate readers can probably access the file at the
|
|
-** same time, unless they are unlucky and choose the same lock byte.
|
|
-** An EXCLUSIVE_LOCK is obtained by locking all bytes in the range.
|
|
-** There can only be one writer. A RESERVED_LOCK is obtained by locking
|
|
-** a single byte of the file that is designated as the reserved lock byte.
|
|
-** A PENDING_LOCK is obtained by locking a designated byte different from
|
|
-** the RESERVED_LOCK byte.
|
|
-**
|
|
-** On WinNT/2K/XP systems, LockFileEx() and UnlockFileEx() are available,
|
|
-** which means we can use reader/writer locks. When reader/writer locks
|
|
-** are used, the lock is placed on the same range of bytes that is used
|
|
-** for probabilistic locking in Win95/98/ME. Hence, the locking scheme
|
|
-** will support two or more Win95 readers or two or more WinNT readers.
|
|
-** But a single Win95 reader will lock out all WinNT readers and a single
|
|
-** WinNT reader will lock out all other Win95 readers.
|
|
-**
|
|
-** The following #defines specify the range of bytes used for locking.
|
|
-** SHARED_SIZE is the number of bytes available in the pool from which
|
|
-** a random byte is selected for a shared lock. The pool of bytes for
|
|
-** shared locks begins at SHARED_FIRST.
|
|
-**
|
|
-** The same locking strategy and
|
|
-** byte ranges are used for Unix. This leaves open the possibility of having
|
|
-** clients on win95, winNT, and unix all talking to the same shared file
|
|
-** and all locking correctly. To do so would require that samba (or whatever
|
|
-** tool is being used for file sharing) implements locks correctly between
|
|
-** windows and unix. I'm guessing that isn't likely to happen, but by
|
|
-** using the same locking range we are at least open to the possibility.
|
|
-**
|
|
-** Locking in windows is manditory. For this reason, we cannot store
|
|
-** actual data in the bytes used for locking. The pager never allocates
|
|
-** the pages involved in locking therefore. SHARED_SIZE is selected so
|
|
-** that all locks will fit on a single page even at the minimum page size.
|
|
-** PENDING_BYTE defines the beginning of the locks. By default PENDING_BYTE
|
|
-** is set high so that we don't have to allocate an unused page except
|
|
-** for very large databases. But one should test the page skipping logic
|
|
-** by setting PENDING_BYTE low and running the entire regression suite.
|
|
-**
|
|
-** Changing the value of PENDING_BYTE results in a subtly incompatible
|
|
-** file format. Depending on how it is changed, you might not notice
|
|
-** the incompatibility right away, even running a full regression test.
|
|
-** The default location of PENDING_BYTE is the first byte past the
|
|
-** 1GB boundary.
|
|
-**
|
|
-*/
|
|
-#ifdef SQLITE_OMIT_WSD
|
|
-# define PENDING_BYTE (0x40000000)
|
|
-#else
|
|
-# define PENDING_BYTE sqlite3PendingByte
|
|
-#endif
|
|
-#define RESERVED_BYTE (PENDING_BYTE+1)
|
|
-#define SHARED_FIRST (PENDING_BYTE+2)
|
|
-#define SHARED_SIZE 510
|
|
-
|
|
-/*
|
|
-** Wrapper around OS specific sqlite3_os_init() function.
|
|
-*/
|
|
-SQLITE_PRIVATE int sqlite3OsInit(void);
|
|
-
|
|
-/*
|
|
-** Functions for accessing sqlite3_file methods
|
|
-*/
|
|
-SQLITE_PRIVATE void sqlite3OsClose(sqlite3_file*);
|
|
-SQLITE_PRIVATE int sqlite3OsRead(sqlite3_file*, void*, int amt, i64 offset);
|
|
-SQLITE_PRIVATE int sqlite3OsWrite(sqlite3_file*, const void*, int amt, i64 offset);
|
|
-SQLITE_PRIVATE int sqlite3OsTruncate(sqlite3_file*, i64 size);
|
|
-SQLITE_PRIVATE int sqlite3OsSync(sqlite3_file*, int);
|
|
-SQLITE_PRIVATE int sqlite3OsFileSize(sqlite3_file*, i64 *pSize);
|
|
-SQLITE_PRIVATE int sqlite3OsLock(sqlite3_file*, int);
|
|
-SQLITE_PRIVATE int sqlite3OsUnlock(sqlite3_file*, int);
|
|
-SQLITE_PRIVATE int sqlite3OsCheckReservedLock(sqlite3_file *id, int *pResOut);
|
|
-SQLITE_PRIVATE int sqlite3OsFileControl(sqlite3_file*,int,void*);
|
|
-SQLITE_PRIVATE void sqlite3OsFileControlHint(sqlite3_file*,int,void*);
|
|
-#define SQLITE_FCNTL_DB_UNCHANGED 0xca093fa0
|
|
-SQLITE_PRIVATE int sqlite3OsSectorSize(sqlite3_file *id);
|
|
-SQLITE_PRIVATE int sqlite3OsDeviceCharacteristics(sqlite3_file *id);
|
|
-#ifndef SQLITE_OMIT_WAL
|
|
-SQLITE_PRIVATE int sqlite3OsShmMap(sqlite3_file *,int,int,int,void volatile **);
|
|
-SQLITE_PRIVATE int sqlite3OsShmLock(sqlite3_file *id, int, int, int);
|
|
-SQLITE_PRIVATE void sqlite3OsShmBarrier(sqlite3_file *id);
|
|
-SQLITE_PRIVATE int sqlite3OsShmUnmap(sqlite3_file *id, int);
|
|
-#endif /* SQLITE_OMIT_WAL */
|
|
-SQLITE_PRIVATE int sqlite3OsFetch(sqlite3_file *id, i64, int, void **);
|
|
-SQLITE_PRIVATE int sqlite3OsUnfetch(sqlite3_file *, i64, void *);
|
|
-
|
|
-
|
|
-/*
|
|
-** Functions for accessing sqlite3_vfs methods
|
|
-*/
|
|
-SQLITE_PRIVATE int sqlite3OsOpen(sqlite3_vfs *, const char *, sqlite3_file*, int, int *);
|
|
-SQLITE_PRIVATE int sqlite3OsDelete(sqlite3_vfs *, const char *, int);
|
|
-SQLITE_PRIVATE int sqlite3OsAccess(sqlite3_vfs *, const char *, int, int *pResOut);
|
|
-SQLITE_PRIVATE int sqlite3OsFullPathname(sqlite3_vfs *, const char *, int, char *);
|
|
-#ifndef SQLITE_OMIT_LOAD_EXTENSION
|
|
-SQLITE_PRIVATE void *sqlite3OsDlOpen(sqlite3_vfs *, const char *);
|
|
-SQLITE_PRIVATE void sqlite3OsDlError(sqlite3_vfs *, int, char *);
|
|
-SQLITE_PRIVATE void (*sqlite3OsDlSym(sqlite3_vfs *, void *, const char *))(void);
|
|
-SQLITE_PRIVATE void sqlite3OsDlClose(sqlite3_vfs *, void *);
|
|
-#endif /* SQLITE_OMIT_LOAD_EXTENSION */
|
|
-SQLITE_PRIVATE int sqlite3OsRandomness(sqlite3_vfs *, int, char *);
|
|
-SQLITE_PRIVATE int sqlite3OsSleep(sqlite3_vfs *, int);
|
|
-SQLITE_PRIVATE int sqlite3OsGetLastError(sqlite3_vfs*);
|
|
-SQLITE_PRIVATE int sqlite3OsCurrentTimeInt64(sqlite3_vfs *, sqlite3_int64*);
|
|
-
|
|
-/*
|
|
-** Convenience functions for opening and closing files using
|
|
-** sqlite3_malloc() to obtain space for the file-handle structure.
|
|
-*/
|
|
-SQLITE_PRIVATE int sqlite3OsOpenMalloc(sqlite3_vfs *, const char *, sqlite3_file **, int,int*);
|
|
-SQLITE_PRIVATE void sqlite3OsCloseFree(sqlite3_file *);
|
|
-
|
|
-#endif /* _SQLITE_OS_H_ */
|
|
-
|
|
-/************** End of os.h **************************************************/
|
|
-/************** Continuing where we left off in sqliteInt.h ******************/
|
|
/************** Include mutex.h in the middle of sqliteInt.h *****************/
|
|
/************** Begin file mutex.h *******************************************/
|
|
/*
|
|
@@ -16424,9 +16803,9 @@ SQLITE_PRIVATE void sqlite3OsCloseFree(sqlite3_file *);
|
|
*/
|
|
#define sqlite3_mutex_alloc(X) ((sqlite3_mutex*)8)
|
|
#define sqlite3_mutex_free(X)
|
|
-#define sqlite3_mutex_enter(X)
|
|
+#define sqlite3_mutex_enter(X)
|
|
#define sqlite3_mutex_try(X) SQLITE_OK
|
|
-#define sqlite3_mutex_leave(X)
|
|
+#define sqlite3_mutex_leave(X)
|
|
#define sqlite3_mutex_held(X) ((void)(X),1)
|
|
#define sqlite3_mutex_notheld(X) ((void)(X),1)
|
|
#define sqlite3MutexAlloc(X) ((sqlite3_mutex*)8)
|
|
@@ -16539,7 +16918,6 @@ struct Schema {
|
|
*/
|
|
#define DB_SchemaLoaded 0x0001 /* The schema has been loaded */
|
|
#define DB_UnresetViews 0x0002 /* Some views have defined column names */
|
|
-#define DB_Empty 0x0004 /* The file is empty (length 0 bytes) */
|
|
#define DB_ResetWanted 0x0008 /* Reset the schema when nSchemaLock==0 */
|
|
|
|
/*
|
|
@@ -16610,6 +16988,7 @@ struct Lookaside {
|
|
#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
|
|
void *pStart; /* First byte of available memory space */
|
|
void *pEnd; /* First byte past end of available space */
|
|
+ void *pTrueEnd; /* True value of pEnd, when db->pnBytesFreed!=0 */
|
|
};
|
|
struct LookasideSlot {
|
|
LookasideSlot *pNext; /* Next buffer in the list of free buffers */
|
|
@@ -16690,6 +17069,11 @@ SQLITE_PRIVATE void sqlite3CryptFunc(sqlite3_context*,int,sqlite3_value**);
|
|
#endif /* SQLITE_OMIT_DEPRECATED */
|
|
#define SQLITE_TRACE_NONLEGACY_MASK 0x0f /* Normal flags */
|
|
|
|
+/*
|
|
+** Maximum number of sqlite3.aDb[] entries. This is the number of attached
|
|
+** databases plus 2 for "main" and "temp".
|
|
+*/
|
|
+#define SQLITE_MAX_DB (SQLITE_MAX_ATTACHED+2)
|
|
|
|
/*
|
|
** Each database connection is an instance of the following structure.
|
|
@@ -16697,7 +17081,7 @@ SQLITE_PRIVATE void sqlite3CryptFunc(sqlite3_context*,int,sqlite3_value**);
|
|
struct sqlite3 {
|
|
sqlite3_vfs *pVfs; /* OS Interface */
|
|
struct Vdbe *pVdbe; /* List of active virtual machines */
|
|
- CollSeq *pDfltColl; /* The default collating sequence (BINARY) */
|
|
+ CollSeq *pDfltColl; /* BINARY collseq for the database encoding */
|
|
sqlite3_mutex *mutex; /* Connection mutex */
|
|
Db *aDb; /* All backends */
|
|
int nDb; /* Number of backends currently in use */
|
|
@@ -16708,9 +17092,10 @@ struct sqlite3 {
|
|
u32 nSchemaLock; /* Do not reset the schema when non-zero */
|
|
unsigned int openFlags; /* Flags passed to sqlite3_vfs.xOpen() */
|
|
int errCode; /* Most recent error code (SQLITE_*) */
|
|
+ int errByteOffset; /* Byte offset of error in SQL statement */
|
|
int errMask; /* & result codes with this before returning */
|
|
int iSysErrno; /* Errno value from last system error */
|
|
- u16 dbOptFlags; /* Flags to enable/disable optimizations */
|
|
+ u32 dbOptFlags; /* Flags to enable/disable optimizations */
|
|
u8 enc; /* Text encoding */
|
|
u8 autoCommit; /* The auto-commit flag. */
|
|
u8 temp_store; /* 1: file 2: memory 0: default */
|
|
@@ -16724,20 +17109,20 @@ struct sqlite3 {
|
|
u8 mTrace; /* zero or more SQLITE_TRACE flags */
|
|
u8 noSharedCache; /* True if no shared-cache backends */
|
|
u8 nSqlExec; /* Number of pending OP_SqlExec opcodes */
|
|
+ u8 eOpenState; /* Current condition of the connection */
|
|
int nextPagesize; /* Pagesize after VACUUM if >0 */
|
|
- u32 magic; /* Magic number for detect library misuse */
|
|
- int nChange; /* Value returned by sqlite3_changes() */
|
|
- int nTotalChange; /* Value returned by sqlite3_total_changes() */
|
|
+ i64 nChange; /* Value returned by sqlite3_changes() */
|
|
+ i64 nTotalChange; /* Value returned by sqlite3_total_changes() */
|
|
int aLimit[SQLITE_N_LIMIT]; /* Limits */
|
|
int nMaxSorterMmap; /* Maximum size of regions mapped by sorter */
|
|
struct sqlite3InitInfo { /* Information used during initialization */
|
|
- int newTnum; /* Rootpage of table being initialized */
|
|
+ Pgno newTnum; /* Rootpage of table being initialized */
|
|
u8 iDb; /* Which db file is being initialized */
|
|
u8 busy; /* TRUE if currently initializing */
|
|
unsigned orphanTrigger : 1; /* Last statement is orphaned TEMP trigger */
|
|
unsigned imposterTable : 1; /* Building an imposter table */
|
|
unsigned reopenMemdb : 1; /* ATTACH is really a reopen using MemDB */
|
|
- char **azInit; /* "type", "name", and "tbl_name" columns */
|
|
+ const char **azInit; /* "type", "name", and "tbl_name" columns */
|
|
} init;
|
|
int nVdbeActive; /* Number of VDBEs currently running */
|
|
int nVdbeRead; /* Number of active VDBEs that read or write */
|
|
@@ -16746,8 +17131,11 @@ struct sqlite3 {
|
|
int nVDestroy; /* Number of active OP_VDestroy operations */
|
|
int nExtension; /* Number of loaded extensions */
|
|
void **aExtension; /* Array of shared library handles */
|
|
- int (*xTrace)(u32,void*,void*,void*); /* Trace function */
|
|
- void *pTraceArg; /* Argument to the trace function */
|
|
+ union {
|
|
+ void (*xLegacy)(void*,const char*); /* mTrace==SQLITE_TRACE_LEGACY */
|
|
+ int (*xV2)(u32,void*,void*,void*); /* All other mTrace values */
|
|
+ } trace;
|
|
+ void *pTraceArg; /* Argument to the trace function */
|
|
#ifndef SQLITE_OMIT_DEPRECATED
|
|
void (*xProfile)(void*,const char*,u64); /* Profiling function */
|
|
void *pProfileArg; /* Argument to profile function */
|
|
@@ -16758,6 +17146,9 @@ struct sqlite3 {
|
|
void (*xRollbackCallback)(void*); /* Invoked at every commit. */
|
|
void *pUpdateArg;
|
|
void (*xUpdateCallback)(void*,int, const char*,const char*,sqlite_int64);
|
|
+ void *pAutovacPagesArg; /* Client argument to autovac_pages */
|
|
+ void (*xAutovacDestr)(void*); /* Destructor for pAutovacPAgesArg */
|
|
+ unsigned int (*xAutovacPages)(void*,const char*,u32,u32,u32);
|
|
Parse *pParse; /* Current parse */
|
|
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
|
|
void *pPreUpdateArg; /* First argument to xPreUpdateCallback */
|
|
@@ -16800,6 +17191,7 @@ struct sqlite3 {
|
|
BusyHandler busyHandler; /* Busy callback */
|
|
Db aDbStatic[2]; /* Static space for the 2 default backends */
|
|
Savepoint *pSavepoint; /* List of active savepoints */
|
|
+ int nAnalysisLimit; /* Number of index rows to ANALYZE */
|
|
int busyTimeout; /* Busy handler timeout, in msec */
|
|
int nSavepoint; /* Number of non-transaction savepoints */
|
|
int nStatement; /* Number of nested statement-transactions */
|
|
@@ -16807,7 +17199,7 @@ struct sqlite3 {
|
|
i64 nDeferredImmCons; /* Net deferred immediate constraints */
|
|
int *pnBytesFreed; /* If not NULL, increment this in DbFree() */
|
|
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
|
|
- /* The following variables are all protected by the STATIC_MASTER
|
|
+ /* The following variables are all protected by the STATIC_MAIN
|
|
** mutex, not by sqlite3.mutex. They are used by code in notify.c.
|
|
**
|
|
** When X.pUnlockConnection==Y, that means that X is waiting for Y to
|
|
@@ -16849,7 +17241,7 @@ struct sqlite3 {
|
|
** SQLITE_CkptFullFSync == PAGER_CKPT_FULLFSYNC
|
|
** SQLITE_CacheSpill == PAGER_CACHE_SPILL
|
|
*/
|
|
-#define SQLITE_WriteSchema 0x00000001 /* OK to update SQLITE_MASTER */
|
|
+#define SQLITE_WriteSchema 0x00000001 /* OK to update SQLITE_SCHEMA */
|
|
#define SQLITE_LegacyFileFmt 0x00000002 /* Create new databases in format 1 */
|
|
#define SQLITE_FullColNames 0x00000004 /* Show full column names on SELECT */
|
|
#define SQLITE_FullFSync 0x00000008 /* Use full fsync on the backend */
|
|
@@ -16886,6 +17278,7 @@ struct sqlite3 {
|
|
#define SQLITE_CountRows HI(0x00001) /* Count rows changed by INSERT, */
|
|
/* DELETE, or UPDATE and return */
|
|
/* the count using a callback. */
|
|
+#define SQLITE_CorruptRdOnly HI(0x00002) /* Prohibit writes due to error */
|
|
|
|
/* Flags used only if debugging */
|
|
#ifdef SQLITE_DEBUG
|
|
@@ -16906,30 +17299,43 @@ struct sqlite3 {
|
|
#define DBFLAG_VacuumInto 0x0008 /* Currently running VACUUM INTO */
|
|
#define DBFLAG_SchemaKnownOk 0x0010 /* Schema is known to be valid */
|
|
#define DBFLAG_InternalFunc 0x0020 /* Allow use of internal functions */
|
|
+#define DBFLAG_EncodingFixed 0x0040 /* No longer possible to change enc. */
|
|
|
|
/*
|
|
** Bits of the sqlite3.dbOptFlags field that are used by the
|
|
** sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS,...) interface to
|
|
** selectively disable various optimizations.
|
|
*/
|
|
-#define SQLITE_QueryFlattener 0x0001 /* Query flattening */
|
|
-#define SQLITE_WindowFunc 0x0002 /* Use xInverse for window functions */
|
|
-#define SQLITE_GroupByOrder 0x0004 /* GROUPBY cover of ORDERBY */
|
|
-#define SQLITE_FactorOutConst 0x0008 /* Constant factoring */
|
|
-#define SQLITE_DistinctOpt 0x0010 /* DISTINCT using indexes */
|
|
-#define SQLITE_CoverIdxScan 0x0020 /* Covering index scans */
|
|
-#define SQLITE_OrderByIdxJoin 0x0040 /* ORDER BY of joins via index */
|
|
-#define SQLITE_Transitive 0x0080 /* Transitive constraints */
|
|
-#define SQLITE_OmitNoopJoin 0x0100 /* Omit unused tables in joins */
|
|
-#define SQLITE_CountOfView 0x0200 /* The count-of-view optimization */
|
|
-#define SQLITE_CursorHints 0x0400 /* Add OP_CursorHint opcodes */
|
|
-#define SQLITE_Stat4 0x0800 /* Use STAT4 data */
|
|
- /* TH3 expects the Stat4 ^^^^^^ value to be 0x0800. Don't change it */
|
|
-#define SQLITE_PushDown 0x1000 /* The push-down optimization */
|
|
-#define SQLITE_SimplifyJoin 0x2000 /* Convert LEFT JOIN to JOIN */
|
|
-#define SQLITE_SkipScan 0x4000 /* Skip-scans */
|
|
-#define SQLITE_PropagateConst 0x8000 /* The constant propagation opt */
|
|
-#define SQLITE_AllOpts 0xffff /* All optimizations */
|
|
+#define SQLITE_QueryFlattener 0x00000001 /* Query flattening */
|
|
+#define SQLITE_WindowFunc 0x00000002 /* Use xInverse for window functions */
|
|
+#define SQLITE_GroupByOrder 0x00000004 /* GROUPBY cover of ORDERBY */
|
|
+#define SQLITE_FactorOutConst 0x00000008 /* Constant factoring */
|
|
+#define SQLITE_DistinctOpt 0x00000010 /* DISTINCT using indexes */
|
|
+#define SQLITE_CoverIdxScan 0x00000020 /* Covering index scans */
|
|
+#define SQLITE_OrderByIdxJoin 0x00000040 /* ORDER BY of joins via index */
|
|
+#define SQLITE_Transitive 0x00000080 /* Transitive constraints */
|
|
+#define SQLITE_OmitNoopJoin 0x00000100 /* Omit unused tables in joins */
|
|
+#define SQLITE_CountOfView 0x00000200 /* The count-of-view optimization */
|
|
+#define SQLITE_CursorHints 0x00000400 /* Add OP_CursorHint opcodes */
|
|
+#define SQLITE_Stat4 0x00000800 /* Use STAT4 data */
|
|
+ /* TH3 expects this value ^^^^^^^^^^ to be 0x0000800. Don't change it */
|
|
+#define SQLITE_PushDown 0x00001000 /* The push-down optimization */
|
|
+#define SQLITE_SimplifyJoin 0x00002000 /* Convert LEFT JOIN to JOIN */
|
|
+#define SQLITE_SkipScan 0x00004000 /* Skip-scans */
|
|
+#define SQLITE_PropagateConst 0x00008000 /* The constant propagation opt */
|
|
+#define SQLITE_MinMaxOpt 0x00010000 /* The min/max optimization */
|
|
+#define SQLITE_SeekScan 0x00020000 /* The OP_SeekScan optimization */
|
|
+#define SQLITE_OmitOrderBy 0x00040000 /* Omit pointless ORDER BY */
|
|
+ /* TH3 expects this value ^^^^^^^^^^ to be 0x40000. Coordinate any change */
|
|
+#define SQLITE_BloomFilter 0x00080000 /* Use a Bloom filter on searches */
|
|
+#define SQLITE_BloomPulldown 0x00100000 /* Run Bloom filters early */
|
|
+#define SQLITE_BalancedMerge 0x00200000 /* Balance multi-way merges */
|
|
+#define SQLITE_ReleaseReg 0x00400000 /* Use OP_ReleaseReg for testing */
|
|
+#define SQLITE_FlttnUnionAll 0x00800000 /* Disable the UNION ALL flattener */
|
|
+ /* TH3 expects this value ^^^^^^^^^^ See flatten04.test */
|
|
+#define SQLITE_IndexedExpr 0x01000000 /* Pull exprs from index when able */
|
|
+#define SQLITE_Coroutines 0x02000000 /* Co-routines for subqueries */
|
|
+#define SQLITE_AllOpts 0xffffffff /* All optimizations */
|
|
|
|
/*
|
|
** Macros for testing whether or not optimizations are enabled or disabled.
|
|
@@ -16943,17 +17349,16 @@ struct sqlite3 {
|
|
*/
|
|
#define ConstFactorOk(P) ((P)->okConstFactor)
|
|
|
|
-/*
|
|
-** Possible values for the sqlite.magic field.
|
|
-** The numbers are obtained at random and have no special meaning, other
|
|
-** than being distinct from one another.
|
|
+/* Possible values for the sqlite3.eOpenState field.
|
|
+** The numbers are randomly selected such that a minimum of three bits must
|
|
+** change to convert any number to another or to zero
|
|
*/
|
|
-#define SQLITE_MAGIC_OPEN 0xa029a697 /* Database is open */
|
|
-#define SQLITE_MAGIC_CLOSED 0x9f3c2d33 /* Database is closed */
|
|
-#define SQLITE_MAGIC_SICK 0x4b771290 /* Error and awaiting close */
|
|
-#define SQLITE_MAGIC_BUSY 0xf03b7906 /* Database currently in use */
|
|
-#define SQLITE_MAGIC_ERROR 0xb5357930 /* An SQLITE_MISUSE error occurred */
|
|
-#define SQLITE_MAGIC_ZOMBIE 0x64cffc7f /* Close with last statement close */
|
|
+#define SQLITE_STATE_OPEN 0x76 /* Database is open */
|
|
+#define SQLITE_STATE_CLOSED 0xce /* Database is closed */
|
|
+#define SQLITE_STATE_SICK 0xba /* Error and awaiting close */
|
|
+#define SQLITE_STATE_BUSY 0x6d /* Database currently in use */
|
|
+#define SQLITE_STATE_ERROR 0xd5 /* An SQLITE_MISUSE error occurred */
|
|
+#define SQLITE_STATE_ZOMBIE 0xa7 /* Close with last statement close */
|
|
|
|
/*
|
|
** Each SQL function is defined by an instance of the following
|
|
@@ -16978,7 +17383,7 @@ struct FuncDef {
|
|
union {
|
|
FuncDef *pHash; /* Next with a different name but the same hash */
|
|
FuncDestructor *pDestructor; /* Reference counted destructor function */
|
|
- } u;
|
|
+ } u; /* pHash if SQLITE_FUNC_BUILTIN, pDestructor otherwise */
|
|
};
|
|
|
|
/*
|
|
@@ -17008,13 +17413,20 @@ struct FuncDestructor {
|
|
** are assert() statements in the code to verify this.
|
|
**
|
|
** Value constraints (enforced via assert()):
|
|
-** SQLITE_FUNC_MINMAX == NC_MinMaxAgg == SF_MinMaxAgg
|
|
-** SQLITE_FUNC_LENGTH == OPFLAG_LENGTHARG
|
|
-** SQLITE_FUNC_TYPEOF == OPFLAG_TYPEOFARG
|
|
-** SQLITE_FUNC_CONSTANT == SQLITE_DETERMINISTIC from the API
|
|
-** SQLITE_FUNC_DIRECT == SQLITE_DIRECTONLY from the API
|
|
-** SQLITE_FUNC_UNSAFE == SQLITE_INNOCUOUS
|
|
+** SQLITE_FUNC_MINMAX == NC_MinMaxAgg == SF_MinMaxAgg
|
|
+** SQLITE_FUNC_ANYORDER == NC_OrderAgg == SF_OrderByReqd
|
|
+** SQLITE_FUNC_LENGTH == OPFLAG_LENGTHARG
|
|
+** SQLITE_FUNC_TYPEOF == OPFLAG_TYPEOFARG
|
|
+** SQLITE_FUNC_CONSTANT == SQLITE_DETERMINISTIC from the API
|
|
+** SQLITE_FUNC_DIRECT == SQLITE_DIRECTONLY from the API
|
|
+** SQLITE_FUNC_UNSAFE == SQLITE_INNOCUOUS -- opposite meanings!!!
|
|
** SQLITE_FUNC_ENCMASK depends on SQLITE_UTF* macros in the API
|
|
+**
|
|
+** Note that even though SQLITE_FUNC_UNSAFE and SQLITE_INNOCUOUS have the
|
|
+** same bit value, their meanings are inverted. SQLITE_FUNC_UNSAFE is
|
|
+** used internally and if set means tha the function has side effects.
|
|
+** SQLITE_INNOCUOUS is used by application code and means "not unsafe".
|
|
+** See multiple instances of tag-20230109-1.
|
|
*/
|
|
#define SQLITE_FUNC_ENCMASK 0x0003 /* SQLITE_UTF8, SQLITE_UTF16BE or UTF16LE */
|
|
#define SQLITE_FUNC_LIKE 0x0004 /* Candidate for the LIKE optimization */
|
|
@@ -17024,27 +17436,31 @@ struct FuncDestructor {
|
|
#define SQLITE_FUNC_LENGTH 0x0040 /* Built-in length() function */
|
|
#define SQLITE_FUNC_TYPEOF 0x0080 /* Built-in typeof() function */
|
|
#define SQLITE_FUNC_COUNT 0x0100 /* Built-in count(*) aggregate */
|
|
-#define SQLITE_FUNC_COALESCE 0x0200 /* Built-in coalesce() or ifnull() */
|
|
+/* 0x0200 -- available for reuse */
|
|
#define SQLITE_FUNC_UNLIKELY 0x0400 /* Built-in unlikely() function */
|
|
#define SQLITE_FUNC_CONSTANT 0x0800 /* Constant inputs give a constant output */
|
|
#define SQLITE_FUNC_MINMAX 0x1000 /* True for min() and max() aggregates */
|
|
#define SQLITE_FUNC_SLOCHNG 0x2000 /* "Slow Change". Value constant during a
|
|
** single query - might change over time */
|
|
#define SQLITE_FUNC_TEST 0x4000 /* Built-in testing functions */
|
|
-#define SQLITE_FUNC_OFFSET 0x8000 /* Built-in sqlite_offset() function */
|
|
+/* 0x8000 -- available for reuse */
|
|
#define SQLITE_FUNC_WINDOW 0x00010000 /* Built-in window-only function */
|
|
#define SQLITE_FUNC_INTERNAL 0x00040000 /* For use by NestedParse() only */
|
|
#define SQLITE_FUNC_DIRECT 0x00080000 /* Not for use in TRIGGERs or VIEWs */
|
|
#define SQLITE_FUNC_SUBTYPE 0x00100000 /* Result likely to have sub-type */
|
|
#define SQLITE_FUNC_UNSAFE 0x00200000 /* Function has side effects */
|
|
#define SQLITE_FUNC_INLINE 0x00400000 /* Functions implemented in-line */
|
|
+#define SQLITE_FUNC_BUILTIN 0x00800000 /* This is a built-in function */
|
|
+#define SQLITE_FUNC_ANYORDER 0x08000000 /* count/min/max aggregate */
|
|
|
|
/* Identifier numbers for each in-line function */
|
|
#define INLINEFUNC_coalesce 0
|
|
#define INLINEFUNC_implies_nonnull_row 1
|
|
#define INLINEFUNC_expr_implies_expr 2
|
|
-#define INLINEFUNC_expr_compare 3
|
|
+#define INLINEFUNC_expr_compare 3
|
|
#define INLINEFUNC_affinity 4
|
|
+#define INLINEFUNC_iif 5
|
|
+#define INLINEFUNC_sqlite_offset 6
|
|
#define INLINEFUNC_unlikely 99 /* Default case */
|
|
|
|
/*
|
|
@@ -17084,10 +17500,13 @@ struct FuncDestructor {
|
|
** a single query. The iArg is ignored. The user-data is always set
|
|
** to a NULL pointer. The bNC parameter is not used.
|
|
**
|
|
+** MFUNCTION(zName, nArg, xPtr, xFunc)
|
|
+** For math-library functions. xPtr is an arbitrary pointer.
|
|
+**
|
|
** PURE_DATE(zName, nArg, iArg, bNC, xFunc)
|
|
** Used for "pure" date/time functions, this macro is like DFUNCTION
|
|
** except that it does set the SQLITE_FUNC_CONSTANT flags. iArg is
|
|
-** ignored and the user-data for these functions is set to an
|
|
+** ignored and the user-data for these functions is set to an
|
|
** arbitrary non-NULL pointer. The bNC parameter is not used.
|
|
**
|
|
** AGGREGATE(zName, nArg, iArg, bNC, xStep, xFinal)
|
|
@@ -17096,7 +17515,7 @@ struct FuncDestructor {
|
|
** are interpreted in the same way as the first 4 parameters to
|
|
** FUNCTION().
|
|
**
|
|
-** WFUNCTION(zName, nArg, iArg, xStep, xFinal, xValue, xInverse)
|
|
+** WAGGREGATE(zName, nArg, iArg, xStep, xFinal, xValue, xInverse)
|
|
** Used to create an aggregate function definition implemented by
|
|
** the C functions xStep and xFinal. The first four parameters
|
|
** are interpreted in the same way as the first 4 parameters to
|
|
@@ -17111,41 +17530,55 @@ struct FuncDestructor {
|
|
** parameter.
|
|
*/
|
|
#define FUNCTION(zName, nArg, iArg, bNC, xFunc) \
|
|
- {nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
|
|
+ {nArg, SQLITE_FUNC_BUILTIN|\
|
|
+ SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
|
|
SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} }
|
|
#define VFUNCTION(zName, nArg, iArg, bNC, xFunc) \
|
|
- {nArg, SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
|
|
+ {nArg, SQLITE_FUNC_BUILTIN|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
|
|
SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} }
|
|
#define SFUNCTION(zName, nArg, iArg, bNC, xFunc) \
|
|
- {nArg, SQLITE_UTF8|SQLITE_DIRECTONLY|SQLITE_FUNC_UNSAFE, \
|
|
+ {nArg, SQLITE_FUNC_BUILTIN|SQLITE_UTF8|SQLITE_DIRECTONLY|SQLITE_FUNC_UNSAFE, \
|
|
+ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} }
|
|
+#define MFUNCTION(zName, nArg, xPtr, xFunc) \
|
|
+ {nArg, SQLITE_FUNC_BUILTIN|SQLITE_FUNC_CONSTANT|SQLITE_UTF8, \
|
|
+ xPtr, 0, xFunc, 0, 0, 0, #zName, {0} }
|
|
+#define JFUNCTION(zName, nArg, iArg, xFunc) \
|
|
+ {nArg, SQLITE_FUNC_BUILTIN|SQLITE_DETERMINISTIC|\
|
|
+ SQLITE_FUNC_CONSTANT|SQLITE_UTF8, \
|
|
SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} }
|
|
#define INLINE_FUNC(zName, nArg, iArg, mFlags) \
|
|
- {nArg, SQLITE_UTF8|SQLITE_FUNC_INLINE|SQLITE_FUNC_CONSTANT|(mFlags), \
|
|
+ {nArg, SQLITE_FUNC_BUILTIN|\
|
|
+ SQLITE_UTF8|SQLITE_FUNC_INLINE|SQLITE_FUNC_CONSTANT|(mFlags), \
|
|
SQLITE_INT_TO_PTR(iArg), 0, noopFunc, 0, 0, 0, #zName, {0} }
|
|
#define TEST_FUNC(zName, nArg, iArg, mFlags) \
|
|
- {nArg, SQLITE_UTF8|SQLITE_FUNC_INTERNAL|SQLITE_FUNC_TEST| \
|
|
+ {nArg, SQLITE_FUNC_BUILTIN|\
|
|
+ SQLITE_UTF8|SQLITE_FUNC_INTERNAL|SQLITE_FUNC_TEST| \
|
|
SQLITE_FUNC_INLINE|SQLITE_FUNC_CONSTANT|(mFlags), \
|
|
SQLITE_INT_TO_PTR(iArg), 0, noopFunc, 0, 0, 0, #zName, {0} }
|
|
#define DFUNCTION(zName, nArg, iArg, bNC, xFunc) \
|
|
- {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8, \
|
|
+ {nArg, SQLITE_FUNC_BUILTIN|SQLITE_FUNC_SLOCHNG|SQLITE_UTF8, \
|
|
0, 0, xFunc, 0, 0, 0, #zName, {0} }
|
|
#define PURE_DATE(zName, nArg, iArg, bNC, xFunc) \
|
|
- {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|SQLITE_FUNC_CONSTANT, \
|
|
+ {nArg, SQLITE_FUNC_BUILTIN|\
|
|
+ SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|SQLITE_FUNC_CONSTANT, \
|
|
(void*)&sqlite3Config, 0, xFunc, 0, 0, 0, #zName, {0} }
|
|
#define FUNCTION2(zName, nArg, iArg, bNC, xFunc, extraFlags) \
|
|
- {nArg,SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL)|extraFlags,\
|
|
+ {nArg, SQLITE_FUNC_BUILTIN|\
|
|
+ SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL)|extraFlags,\
|
|
SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} }
|
|
#define STR_FUNCTION(zName, nArg, pArg, bNC, xFunc) \
|
|
- {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
|
|
+ {nArg, SQLITE_FUNC_BUILTIN|\
|
|
+ SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
|
|
pArg, 0, xFunc, 0, 0, 0, #zName, }
|
|
#define LIKEFUNC(zName, nArg, arg, flags) \
|
|
- {nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|flags, \
|
|
+ {nArg, SQLITE_FUNC_BUILTIN|SQLITE_FUNC_CONSTANT|SQLITE_UTF8|flags, \
|
|
(void *)arg, 0, likeFunc, 0, 0, 0, #zName, {0} }
|
|
#define WAGGREGATE(zName, nArg, arg, nc, xStep, xFinal, xValue, xInverse, f) \
|
|
- {nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL)|f, \
|
|
+ {nArg, SQLITE_FUNC_BUILTIN|SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL)|f, \
|
|
SQLITE_INT_TO_PTR(arg), 0, xStep,xFinal,xValue,xInverse,#zName, {0}}
|
|
#define INTERNAL_FUNCTION(zName, nArg, xFunc) \
|
|
- {nArg, SQLITE_FUNC_INTERNAL|SQLITE_UTF8|SQLITE_FUNC_CONSTANT, \
|
|
+ {nArg, SQLITE_FUNC_BUILTIN|\
|
|
+ SQLITE_FUNC_INTERNAL|SQLITE_UTF8|SQLITE_FUNC_CONSTANT, \
|
|
0, 0, xFunc, 0, 0, 0, #zName, {0} }
|
|
|
|
|
|
@@ -17201,18 +17634,48 @@ struct Module {
|
|
** or equal to the table column index. It is
|
|
** equal if and only if there are no VIRTUAL
|
|
** columns to the left.
|
|
+**
|
|
+** Notes on zCnName:
|
|
+** The zCnName field stores the name of the column, the datatype of the
|
|
+** column, and the collating sequence for the column, in that order, all in
|
|
+** a single allocation. Each string is 0x00 terminated. The datatype
|
|
+** is only included if the COLFLAG_HASTYPE bit of colFlags is set and the
|
|
+** collating sequence name is only included if the COLFLAG_HASCOLL bit is
|
|
+** set.
|
|
*/
|
|
struct Column {
|
|
- char *zName; /* Name of this column, \000, then the type */
|
|
- Expr *pDflt; /* Default value or GENERATED ALWAYS AS value */
|
|
- char *zColl; /* Collating sequence. If NULL, use the default */
|
|
- u8 notNull; /* An OE_ code for handling a NOT NULL constraint */
|
|
- char affinity; /* One of the SQLITE_AFF_... values */
|
|
- u8 szEst; /* Estimated size of value in this column. sizeof(INT)==1 */
|
|
- u16 colFlags; /* Boolean properties. See COLFLAG_ defines below */
|
|
+ char *zCnName; /* Name of this column */
|
|
+ unsigned notNull :4; /* An OE_ code for handling a NOT NULL constraint */
|
|
+ unsigned eCType :4; /* One of the standard types */
|
|
+ char affinity; /* One of the SQLITE_AFF_... values */
|
|
+ u8 szEst; /* Est size of value in this column. sizeof(INT)==1 */
|
|
+ u8 hName; /* Column name hash for faster lookup */
|
|
+ u16 iDflt; /* 1-based index of DEFAULT. 0 means "none" */
|
|
+ u16 colFlags; /* Boolean properties. See COLFLAG_ defines below */
|
|
};
|
|
|
|
-/* Allowed values for Column.colFlags:
|
|
+/* Allowed values for Column.eCType.
|
|
+**
|
|
+** Values must match entries in the global constant arrays
|
|
+** sqlite3StdTypeLen[] and sqlite3StdType[]. Each value is one more
|
|
+** than the offset into these arrays for the corresponding name.
|
|
+** Adjust the SQLITE_N_STDTYPE value if adding or removing entries.
|
|
+*/
|
|
+#define COLTYPE_CUSTOM 0 /* Type appended to zName */
|
|
+#define COLTYPE_ANY 1
|
|
+#define COLTYPE_BLOB 2
|
|
+#define COLTYPE_INT 3
|
|
+#define COLTYPE_INTEGER 4
|
|
+#define COLTYPE_REAL 5
|
|
+#define COLTYPE_TEXT 6
|
|
+#define SQLITE_N_STDTYPE 6 /* Number of standard types */
|
|
+
|
|
+/* Allowed values for Column.colFlags.
|
|
+**
|
|
+** Constraints:
|
|
+** TF_HasVirtual == COLFLAG_VIRTUAL
|
|
+** TF_HasStored == COLFLAG_STORED
|
|
+** TF_HasHidden == COLFLAG_HIDDEN
|
|
*/
|
|
#define COLFLAG_PRIMKEY 0x0001 /* Column is part of the primary key */
|
|
#define COLFLAG_HIDDEN 0x0002 /* A hidden column in a virtual table */
|
|
@@ -17223,6 +17686,8 @@ struct Column {
|
|
#define COLFLAG_STORED 0x0040 /* GENERATED ALWAYS AS ... STORED */
|
|
#define COLFLAG_NOTAVAIL 0x0080 /* STORED column not yet calculated */
|
|
#define COLFLAG_BUSY 0x0100 /* Blocks recursion on GENERATED columns */
|
|
+#define COLFLAG_HASCOLL 0x0200 /* Has collating sequence name in zCnName */
|
|
+#define COLFLAG_NOEXPAND 0x0400 /* Omit this column when expanding "*" */
|
|
#define COLFLAG_GENERATED 0x0060 /* Combo: _STORED, _VIRTUAL */
|
|
#define COLFLAG_NOINSERT 0x0062 /* Combo: _HIDDEN, _STORED, _VIRTUAL */
|
|
|
|
@@ -17270,6 +17735,7 @@ struct CollSeq {
|
|
#define SQLITE_AFF_NUMERIC 0x43 /* 'C' */
|
|
#define SQLITE_AFF_INTEGER 0x44 /* 'D' */
|
|
#define SQLITE_AFF_REAL 0x45 /* 'E' */
|
|
+#define SQLITE_AFF_FLEXNUM 0x46 /* 'F' */
|
|
|
|
#define sqlite3IsNumericAffinity(X) ((X)>=SQLITE_AFF_NUMERIC)
|
|
|
|
@@ -17288,9 +17754,7 @@ struct CollSeq {
|
|
** operator is NULL. It is added to certain comparison operators to
|
|
** prove that the operands are always NOT NULL.
|
|
*/
|
|
-#define SQLITE_KEEPNULL 0x08 /* Used by vector == or <> */
|
|
#define SQLITE_JUMPIFNULL 0x10 /* jumps if either operand is NULL */
|
|
-#define SQLITE_STOREP2 0x20 /* Store result in reg[P2] rather than jump */
|
|
#define SQLITE_NULLEQ 0x80 /* NULL=NULL */
|
|
#define SQLITE_NOTNULL 0x90 /* Assert that operands are never NULL */
|
|
|
|
@@ -17354,19 +17818,17 @@ struct VTable {
|
|
#define SQLITE_VTABRISK_High 2
|
|
|
|
/*
|
|
-** The schema for each SQL table and view is represented in memory
|
|
-** by an instance of the following structure.
|
|
+** The schema for each SQL table, virtual table, and view is represented
|
|
+** in memory by an instance of the following structure.
|
|
*/
|
|
struct Table {
|
|
char *zName; /* Name of the table or view */
|
|
Column *aCol; /* Information about each column */
|
|
Index *pIndex; /* List of SQL indexes on this table. */
|
|
- Select *pSelect; /* NULL for tables. Points to definition if a view. */
|
|
- FKey *pFKey; /* Linked list of all foreign keys in this table */
|
|
char *zColAff; /* String defining the affinity of each column */
|
|
ExprList *pCheck; /* All CHECK constraints */
|
|
/* ... also used as column name list in a VIEW */
|
|
- int tnum; /* Root BTree page for this table */
|
|
+ Pgno tnum; /* Root BTree page for this table */
|
|
u32 nTabRef; /* Number of pointers to this Table */
|
|
u32 tabFlags; /* Mask of TF_* values */
|
|
i16 iPKey; /* If not negative, use aCol[iPKey] as the rowid */
|
|
@@ -17378,17 +17840,25 @@ struct Table {
|
|
LogEst costMult; /* Cost multiplier for using this table */
|
|
#endif
|
|
u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */
|
|
-#ifndef SQLITE_OMIT_ALTERTABLE
|
|
- int addColOffset; /* Offset in CREATE TABLE stmt to add a new column */
|
|
-#endif
|
|
-#ifndef SQLITE_OMIT_VIRTUALTABLE
|
|
- int nModuleArg; /* Number of arguments to the module */
|
|
- char **azModuleArg; /* 0: module 1: schema 2: vtab name 3...: args */
|
|
- VTable *pVTable; /* List of VTable objects. */
|
|
-#endif
|
|
- Trigger *pTrigger; /* List of triggers stored in pSchema */
|
|
+ u8 eTabType; /* 0: normal, 1: virtual, 2: view */
|
|
+ union {
|
|
+ struct { /* Used by ordinary tables: */
|
|
+ int addColOffset; /* Offset in CREATE TABLE stmt to add a new column */
|
|
+ FKey *pFKey; /* Linked list of all foreign keys in this table */
|
|
+ ExprList *pDfltList; /* DEFAULT clauses on various columns.
|
|
+ ** Or the AS clause for generated columns. */
|
|
+ } tab;
|
|
+ struct { /* Used by views: */
|
|
+ Select *pSelect; /* View definition */
|
|
+ } view;
|
|
+ struct { /* Used by virtual tables only: */
|
|
+ int nArg; /* Number of arguments to the module */
|
|
+ char **azArg; /* 0: module 1: schema 2: vtab name 3...: args */
|
|
+ VTable *p; /* List of VTable objects. */
|
|
+ } vtab;
|
|
+ } u;
|
|
+ Trigger *pTrigger; /* List of triggers on this object */
|
|
Schema *pSchema; /* Schema that contains this table */
|
|
- Table *pNextZombie; /* Next on the Parse.pZombieTab list */
|
|
};
|
|
|
|
/*
|
|
@@ -17402,24 +17872,39 @@ struct Table {
|
|
**
|
|
** Constraints:
|
|
**
|
|
-** TF_HasVirtual == COLFLAG_Virtual
|
|
-** TF_HasStored == COLFLAG_Stored
|
|
-*/
|
|
-#define TF_Readonly 0x0001 /* Read-only system table */
|
|
-#define TF_Ephemeral 0x0002 /* An ephemeral table */
|
|
-#define TF_HasPrimaryKey 0x0004 /* Table has a primary key */
|
|
-#define TF_Autoincrement 0x0008 /* Integer primary key is autoincrement */
|
|
-#define TF_HasStat1 0x0010 /* nRowLogEst set from sqlite_stat1 */
|
|
-#define TF_HasVirtual 0x0020 /* Has one or more VIRTUAL columns */
|
|
-#define TF_HasStored 0x0040 /* Has one or more STORED columns */
|
|
-#define TF_HasGenerated 0x0060 /* Combo: HasVirtual + HasStored */
|
|
-#define TF_WithoutRowid 0x0080 /* No rowid. PRIMARY KEY is the key */
|
|
-#define TF_StatsUsed 0x0100 /* Query planner decisions affected by
|
|
+** TF_HasVirtual == COLFLAG_VIRTUAL
|
|
+** TF_HasStored == COLFLAG_STORED
|
|
+** TF_HasHidden == COLFLAG_HIDDEN
|
|
+*/
|
|
+#define TF_Readonly 0x00000001 /* Read-only system table */
|
|
+#define TF_HasHidden 0x00000002 /* Has one or more hidden columns */
|
|
+#define TF_HasPrimaryKey 0x00000004 /* Table has a primary key */
|
|
+#define TF_Autoincrement 0x00000008 /* Integer primary key is autoincrement */
|
|
+#define TF_HasStat1 0x00000010 /* nRowLogEst set from sqlite_stat1 */
|
|
+#define TF_HasVirtual 0x00000020 /* Has one or more VIRTUAL columns */
|
|
+#define TF_HasStored 0x00000040 /* Has one or more STORED columns */
|
|
+#define TF_HasGenerated 0x00000060 /* Combo: HasVirtual + HasStored */
|
|
+#define TF_WithoutRowid 0x00000080 /* No rowid. PRIMARY KEY is the key */
|
|
+#define TF_StatsUsed 0x00000100 /* Query planner decisions affected by
|
|
** Index.aiRowLogEst[] values */
|
|
-#define TF_NoVisibleRowid 0x0200 /* No user-visible "rowid" column */
|
|
-#define TF_OOOHidden 0x0400 /* Out-of-Order hidden columns */
|
|
-#define TF_HasNotNull 0x0800 /* Contains NOT NULL constraints */
|
|
-#define TF_Shadow 0x1000 /* True for a shadow table */
|
|
+#define TF_NoVisibleRowid 0x00000200 /* No user-visible "rowid" column */
|
|
+#define TF_OOOHidden 0x00000400 /* Out-of-Order hidden columns */
|
|
+#define TF_HasNotNull 0x00000800 /* Contains NOT NULL constraints */
|
|
+#define TF_Shadow 0x00001000 /* True for a shadow table */
|
|
+#define TF_HasStat4 0x00002000 /* STAT4 info available for this table */
|
|
+#define TF_Ephemeral 0x00004000 /* An ephemeral table */
|
|
+#define TF_Eponymous 0x00008000 /* An eponymous virtual table */
|
|
+#define TF_Strict 0x00010000 /* STRICT mode */
|
|
+
|
|
+/*
|
|
+** Allowed values for Table.eTabType
|
|
+*/
|
|
+#define TABTYP_NORM 0 /* Ordinary table */
|
|
+#define TABTYP_VTAB 1 /* Virtual table */
|
|
+#define TABTYP_VIEW 2 /* A view */
|
|
+
|
|
+#define IsView(X) ((X)->eTabType==TABTYP_VIEW)
|
|
+#define IsOrdinaryTable(X) ((X)->eTabType==TABTYP_NORM)
|
|
|
|
/*
|
|
** Test to see whether or not a table is a virtual table. This is
|
|
@@ -17427,9 +17912,12 @@ struct Table {
|
|
** table support is omitted from the build.
|
|
*/
|
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
|
-# define IsVirtual(X) ((X)->nModuleArg)
|
|
+# define IsVirtual(X) ((X)->eTabType==TABTYP_VTAB)
|
|
+# define ExprIsVtab(X) \
|
|
+ ((X)->op==TK_COLUMN && (X)->y.pTab->eTabType==TABTYP_VTAB)
|
|
#else
|
|
# define IsVirtual(X) 0
|
|
+# define ExprIsVtab(X) 0
|
|
#endif
|
|
|
|
/*
|
|
@@ -17513,16 +18001,22 @@ struct FKey {
|
|
** is returned. REPLACE means that preexisting database rows that caused
|
|
** a UNIQUE constraint violation are removed so that the new insert or
|
|
** update can proceed. Processing continues and no error is reported.
|
|
+** UPDATE applies to insert operations only and means that the insert
|
|
+** is omitted and the DO UPDATE clause of an upsert is run instead.
|
|
**
|
|
-** RESTRICT, SETNULL, and CASCADE actions apply only to foreign keys.
|
|
+** RESTRICT, SETNULL, SETDFLT, and CASCADE actions apply only to foreign keys.
|
|
** RESTRICT is the same as ABORT for IMMEDIATE foreign keys and the
|
|
** same as ROLLBACK for DEFERRED keys. SETNULL means that the foreign
|
|
-** key is set to NULL. CASCADE means that a DELETE or UPDATE of the
|
|
+** key is set to NULL. SETDFLT means that the foreign key is set
|
|
+** to its default value. CASCADE means that a DELETE or UPDATE of the
|
|
** referenced table row is propagated into the row that holds the
|
|
** foreign key.
|
|
**
|
|
+** The OE_Default value is a place holder that means to use whatever
|
|
+** conflict resolution algorthm is required from context.
|
|
+**
|
|
** The following symbolic values are used to record which type
|
|
-** of action to take.
|
|
+** of conflict resolution action to take.
|
|
*/
|
|
#define OE_None 0 /* There is no constraint to check */
|
|
#define OE_Rollback 1 /* Fail the operation and rollback the transaction */
|
|
@@ -17601,6 +18095,11 @@ struct KeyInfo {
|
|
struct UnpackedRecord {
|
|
KeyInfo *pKeyInfo; /* Collation and sort-order information */
|
|
Mem *aMem; /* Values */
|
|
+ union {
|
|
+ char *z; /* Cache of aMem[0].z for vdbeRecordCompareString() */
|
|
+ i64 i; /* Cache of aMem[0].u.i for vdbeRecordCompareInt() */
|
|
+ } u;
|
|
+ int n; /* Cache of aMem[0].n used by vdbeRecordCompareString() */
|
|
u16 nField; /* Number of entries in apMem[] */
|
|
i8 default_rc; /* Comparison result if keys are equal */
|
|
u8 errCode; /* Error detected by xRecordCompare (CORRUPT or NOMEM) */
|
|
@@ -17632,12 +18131,24 @@ struct UnpackedRecord {
|
|
** The Index.onError field determines whether or not the indexed columns
|
|
** must be unique and what to do if they are not. When Index.onError=OE_None,
|
|
** it means this is not a unique index. Otherwise it is a unique index
|
|
-** and the value of Index.onError indicate the which conflict resolution
|
|
-** algorithm to employ whenever an attempt is made to insert a non-unique
|
|
+** and the value of Index.onError indicates which conflict resolution
|
|
+** algorithm to employ when an attempt is made to insert a non-unique
|
|
** element.
|
|
**
|
|
+** The colNotIdxed bitmask is used in combination with SrcItem.colUsed
|
|
+** for a fast test to see if an index can serve as a covering index.
|
|
+** colNotIdxed has a 1 bit for every column of the original table that
|
|
+** is *not* available in the index. Thus the expression
|
|
+** "colUsed & colNotIdxed" will be non-zero if the index is not a
|
|
+** covering index. The most significant bit of of colNotIdxed will always
|
|
+** be true (note-20221022-a). If a column beyond the 63rd column of the
|
|
+** table is used, the "colUsed & colNotIdxed" test will always be non-zero
|
|
+** and we have to assume either that the index is not covering, or use
|
|
+** an alternative (slower) algorithm to determine whether or not
|
|
+** the index is covering.
|
|
+**
|
|
** While parsing a CREATE TABLE or CREATE INDEX statement in order to
|
|
-** generate VDBE code (as opposed to parsing one read from an sqlite_master
|
|
+** generate VDBE code (as opposed to parsing one read from an sqlite_schema
|
|
** table as part of parsing an existing database schema), transient instances
|
|
** of this structure may be created. In this case the Index.tnum variable is
|
|
** used to store the address of a VDBE instruction, not a database page
|
|
@@ -17656,7 +18167,7 @@ struct Index {
|
|
const char **azColl; /* Array of collation sequence names for index */
|
|
Expr *pPartIdxWhere; /* WHERE clause for partial indices */
|
|
ExprList *aColExpr; /* Column expressions */
|
|
- int tnum; /* DB Page containing root of this index */
|
|
+ Pgno tnum; /* DB Page containing root of this index */
|
|
LogEst szIdxRow; /* Estimated average row size in bytes */
|
|
u16 nKeyCol; /* Number of columns forming the key */
|
|
u16 nColumn; /* Number of columns stored in the index */
|
|
@@ -17671,6 +18182,8 @@ struct Index {
|
|
unsigned bNoQuery:1; /* Do not use this index to optimize queries */
|
|
unsigned bAscKeyBug:1; /* True if the bba7b69f9849b5bf bug applies */
|
|
unsigned bHasVCol:1; /* Index references one or more VIRTUAL columns */
|
|
+ unsigned bHasExpr:1; /* Index contains an expression, either a literal
|
|
+ ** expression, or a reference to a VIRTUAL column */
|
|
#ifdef SQLITE_ENABLE_STAT4
|
|
int nSample; /* Number of elements in aSample[] */
|
|
int nSampleCol; /* Size of IndexSample.anEq[] and so on */
|
|
@@ -17679,7 +18192,7 @@ struct Index {
|
|
tRowcnt *aiRowEst; /* Non-logarithmic stat1 data for this index */
|
|
tRowcnt nRowEst0; /* Non-logarithmic number of rows in the index */
|
|
#endif
|
|
- Bitmask colNotIdxed; /* 0 for unindexed columns in pTab */
|
|
+ Bitmask colNotIdxed; /* Unindexed columns in pTab */
|
|
};
|
|
|
|
/*
|
|
@@ -17741,7 +18254,7 @@ struct Token {
|
|
** code for a SELECT that contains aggregate functions.
|
|
**
|
|
** If Expr.op==TK_AGG_COLUMN or TK_AGG_FUNCTION then Expr.pAggInfo is a
|
|
-** pointer to this structure. The Expr.iColumn field is the index in
|
|
+** pointer to this structure. The Expr.iAgg field is the index in
|
|
** AggInfo.aCol[] or AggInfo.aFunc[] of information needed to generate
|
|
** code for that node.
|
|
**
|
|
@@ -17754,32 +18267,46 @@ struct AggInfo {
|
|
** from source tables rather than from accumulators */
|
|
u8 useSortingIdx; /* In direct mode, reference the sorting index rather
|
|
** than the source table */
|
|
+ u16 nSortingColumn; /* Number of columns in the sorting index */
|
|
int sortingIdx; /* Cursor number of the sorting index */
|
|
int sortingIdxPTab; /* Cursor number of pseudo-table */
|
|
- int nSortingColumn; /* Number of columns in the sorting index */
|
|
- int mnReg, mxReg; /* Range of registers allocated for aCol and aFunc */
|
|
+ int iFirstReg; /* First register in range for aCol[] and aFunc[] */
|
|
ExprList *pGroupBy; /* The group by clause */
|
|
struct AggInfo_col { /* For each column used in source tables */
|
|
Table *pTab; /* Source table */
|
|
+ Expr *pCExpr; /* The original expression */
|
|
int iTable; /* Cursor number of the source table */
|
|
- int iColumn; /* Column number within the source table */
|
|
- int iSorterColumn; /* Column number in the sorting index */
|
|
- int iMem; /* Memory location that acts as accumulator */
|
|
- Expr *pExpr; /* The original expression */
|
|
+ i16 iColumn; /* Column number within the source table */
|
|
+ i16 iSorterColumn; /* Column number in the sorting index */
|
|
} *aCol;
|
|
int nColumn; /* Number of used entries in aCol[] */
|
|
int nAccumulator; /* Number of columns that show through to the output.
|
|
** Additional columns are used only as parameters to
|
|
** aggregate functions */
|
|
struct AggInfo_func { /* For each aggregate function */
|
|
- Expr *pExpr; /* Expression encoding the function */
|
|
+ Expr *pFExpr; /* Expression encoding the function */
|
|
FuncDef *pFunc; /* The aggregate function implementation */
|
|
- int iMem; /* Memory location that acts as accumulator */
|
|
int iDistinct; /* Ephemeral table used to enforce DISTINCT */
|
|
+ int iDistAddr; /* Address of OP_OpenEphemeral */
|
|
} *aFunc;
|
|
int nFunc; /* Number of entries in aFunc[] */
|
|
+ u32 selId; /* Select to which this AggInfo belongs */
|
|
+#ifdef SQLITE_DEBUG
|
|
+ Select *pSelect; /* SELECT statement that this AggInfo supports */
|
|
+#endif
|
|
};
|
|
|
|
+/*
|
|
+** Macros to compute aCol[] and aFunc[] register numbers.
|
|
+**
|
|
+** These macros should not be used prior to the call to
|
|
+** assignAggregateRegisters() that computes the value of pAggInfo->iFirstReg.
|
|
+** The assert()s that are part of this macro verify that constraint.
|
|
+*/
|
|
+#define AggInfoColumnReg(A,I) (assert((A)->iFirstReg),(A)->iFirstReg+(I))
|
|
+#define AggInfoFuncReg(A,I) \
|
|
+ (assert((A)->iFirstReg),(A)->iFirstReg+(A)->nColumn+(I))
|
|
+
|
|
/*
|
|
** The datatype ynVar is a signed integer, either 16-bit or 32-bit.
|
|
** Usually it is 16-bits. But if SQLITE_MAX_VARIABLE_NUMBER is greater
|
|
@@ -17787,10 +18314,10 @@ struct AggInfo {
|
|
** it uses less memory in the Expr object, which is a big memory user
|
|
** in systems with lots of prepared statements. And few applications
|
|
** need more than about 10 or 20 variables. But some extreme users want
|
|
-** to have prepared statements with over 32767 variables, and for them
|
|
+** to have prepared statements with over 32766 variables, and for them
|
|
** the option is available (at compile-time).
|
|
*/
|
|
-#if SQLITE_MAX_VARIABLE_NUMBER<=32767
|
|
+#if SQLITE_MAX_VARIABLE_NUMBER<32767
|
|
typedef i16 ynVar;
|
|
#else
|
|
typedef int ynVar;
|
|
@@ -17807,10 +18334,10 @@ typedef int ynVar;
|
|
** tree.
|
|
**
|
|
** If the expression is an SQL literal (TK_INTEGER, TK_FLOAT, TK_BLOB,
|
|
-** or TK_STRING), then Expr.token contains the text of the SQL literal. If
|
|
-** the expression is a variable (TK_VARIABLE), then Expr.token contains the
|
|
+** or TK_STRING), then Expr.u.zToken contains the text of the SQL literal. If
|
|
+** the expression is a variable (TK_VARIABLE), then Expr.u.zToken contains the
|
|
** variable name. Finally, if the expression is an SQL function (TK_FUNCTION),
|
|
-** then Expr.token contains the name of the function.
|
|
+** then Expr.u.zToken contains the name of the function.
|
|
**
|
|
** Expr.pRight and Expr.pLeft are the left and right subexpressions of a
|
|
** binary operator. Either or both may be NULL.
|
|
@@ -17850,7 +18377,7 @@ typedef int ynVar;
|
|
** help reduce memory requirements, sometimes an Expr object will be
|
|
** truncated. And to reduce the number of memory allocations, sometimes
|
|
** two or more Expr objects will be stored in a single memory allocation,
|
|
-** together with Expr.zToken strings.
|
|
+** together with Expr.u.zToken strings.
|
|
**
|
|
** If the EP_Reduced and EP_TokenOnly flags are set when
|
|
** an Expr object is truncated. When EP_Reduced is set, then all
|
|
@@ -17866,6 +18393,9 @@ struct Expr {
|
|
** TK_COLUMN: the value of p5 for OP_Column
|
|
** TK_AGG_FUNCTION: nesting depth
|
|
** TK_FUNCTION: NC_SelfRef flag if needs OP_PureFunc */
|
|
+#ifdef SQLITE_DEBUG
|
|
+ u8 vvaFlags; /* Verification flags. */
|
|
+#endif
|
|
u32 flags; /* Various flags. EP_* See below */
|
|
union {
|
|
char *zToken; /* Token value. Zero terminated and dequoted */
|
|
@@ -17903,7 +18433,10 @@ struct Expr {
|
|
** TK_VARIABLE: variable number (always >= 1).
|
|
** TK_SELECT_COLUMN: column of the result vector */
|
|
i16 iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */
|
|
- i16 iRightJoinTable; /* If EP_FromJoin, the right table of the join */
|
|
+ union {
|
|
+ int iJoin; /* If EP_OuterON or EP_InnerON, the right table */
|
|
+ int iOfst; /* else: start of token from start of statement */
|
|
+ } w;
|
|
AggInfo *pAggInfo; /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */
|
|
union {
|
|
Table *pTab; /* TK_COLUMN: Table containing column. Can be NULL
|
|
@@ -17916,36 +18449,35 @@ struct Expr {
|
|
} y;
|
|
};
|
|
|
|
-/*
|
|
-** The following are the meanings of bits in the Expr.flags field.
|
|
+/* The following are the meanings of bits in the Expr.flags field.
|
|
** Value restrictions:
|
|
**
|
|
** EP_Agg == NC_HasAgg == SF_HasAgg
|
|
** EP_Win == NC_HasWin
|
|
*/
|
|
-#define EP_FromJoin 0x000001 /* Originates in ON/USING clause of outer join */
|
|
-#define EP_Distinct 0x000002 /* Aggregate function with DISTINCT keyword */
|
|
-#define EP_HasFunc 0x000004 /* Contains one or more functions of any kind */
|
|
-#define EP_FixedCol 0x000008 /* TK_Column with a known fixed value */
|
|
+#define EP_OuterON 0x000001 /* Originates in ON/USING clause of outer join */
|
|
+#define EP_InnerON 0x000002 /* Originates in ON/USING of an inner join */
|
|
+#define EP_Distinct 0x000004 /* Aggregate function with DISTINCT keyword */
|
|
+#define EP_HasFunc 0x000008 /* Contains one or more functions of any kind */
|
|
#define EP_Agg 0x000010 /* Contains one or more aggregate functions */
|
|
-#define EP_VarSelect 0x000020 /* pSelect is correlated, not constant */
|
|
-#define EP_DblQuoted 0x000040 /* token.z was originally in "..." */
|
|
-#define EP_InfixFunc 0x000080 /* True for an infix function: LIKE, GLOB, etc */
|
|
-#define EP_Collate 0x000100 /* Tree contains a TK_COLLATE operator */
|
|
-#define EP_Commuted 0x000200 /* Comparison operator has been commuted */
|
|
-#define EP_IntValue 0x000400 /* Integer value contained in u.iValue */
|
|
-#define EP_xIsSelect 0x000800 /* x.pSelect is valid (otherwise x.pList is) */
|
|
-#define EP_Skip 0x001000 /* Operator does not contribute to affinity */
|
|
-#define EP_Reduced 0x002000 /* Expr struct EXPR_REDUCEDSIZE bytes only */
|
|
-#define EP_TokenOnly 0x004000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */
|
|
+#define EP_FixedCol 0x000020 /* TK_Column with a known fixed value */
|
|
+#define EP_VarSelect 0x000040 /* pSelect is correlated, not constant */
|
|
+#define EP_DblQuoted 0x000080 /* token.z was originally in "..." */
|
|
+#define EP_InfixFunc 0x000100 /* True for an infix function: LIKE, GLOB, etc */
|
|
+#define EP_Collate 0x000200 /* Tree contains a TK_COLLATE operator */
|
|
+#define EP_Commuted 0x000400 /* Comparison operator has been commuted */
|
|
+#define EP_IntValue 0x000800 /* Integer value contained in u.iValue */
|
|
+#define EP_xIsSelect 0x001000 /* x.pSelect is valid (otherwise x.pList is) */
|
|
+#define EP_Skip 0x002000 /* Operator does not contribute to affinity */
|
|
+#define EP_Reduced 0x004000 /* Expr struct EXPR_REDUCEDSIZE bytes only */
|
|
#define EP_Win 0x008000 /* Contains window functions */
|
|
-#define EP_MemToken 0x010000 /* Need to sqlite3DbFree() Expr.zToken */
|
|
-#define EP_NoReduce 0x020000 /* Cannot EXPRDUP_REDUCE this Expr */
|
|
-#define EP_Unlikely 0x040000 /* unlikely() or likelihood() function */
|
|
-#define EP_ConstFunc 0x080000 /* A SQLITE_FUNC_CONSTANT or _SLOCHNG function */
|
|
-#define EP_CanBeNull 0x100000 /* Can be null despite NOT NULL constraint */
|
|
-#define EP_Subquery 0x200000 /* Tree contains a TK_SELECT operator */
|
|
-#define EP_Alias 0x400000 /* Is an alias for a result set column */
|
|
+#define EP_TokenOnly 0x010000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */
|
|
+ /* 0x020000 // Available for reuse */
|
|
+#define EP_IfNullRow 0x040000 /* The TK_IF_NULL_ROW opcode */
|
|
+#define EP_Unlikely 0x080000 /* unlikely() or likelihood() function */
|
|
+#define EP_ConstFunc 0x100000 /* A SQLITE_FUNC_CONSTANT or _SLOCHNG function */
|
|
+#define EP_CanBeNull 0x200000 /* Can be null despite NOT NULL constraint */
|
|
+#define EP_Subquery 0x400000 /* Tree contains a TK_SELECT operator */
|
|
#define EP_Leaf 0x800000 /* Expr.pLeft, .pRight, .u.pSelect all NULL */
|
|
#define EP_WinFunc 0x1000000 /* TK_FUNCTION with Expr.y.pWin set */
|
|
#define EP_Subrtn 0x2000000 /* Uses Expr.y.sub. TK_IN, _SELECT, or _EXISTS */
|
|
@@ -17953,33 +18485,52 @@ struct Expr {
|
|
#define EP_Static 0x8000000 /* Held in memory not obtained from malloc() */
|
|
#define EP_IsTrue 0x10000000 /* Always has boolean value of TRUE */
|
|
#define EP_IsFalse 0x20000000 /* Always has boolean value of FALSE */
|
|
-#define EP_FromDDL 0x40000000 /* Originates from sqlite_master */
|
|
+#define EP_FromDDL 0x40000000 /* Originates from sqlite_schema */
|
|
+ /* 0x80000000 // Available */
|
|
|
|
-/*
|
|
-** The EP_Propagate mask is a set of properties that automatically propagate
|
|
+/* The EP_Propagate mask is a set of properties that automatically propagate
|
|
** upwards into parent nodes.
|
|
*/
|
|
#define EP_Propagate (EP_Collate|EP_Subquery|EP_HasFunc)
|
|
|
|
-/*
|
|
-** These macros can be used to test, set, or clear bits in the
|
|
+/* Macros can be used to test, set, or clear bits in the
|
|
** Expr.flags field.
|
|
*/
|
|
#define ExprHasProperty(E,P) (((E)->flags&(P))!=0)
|
|
#define ExprHasAllProperty(E,P) (((E)->flags&(P))==(P))
|
|
#define ExprSetProperty(E,P) (E)->flags|=(P)
|
|
#define ExprClearProperty(E,P) (E)->flags&=~(P)
|
|
-#define ExprAlwaysTrue(E) (((E)->flags&(EP_FromJoin|EP_IsTrue))==EP_IsTrue)
|
|
-#define ExprAlwaysFalse(E) (((E)->flags&(EP_FromJoin|EP_IsFalse))==EP_IsFalse)
|
|
+#define ExprAlwaysTrue(E) (((E)->flags&(EP_OuterON|EP_IsTrue))==EP_IsTrue)
|
|
+#define ExprAlwaysFalse(E) (((E)->flags&(EP_OuterON|EP_IsFalse))==EP_IsFalse)
|
|
+
|
|
+/* 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 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)
|
|
+#define ExprUseYWin(E) (((E)->flags&EP_WinFunc)!=0)
|
|
+#define ExprUseYSub(E) (((E)->flags&EP_Subrtn)!=0)
|
|
+
|
|
+/* Flags for use with Expr.vvaFlags
|
|
+*/
|
|
+#define EP_NoReduce 0x01 /* Cannot EXPRDUP_REDUCE this Expr */
|
|
+#define EP_Immutable 0x02 /* Do not change this Expr node */
|
|
|
|
/* The ExprSetVVAProperty() macro is used for Verification, Validation,
|
|
** and Accreditation only. It works like ExprSetProperty() during VVA
|
|
** processes but is a no-op for delivery.
|
|
*/
|
|
#ifdef SQLITE_DEBUG
|
|
-# define ExprSetVVAProperty(E,P) (E)->flags|=(P)
|
|
+# define ExprSetVVAProperty(E,P) (E)->vvaFlags|=(P)
|
|
+# define ExprHasVVAProperty(E,P) (((E)->vvaFlags&(P))!=0)
|
|
+# define ExprClearVVAProperties(E) (E)->vvaFlags = 0
|
|
#else
|
|
# define ExprSetVVAProperty(E,P)
|
|
+# define ExprHasVVAProperty(E,P) 0
|
|
+# define ExprClearVVAProperties(E)
|
|
#endif
|
|
|
|
/*
|
|
@@ -18033,21 +18584,29 @@ struct Expr {
|
|
*/
|
|
struct ExprList {
|
|
int nExpr; /* Number of expressions on the list */
|
|
+ int nAlloc; /* Number of a[] slots allocated */
|
|
struct ExprList_item { /* For each expression in the list */
|
|
Expr *pExpr; /* The parse tree for this expression */
|
|
char *zEName; /* Token associated with this expression */
|
|
- u8 sortFlags; /* Mask of KEYINFO_ORDER_* flags */
|
|
- unsigned eEName :2; /* Meaning of zEName */
|
|
- unsigned done :1; /* A flag to indicate when processing is finished */
|
|
- unsigned reusable :1; /* Constant expression is reusable */
|
|
- unsigned bSorterRef :1; /* Defer evaluation until after sorting */
|
|
- unsigned bNulls: 1; /* True if explicit "NULLS FIRST/LAST" */
|
|
+ struct {
|
|
+ u8 sortFlags; /* Mask of KEYINFO_ORDER_* flags */
|
|
+ unsigned eEName :2; /* Meaning of zEName */
|
|
+ unsigned done :1; /* Indicates when processing is finished */
|
|
+ unsigned reusable :1; /* Constant expression is reusable */
|
|
+ unsigned bSorterRef :1; /* Defer evaluation until after sorting */
|
|
+ unsigned bNulls :1; /* True if explicit "NULLS FIRST/LAST" */
|
|
+ unsigned bUsed :1; /* This column used in a SF_NestedFrom subquery */
|
|
+ unsigned bUsingTerm:1; /* Term from the USING clause of a NestedFrom */
|
|
+ unsigned bNoExpand: 1; /* Term is an auxiliary in NestedFrom and should
|
|
+ ** not be expanded by "*" in parent queries */
|
|
+ } fg;
|
|
union {
|
|
- struct {
|
|
+ struct { /* Used by any ExprList other than Parse.pConsExpr */
|
|
u16 iOrderByCol; /* For ORDER BY, column number in result set */
|
|
u16 iAlias; /* Index into Parse.aAlias[] for zName */
|
|
} x;
|
|
- int iConstExprReg; /* Register in which Expr value is cached */
|
|
+ int iConstExprReg; /* Register in which Expr value is cached. Used only
|
|
+ ** by Parse.pConstExpr */
|
|
} u;
|
|
} a[1]; /* One slot for each expression in the list */
|
|
};
|
|
@@ -18075,23 +18634,28 @@ struct ExprList {
|
|
** If "a" is the k-th column of table "t", then IdList.a[0].idx==k.
|
|
*/
|
|
struct IdList {
|
|
+ int nId; /* Number of identifiers on the list */
|
|
+ u8 eU4; /* Which element of a.u4 is valid */
|
|
struct IdList_item {
|
|
char *zName; /* Name of the identifier */
|
|
- int idx; /* Index in some Table.aCol[] of a column named zName */
|
|
- } *a;
|
|
- int nId; /* Number of identifiers on the list */
|
|
+ union {
|
|
+ int idx; /* Index in some Table.aCol[] of a column named zName */
|
|
+ Expr *pExpr; /* Expr to implement a USING variable -- NOT USED */
|
|
+ } u4;
|
|
+ } a[1];
|
|
};
|
|
|
|
/*
|
|
-** The following structure describes the FROM clause of a SELECT statement.
|
|
-** Each table or subquery in the FROM clause is a separate element of
|
|
-** the SrcList.a[] array.
|
|
-**
|
|
-** With the addition of multiple database support, the following structure
|
|
-** can also be used to describe a particular table such as the table that
|
|
-** is modified by an INSERT, DELETE, or UPDATE statement. In standard SQL,
|
|
-** such a table must be a simple name: ID. But in SQLite, the table can
|
|
-** now be identified by a database name, a dot, then the table name: ID.ID.
|
|
+** Allowed values for IdList.eType, which determines which value of the a.u4
|
|
+** is valid.
|
|
+*/
|
|
+#define EU4_NONE 0 /* Does not use IdList.a.u4 */
|
|
+#define EU4_IDX 1 /* Uses IdList.a.u4.idx */
|
|
+#define EU4_EXPR 2 /* Uses IdList.a.u4.pExpr -- NOT CURRENTLY USED */
|
|
+
|
|
+/*
|
|
+** The SrcItem object represents a single term in the FROM clause of a query.
|
|
+** The SrcList object is mostly an array of SrcItems.
|
|
**
|
|
** The jointype starts out showing the join type between the current table
|
|
** and the next table on the list. The parser builds the list this way.
|
|
@@ -18100,53 +18664,91 @@ struct IdList {
|
|
**
|
|
** In the colUsed field, the high-order bit (bit 63) is set if the table
|
|
** contains more than 63 columns and the 64-th or later column is used.
|
|
+**
|
|
+** Union member validity:
|
|
+**
|
|
+** u1.zIndexedBy fg.isIndexedBy && !fg.isTabFunc
|
|
+** u1.pFuncArg fg.isTabFunc && !fg.isIndexedBy
|
|
+** u2.pIBIndex fg.isIndexedBy && !fg.isCte
|
|
+** u2.pCteUse fg.isCte && !fg.isIndexedBy
|
|
+*/
|
|
+struct SrcItem {
|
|
+ Schema *pSchema; /* Schema to which this item is fixed */
|
|
+ char *zDatabase; /* Name of database holding this table */
|
|
+ char *zName; /* Name of the table */
|
|
+ char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */
|
|
+ Table *pTab; /* An SQL table corresponding to zName */
|
|
+ Select *pSelect; /* A SELECT statement used in place of a table name */
|
|
+ int addrFillSub; /* Address of subroutine to manifest a subquery */
|
|
+ int regReturn; /* Register holding return address of addrFillSub */
|
|
+ int regResult; /* Registers holding results of a co-routine */
|
|
+ struct {
|
|
+ u8 jointype; /* Type of join between this table and the previous */
|
|
+ unsigned notIndexed :1; /* True if there is a NOT INDEXED clause */
|
|
+ unsigned isIndexedBy :1; /* True if there is an INDEXED BY clause */
|
|
+ unsigned isTabFunc :1; /* True if table-valued-function syntax */
|
|
+ unsigned isCorrelated :1; /* True if sub-query is correlated */
|
|
+ unsigned isMaterialized:1; /* This is a materialized view */
|
|
+ unsigned viaCoroutine :1; /* Implemented as a co-routine */
|
|
+ unsigned isRecursive :1; /* True for recursive reference in WITH */
|
|
+ unsigned fromDDL :1; /* Comes from sqlite_schema */
|
|
+ unsigned isCte :1; /* This is a CTE */
|
|
+ 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 isNestedFrom :1; /* pSelect is a SF_NestedFrom subquery */
|
|
+ } fg;
|
|
+ int iCursor; /* The VDBE cursor number used to access this table */
|
|
+ union {
|
|
+ Expr *pOn; /* fg.isUsing==0 => The ON clause of a join */
|
|
+ IdList *pUsing; /* fg.isUsing==1 => The USING clause of a join */
|
|
+ } u3;
|
|
+ Bitmask colUsed; /* Bit N set if column N used. Details above for N>62 */
|
|
+ union {
|
|
+ char *zIndexedBy; /* Identifier from "INDEXED BY <zIndex>" clause */
|
|
+ ExprList *pFuncArg; /* Arguments to table-valued-function */
|
|
+ } u1;
|
|
+ union {
|
|
+ Index *pIBIndex; /* Index structure corresponding to u1.zIndexedBy */
|
|
+ CteUse *pCteUse; /* CTE Usage info when fg.isCte is true */
|
|
+ } u2;
|
|
+};
|
|
+
|
|
+/*
|
|
+** The OnOrUsing object represents either an ON clause or a USING clause.
|
|
+** It can never be both at the same time, but it can be neither.
|
|
+*/
|
|
+struct OnOrUsing {
|
|
+ Expr *pOn; /* The ON clause of a join */
|
|
+ IdList *pUsing; /* The USING clause of a join */
|
|
+};
|
|
+
|
|
+/*
|
|
+** This object represents one or more tables that are the source of
|
|
+** content for an SQL statement. For example, a single SrcList object
|
|
+** is used to hold the FROM clause of a SELECT statement. SrcList also
|
|
+** represents the target tables for DELETE, INSERT, and UPDATE statements.
|
|
+**
|
|
*/
|
|
struct SrcList {
|
|
int nSrc; /* Number of tables or subqueries in the FROM clause */
|
|
u32 nAlloc; /* Number of entries allocated in a[] below */
|
|
- struct SrcList_item {
|
|
- Schema *pSchema; /* Schema to which this item is fixed */
|
|
- char *zDatabase; /* Name of database holding this table */
|
|
- char *zName; /* Name of the table */
|
|
- char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */
|
|
- Table *pTab; /* An SQL table corresponding to zName */
|
|
- Select *pSelect; /* A SELECT statement used in place of a table name */
|
|
- int addrFillSub; /* Address of subroutine to manifest a subquery */
|
|
- int regReturn; /* Register holding return address of addrFillSub */
|
|
- int regResult; /* Registers holding results of a co-routine */
|
|
- struct {
|
|
- u8 jointype; /* Type of join between this table and the previous */
|
|
- unsigned notIndexed :1; /* True if there is a NOT INDEXED clause */
|
|
- unsigned isIndexedBy :1; /* True if there is an INDEXED BY clause */
|
|
- unsigned isTabFunc :1; /* True if table-valued-function syntax */
|
|
- unsigned isCorrelated :1; /* True if sub-query is correlated */
|
|
- unsigned viaCoroutine :1; /* Implemented as a co-routine */
|
|
- unsigned isRecursive :1; /* True for recursive reference in WITH */
|
|
- unsigned fromDDL :1; /* Comes from sqlite_master */
|
|
- } fg;
|
|
- int iCursor; /* The VDBE cursor number used to access this table */
|
|
- Expr *pOn; /* The ON clause of a join */
|
|
- IdList *pUsing; /* The USING clause of a join */
|
|
- Bitmask colUsed; /* Bit N (1<<N) set if column N of pTab is used */
|
|
- union {
|
|
- char *zIndexedBy; /* Identifier from "INDEXED BY <zIndex>" clause */
|
|
- ExprList *pFuncArg; /* Arguments to table-valued-function */
|
|
- } u1;
|
|
- Index *pIBIndex; /* Index structure corresponding to u1.zIndexedBy */
|
|
- } a[1]; /* One entry for each identifier on the list */
|
|
+ SrcItem a[1]; /* One entry for each identifier on the list */
|
|
};
|
|
|
|
/*
|
|
** Permitted values of the SrcList.a.jointype field
|
|
*/
|
|
-#define JT_INNER 0x0001 /* Any kind of inner or cross join */
|
|
-#define JT_CROSS 0x0002 /* Explicit use of the CROSS keyword */
|
|
-#define JT_NATURAL 0x0004 /* True for a "natural" join */
|
|
-#define JT_LEFT 0x0008 /* Left outer join */
|
|
-#define JT_RIGHT 0x0010 /* Right outer join */
|
|
-#define JT_OUTER 0x0020 /* The "OUTER" keyword is present */
|
|
-#define JT_ERROR 0x0040 /* unknown or unsupported join type */
|
|
-
|
|
+#define JT_INNER 0x01 /* Any kind of inner or cross join */
|
|
+#define JT_CROSS 0x02 /* Explicit use of the CROSS keyword */
|
|
+#define JT_NATURAL 0x04 /* True for a "natural" join */
|
|
+#define JT_LEFT 0x08 /* Left outer join */
|
|
+#define JT_RIGHT 0x10 /* Right outer join */
|
|
+#define JT_OUTER 0x20 /* The "OUTER" keyword is present */
|
|
+#define JT_LTORJ 0x40 /* One of the LEFT operands of a RIGHT JOIN
|
|
+ ** Mnemonic: Left Table Of Right Join */
|
|
+#define JT_ERROR 0x80 /* unknown or unsupported join type */
|
|
|
|
/*
|
|
** Flags appropriate for the wctrlFlags parameter of sqlite3WhereBegin()
|
|
@@ -18167,9 +18769,9 @@ struct SrcList {
|
|
#define WHERE_DISTINCTBY 0x0080 /* pOrderby is really a DISTINCT clause */
|
|
#define WHERE_WANT_DISTINCT 0x0100 /* All output needs to be distinct */
|
|
#define WHERE_SORTBYGROUP 0x0200 /* Support sqlite3WhereIsSorted() */
|
|
-#define WHERE_SEEK_TABLE 0x0400 /* Do not defer seeks on main table */
|
|
+#define WHERE_AGG_DISTINCT 0x0400 /* Query is "SELECT agg(DISTINCT ...)" */
|
|
#define WHERE_ORDERBY_LIMIT 0x0800 /* ORDERBY+LIMIT on the inner loop */
|
|
-#define WHERE_SEEK_UNIQ_TABLE 0x1000 /* Do not defer seeks if unique */
|
|
+#define WHERE_RIGHT_JOIN 0x1000 /* Processing a RIGHT JOIN */
|
|
/* 0x2000 not currently used */
|
|
#define WHERE_USE_LIMIT 0x4000 /* Use the LIMIT in cost estimates */
|
|
/* 0x8000 not currently used */
|
|
@@ -18209,10 +18811,11 @@ struct NameContext {
|
|
ExprList *pEList; /* Optional list of result-set columns */
|
|
AggInfo *pAggInfo; /* Information about aggregates at this level */
|
|
Upsert *pUpsert; /* ON CONFLICT clause information from an upsert */
|
|
+ int iBaseReg; /* For TK_REGISTER when parsing RETURNING */
|
|
} uNC;
|
|
NameContext *pNext; /* Next outer name context. NULL for outermost */
|
|
int nRef; /* Number of names resolved by this context */
|
|
- int nErr; /* Number of errors encountered while resolving names */
|
|
+ int nNcErr; /* Number of errors encountered while resolving names */
|
|
int ncFlags; /* Zero or more NC_* flags defined below */
|
|
Select *pWinSelect; /* SELECT statement for any window functions */
|
|
};
|
|
@@ -18221,29 +18824,33 @@ struct NameContext {
|
|
** Allowed values for the NameContext, ncFlags field.
|
|
**
|
|
** Value constraints (all checked via assert()):
|
|
-** NC_HasAgg == SF_HasAgg == EP_Agg
|
|
-** NC_MinMaxAgg == SF_MinMaxAgg == SQLITE_FUNC_MINMAX
|
|
+** NC_HasAgg == SF_HasAgg == EP_Agg
|
|
+** NC_MinMaxAgg == SF_MinMaxAgg == SQLITE_FUNC_MINMAX
|
|
+** NC_OrderAgg == SF_OrderByReqd == SQLITE_FUNC_ANYORDER
|
|
** NC_HasWin == EP_Win
|
|
**
|
|
*/
|
|
-#define NC_AllowAgg 0x00001 /* Aggregate functions are allowed here */
|
|
-#define NC_PartIdx 0x00002 /* True if resolving a partial index WHERE */
|
|
-#define NC_IsCheck 0x00004 /* True if resolving a CHECK constraint */
|
|
-#define NC_GenCol 0x00008 /* True for a GENERATED ALWAYS AS clause */
|
|
-#define NC_HasAgg 0x00010 /* One or more aggregate functions seen */
|
|
-#define NC_IdxExpr 0x00020 /* True if resolving columns of CREATE INDEX */
|
|
-#define NC_SelfRef 0x0002e /* Combo: PartIdx, isCheck, GenCol, and IdxExpr */
|
|
-#define NC_VarSelect 0x00040 /* A correlated subquery has been seen */
|
|
-#define NC_UEList 0x00080 /* True if uNC.pEList is used */
|
|
-#define NC_UAggInfo 0x00100 /* True if uNC.pAggInfo is used */
|
|
-#define NC_UUpsert 0x00200 /* True if uNC.pUpsert is used */
|
|
-#define NC_MinMaxAgg 0x01000 /* min/max aggregates seen. See note above */
|
|
-#define NC_Complex 0x02000 /* True if a function or subquery seen */
|
|
-#define NC_AllowWin 0x04000 /* Window functions are allowed here */
|
|
-#define NC_HasWin 0x08000 /* One or more window functions seen */
|
|
-#define NC_IsDDL 0x10000 /* Resolving names in a CREATE statement */
|
|
-#define NC_InAggFunc 0x20000 /* True if analyzing arguments to an agg func */
|
|
-#define NC_FromDDL 0x40000 /* SQL text comes from sqlite_master */
|
|
+#define NC_AllowAgg 0x000001 /* Aggregate functions are allowed here */
|
|
+#define NC_PartIdx 0x000002 /* True if resolving a partial index WHERE */
|
|
+#define NC_IsCheck 0x000004 /* True if resolving a CHECK constraint */
|
|
+#define NC_GenCol 0x000008 /* True for a GENERATED ALWAYS AS clause */
|
|
+#define NC_HasAgg 0x000010 /* One or more aggregate functions seen */
|
|
+#define NC_IdxExpr 0x000020 /* True if resolving columns of CREATE INDEX */
|
|
+#define NC_SelfRef 0x00002e /* Combo: PartIdx, isCheck, GenCol, and IdxExpr */
|
|
+#define NC_Subquery 0x000040 /* A subquery has been seen */
|
|
+#define NC_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 */
|
|
+#define NC_UBaseReg 0x000400 /* True if uNC.iBaseReg is used */
|
|
+#define NC_MinMaxAgg 0x001000 /* min/max aggregates seen. See note above */
|
|
+#define NC_Complex 0x002000 /* True if a function or subquery seen */
|
|
+#define NC_AllowWin 0x004000 /* Window functions are allowed here */
|
|
+#define NC_HasWin 0x008000 /* One or more window functions seen */
|
|
+#define NC_IsDDL 0x010000 /* Resolving names in a CREATE statement */
|
|
+#define NC_InAggFunc 0x020000 /* True if analyzing arguments to an agg func */
|
|
+#define NC_FromDDL 0x040000 /* SQL text comes from sqlite_schema */
|
|
+#define NC_NoSelect 0x080000 /* Do not descend into sub-selects */
|
|
+#define NC_OrderAgg 0x8000000 /* Has an aggregate other than count/min/max */
|
|
|
|
/*
|
|
** An instance of the following object describes a single ON CONFLICT
|
|
@@ -18254,21 +18861,27 @@ struct NameContext {
|
|
** conflict-target clause.) The pUpsertTargetWhere is the optional
|
|
** WHERE clause used to identify partial unique indexes.
|
|
**
|
|
-** pUpsertSet is the list of column=expr terms of the UPDATE statement.
|
|
+** pUpsertSet is the list of column=expr terms of the UPDATE statement.
|
|
** The pUpsertSet field is NULL for a ON CONFLICT DO NOTHING. The
|
|
** pUpsertWhere is the WHERE clause for the UPDATE and is NULL if the
|
|
** WHERE clause is omitted.
|
|
*/
|
|
struct Upsert {
|
|
- ExprList *pUpsertTarget; /* Optional description of conflicting index */
|
|
+ ExprList *pUpsertTarget; /* Optional description of conflict target */
|
|
Expr *pUpsertTargetWhere; /* WHERE clause for partial index targets */
|
|
ExprList *pUpsertSet; /* The SET clause from an ON CONFLICT UPDATE */
|
|
Expr *pUpsertWhere; /* WHERE clause for the ON CONFLICT UPDATE */
|
|
- /* The fields above comprise the parse tree for the upsert clause.
|
|
- ** The fields below are used to transfer information from the INSERT
|
|
- ** processing down into the UPDATE processing while generating code.
|
|
- ** Upsert owns the memory allocated above, but not the memory below. */
|
|
- Index *pUpsertIdx; /* Constraint that pUpsertTarget identifies */
|
|
+ Upsert *pNextUpsert; /* Next ON CONFLICT clause in the list */
|
|
+ u8 isDoUpdate; /* True for DO UPDATE. False for DO NOTHING */
|
|
+ /* Above this point is the parse tree for the ON CONFLICT clauses.
|
|
+ ** The next group of fields stores intermediate data. */
|
|
+ void *pToFree; /* Free memory when deleting the Upsert object */
|
|
+ /* All fields above are owned by the Upsert object and must be freed
|
|
+ ** when the Upsert is destroyed. The fields below are used to transfer
|
|
+ ** information from the INSERT processing down into the UPDATE processing
|
|
+ ** while generating code. The fields below are owned by the INSERT
|
|
+ ** statement and will be freed by INSERT processing. */
|
|
+ Index *pUpsertIdx; /* UNIQUE constraint specified by pUpsertTarget */
|
|
SrcList *pUpsertSrc; /* Table to be updated */
|
|
int regData; /* First register holding array of VALUES */
|
|
int iDataCur; /* Index of the data cursor */
|
|
@@ -18320,9 +18933,10 @@ struct Select {
|
|
** "Select Flag".
|
|
**
|
|
** Value constraints (all checked via assert())
|
|
-** SF_HasAgg == NC_HasAgg
|
|
-** SF_MinMaxAgg == NC_MinMaxAgg == SQLITE_FUNC_MINMAX
|
|
-** SF_FixedLimit == WHERE_USE_LIMIT
|
|
+** SF_HasAgg == NC_HasAgg
|
|
+** SF_MinMaxAgg == NC_MinMaxAgg == SQLITE_FUNC_MINMAX
|
|
+** SF_OrderByReqd == NC_OrderAgg == SQLITE_FUNC_ANYORDER
|
|
+** SF_FixedLimit == WHERE_USE_LIMIT
|
|
*/
|
|
#define SF_Distinct 0x0000001 /* Output should be DISTINCT */
|
|
#define SF_All 0x0000002 /* Includes the ALL keyword */
|
|
@@ -18346,6 +18960,16 @@ struct Select {
|
|
#define SF_WhereBegin 0x0080000 /* Really a WhereBegin() call. Debug Only */
|
|
#define SF_WinRewrite 0x0100000 /* Window function rewrite accomplished */
|
|
#define SF_View 0x0200000 /* SELECT statement is a view */
|
|
+#define SF_NoopOrderBy 0x0400000 /* ORDER BY is ignored for this query */
|
|
+#define SF_UFSrcCheck 0x0800000 /* Check pSrc as required by UPDATE...FROM */
|
|
+#define SF_PushDown 0x1000000 /* SELECT has be modified by push-down opt */
|
|
+#define SF_MultiPart 0x2000000 /* Has multiple incompatible PARTITIONs */
|
|
+#define SF_CopyCte 0x4000000 /* SELECT statement is a copy of a CTE */
|
|
+#define SF_OrderByReqd 0x8000000 /* The ORDER BY clause may not be omitted */
|
|
+#define SF_UpdateFrom 0x10000000 /* Query originates with UPDATE FROM */
|
|
+
|
|
+/* True if S exists and has SF_NestedFrom */
|
|
+#define IsNestedFrom(S) ((S)!=0 && ((S)->selFlags&SF_NestedFrom)!=0)
|
|
|
|
/*
|
|
** The results of a SELECT can be distributed in several ways, as defined
|
|
@@ -18364,9 +18988,6 @@ struct Select {
|
|
** statements within triggers whose only purpose is
|
|
** the side-effects of functions.
|
|
**
|
|
-** All of the above are free to ignore their ORDER BY clause. Those that
|
|
-** follow must honor the ORDER BY clause.
|
|
-**
|
|
** SRT_Output Generate a row of output (using the OP_ResultRow
|
|
** opcode) for each row in the result set.
|
|
**
|
|
@@ -18410,18 +19031,31 @@ struct Select {
|
|
** SRT_DistQueue Store results in priority queue pDest->iSDParm only if
|
|
** the same record has never been stored before. The
|
|
** index at pDest->iSDParm+1 hold all prior stores.
|
|
+**
|
|
+** SRT_Upfrom Store results in the temporary table already opened by
|
|
+** pDest->iSDParm. If (pDest->iSDParm<0), then the temp
|
|
+** table is an intkey table - in this case the first
|
|
+** column returned by the SELECT is used as the integer
|
|
+** key. If (pDest->iSDParm>0), then the table is an index
|
|
+** table. (pDest->iSDParm) is the number of key columns in
|
|
+** each index record in this case.
|
|
*/
|
|
#define SRT_Union 1 /* Store result as keys in an index */
|
|
#define SRT_Except 2 /* Remove result from a UNION index */
|
|
#define SRT_Exists 3 /* Store 1 if the result is not empty */
|
|
#define SRT_Discard 4 /* Do not save the results anywhere */
|
|
-#define SRT_Fifo 5 /* Store result as data with an automatic rowid */
|
|
-#define SRT_DistFifo 6 /* Like SRT_Fifo, but unique results only */
|
|
+#define SRT_DistFifo 5 /* Like SRT_Fifo, but unique results only */
|
|
+#define SRT_DistQueue 6 /* Like SRT_Queue, but unique results only */
|
|
+
|
|
+/* The DISTINCT clause is ignored for all of the above. Not that
|
|
+** IgnorableDistinct() implies IgnorableOrderby() */
|
|
+#define IgnorableDistinct(X) ((X->eDest)<=SRT_DistQueue)
|
|
+
|
|
#define SRT_Queue 7 /* Store result in an queue */
|
|
-#define SRT_DistQueue 8 /* Like SRT_Queue, but unique results only */
|
|
+#define SRT_Fifo 8 /* Store result as data with an automatic rowid */
|
|
|
|
/* The ORDER BY clause is ignored for all of the above */
|
|
-#define IgnorableOrderby(X) ((X->eDest)<=SRT_DistQueue)
|
|
+#define IgnorableOrderby(X) ((X->eDest)<=SRT_Fifo)
|
|
|
|
#define SRT_Output 9 /* Output each row of result */
|
|
#define SRT_Mem 10 /* Store result in a memory cell */
|
|
@@ -18429,17 +19063,19 @@ struct Select {
|
|
#define SRT_EphemTab 12 /* Create transient tab and store like SRT_Table */
|
|
#define SRT_Coroutine 13 /* Generate a single row of result */
|
|
#define SRT_Table 14 /* Store result as data with an automatic rowid */
|
|
+#define SRT_Upfrom 15 /* Store result as data with rowid */
|
|
|
|
/*
|
|
** An instance of this object describes where to put of the results of
|
|
** a SELECT statement.
|
|
*/
|
|
struct SelectDest {
|
|
- u8 eDest; /* How to dispose of the results. On of SRT_* above. */
|
|
+ u8 eDest; /* How to dispose of the results. One of SRT_* above. */
|
|
int iSDParm; /* A parameter used by the eDest disposal method */
|
|
+ int iSDParm2; /* A second parameter for the eDest disposal method */
|
|
int iSdst; /* Base register where results are written */
|
|
int nSdst; /* Number of registers allocated */
|
|
- char *zAffSdst; /* Affinity used when eDest==SRT_Set */
|
|
+ char *zAffSdst; /* Affinity used for SRT_Set */
|
|
ExprList *pOrderBy; /* Key columns for SRT_Queue and SRT_DistQueue */
|
|
};
|
|
|
|
@@ -18498,11 +19134,45 @@ struct TriggerPrg {
|
|
#else
|
|
typedef unsigned int yDbMask;
|
|
# define DbMaskTest(M,I) (((M)&(((yDbMask)1)<<(I)))!=0)
|
|
-# define DbMaskZero(M) (M)=0
|
|
-# define DbMaskSet(M,I) (M)|=(((yDbMask)1)<<(I))
|
|
-# define DbMaskAllZero(M) (M)==0
|
|
-# define DbMaskNonZero(M) (M)!=0
|
|
+# define DbMaskZero(M) ((M)=0)
|
|
+# define DbMaskSet(M,I) ((M)|=(((yDbMask)1)<<(I)))
|
|
+# define DbMaskAllZero(M) ((M)==0)
|
|
+# define DbMaskNonZero(M) ((M)!=0)
|
|
+#endif
|
|
+
|
|
+/*
|
|
+** For each index X that has as one of its arguments either an expression
|
|
+** or the name of a virtual generated column, and if X is in scope such that
|
|
+** the value of the expression can simply be read from the index, then
|
|
+** there is an instance of this object on the Parse.pIdxExpr list.
|
|
+**
|
|
+** During code generation, while generating code to evaluate expressions,
|
|
+** this list is consulted and if a matching expression is found, the value
|
|
+** is read from the index rather than being recomputed.
|
|
+*/
|
|
+struct IndexedExpr {
|
|
+ Expr *pExpr; /* The expression contained in the index */
|
|
+ int iDataCur; /* The data cursor associated with the index */
|
|
+ int iIdxCur; /* The index cursor */
|
|
+ int iIdxCol; /* The index column that contains value of pExpr */
|
|
+ u8 bMaybeNullRow; /* True if we need an OP_IfNullRow check */
|
|
+ u8 aff; /* Affinity of the pExpr expression */
|
|
+ IndexedExpr *pIENext; /* Next in a list of all indexed expressions */
|
|
+#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
|
|
+ const char *zIdxName; /* Name of index, used only for bytecode comments */
|
|
#endif
|
|
+};
|
|
+
|
|
+/*
|
|
+** An instance of the ParseCleanup object specifies an operation that
|
|
+** should be performed after parsing to deallocation resources obtained
|
|
+** during the parse and which are no longer needed.
|
|
+*/
|
|
+struct ParseCleanup {
|
|
+ ParseCleanup *pNext; /* Next cleanup task */
|
|
+ void *pPtr; /* Pointer to object to deallocate */
|
|
+ void (*xCleanup)(sqlite3*,void*); /* Deallocation routine */
|
|
+};
|
|
|
|
/*
|
|
** An SQL parser context. A copy of this structure is passed through
|
|
@@ -18534,7 +19204,14 @@ struct Parse {
|
|
u8 hasCompound; /* Need to invoke convertCompoundSelectToSubquery() */
|
|
u8 okConstFactor; /* OK to factor out constants */
|
|
u8 disableLookaside; /* Number of times lookaside has been disabled */
|
|
- u8 disableVtab; /* Disable all virtual tables for this parse */
|
|
+ u8 prepFlags; /* SQLITE_PREPARE_* flags */
|
|
+ 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 */
|
|
int nErr; /* Number of errors seen */
|
|
@@ -18547,6 +19224,7 @@ struct Parse {
|
|
int nLabelAlloc; /* Number of slots in aLabel */
|
|
int *aLabel; /* Space to hold the labels */
|
|
ExprList *pConstExpr;/* Constant expressions */
|
|
+ IndexedExpr *pIdxEpr;/* List of expressions used by active indexes */
|
|
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 */
|
|
@@ -18561,12 +19239,20 @@ struct Parse {
|
|
AutoincInfo *pAinc; /* Information about AUTOINCREMENT counters */
|
|
Parse *pToplevel; /* Parse structure for main program (or NULL) */
|
|
Table *pTriggerTab; /* Table triggers are being coded for */
|
|
- Parse *pParentParse; /* Parent parser if this parser is nested */
|
|
- int addrCrTab; /* Address of OP_CreateBtree opcode on CREATE TABLE */
|
|
+ TriggerPrg *pTriggerPrg; /* Linked list of coded triggers */
|
|
+ ParseCleanup *pCleanup; /* List of cleanup operations to run after parse */
|
|
+ union {
|
|
+ int addrCrTab; /* Address of OP_CreateBtree on CREATE TABLE */
|
|
+ Returning *pReturning; /* The RETURNING clause */
|
|
+ } u1;
|
|
u32 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
|
|
u8 eTriggerOp; /* TK_UPDATE, TK_INSERT or TK_DELETE */
|
|
+ u8 bReturning; /* Coding a RETURNING trigger */
|
|
u8 eOrconf; /* Default ON CONFLICT policy for trigger steps */
|
|
u8 disableTriggers; /* True to disable triggers */
|
|
|
|
@@ -18578,6 +19264,7 @@ struct Parse {
|
|
**************************************************************************/
|
|
|
|
int aTempReg[8]; /* Holding area for temporary registers */
|
|
+ Parse *pOuterParse; /* Outer Parse object when nested */
|
|
Token sNameToken; /* Token with unqualified schema object name */
|
|
|
|
/************************************************************************
|
|
@@ -18591,9 +19278,7 @@ struct Parse {
|
|
ynVar nVar; /* Number of '?' variables seen in the SQL so far */
|
|
u8 iPkSortOrder; /* ASC or DESC for INTEGER PRIMARY KEY */
|
|
u8 explain; /* True if the EXPLAIN flag is found on the query */
|
|
-#if !(defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_OMIT_ALTERTABLE))
|
|
u8 eParseMode; /* PARSE_MODE_XXX constant */
|
|
-#endif
|
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
|
int nVtabLock; /* Number of virtual tables to lock */
|
|
#endif
|
|
@@ -18614,15 +19299,14 @@ struct Parse {
|
|
Token sArg; /* Complete text of a module argument */
|
|
Table **apVtabLock; /* Pointer to virtual tables needing locking */
|
|
#endif
|
|
- Table *pZombieTab; /* List of Table objects to delete after code gen */
|
|
- TriggerPrg *pTriggerPrg; /* Linked list of coded triggers */
|
|
With *pWith; /* Current WITH clause, or NULL */
|
|
- With *pWithToFree; /* Free this WITH object at the end of the parse */
|
|
#ifndef SQLITE_OMIT_ALTERTABLE
|
|
RenameToken *pRename; /* Tokens subject to renaming by ALTER TABLE */
|
|
#endif
|
|
};
|
|
|
|
+/* Allowed values for Parse.eParseMode
|
|
+*/
|
|
#define PARSE_MODE_NORMAL 0
|
|
#define PARSE_MODE_DECLARE_VTAB 1
|
|
#define PARSE_MODE_RENAME 2
|
|
@@ -18631,7 +19315,8 @@ struct Parse {
|
|
/*
|
|
** Sizes and pointers of various parts of the Parse object.
|
|
*/
|
|
-#define PARSE_HDR_SZ offsetof(Parse,aTempReg) /* Recursive part w/o aColCache*/
|
|
+#define PARSE_HDR(X) (((char*)(X))+offsetof(Parse,zErrMsg))
|
|
+#define PARSE_HDR_SZ (offsetof(Parse,aTempReg)-offsetof(Parse,zErrMsg)) /* Recursive part w/o aColCache*/
|
|
#define PARSE_RECURSE_SZ offsetof(Parse,sLastToken) /* Recursive part */
|
|
#define PARSE_TAIL_SZ (sizeof(Parse)-PARSE_RECURSE_SZ) /* Non-recursive part */
|
|
#define PARSE_TAIL(X) (((char*)(X))+PARSE_RECURSE_SZ) /* Pointer to tail */
|
|
@@ -18697,27 +19382,29 @@ struct AuthContext {
|
|
#define OPFLAG_SAVEPOSITION 0x02 /* OP_Delete/Insert: save cursor pos */
|
|
#define OPFLAG_AUXDELETE 0x04 /* OP_Delete: index in a DELETE op */
|
|
#define OPFLAG_NOCHNG_MAGIC 0x6d /* OP_MakeRecord: serialtype 10 is ok */
|
|
+#define OPFLAG_PREFORMAT 0x80 /* OP_Insert uses preformatted cell */
|
|
|
|
/*
|
|
- * Each trigger present in the database schema is stored as an instance of
|
|
- * struct Trigger.
|
|
- *
|
|
- * Pointers to instances of struct Trigger are stored in two ways.
|
|
- * 1. In the "trigHash" hash table (part of the sqlite3* that represents the
|
|
- * database). This allows Trigger structures to be retrieved by name.
|
|
- * 2. All triggers associated with a single table form a linked list, using the
|
|
- * pNext member of struct Trigger. A pointer to the first element of the
|
|
- * linked list is stored as the "pTrigger" member of the associated
|
|
- * struct Table.
|
|
- *
|
|
- * The "step_list" member points to the first element of a linked list
|
|
- * containing the SQL statements specified as the trigger program.
|
|
- */
|
|
+** Each trigger present in the database schema is stored as an instance of
|
|
+** struct Trigger.
|
|
+**
|
|
+** Pointers to instances of struct Trigger are stored in two ways.
|
|
+** 1. In the "trigHash" hash table (part of the sqlite3* that represents the
|
|
+** database). This allows Trigger structures to be retrieved by name.
|
|
+** 2. All triggers associated with a single table form a linked list, using the
|
|
+** pNext member of struct Trigger. A pointer to the first element of the
|
|
+** linked list is stored as the "pTrigger" member of the associated
|
|
+** struct Table.
|
|
+**
|
|
+** The "step_list" member points to the first element of a linked list
|
|
+** containing the SQL statements specified as the trigger program.
|
|
+*/
|
|
struct Trigger {
|
|
char *zName; /* The name of the trigger */
|
|
char *table; /* The table or view to which the trigger applies */
|
|
u8 op; /* One of TK_DELETE, TK_UPDATE, TK_INSERT */
|
|
u8 tr_tm; /* One of TRIGGER_BEFORE, TRIGGER_AFTER */
|
|
+ u8 bReturning; /* This trigger implements a RETURNING clause */
|
|
Expr *pWhen; /* The WHEN clause of the expression (may be NULL) */
|
|
IdList *pColumns; /* If this is an UPDATE OF <column-list> trigger,
|
|
the <column-list> is stored here */
|
|
@@ -18738,51 +19425,58 @@ struct Trigger {
|
|
#define TRIGGER_AFTER 2
|
|
|
|
/*
|
|
- * An instance of struct TriggerStep is used to store a single SQL statement
|
|
- * that is a part of a trigger-program.
|
|
- *
|
|
- * Instances of struct TriggerStep are stored in a singly linked list (linked
|
|
- * using the "pNext" member) referenced by the "step_list" member of the
|
|
- * associated struct Trigger instance. The first element of the linked list is
|
|
- * the first step of the trigger-program.
|
|
- *
|
|
- * The "op" member indicates whether this is a "DELETE", "INSERT", "UPDATE" or
|
|
- * "SELECT" statement. The meanings of the other members is determined by the
|
|
- * value of "op" as follows:
|
|
- *
|
|
- * (op == TK_INSERT)
|
|
- * orconf -> stores the ON CONFLICT algorithm
|
|
- * pSelect -> If this is an INSERT INTO ... SELECT ... statement, then
|
|
- * this stores a pointer to the SELECT statement. Otherwise NULL.
|
|
- * zTarget -> Dequoted name of the table to insert into.
|
|
- * pExprList -> If this is an INSERT INTO ... VALUES ... statement, then
|
|
- * this stores values to be inserted. Otherwise NULL.
|
|
- * pIdList -> If this is an INSERT INTO ... (<column-names>) VALUES ...
|
|
- * statement, then this stores the column-names to be
|
|
- * inserted into.
|
|
- *
|
|
- * (op == TK_DELETE)
|
|
- * zTarget -> Dequoted name of the table to delete from.
|
|
- * pWhere -> The WHERE clause of the DELETE statement if one is specified.
|
|
- * Otherwise NULL.
|
|
- *
|
|
- * (op == TK_UPDATE)
|
|
- * zTarget -> Dequoted name of the table to update.
|
|
- * pWhere -> The WHERE clause of the UPDATE statement if one is specified.
|
|
- * Otherwise NULL.
|
|
- * pExprList -> A list of the columns to update and the expressions to update
|
|
- * them to. See sqlite3Update() documentation of "pChanges"
|
|
- * argument.
|
|
- *
|
|
- */
|
|
+** An instance of struct TriggerStep is used to store a single SQL statement
|
|
+** that is a part of a trigger-program.
|
|
+**
|
|
+** Instances of struct TriggerStep are stored in a singly linked list (linked
|
|
+** using the "pNext" member) referenced by the "step_list" member of the
|
|
+** associated struct Trigger instance. The first element of the linked list is
|
|
+** the first step of the trigger-program.
|
|
+**
|
|
+** The "op" member indicates whether this is a "DELETE", "INSERT", "UPDATE" or
|
|
+** "SELECT" statement. The meanings of the other members is determined by the
|
|
+** value of "op" as follows:
|
|
+**
|
|
+** (op == TK_INSERT)
|
|
+** orconf -> stores the ON CONFLICT algorithm
|
|
+** pSelect -> The content to be inserted - either a SELECT statement or
|
|
+** a VALUES clause.
|
|
+** zTarget -> Dequoted name of the table to insert into.
|
|
+** pIdList -> If this is an INSERT INTO ... (<column-names>) VALUES ...
|
|
+** statement, then this stores the column-names to be
|
|
+** inserted into.
|
|
+** pUpsert -> The ON CONFLICT clauses for an Upsert
|
|
+**
|
|
+** (op == TK_DELETE)
|
|
+** zTarget -> Dequoted name of the table to delete from.
|
|
+** pWhere -> The WHERE clause of the DELETE statement if one is specified.
|
|
+** Otherwise NULL.
|
|
+**
|
|
+** (op == TK_UPDATE)
|
|
+** zTarget -> Dequoted name of the table to update.
|
|
+** pWhere -> The WHERE clause of the UPDATE statement if one is specified.
|
|
+** Otherwise NULL.
|
|
+** pExprList -> A list of the columns to update and the expressions to update
|
|
+** them to. See sqlite3Update() documentation of "pChanges"
|
|
+** argument.
|
|
+**
|
|
+** (op == TK_SELECT)
|
|
+** pSelect -> The SELECT statement
|
|
+**
|
|
+** (op == TK_RETURNING)
|
|
+** pExprList -> The list of expressions that follow the RETURNING keyword.
|
|
+**
|
|
+*/
|
|
struct TriggerStep {
|
|
- u8 op; /* One of TK_DELETE, TK_UPDATE, TK_INSERT, TK_SELECT */
|
|
+ u8 op; /* One of TK_DELETE, TK_UPDATE, TK_INSERT, TK_SELECT,
|
|
+ ** or TK_RETURNING */
|
|
u8 orconf; /* OE_Rollback etc. */
|
|
Trigger *pTrig; /* The trigger that this step is a part of */
|
|
Select *pSelect; /* SELECT statement or RHS of INSERT INTO SELECT ... */
|
|
char *zTarget; /* Target table for DELETE, UPDATE, INSERT */
|
|
+ SrcList *pFrom; /* FROM clause for UPDATE statement (if any) */
|
|
Expr *pWhere; /* The WHERE clause for DELETE or UPDATE steps */
|
|
- ExprList *pExprList; /* SET clause for UPDATE */
|
|
+ ExprList *pExprList; /* SET clause for UPDATE, or RETURNING clause */
|
|
IdList *pIdList; /* Column names for INSERT */
|
|
Upsert *pUpsert; /* Upsert clauses on an INSERT */
|
|
char *zSpan; /* Original SQL text of this command */
|
|
@@ -18791,18 +19485,16 @@ struct TriggerStep {
|
|
};
|
|
|
|
/*
|
|
-** The following structure contains information used by the sqliteFix...
|
|
-** routines as they walk the parse tree to make database references
|
|
-** explicit.
|
|
+** Information about a RETURNING clause
|
|
*/
|
|
-typedef struct DbFixer DbFixer;
|
|
-struct DbFixer {
|
|
- Parse *pParse; /* The parsing context. Error messages written here */
|
|
- Schema *pSchema; /* Fix items to this schema */
|
|
- u8 bTemp; /* True for TEMP schema entries */
|
|
- const char *zDb; /* Make sure all objects are contained in this database */
|
|
- const char *zType; /* Type of the container - used for error messages */
|
|
- const Token *pName; /* Name of the container - used for error messages */
|
|
+struct Returning {
|
|
+ Parse *pParse; /* The parse that includes the RETURNING clause */
|
|
+ ExprList *pReturnEL; /* List of expressions to return */
|
|
+ Trigger retTrig; /* The transient trigger that implements RETURNING */
|
|
+ TriggerStep retTStep; /* The trigger step */
|
|
+ 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 */
|
|
};
|
|
|
|
/*
|
|
@@ -18836,12 +19528,32 @@ typedef struct {
|
|
int rc; /* Result code stored here */
|
|
u32 mInitFlags; /* Flags controlling error messages */
|
|
u32 nInitRow; /* Number of rows processed */
|
|
+ Pgno mxPage; /* Maximum page number. 0 for no limit. */
|
|
} InitData;
|
|
|
|
/*
|
|
** Allowed values for mInitFlags
|
|
*/
|
|
-#define INITFLAG_AlterTable 0x0001 /* This is a reparse after ALTER TABLE */
|
|
+#define INITFLAG_AlterMask 0x0003 /* Types of ALTER */
|
|
+#define INITFLAG_AlterRename 0x0001 /* Reparse after a RENAME */
|
|
+#define INITFLAG_AlterDrop 0x0002 /* Reparse after a DROP COLUMN */
|
|
+#define INITFLAG_AlterAdd 0x0003 /* Reparse after an ADD COLUMN */
|
|
+
|
|
+/* 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
|
|
+** be used on trunk check-ins. They are a temporary mechanism available
|
|
+** for transient development builds only.
|
|
+**
|
|
+** Tuning parameters are numbered starting with 1.
|
|
+*/
|
|
+#define SQLITE_NTUNE 6 /* Should be zero for all trunk check-ins */
|
|
+#ifdef SQLITE_DEBUG
|
|
+# define Tuning(X) (sqlite3Config.aTune[(X)-1])
|
|
+#else
|
|
+# define Tuning(X) 0
|
|
+#endif
|
|
|
|
/*
|
|
** Structure containing global configuration data for the SQLite library.
|
|
@@ -18897,16 +19609,21 @@ struct Sqlite3Config {
|
|
void (*xVdbeBranch)(void*,unsigned iSrcLine,u8 eThis,u8 eMx); /* Callback */
|
|
void *pVdbeBranchArg; /* 1st argument */
|
|
#endif
|
|
-#ifdef SQLITE_ENABLE_DESERIALIZE
|
|
+#ifndef SQLITE_OMIT_DESERIALIZE
|
|
sqlite3_int64 mxMemdbSize; /* Default max memdb size */
|
|
#endif
|
|
#ifndef SQLITE_UNTESTABLE
|
|
int (*xTestCallback)(int); /* Invoked by sqlite3FaultSim() */
|
|
#endif
|
|
int bLocaltimeFault; /* True to fail localtime() calls */
|
|
+ int (*xAltLocaltime)(const void*,void*); /* Alternative localtime() routine */
|
|
int iOnceResetThreshold; /* When to reset OP_Once counters */
|
|
u32 szSorterRef; /* Min size in bytes to use sorter-refs */
|
|
unsigned int iPrngSeed; /* Alternative fixed seed for the PRNG */
|
|
+ /* vvvv--- must be last ---vvv */
|
|
+#ifdef SQLITE_DEBUG
|
|
+ sqlite3_int64 aTune[SQLITE_NTUNE]; /* Tuning parameters */
|
|
+#endif
|
|
};
|
|
|
|
/*
|
|
@@ -18942,20 +19659,37 @@ struct Walker {
|
|
int n; /* A counter */
|
|
int iCur; /* A cursor number */
|
|
SrcList *pSrcList; /* FROM clause */
|
|
- struct SrcCount *pSrcCount; /* Counting column references */
|
|
struct CCurHint *pCCurHint; /* Used by codeCursorHint() */
|
|
+ struct RefSrcList *pRefSrcList; /* sqlite3ReferencesSrcList() */
|
|
int *aiCol; /* array of column indexes */
|
|
struct IdxCover *pIdxCover; /* Check for index coverage */
|
|
- struct IdxExprTrans *pIdxTrans; /* Convert idxed expr to column */
|
|
ExprList *pGroupBy; /* GROUP BY clause */
|
|
Select *pSelect; /* HAVING to WHERE clause ctx */
|
|
struct WindowRewrite *pRewrite; /* Window rewrite context */
|
|
struct WhereConst *pConst; /* WHERE clause constants */
|
|
struct RenameCtx *pRename; /* RENAME COLUMN context */
|
|
struct Table *pTab; /* Table of generated column */
|
|
+ struct CoveringIndexCheck *pCovIdxCk; /* Check for covering index */
|
|
+ SrcItem *pSrcItem; /* A single FROM clause item */
|
|
+ DbFixer *pFix; /* See sqlite3FixSelect() */
|
|
} u;
|
|
};
|
|
|
|
+/*
|
|
+** The following structure contains information used by the sqliteFix...
|
|
+** routines as they walk the parse tree to make database references
|
|
+** explicit.
|
|
+*/
|
|
+struct DbFixer {
|
|
+ Parse *pParse; /* The parsing context. Error messages written here */
|
|
+ Walker w; /* Walker object */
|
|
+ Schema *pSchema; /* Fix items to this schema */
|
|
+ u8 bTemp; /* True for TEMP schema entries */
|
|
+ const char *zDb; /* Make sure all objects are contained in this database */
|
|
+ const char *zType; /* Type of the container - used for error messages */
|
|
+ const Token *pName; /* Name of the container - used for error messages */
|
|
+};
|
|
+
|
|
/* Forward declarations */
|
|
SQLITE_PRIVATE int sqlite3WalkExpr(Walker*, Expr*);
|
|
SQLITE_PRIVATE int sqlite3WalkExprList(Walker*, ExprList*);
|
|
@@ -18965,10 +19699,20 @@ SQLITE_PRIVATE int sqlite3WalkSelectFrom(Walker*, Select*);
|
|
SQLITE_PRIVATE int sqlite3ExprWalkNoop(Walker*, Expr*);
|
|
SQLITE_PRIVATE int sqlite3SelectWalkNoop(Walker*, Select*);
|
|
SQLITE_PRIVATE int sqlite3SelectWalkFail(Walker*, Select*);
|
|
+SQLITE_PRIVATE int sqlite3WalkerDepthIncrease(Walker*,Select*);
|
|
+SQLITE_PRIVATE void sqlite3WalkerDepthDecrease(Walker*,Select*);
|
|
+SQLITE_PRIVATE void sqlite3WalkWinDefnDummyCallback(Walker*,Select*);
|
|
+
|
|
#ifdef SQLITE_DEBUG
|
|
SQLITE_PRIVATE void sqlite3SelectWalkAssert2(Walker*, Select*);
|
|
#endif
|
|
|
|
+#ifndef SQLITE_OMIT_CTE
|
|
+SQLITE_PRIVATE void sqlite3SelectPopWith(Walker*, Select*);
|
|
+#else
|
|
+# define sqlite3SelectPopWith 0
|
|
+#endif
|
|
+
|
|
/*
|
|
** Return code from the parse-tree walking primitives and their
|
|
** callbacks.
|
|
@@ -18978,20 +19722,56 @@ SQLITE_PRIVATE void sqlite3SelectWalkAssert2(Walker*, Select*);
|
|
#define WRC_Abort 2 /* Abandon the tree walk */
|
|
|
|
/*
|
|
-** An instance of this structure represents a set of one or more CTEs
|
|
-** (common table expressions) created by a single WITH clause.
|
|
+** A single common table expression
|
|
+*/
|
|
+struct Cte {
|
|
+ char *zName; /* Name of this CTE */
|
|
+ ExprList *pCols; /* List of explicit column names, or NULL */
|
|
+ Select *pSelect; /* The definition of this CTE */
|
|
+ const char *zCteErr; /* Error message for circular references */
|
|
+ CteUse *pUse; /* Usage information for this CTE */
|
|
+ u8 eM10d; /* The MATERIALIZED flag */
|
|
+};
|
|
+
|
|
+/*
|
|
+** Allowed values for the materialized flag (eM10d):
|
|
+*/
|
|
+#define M10d_Yes 0 /* AS MATERIALIZED */
|
|
+#define M10d_Any 1 /* Not specified. Query planner's choice */
|
|
+#define M10d_No 2 /* AS NOT MATERIALIZED */
|
|
+
|
|
+/*
|
|
+** An instance of the With object represents a WITH clause containing
|
|
+** one or more CTEs (common table expressions).
|
|
*/
|
|
struct With {
|
|
- int nCte; /* Number of CTEs in the WITH clause */
|
|
- With *pOuter; /* Containing WITH clause, or NULL */
|
|
- struct Cte { /* For each CTE in the WITH clause.... */
|
|
- char *zName; /* Name of this CTE */
|
|
- ExprList *pCols; /* List of explicit column names, or NULL */
|
|
- Select *pSelect; /* The definition of this CTE */
|
|
- const char *zCteErr; /* Error message for circular references */
|
|
- } a[1];
|
|
+ int nCte; /* Number of CTEs in the WITH clause */
|
|
+ int bView; /* Belongs to the outermost Select of a view */
|
|
+ With *pOuter; /* Containing WITH clause, or NULL */
|
|
+ Cte a[1]; /* For each CTE in the WITH clause.... */
|
|
+};
|
|
+
|
|
+/*
|
|
+** The Cte object is not guaranteed to persist for the entire duration
|
|
+** of code generation. (The query flattener or other parser tree
|
|
+** edits might delete it.) The following object records information
|
|
+** about each Common Table Expression that must be preserved for the
|
|
+** duration of the parse.
|
|
+**
|
|
+** The CteUse objects are freed using sqlite3ParserAddCleanup() rather
|
|
+** than sqlite3SelectDelete(), which is what enables them to persist
|
|
+** until the end of code generation.
|
|
+*/
|
|
+struct CteUse {
|
|
+ int nUse; /* Number of users of this CTE */
|
|
+ int addrM9e; /* Start of subroutine to compute materialization */
|
|
+ int regRtn; /* Return address register for addrM9e subroutine */
|
|
+ int iCur; /* Ephemeral table holding the materialization */
|
|
+ LogEst nRowEst; /* Estimated number of rows in the table */
|
|
+ u8 eM10d; /* The MATERIALIZED flag */
|
|
};
|
|
|
|
+
|
|
#ifdef SQLITE_DEBUG
|
|
/*
|
|
** An instance of the TreeView object is used for printing the content of
|
|
@@ -19041,7 +19821,7 @@ struct Window {
|
|
Window **ppThis; /* Pointer to this object in Select.pWin list */
|
|
Window *pNextWin; /* Next window function belonging to this SELECT */
|
|
Expr *pFilter; /* The FILTER expression */
|
|
- FuncDef *pFunc; /* The function */
|
|
+ FuncDef *pWFunc; /* The function */
|
|
int iEphCsr; /* Partition buffer or Peer buffer */
|
|
int regAccum; /* Accumulator */
|
|
int regResult; /* Interim result */
|
|
@@ -19065,11 +19845,10 @@ SQLITE_PRIVATE void sqlite3WindowListDelete(sqlite3 *db, Window *p);
|
|
SQLITE_PRIVATE Window *sqlite3WindowAlloc(Parse*, int, int, Expr*, int , Expr*, u8);
|
|
SQLITE_PRIVATE void sqlite3WindowAttach(Parse*, Expr*, Window*);
|
|
SQLITE_PRIVATE void sqlite3WindowLink(Select *pSel, Window *pWin);
|
|
-SQLITE_PRIVATE int sqlite3WindowCompare(Parse*, Window*, Window*, int);
|
|
+SQLITE_PRIVATE int sqlite3WindowCompare(const Parse*, const Window*, const Window*, int);
|
|
SQLITE_PRIVATE void sqlite3WindowCodeInit(Parse*, Select*);
|
|
SQLITE_PRIVATE void sqlite3WindowCodeStep(Parse*, Select*, WhereInfo*, int, int);
|
|
SQLITE_PRIVATE int sqlite3WindowRewrite(Parse*, Select*);
|
|
-SQLITE_PRIVATE int sqlite3ExpandSubquery(Parse*, struct SrcList_item*);
|
|
SQLITE_PRIVATE void sqlite3WindowUpdate(Parse*, Window*, Window*, FuncDef*);
|
|
SQLITE_PRIVATE Window *sqlite3WindowDup(sqlite3 *db, Expr *pOwner, Window *p);
|
|
SQLITE_PRIVATE Window *sqlite3WindowListDup(sqlite3 *db, Window *p);
|
|
@@ -19109,13 +19888,16 @@ SQLITE_PRIVATE int sqlite3CantopenError(int);
|
|
#ifdef SQLITE_DEBUG
|
|
SQLITE_PRIVATE int sqlite3NomemError(int);
|
|
SQLITE_PRIVATE int sqlite3IoerrnomemError(int);
|
|
-SQLITE_PRIVATE int sqlite3CorruptPgnoError(int,Pgno);
|
|
# define SQLITE_NOMEM_BKPT sqlite3NomemError(__LINE__)
|
|
# define SQLITE_IOERR_NOMEM_BKPT sqlite3IoerrnomemError(__LINE__)
|
|
-# define SQLITE_CORRUPT_PGNO(P) sqlite3CorruptPgnoError(__LINE__,(P))
|
|
#else
|
|
# define SQLITE_NOMEM_BKPT SQLITE_NOMEM
|
|
# define SQLITE_IOERR_NOMEM_BKPT SQLITE_IOERR_NOMEM
|
|
+#endif
|
|
+#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_CORRUPT_PGNO)
|
|
+SQLITE_PRIVATE int sqlite3CorruptPgnoError(int,Pgno);
|
|
+# define SQLITE_CORRUPT_PGNO(P) sqlite3CorruptPgnoError(__LINE__,(P))
|
|
+#else
|
|
# define SQLITE_CORRUPT_PGNO(P) sqlite3CorruptError(__LINE__)
|
|
#endif
|
|
|
|
@@ -19195,8 +19977,9 @@ SQLITE_PRIVATE void *sqlite3DbReallocOrFree(sqlite3 *, void *, u64);
|
|
SQLITE_PRIVATE void *sqlite3DbRealloc(sqlite3 *, void *, u64);
|
|
SQLITE_PRIVATE void sqlite3DbFree(sqlite3*, void*);
|
|
SQLITE_PRIVATE void sqlite3DbFreeNN(sqlite3*, void*);
|
|
-SQLITE_PRIVATE int sqlite3MallocSize(void*);
|
|
-SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3*, void*);
|
|
+SQLITE_PRIVATE void sqlite3DbNNFreeNN(sqlite3*, void*);
|
|
+SQLITE_PRIVATE int sqlite3MallocSize(const void*);
|
|
+SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3*, const void*);
|
|
SQLITE_PRIVATE void *sqlite3PageMalloc(int);
|
|
SQLITE_PRIVATE void sqlite3PageFree(void*);
|
|
SQLITE_PRIVATE void sqlite3MemSetDefault(void);
|
|
@@ -19215,12 +19998,14 @@ SQLITE_PRIVATE int sqlite3HeapNearlyFull(void);
|
|
*/
|
|
#ifdef SQLITE_USE_ALLOCA
|
|
# define sqlite3StackAllocRaw(D,N) alloca(N)
|
|
-# define sqlite3StackAllocZero(D,N) memset(alloca(N), 0, N)
|
|
+# define sqlite3StackAllocRawNN(D,N) alloca(N)
|
|
# define sqlite3StackFree(D,P)
|
|
+# define sqlite3StackFreeNN(D,P)
|
|
#else
|
|
# define sqlite3StackAllocRaw(D,N) sqlite3DbMallocRaw(D,N)
|
|
-# define sqlite3StackAllocZero(D,N) sqlite3DbMallocZero(D,N)
|
|
+# define sqlite3StackAllocRawNN(D,N) sqlite3DbMallocRawNN(D,N)
|
|
# define sqlite3StackFree(D,P) sqlite3DbFree(D,P)
|
|
+# define sqlite3StackFreeNN(D,P) sqlite3DbFreeNN(D,P)
|
|
#endif
|
|
|
|
/* Do not allow both MEMSYS5 and MEMSYS3 to be defined together. If they
|
|
@@ -19294,27 +20079,64 @@ SQLITE_PRIVATE void *sqlite3TestTextToPtr(const char*);
|
|
#endif
|
|
|
|
#if defined(SQLITE_DEBUG)
|
|
+SQLITE_PRIVATE void sqlite3TreeViewLine(TreeView*, const char *zFormat, ...);
|
|
SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView*, const Expr*, u8);
|
|
SQLITE_PRIVATE void sqlite3TreeViewBareExprList(TreeView*, const ExprList*, const char*);
|
|
SQLITE_PRIVATE void sqlite3TreeViewExprList(TreeView*, const ExprList*, u8, const char*);
|
|
+SQLITE_PRIVATE void sqlite3TreeViewBareIdList(TreeView*, const IdList*, const char*);
|
|
+SQLITE_PRIVATE void sqlite3TreeViewIdList(TreeView*, const IdList*, u8, const char*);
|
|
+SQLITE_PRIVATE void sqlite3TreeViewColumnList(TreeView*, const Column*, int, u8);
|
|
SQLITE_PRIVATE void sqlite3TreeViewSrcList(TreeView*, const SrcList*);
|
|
SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView*, const Select*, u8);
|
|
SQLITE_PRIVATE void sqlite3TreeViewWith(TreeView*, const With*, u8);
|
|
+SQLITE_PRIVATE void sqlite3TreeViewUpsert(TreeView*, const Upsert*, u8);
|
|
+#if TREETRACE_ENABLED
|
|
+SQLITE_PRIVATE void sqlite3TreeViewDelete(const With*, const SrcList*, const Expr*,
|
|
+ const ExprList*,const Expr*, const Trigger*);
|
|
+SQLITE_PRIVATE void sqlite3TreeViewInsert(const With*, const SrcList*,
|
|
+ const IdList*, const Select*, const ExprList*,
|
|
+ int, const Upsert*, const Trigger*);
|
|
+SQLITE_PRIVATE void sqlite3TreeViewUpdate(const With*, const SrcList*, const ExprList*,
|
|
+ const Expr*, int, const ExprList*, const Expr*,
|
|
+ const Upsert*, const Trigger*);
|
|
+#endif
|
|
+#ifndef SQLITE_OMIT_TRIGGER
|
|
+SQLITE_PRIVATE void sqlite3TreeViewTriggerStep(TreeView*, const TriggerStep*, u8, u8);
|
|
+SQLITE_PRIVATE void sqlite3TreeViewTrigger(TreeView*, const Trigger*, u8, u8);
|
|
+#endif
|
|
#ifndef SQLITE_OMIT_WINDOWFUNC
|
|
SQLITE_PRIVATE void sqlite3TreeViewWindow(TreeView*, const Window*, u8);
|
|
SQLITE_PRIVATE void sqlite3TreeViewWinFunc(TreeView*, const Window*, u8);
|
|
#endif
|
|
+SQLITE_PRIVATE void sqlite3ShowExpr(const Expr*);
|
|
+SQLITE_PRIVATE void sqlite3ShowExprList(const ExprList*);
|
|
+SQLITE_PRIVATE void sqlite3ShowIdList(const IdList*);
|
|
+SQLITE_PRIVATE void sqlite3ShowSrcList(const SrcList*);
|
|
+SQLITE_PRIVATE void sqlite3ShowSelect(const Select*);
|
|
+SQLITE_PRIVATE void sqlite3ShowWith(const With*);
|
|
+SQLITE_PRIVATE void sqlite3ShowUpsert(const Upsert*);
|
|
+#ifndef SQLITE_OMIT_TRIGGER
|
|
+SQLITE_PRIVATE void sqlite3ShowTriggerStep(const TriggerStep*);
|
|
+SQLITE_PRIVATE void sqlite3ShowTriggerStepList(const TriggerStep*);
|
|
+SQLITE_PRIVATE void sqlite3ShowTrigger(const Trigger*);
|
|
+SQLITE_PRIVATE void sqlite3ShowTriggerList(const Trigger*);
|
|
+#endif
|
|
+#ifndef SQLITE_OMIT_WINDOWFUNC
|
|
+SQLITE_PRIVATE void sqlite3ShowWindow(const Window*);
|
|
+SQLITE_PRIVATE void sqlite3ShowWinFunc(const Window*);
|
|
+#endif
|
|
#endif
|
|
-
|
|
|
|
SQLITE_PRIVATE void sqlite3SetString(char **, sqlite3*, const char*);
|
|
+SQLITE_PRIVATE void sqlite3ProgressCheck(Parse*);
|
|
SQLITE_PRIVATE void sqlite3ErrorMsg(Parse*, const char*, ...);
|
|
SQLITE_PRIVATE int sqlite3ErrorToParser(sqlite3*,int);
|
|
SQLITE_PRIVATE void sqlite3Dequote(char*);
|
|
SQLITE_PRIVATE void sqlite3DequoteExpr(Expr*);
|
|
+SQLITE_PRIVATE void sqlite3DequoteToken(Token*);
|
|
SQLITE_PRIVATE void sqlite3TokenInit(Token*,char*);
|
|
SQLITE_PRIVATE int sqlite3KeywordCode(const unsigned char*, int);
|
|
-SQLITE_PRIVATE int sqlite3RunParser(Parse*, const char*, char **);
|
|
+SQLITE_PRIVATE int sqlite3RunParser(Parse*, const char*);
|
|
SQLITE_PRIVATE void sqlite3FinishCoding(Parse*);
|
|
SQLITE_PRIVATE int sqlite3GetTempReg(Parse*);
|
|
SQLITE_PRIVATE void sqlite3ReleaseTempReg(Parse*,int);
|
|
@@ -19331,15 +20153,17 @@ SQLITE_PRIVATE Expr *sqlite3PExpr(Parse*, int, Expr*, Expr*);
|
|
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*, Token*, int);
|
|
-SQLITE_PRIVATE void sqlite3ExprFunctionUsable(Parse*,Expr*,FuncDef*);
|
|
+SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse*,ExprList*, const Token*, int);
|
|
+SQLITE_PRIVATE void sqlite3ExprFunctionUsable(Parse*,const Expr*,const FuncDef*);
|
|
SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse*, Expr*, u32);
|
|
SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3*, Expr*);
|
|
+SQLITE_PRIVATE void sqlite3ExprDeferredDelete(Parse*, Expr*);
|
|
SQLITE_PRIVATE void sqlite3ExprUnmapAndDelete(Parse*, Expr*);
|
|
SQLITE_PRIVATE ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*);
|
|
SQLITE_PRIVATE ExprList *sqlite3ExprListAppendVector(Parse*,ExprList*,IdList*,Expr*);
|
|
+SQLITE_PRIVATE Select *sqlite3ExprListToValues(Parse*, int, ExprList*);
|
|
SQLITE_PRIVATE void sqlite3ExprListSetSortOrder(ExprList*,int,int);
|
|
-SQLITE_PRIVATE void sqlite3ExprListSetName(Parse*,ExprList*,Token*,int);
|
|
+SQLITE_PRIVATE void sqlite3ExprListSetName(Parse*,ExprList*,const Token*,int);
|
|
SQLITE_PRIVATE void sqlite3ExprListSetSpan(Parse*,ExprList*,const char*,const char*);
|
|
SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3*, ExprList*);
|
|
SQLITE_PRIVATE u32 sqlite3ExprListFlags(const ExprList*);
|
|
@@ -19355,11 +20179,16 @@ SQLITE_PRIVATE void sqlite3ResetAllSchemasOfConnection(sqlite3*);
|
|
SQLITE_PRIVATE void sqlite3ResetOneSchema(sqlite3*,int);
|
|
SQLITE_PRIVATE void sqlite3CollapseDatabaseArray(sqlite3*);
|
|
SQLITE_PRIVATE void sqlite3CommitInternalChanges(sqlite3*);
|
|
+SQLITE_PRIVATE void sqlite3ColumnSetExpr(Parse*,Table*,Column*,Expr*);
|
|
+SQLITE_PRIVATE Expr *sqlite3ColumnExpr(Table*,Column*);
|
|
+SQLITE_PRIVATE void sqlite3ColumnSetColl(sqlite3*,Column*,const char*zColl);
|
|
+SQLITE_PRIVATE const char *sqlite3ColumnColl(Column*);
|
|
SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3*,Table*);
|
|
+SQLITE_PRIVATE void sqlite3GenerateColumnNames(Parse *pParse, Select *pSelect);
|
|
SQLITE_PRIVATE int sqlite3ColumnsFromExprList(Parse*,ExprList*,i16*,Column**);
|
|
-SQLITE_PRIVATE void sqlite3SelectAddColumnTypeAndCollation(Parse*,Table*,Select*,char);
|
|
+SQLITE_PRIVATE void sqlite3SubqueryColumnTypes(Parse*,Table*,Select*,char);
|
|
SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse*,Select*,char);
|
|
-SQLITE_PRIVATE void sqlite3OpenMasterTable(Parse *, int);
|
|
+SQLITE_PRIVATE void sqlite3OpenSchemaTable(Parse *, int);
|
|
SQLITE_PRIVATE Index *sqlite3PrimaryKeyIndex(Table*);
|
|
SQLITE_PRIVATE i16 sqlite3TableColumnToIndex(Index*, i16);
|
|
#ifdef SQLITE_OMIT_GENERATED_COLUMNS
|
|
@@ -19375,21 +20204,18 @@ SQLITE_PRIVATE void sqlite3ColumnPropertiesFromName(Table*, Column*);
|
|
#else
|
|
# define sqlite3ColumnPropertiesFromName(T,C) /* no-op */
|
|
#endif
|
|
-SQLITE_PRIVATE void sqlite3AddColumn(Parse*,Token*,Token*);
|
|
+SQLITE_PRIVATE void sqlite3AddColumn(Parse*,Token,Token);
|
|
SQLITE_PRIVATE void sqlite3AddNotNull(Parse*, int);
|
|
SQLITE_PRIVATE void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int, int);
|
|
-SQLITE_PRIVATE void sqlite3AddCheckConstraint(Parse*, Expr*);
|
|
+SQLITE_PRIVATE void sqlite3AddCheckConstraint(Parse*, Expr*, const char*, const char*);
|
|
SQLITE_PRIVATE void sqlite3AddDefaultValue(Parse*,Expr*,const char*,const char*);
|
|
SQLITE_PRIVATE void sqlite3AddCollateType(Parse*, Token*);
|
|
SQLITE_PRIVATE void sqlite3AddGenerated(Parse*,Expr*,Token*);
|
|
-SQLITE_PRIVATE void sqlite3EndTable(Parse*,Token*,Token*,u8,Select*);
|
|
+SQLITE_PRIVATE void sqlite3EndTable(Parse*,Token*,Token*,u32,Select*);
|
|
+SQLITE_PRIVATE void sqlite3AddReturning(Parse*,ExprList*);
|
|
SQLITE_PRIVATE int sqlite3ParseUri(const char*,const char*,unsigned int*,
|
|
sqlite3_vfs**,char**,char **);
|
|
-#ifdef SQLITE_HAS_CODEC
|
|
-SQLITE_PRIVATE int sqlite3CodecQueryParameters(sqlite3*,const char*,const char*);
|
|
-#else
|
|
-# define sqlite3CodecQueryParameters(A,B,C) 0
|
|
-#endif
|
|
+#define sqlite3CodecQueryParameters(A,B,C) 0
|
|
SQLITE_PRIVATE Btree *sqlite3DbNameToBtree(sqlite3*,const char*);
|
|
|
|
#ifdef SQLITE_UNTESTABLE
|
|
@@ -19446,15 +20272,17 @@ SQLITE_PRIVATE void *sqlite3ArrayAllocate(sqlite3*,void*,int,int*,int*);
|
|
SQLITE_PRIVATE IdList *sqlite3IdListAppend(Parse*, IdList*, Token*);
|
|
SQLITE_PRIVATE int sqlite3IdListIndex(IdList*,const char*);
|
|
SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge(Parse*, SrcList*, int, int);
|
|
+SQLITE_PRIVATE SrcList *sqlite3SrcListAppendList(Parse *pParse, SrcList *p1, SrcList *p2);
|
|
SQLITE_PRIVATE SrcList *sqlite3SrcListAppend(Parse*, SrcList*, Token*, Token*);
|
|
SQLITE_PRIVATE SrcList *sqlite3SrcListAppendFromTerm(Parse*, SrcList*, Token*, Token*,
|
|
- Token*, Select*, Expr*, IdList*);
|
|
+ Token*, Select*, OnOrUsing*);
|
|
SQLITE_PRIVATE void sqlite3SrcListIndexedBy(Parse *, SrcList *, Token *);
|
|
SQLITE_PRIVATE void sqlite3SrcListFuncArgs(Parse*, SrcList*, ExprList*);
|
|
-SQLITE_PRIVATE int sqlite3IndexedByLookup(Parse *, struct SrcList_item *);
|
|
-SQLITE_PRIVATE void sqlite3SrcListShiftJoinType(SrcList*);
|
|
+SQLITE_PRIVATE int sqlite3IndexedByLookup(Parse *, SrcItem *);
|
|
+SQLITE_PRIVATE void sqlite3SrcListShiftJoinType(Parse*,SrcList*);
|
|
SQLITE_PRIVATE void sqlite3SrcListAssignCursors(Parse*, SrcList*);
|
|
SQLITE_PRIVATE void sqlite3IdListDelete(sqlite3*, IdList*);
|
|
+SQLITE_PRIVATE void sqlite3ClearOnOrUsing(sqlite3*, OnOrUsing*);
|
|
SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3*, SrcList*);
|
|
SQLITE_PRIVATE Index *sqlite3AllocateIndexObject(sqlite3*,i16,int,char**);
|
|
SQLITE_PRIVATE void sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*,
|
|
@@ -19464,22 +20292,24 @@ SQLITE_PRIVATE int sqlite3Select(Parse*, Select*, SelectDest*);
|
|
SQLITE_PRIVATE Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*,
|
|
Expr*,ExprList*,u32,Expr*);
|
|
SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3*, Select*);
|
|
-SQLITE_PRIVATE void sqlite3SelectReset(Parse*, Select*);
|
|
SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse*, SrcList*);
|
|
SQLITE_PRIVATE int sqlite3IsReadOnly(Parse*, Table*, int);
|
|
SQLITE_PRIVATE void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int);
|
|
#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY)
|
|
SQLITE_PRIVATE Expr *sqlite3LimitWhere(Parse*,SrcList*,Expr*,ExprList*,Expr*,char*);
|
|
#endif
|
|
+SQLITE_PRIVATE void sqlite3CodeChangeCount(Vdbe*,int,const char*);
|
|
SQLITE_PRIVATE void sqlite3DeleteFrom(Parse*, SrcList*, Expr*, ExprList*, Expr*);
|
|
SQLITE_PRIVATE void sqlite3Update(Parse*, SrcList*, ExprList*,Expr*,int,ExprList*,Expr*,
|
|
Upsert*);
|
|
-SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(Parse*,SrcList*,Expr*,ExprList*,ExprList*,u16,int);
|
|
+SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(Parse*,SrcList*,Expr*,ExprList*,
|
|
+ ExprList*,Select*,u16,int);
|
|
SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo*);
|
|
SQLITE_PRIVATE LogEst sqlite3WhereOutputRowCount(WhereInfo*);
|
|
SQLITE_PRIVATE int sqlite3WhereIsDistinct(WhereInfo*);
|
|
SQLITE_PRIVATE int sqlite3WhereIsOrdered(WhereInfo*);
|
|
SQLITE_PRIVATE int sqlite3WhereOrderByLimitOptLabel(WhereInfo*);
|
|
+SQLITE_PRIVATE void sqlite3WhereMinMaxOptEarlyOut(Vdbe*,WhereInfo*);
|
|
SQLITE_PRIVATE int sqlite3WhereIsSorted(WhereInfo*);
|
|
SQLITE_PRIVATE int sqlite3WhereContinueLabel(WhereInfo*);
|
|
SQLITE_PRIVATE int sqlite3WhereBreakLabel(WhereInfo*);
|
|
@@ -19494,11 +20324,11 @@ SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int
|
|
SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse*, int, int, int);
|
|
SQLITE_PRIVATE void sqlite3ExprCode(Parse*, Expr*, int);
|
|
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
|
|
-SQLITE_PRIVATE void sqlite3ExprCodeGeneratedColumn(Parse*, Column*, int);
|
|
+SQLITE_PRIVATE void sqlite3ExprCodeGeneratedColumn(Parse*, Table*, Column*, int);
|
|
#endif
|
|
SQLITE_PRIVATE void sqlite3ExprCodeCopy(Parse*, Expr*, int);
|
|
SQLITE_PRIVATE void sqlite3ExprCodeFactorable(Parse*, Expr*, int);
|
|
-SQLITE_PRIVATE int sqlite3ExprCodeAtInit(Parse*, Expr*, int);
|
|
+SQLITE_PRIVATE int sqlite3ExprCodeRunJustOnce(Parse*, Expr*, int);
|
|
SQLITE_PRIVATE int sqlite3ExprCodeTemp(Parse*, Expr*, int*);
|
|
SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse*, Expr*, int);
|
|
SQLITE_PRIVATE int sqlite3ExprCodeExprList(Parse*, ExprList*, int, int, u8);
|
|
@@ -19513,22 +20343,24 @@ SQLITE_PRIVATE Table *sqlite3FindTable(sqlite3*,const char*, const char*);
|
|
#define LOCATE_VIEW 0x01
|
|
#define LOCATE_NOERR 0x02
|
|
SQLITE_PRIVATE Table *sqlite3LocateTable(Parse*,u32 flags,const char*, const char*);
|
|
-SQLITE_PRIVATE Table *sqlite3LocateTableItem(Parse*,u32 flags,struct SrcList_item *);
|
|
+SQLITE_PRIVATE const char *sqlite3PreferredTableName(const char*);
|
|
+SQLITE_PRIVATE Table *sqlite3LocateTableItem(Parse*,u32 flags,SrcItem *);
|
|
SQLITE_PRIVATE Index *sqlite3FindIndex(sqlite3*,const char*, const char*);
|
|
SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTable(sqlite3*,int,const char*);
|
|
SQLITE_PRIVATE void sqlite3UnlinkAndDeleteIndex(sqlite3*,int,const char*);
|
|
SQLITE_PRIVATE void sqlite3Vacuum(Parse*,Token*,Expr*);
|
|
SQLITE_PRIVATE int sqlite3RunVacuum(char**, sqlite3*, int, sqlite3_value*);
|
|
-SQLITE_PRIVATE char *sqlite3NameFromToken(sqlite3*, Token*);
|
|
-SQLITE_PRIVATE int sqlite3ExprCompare(Parse*,Expr*, Expr*, int);
|
|
-SQLITE_PRIVATE int sqlite3ExprCompareSkip(Expr*, Expr*, int);
|
|
-SQLITE_PRIVATE int sqlite3ExprListCompare(ExprList*, ExprList*, int);
|
|
-SQLITE_PRIVATE int sqlite3ExprImpliesExpr(Parse*,Expr*, Expr*, int);
|
|
+SQLITE_PRIVATE char *sqlite3NameFromToken(sqlite3*, const Token*);
|
|
+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 void sqlite3AggInfoPersistWalkerInit(Walker*,Parse*);
|
|
SQLITE_PRIVATE void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
|
|
SQLITE_PRIVATE void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*);
|
|
SQLITE_PRIVATE int sqlite3ExprCoveredByIndex(Expr*, int iCur, Index *pIdx);
|
|
-SQLITE_PRIVATE int sqlite3FunctionUsesThisSrc(Expr*, SrcList*);
|
|
+SQLITE_PRIVATE int sqlite3ReferencesSrcList(Parse*, Expr*, SrcList*);
|
|
SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse*);
|
|
#ifndef SQLITE_UNTESTABLE
|
|
SQLITE_PRIVATE void sqlite3PrngSaveState(void);
|
|
@@ -19550,10 +20382,11 @@ 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*);
|
|
#ifdef SQLITE_ENABLE_CURSOR_HINTS
|
|
SQLITE_PRIVATE int sqlite3ExprContainsSubquery(Expr*);
|
|
#endif
|
|
-SQLITE_PRIVATE int sqlite3ExprIsInteger(Expr*, int*);
|
|
+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*);
|
|
@@ -19578,20 +20411,26 @@ SQLITE_PRIVATE void sqlite3MayAbort(Parse*);
|
|
SQLITE_PRIVATE void sqlite3HaltConstraint(Parse*, int, int, char*, i8, u8);
|
|
SQLITE_PRIVATE void sqlite3UniqueConstraint(Parse*, int, Index*);
|
|
SQLITE_PRIVATE void sqlite3RowidConstraint(Parse*, int, Table*);
|
|
-SQLITE_PRIVATE Expr *sqlite3ExprDup(sqlite3*,Expr*,int);
|
|
-SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3*,ExprList*,int);
|
|
-SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3*,SrcList*,int);
|
|
-SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3*,IdList*);
|
|
-SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3*,Select*,int);
|
|
+SQLITE_PRIVATE Expr *sqlite3ExprDup(sqlite3*,const Expr*,int);
|
|
+SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3*,const ExprList*,int);
|
|
+SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3*,const SrcList*,int);
|
|
+SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3*,const IdList*);
|
|
+SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3*,const Select*,int);
|
|
SQLITE_PRIVATE FuncDef *sqlite3FunctionSearch(int,const char*);
|
|
SQLITE_PRIVATE void sqlite3InsertBuiltinFuncs(FuncDef*,int);
|
|
SQLITE_PRIVATE FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,u8,u8);
|
|
+SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum*,sqlite3_value*);
|
|
SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void);
|
|
SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void);
|
|
+SQLITE_PRIVATE void sqlite3RegisterJsonFunctions(void);
|
|
SQLITE_PRIVATE void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3*);
|
|
+#if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_JSON)
|
|
+SQLITE_PRIVATE int sqlite3JsonTableFunctions(sqlite3*);
|
|
+#endif
|
|
SQLITE_PRIVATE int sqlite3SafetyCheckOk(sqlite3*);
|
|
SQLITE_PRIVATE int sqlite3SafetyCheckSickOrOk(sqlite3*);
|
|
SQLITE_PRIVATE void sqlite3ChangeCookie(Parse*, int);
|
|
+SQLITE_PRIVATE With *sqlite3WithDup(sqlite3 *db, With *p);
|
|
|
|
#if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER)
|
|
SQLITE_PRIVATE void sqlite3MaterializeView(Parse*, Table*, Expr*, ExprList*,Expr*,int);
|
|
@@ -19615,13 +20454,14 @@ SQLITE_PRIVATE TriggerStep *sqlite3TriggerSelectStep(sqlite3*,Select*,
|
|
SQLITE_PRIVATE TriggerStep *sqlite3TriggerInsertStep(Parse*,Token*, IdList*,
|
|
Select*,u8,Upsert*,
|
|
const char*,const char*);
|
|
-SQLITE_PRIVATE TriggerStep *sqlite3TriggerUpdateStep(Parse*,Token*,ExprList*, Expr*, u8,
|
|
- const char*,const char*);
|
|
+SQLITE_PRIVATE TriggerStep *sqlite3TriggerUpdateStep(Parse*,Token*,SrcList*,ExprList*,
|
|
+ Expr*, u8, const char*,const char*);
|
|
SQLITE_PRIVATE TriggerStep *sqlite3TriggerDeleteStep(Parse*,Token*, Expr*,
|
|
const char*,const char*);
|
|
SQLITE_PRIVATE void sqlite3DeleteTrigger(sqlite3*, Trigger*);
|
|
SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTrigger(sqlite3*,int,const char*);
|
|
SQLITE_PRIVATE u32 sqlite3TriggerColmask(Parse*,Trigger*,ExprList*,int,int,Table*,int);
|
|
+SQLITE_PRIVATE SrcList *sqlite3TriggerStepSrc(Parse*, TriggerStep*);
|
|
# define sqlite3ParseToplevel(p) ((p)->pToplevel ? (p)->pToplevel : (p))
|
|
# define sqlite3IsToplevel(p) ((p)->pToplevel==0)
|
|
#else
|
|
@@ -19635,10 +20475,13 @@ SQLITE_PRIVATE u32 sqlite3TriggerColmask(Parse*,Trigger*,ExprList*,int,int,Tab
|
|
# define sqlite3ParseToplevel(p) p
|
|
# define sqlite3IsToplevel(p) 1
|
|
# define sqlite3TriggerColmask(A,B,C,D,E,F,G) 0
|
|
+# define sqlite3TriggerStepSrc(A,B) 0
|
|
#endif
|
|
|
|
SQLITE_PRIVATE int sqlite3JoinType(Parse*, Token*, Token*, Token*);
|
|
-SQLITE_PRIVATE void sqlite3SetJoinExpr(Expr*,int);
|
|
+SQLITE_PRIVATE int sqlite3ColumnIndex(Table *pTab, const char *zCol);
|
|
+SQLITE_PRIVATE void sqlite3SrcItemColumnUsed(SrcItem*,int);
|
|
+SQLITE_PRIVATE void sqlite3SetJoinExpr(Expr*,int,u32);
|
|
SQLITE_PRIVATE void sqlite3CreateForeignKey(Parse*, ExprList*, Token*, ExprList*, int);
|
|
SQLITE_PRIVATE void sqlite3DeferForeignKey(Parse*, int);
|
|
#ifndef SQLITE_OMIT_AUTHORIZATION
|
|
@@ -19653,17 +20496,20 @@ SQLITE_PRIVATE int sqlite3AuthReadCol(Parse*, const char *, const char *, int)
|
|
# define sqlite3AuthContextPush(a,b,c)
|
|
# define sqlite3AuthContextPop(a) ((void)(a))
|
|
#endif
|
|
+SQLITE_PRIVATE int sqlite3DbIsNamed(sqlite3 *db, int iDb, const char *zName);
|
|
SQLITE_PRIVATE void sqlite3Attach(Parse*, Expr*, Expr*, Expr*);
|
|
SQLITE_PRIVATE void sqlite3Detach(Parse*, Expr*);
|
|
SQLITE_PRIVATE void sqlite3FixInit(DbFixer*, Parse*, int, const char*, const Token*);
|
|
SQLITE_PRIVATE int sqlite3FixSrcList(DbFixer*, SrcList*);
|
|
SQLITE_PRIVATE int sqlite3FixSelect(DbFixer*, Select*);
|
|
SQLITE_PRIVATE int sqlite3FixExpr(DbFixer*, Expr*);
|
|
-SQLITE_PRIVATE int sqlite3FixExprList(DbFixer*, ExprList*);
|
|
SQLITE_PRIVATE int sqlite3FixTriggerStep(DbFixer*, TriggerStep*);
|
|
SQLITE_PRIVATE int sqlite3RealSameAsInt(double,sqlite3_int64);
|
|
+SQLITE_PRIVATE i64 sqlite3RealToI64(double);
|
|
+SQLITE_PRIVATE int sqlite3Int64ToText(i64,char*);
|
|
SQLITE_PRIVATE int sqlite3AtoF(const char *z, double*, int, u8);
|
|
SQLITE_PRIVATE int sqlite3GetInt32(const char *, int*);
|
|
+SQLITE_PRIVATE int sqlite3GetUInt32(const char*, u32*);
|
|
SQLITE_PRIVATE int sqlite3Atoi(const char*);
|
|
#ifndef SQLITE_OMIT_UTF16
|
|
SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *pData, int nChar);
|
|
@@ -19672,14 +20518,8 @@ SQLITE_PRIVATE int sqlite3Utf8CharLen(const char *pData, int nByte);
|
|
SQLITE_PRIVATE u32 sqlite3Utf8Read(const u8**);
|
|
SQLITE_PRIVATE LogEst sqlite3LogEst(u64);
|
|
SQLITE_PRIVATE LogEst sqlite3LogEstAdd(LogEst,LogEst);
|
|
-#ifndef SQLITE_OMIT_VIRTUALTABLE
|
|
SQLITE_PRIVATE LogEst sqlite3LogEstFromDouble(double);
|
|
-#endif
|
|
-#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || \
|
|
- defined(SQLITE_ENABLE_STAT4) || \
|
|
- defined(SQLITE_EXPLAIN_ESTIMATED_ROWS)
|
|
SQLITE_PRIVATE u64 sqlite3LogEstToInt(LogEst);
|
|
-#endif
|
|
SQLITE_PRIVATE VList *sqlite3VListAdd(sqlite3*,VList*,const char*,int,int);
|
|
SQLITE_PRIVATE const char *sqlite3VListNumToName(VList*,int);
|
|
SQLITE_PRIVATE int sqlite3VListNameToNum(VList*,const char*,int);
|
|
@@ -19701,6 +20541,8 @@ SQLITE_PRIVATE int sqlite3VarintLen(u64 v);
|
|
*/
|
|
#define getVarint32(A,B) \
|
|
(u8)((*(A)<(u8)0x80)?((B)=(u32)*(A)),1:sqlite3GetVarint32((A),(u32 *)&(B)))
|
|
+#define getVarint32NR(A,B) \
|
|
+ B=(u32)*(A);if(B>=0x80)sqlite3GetVarint32((A),(u32*)&(B))
|
|
#define putVarint32(A,B) \
|
|
(u8)(((u32)(B)<(u32)0x80)?(*(A)=(unsigned char)(B)),1:\
|
|
sqlite3PutVarint((A),(B)))
|
|
@@ -19709,15 +20551,18 @@ SQLITE_PRIVATE int sqlite3VarintLen(u64 v);
|
|
|
|
|
|
SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(sqlite3*, Index*);
|
|
+SQLITE_PRIVATE char *sqlite3TableAffinityStr(sqlite3*,const Table*);
|
|
SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe*, Table*, int);
|
|
-SQLITE_PRIVATE char sqlite3CompareAffinity(Expr *pExpr, char aff2);
|
|
-SQLITE_PRIVATE int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity);
|
|
-SQLITE_PRIVATE char sqlite3TableColumnAffinity(Table*,int);
|
|
-SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr);
|
|
+SQLITE_PRIVATE char sqlite3CompareAffinity(const Expr *pExpr, char aff2);
|
|
+SQLITE_PRIVATE int sqlite3IndexAffinityOk(const Expr *pExpr, char idx_affinity);
|
|
+SQLITE_PRIVATE char sqlite3TableColumnAffinity(const Table*,int);
|
|
+SQLITE_PRIVATE char sqlite3ExprAffinity(const Expr *pExpr);
|
|
+SQLITE_PRIVATE int sqlite3ExprDataType(const Expr *pExpr);
|
|
SQLITE_PRIVATE int sqlite3Atoi64(const char*, i64*, int, u8);
|
|
SQLITE_PRIVATE int sqlite3DecOrHexToI64(const char*, i64*);
|
|
SQLITE_PRIVATE void sqlite3ErrorWithMsg(sqlite3*, int, const char*,...);
|
|
SQLITE_PRIVATE void sqlite3Error(sqlite3*,int);
|
|
+SQLITE_PRIVATE void sqlite3ErrorClear(sqlite3*);
|
|
SQLITE_PRIVATE void sqlite3SystemError(sqlite3*,int);
|
|
SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3*, const char *z, int n);
|
|
SQLITE_PRIVATE u8 sqlite3HexToInt(int h);
|
|
@@ -19727,8 +20572,11 @@ SQLITE_PRIVATE int sqlite3TwoPartName(Parse *, Token *, Token *, Token **);
|
|
SQLITE_PRIVATE const char *sqlite3ErrName(int);
|
|
#endif
|
|
|
|
-#ifdef SQLITE_ENABLE_DESERIALIZE
|
|
+#ifndef SQLITE_OMIT_DESERIALIZE
|
|
SQLITE_PRIVATE int sqlite3MemdbInit(void);
|
|
+SQLITE_PRIVATE int sqlite3IsMemdb(const sqlite3_vfs*);
|
|
+#else
|
|
+# define sqlite3IsMemdb(X) 0
|
|
#endif
|
|
|
|
SQLITE_PRIVATE const char *sqlite3ErrStr(int);
|
|
@@ -19736,17 +20584,18 @@ SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse);
|
|
SQLITE_PRIVATE CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int);
|
|
SQLITE_PRIVATE int sqlite3IsBinary(const CollSeq*);
|
|
SQLITE_PRIVATE CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName);
|
|
-SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr);
|
|
-SQLITE_PRIVATE CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, Expr *pExpr);
|
|
-SQLITE_PRIVATE int sqlite3ExprCollSeqMatch(Parse*,Expr*,Expr*);
|
|
-SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, const Token*, int);
|
|
-SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*);
|
|
+SQLITE_PRIVATE void sqlite3SetTextEncoding(sqlite3 *db, u8);
|
|
+SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, const Expr *pExpr);
|
|
+SQLITE_PRIVATE CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, const Expr *pExpr);
|
|
+SQLITE_PRIVATE int sqlite3ExprCollSeqMatch(Parse*,const Expr*,const Expr*);
|
|
+SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(const Parse *pParse, Expr*, const Token*, int);
|
|
+SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(const Parse*,Expr*,const char*);
|
|
SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr*);
|
|
SQLITE_PRIVATE Expr *sqlite3ExprSkipCollateAndLikely(Expr*);
|
|
SQLITE_PRIVATE int sqlite3CheckCollSeq(Parse *, CollSeq *);
|
|
SQLITE_PRIVATE int sqlite3WritableSchema(sqlite3*);
|
|
SQLITE_PRIVATE int sqlite3CheckObjectName(Parse*, const char*,const char*,const char*);
|
|
-SQLITE_PRIVATE void sqlite3VdbeSetChanges(sqlite3 *, int);
|
|
+SQLITE_PRIVATE void sqlite3VdbeSetChanges(sqlite3 *, i64);
|
|
SQLITE_PRIVATE int sqlite3AddInt64(i64*,i64);
|
|
SQLITE_PRIVATE int sqlite3SubInt64(i64*,i64);
|
|
SQLITE_PRIVATE int sqlite3MulInt64(i64*,i64);
|
|
@@ -19771,23 +20620,29 @@ SQLITE_PRIVATE sqlite3_value *sqlite3ValueNew(sqlite3 *);
|
|
#ifndef SQLITE_OMIT_UTF16
|
|
SQLITE_PRIVATE char *sqlite3Utf16to8(sqlite3 *, const void*, int, u8);
|
|
#endif
|
|
-SQLITE_PRIVATE int sqlite3ValueFromExpr(sqlite3 *, Expr *, u8, u8, sqlite3_value **);
|
|
+SQLITE_PRIVATE int sqlite3ValueFromExpr(sqlite3 *, const Expr *, u8, u8, sqlite3_value **);
|
|
SQLITE_PRIVATE void sqlite3ValueApplyAffinity(sqlite3_value *, u8, u8);
|
|
#ifndef SQLITE_AMALGAMATION
|
|
SQLITE_PRIVATE const unsigned char sqlite3OpcodeProperty[];
|
|
SQLITE_PRIVATE const char sqlite3StrBINARY[];
|
|
+SQLITE_PRIVATE const unsigned char sqlite3StdTypeLen[];
|
|
+SQLITE_PRIVATE const char sqlite3StdTypeAffinity[];
|
|
+SQLITE_PRIVATE const char *sqlite3StdType[];
|
|
SQLITE_PRIVATE const unsigned char sqlite3UpperToLower[];
|
|
+SQLITE_PRIVATE const unsigned char *sqlite3aLTb;
|
|
+SQLITE_PRIVATE const unsigned char *sqlite3aEQb;
|
|
+SQLITE_PRIVATE const unsigned char *sqlite3aGTb;
|
|
SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[];
|
|
SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config;
|
|
SQLITE_PRIVATE FuncDefHash sqlite3BuiltinFunctions;
|
|
#ifndef SQLITE_OMIT_WSD
|
|
SQLITE_PRIVATE int sqlite3PendingByte;
|
|
#endif
|
|
-#endif
|
|
+#endif /* SQLITE_AMALGAMATION */
|
|
#ifdef VDBE_PROFILE
|
|
SQLITE_PRIVATE sqlite3_uint64 sqlite3NProfileCnt;
|
|
#endif
|
|
-SQLITE_PRIVATE void sqlite3RootPageMoved(sqlite3*, int, int, int);
|
|
+SQLITE_PRIVATE void sqlite3RootPageMoved(sqlite3*, int, Pgno, Pgno);
|
|
SQLITE_PRIVATE void sqlite3Reindex(Parse*, Token*, Token*);
|
|
SQLITE_PRIVATE void sqlite3AlterFunctions(void);
|
|
SQLITE_PRIVATE void sqlite3AlterRenameTable(Parse*, SrcList*, Token*);
|
|
@@ -19798,6 +20653,7 @@ SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3*, int);
|
|
SQLITE_PRIVATE void sqlite3CodeRhsOfIN(Parse*, Expr*, int);
|
|
SQLITE_PRIVATE int sqlite3CodeSubselect(Parse*, Expr*);
|
|
SQLITE_PRIVATE void sqlite3SelectPrep(Parse*, Select*, NameContext*);
|
|
+SQLITE_PRIVATE int sqlite3ExpandSubquery(Parse*, SrcItem*);
|
|
SQLITE_PRIVATE void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p);
|
|
SQLITE_PRIVATE int sqlite3MatchEName(
|
|
const struct ExprList_item*,
|
|
@@ -19805,6 +20661,8 @@ SQLITE_PRIVATE int sqlite3MatchEName(
|
|
const char*,
|
|
const char*
|
|
);
|
|
+SQLITE_PRIVATE Bitmask sqlite3ExprColUsed(Expr*);
|
|
+SQLITE_PRIVATE u8 sqlite3StrIHash(const char*);
|
|
SQLITE_PRIVATE int sqlite3ResolveExprNames(NameContext*, Expr*);
|
|
SQLITE_PRIVATE int sqlite3ResolveExprListNames(NameContext*, ExprList*);
|
|
SQLITE_PRIVATE void sqlite3ResolveSelectNames(Parse*, Select*, NameContext*);
|
|
@@ -19813,14 +20671,15 @@ SQLITE_PRIVATE int sqlite3ResolveOrderGroupBy(Parse*, Select*, ExprList*, const
|
|
SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *, Table *, int, int);
|
|
SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *, Token *);
|
|
SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *, SrcList *);
|
|
-SQLITE_PRIVATE void *sqlite3RenameTokenMap(Parse*, void*, Token*);
|
|
-SQLITE_PRIVATE void sqlite3RenameTokenRemap(Parse*, void *pTo, void *pFrom);
|
|
+SQLITE_PRIVATE void sqlite3AlterDropColumn(Parse*, SrcList*, const Token*);
|
|
+SQLITE_PRIVATE const void *sqlite3RenameTokenMap(Parse*, const void*, const Token*);
|
|
+SQLITE_PRIVATE void sqlite3RenameTokenRemap(Parse*, const void *pTo, const void *pFrom);
|
|
SQLITE_PRIVATE void sqlite3RenameExprUnmap(Parse*, Expr*);
|
|
SQLITE_PRIVATE void sqlite3RenameExprlistUnmap(Parse*, ExprList*);
|
|
SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq(Parse*, u8, CollSeq *, const char*);
|
|
SQLITE_PRIVATE char sqlite3AffinityType(const char*, Column*);
|
|
SQLITE_PRIVATE void sqlite3Analyze(Parse*, Token*, Token*);
|
|
-SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler*, sqlite3_file*);
|
|
+SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler*);
|
|
SQLITE_PRIVATE int sqlite3FindDb(sqlite3*, Token*);
|
|
SQLITE_PRIVATE int sqlite3FindDbName(sqlite3 *, const char *);
|
|
SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3*,int iDB);
|
|
@@ -19836,6 +20695,7 @@ SQLITE_PRIVATE void sqlite3KeyInfoUnref(KeyInfo*);
|
|
SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoRef(KeyInfo*);
|
|
SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoOfIndex(Parse*, Index*);
|
|
SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoFromExprList(Parse*, ExprList*, int, int);
|
|
+SQLITE_PRIVATE const char *sqlite3SelectOpName(int);
|
|
SQLITE_PRIVATE int sqlite3HasExplicitNulls(Parse*, ExprList*);
|
|
|
|
#ifdef SQLITE_DEBUG
|
|
@@ -19843,22 +20703,27 @@ SQLITE_PRIVATE int sqlite3KeyInfoIsWriteable(KeyInfo*);
|
|
#endif
|
|
SQLITE_PRIVATE int sqlite3CreateFunc(sqlite3 *, const char *, int, int, void *,
|
|
void (*)(sqlite3_context*,int,sqlite3_value **),
|
|
- void (*)(sqlite3_context*,int,sqlite3_value **),
|
|
+ void (*)(sqlite3_context*,int,sqlite3_value **),
|
|
void (*)(sqlite3_context*),
|
|
void (*)(sqlite3_context*),
|
|
- void (*)(sqlite3_context*,int,sqlite3_value **),
|
|
+ void (*)(sqlite3_context*,int,sqlite3_value **),
|
|
FuncDestructor *pDestructor
|
|
);
|
|
SQLITE_PRIVATE void sqlite3NoopDestructor(void*);
|
|
-SQLITE_PRIVATE void sqlite3OomFault(sqlite3*);
|
|
+SQLITE_PRIVATE void *sqlite3OomFault(sqlite3*);
|
|
SQLITE_PRIVATE void sqlite3OomClear(sqlite3*);
|
|
SQLITE_PRIVATE int sqlite3ApiExit(sqlite3 *db, int);
|
|
SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *);
|
|
|
|
SQLITE_PRIVATE void sqlite3StrAccumInit(StrAccum*, sqlite3*, char*, int, int);
|
|
+SQLITE_PRIVATE int sqlite3StrAccumEnlarge(StrAccum*, i64);
|
|
SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum*);
|
|
+SQLITE_PRIVATE void sqlite3StrAccumSetError(StrAccum*, u8);
|
|
+SQLITE_PRIVATE void sqlite3ResultStrAccum(sqlite3_context*,StrAccum*);
|
|
SQLITE_PRIVATE void sqlite3SelectDestInit(SelectDest*,int,int);
|
|
SQLITE_PRIVATE Expr *sqlite3CreateColumnExpr(sqlite3 *, SrcList *, int, int);
|
|
+SQLITE_PRIVATE void sqlite3RecordErrorByteOffset(sqlite3*,const char*);
|
|
+SQLITE_PRIVATE void sqlite3RecordErrorOffsetOfExpr(sqlite3*,const Expr*);
|
|
|
|
SQLITE_PRIVATE void sqlite3BackupRestart(sqlite3_backup *);
|
|
SQLITE_PRIVATE void sqlite3BackupUpdate(sqlite3_backup *, Pgno, const u8 *);
|
|
@@ -19899,7 +20764,7 @@ SQLITE_PRIVATE void sqlite3CloseExtensions(sqlite3*);
|
|
#endif
|
|
|
|
#ifndef SQLITE_OMIT_SHARED_CACHE
|
|
-SQLITE_PRIVATE void sqlite3TableLock(Parse *, int, int, u8, const char *);
|
|
+SQLITE_PRIVATE void sqlite3TableLock(Parse *, int, Pgno, u8, const char *);
|
|
#else
|
|
#define sqlite3TableLock(v,w,x,y,z)
|
|
#endif
|
|
@@ -19909,7 +20774,7 @@ SQLITE_PRIVATE int sqlite3Utf8To8(unsigned char*);
|
|
#endif
|
|
|
|
#ifdef SQLITE_OMIT_VIRTUALTABLE
|
|
-# define sqlite3VtabClear(Y)
|
|
+# define sqlite3VtabClear(D,T)
|
|
# define sqlite3VtabSync(X,Y) SQLITE_OK
|
|
# define sqlite3VtabRollback(X)
|
|
# define sqlite3VtabCommit(X)
|
|
@@ -19945,8 +20810,12 @@ SQLITE_PRIVATE Module *sqlite3VtabCreateModule(
|
|
SQLITE_PRIVATE int sqlite3ReadOnlyShadowTables(sqlite3 *db);
|
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
|
SQLITE_PRIVATE int sqlite3ShadowTableName(sqlite3 *db, const char *zName);
|
|
+SQLITE_PRIVATE int sqlite3IsShadowTableOf(sqlite3*,Table*,const char*);
|
|
+SQLITE_PRIVATE void sqlite3MarkAllShadowTablesOf(sqlite3*, Table*);
|
|
#else
|
|
# define sqlite3ShadowTableName(A,B) 0
|
|
+# define sqlite3IsShadowTableOf(A,B,C) 0
|
|
+# define sqlite3MarkAllShadowTablesOf(A,B)
|
|
#endif
|
|
SQLITE_PRIVATE int sqlite3VtabEponymousTableInit(Parse*,Module*);
|
|
SQLITE_PRIVATE void sqlite3VtabEponymousTableClear(sqlite3*,Module*);
|
|
@@ -19959,18 +20828,25 @@ SQLITE_PRIVATE int sqlite3VtabCallCreate(sqlite3*, int, const char *, char **);
|
|
SQLITE_PRIVATE int sqlite3VtabCallConnect(Parse*, Table*);
|
|
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 sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context*);
|
|
SQLITE_PRIVATE int sqlite3VdbeParameterIndex(Vdbe*, const char*, int);
|
|
SQLITE_PRIVATE int sqlite3TransferBindings(sqlite3_stmt *, sqlite3_stmt *);
|
|
-SQLITE_PRIVATE void sqlite3ParserReset(Parse*);
|
|
+SQLITE_PRIVATE void sqlite3ParseObjectInit(Parse*,sqlite3*);
|
|
+SQLITE_PRIVATE void sqlite3ParseObjectReset(Parse*);
|
|
+SQLITE_PRIVATE void *sqlite3ParserAddCleanup(Parse*,void(*)(sqlite3*,void*),void*);
|
|
#ifdef SQLITE_ENABLE_NORMALIZE
|
|
SQLITE_PRIVATE char *sqlite3Normalize(Vdbe*, const char*);
|
|
#endif
|
|
SQLITE_PRIVATE int sqlite3Reprepare(Vdbe*);
|
|
SQLITE_PRIVATE void sqlite3ExprListCheckLength(Parse*, ExprList*, const char*);
|
|
-SQLITE_PRIVATE CollSeq *sqlite3ExprCompareCollSeq(Parse*,Expr*);
|
|
-SQLITE_PRIVATE CollSeq *sqlite3BinaryCompareCollSeq(Parse *, Expr *, Expr *);
|
|
+SQLITE_PRIVATE CollSeq *sqlite3ExprCompareCollSeq(Parse*,const Expr*);
|
|
+SQLITE_PRIVATE CollSeq *sqlite3BinaryCompareCollSeq(Parse *, const Expr*, const Expr*);
|
|
SQLITE_PRIVATE int sqlite3TempInMemory(const sqlite3*);
|
|
SQLITE_PRIVATE const char *sqlite3JournalModename(int);
|
|
#ifndef SQLITE_OMIT_WAL
|
|
@@ -19978,23 +20854,32 @@ SQLITE_PRIVATE int sqlite3Checkpoint(sqlite3*, int, int, int*, int*);
|
|
SQLITE_PRIVATE int sqlite3WalDefaultHook(void*,sqlite3*,const char*,int);
|
|
#endif
|
|
#ifndef SQLITE_OMIT_CTE
|
|
-SQLITE_PRIVATE With *sqlite3WithAdd(Parse*,With*,Token*,ExprList*,Select*);
|
|
+SQLITE_PRIVATE Cte *sqlite3CteNew(Parse*,Token*,ExprList*,Select*,u8);
|
|
+SQLITE_PRIVATE void sqlite3CteDelete(sqlite3*,Cte*);
|
|
+SQLITE_PRIVATE With *sqlite3WithAdd(Parse*,With*,Cte*);
|
|
SQLITE_PRIVATE void sqlite3WithDelete(sqlite3*,With*);
|
|
-SQLITE_PRIVATE void sqlite3WithPush(Parse*, With*, u8);
|
|
+SQLITE_PRIVATE With *sqlite3WithPush(Parse*, With*, u8);
|
|
#else
|
|
-#define sqlite3WithPush(x,y,z)
|
|
-#define sqlite3WithDelete(x,y)
|
|
+# define sqlite3CteNew(P,T,E,S) ((void*)0)
|
|
+# define sqlite3CteDelete(D,C)
|
|
+# define sqlite3CteWithAdd(P,W,C) ((void*)0)
|
|
+# define sqlite3WithDelete(x,y)
|
|
+# define sqlite3WithPush(x,y,z) ((void*)0)
|
|
#endif
|
|
#ifndef SQLITE_OMIT_UPSERT
|
|
-SQLITE_PRIVATE Upsert *sqlite3UpsertNew(sqlite3*,ExprList*,Expr*,ExprList*,Expr*);
|
|
+SQLITE_PRIVATE Upsert *sqlite3UpsertNew(sqlite3*,ExprList*,Expr*,ExprList*,Expr*,Upsert*);
|
|
SQLITE_PRIVATE void sqlite3UpsertDelete(sqlite3*,Upsert*);
|
|
SQLITE_PRIVATE Upsert *sqlite3UpsertDup(sqlite3*,Upsert*);
|
|
SQLITE_PRIVATE int sqlite3UpsertAnalyzeTarget(Parse*,SrcList*,Upsert*);
|
|
SQLITE_PRIVATE void sqlite3UpsertDoUpdate(Parse*,Upsert*,Table*,Index*,int);
|
|
+SQLITE_PRIVATE Upsert *sqlite3UpsertOfIndex(Upsert*,Index*);
|
|
+SQLITE_PRIVATE int sqlite3UpsertNextIsIPK(Upsert*);
|
|
#else
|
|
-#define sqlite3UpsertNew(v,w,x,y,z) ((Upsert*)0)
|
|
+#define sqlite3UpsertNew(u,v,w,x,y,z) ((Upsert*)0)
|
|
#define sqlite3UpsertDelete(x,y)
|
|
-#define sqlite3UpsertDup(x,y) ((Upsert*)0)
|
|
+#define sqlite3UpsertDup(x,y) ((Upsert*)0)
|
|
+#define sqlite3UpsertOfIndex(x,y) ((Upsert*)0)
|
|
+#define sqlite3UpsertNextIsIPK(x) 0
|
|
#endif
|
|
|
|
|
|
@@ -20012,6 +20897,7 @@ SQLITE_PRIVATE void sqlite3FkActions(Parse*, Table*, ExprList*, int, int*, int
|
|
SQLITE_PRIVATE int sqlite3FkRequired(Parse*, Table*, int*, int);
|
|
SQLITE_PRIVATE u32 sqlite3FkOldmask(Parse*, Table*);
|
|
SQLITE_PRIVATE FKey *sqlite3FkReferences(Table *);
|
|
+SQLITE_PRIVATE void sqlite3FkClearTriggerCache(sqlite3*,int);
|
|
#else
|
|
#define sqlite3FkActions(a,b,c,d,e,f)
|
|
#define sqlite3FkCheck(a,b,c,d,e,f)
|
|
@@ -20019,6 +20905,7 @@ SQLITE_PRIVATE FKey *sqlite3FkReferences(Table *);
|
|
#define sqlite3FkOldmask(a,b) 0
|
|
#define sqlite3FkRequired(a,b,c,d) 0
|
|
#define sqlite3FkReferences(a) 0
|
|
+ #define sqlite3FkClearTriggerCache(a,b)
|
|
#endif
|
|
#ifndef SQLITE_OMIT_FOREIGN_KEY
|
|
SQLITE_PRIVATE void sqlite3FkDelete(sqlite3 *, Table*);
|
|
@@ -20076,7 +20963,7 @@ SQLITE_PRIVATE void sqlite3MemJournalOpen(sqlite3_file *);
|
|
|
|
SQLITE_PRIVATE void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p);
|
|
#if SQLITE_MAX_EXPR_DEPTH>0
|
|
-SQLITE_PRIVATE int sqlite3SelectExprHeight(Select *);
|
|
+SQLITE_PRIVATE int sqlite3SelectExprHeight(const Select *);
|
|
SQLITE_PRIVATE int sqlite3ExprCheckHeight(Parse*, int);
|
|
#else
|
|
#define sqlite3SelectExprHeight(x) 0
|
|
@@ -20147,8 +21034,8 @@ SQLITE_API SQLITE_EXTERN void (SQLITE_CDECL *sqlite3IoTrace)(const char*,...);
|
|
*/
|
|
#ifdef SQLITE_MEMDEBUG
|
|
SQLITE_PRIVATE void sqlite3MemdebugSetType(void*,u8);
|
|
-SQLITE_PRIVATE int sqlite3MemdebugHasType(void*,u8);
|
|
-SQLITE_PRIVATE int sqlite3MemdebugNoType(void*,u8);
|
|
+SQLITE_PRIVATE int sqlite3MemdebugHasType(const void*,u8);
|
|
+SQLITE_PRIVATE int sqlite3MemdebugNoType(const void*,u8);
|
|
#else
|
|
# define sqlite3MemdebugSetType(X,Y) /* no-op */
|
|
# define sqlite3MemdebugHasType(X,Y) 1
|
|
@@ -20173,19 +21060,921 @@ SQLITE_PRIVATE int sqlite3DbpageRegister(sqlite3*);
|
|
SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3*);
|
|
#endif
|
|
|
|
-SQLITE_PRIVATE int sqlite3ExprVectorSize(Expr *pExpr);
|
|
-SQLITE_PRIVATE int sqlite3ExprIsVector(Expr *pExpr);
|
|
+SQLITE_PRIVATE int sqlite3ExprVectorSize(const Expr *pExpr);
|
|
+SQLITE_PRIVATE int sqlite3ExprIsVector(const Expr *pExpr);
|
|
SQLITE_PRIVATE Expr *sqlite3VectorFieldSubexpr(Expr*, int);
|
|
-SQLITE_PRIVATE Expr *sqlite3ExprForVectorField(Parse*,Expr*,int);
|
|
+SQLITE_PRIVATE Expr *sqlite3ExprForVectorField(Parse*,Expr*,int,int);
|
|
SQLITE_PRIVATE void sqlite3VectorErrorMsg(Parse*, Expr*);
|
|
|
|
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
|
|
SQLITE_PRIVATE const char **sqlite3CompileOptions(int *pnOpt);
|
|
#endif
|
|
|
|
+#if SQLITE_OS_UNIX && defined(SQLITE_OS_KV_OPTIONAL)
|
|
+SQLITE_PRIVATE int sqlite3KvvfsInit(void);
|
|
+#endif
|
|
+
|
|
+#if defined(VDBE_PROFILE) \
|
|
+ || defined(SQLITE_PERFORMANCE_TRACE) \
|
|
+ || defined(SQLITE_ENABLE_STMT_SCANSTATUS)
|
|
+SQLITE_PRIVATE sqlite3_uint64 sqlite3Hwtime(void);
|
|
+#endif
|
|
+
|
|
#endif /* SQLITEINT_H */
|
|
|
|
/************** End of sqliteInt.h *******************************************/
|
|
+/************** Begin file os_common.h ***************************************/
|
|
+/*
|
|
+** 2004 May 22
|
|
+**
|
|
+** The author disclaims copyright to this source code. In place of
|
|
+** a legal notice, here is a blessing:
|
|
+**
|
|
+** May you do good and not evil.
|
|
+** May you find forgiveness for yourself and forgive others.
|
|
+** May you share freely, never taking more than you give.
|
|
+**
|
|
+******************************************************************************
|
|
+**
|
|
+** This file contains macros and a little bit of code that is common to
|
|
+** all of the platform-specific files (os_*.c) and is #included into those
|
|
+** files.
|
|
+**
|
|
+** This file should be #included by the os_*.c files only. It is not a
|
|
+** general purpose header file.
|
|
+*/
|
|
+#ifndef _OS_COMMON_H_
|
|
+#define _OS_COMMON_H_
|
|
+
|
|
+/*
|
|
+** At least two bugs have slipped in because we changed the MEMORY_DEBUG
|
|
+** macro to SQLITE_DEBUG and some older makefiles have not yet made the
|
|
+** switch. The following code should catch this problem at compile-time.
|
|
+*/
|
|
+#ifdef MEMORY_DEBUG
|
|
+# error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead."
|
|
+#endif
|
|
+
|
|
+/*
|
|
+** Macros for performance tracing. Normally turned off. Only works
|
|
+** on i486 hardware.
|
|
+*/
|
|
+#ifdef SQLITE_PERFORMANCE_TRACE
|
|
+
|
|
+static sqlite_uint64 g_start;
|
|
+static sqlite_uint64 g_elapsed;
|
|
+#define TIMER_START g_start=sqlite3Hwtime()
|
|
+#define TIMER_END g_elapsed=sqlite3Hwtime()-g_start
|
|
+#define TIMER_ELAPSED g_elapsed
|
|
+#else
|
|
+#define TIMER_START
|
|
+#define TIMER_END
|
|
+#define TIMER_ELAPSED ((sqlite_uint64)0)
|
|
+#endif
|
|
+
|
|
+/*
|
|
+** If we compile with the SQLITE_TEST macro set, then the following block
|
|
+** of code will give us the ability to simulate a disk I/O error. This
|
|
+** is used for testing the I/O recovery logic.
|
|
+*/
|
|
+#if defined(SQLITE_TEST)
|
|
+SQLITE_API extern int sqlite3_io_error_hit;
|
|
+SQLITE_API extern int sqlite3_io_error_hardhit;
|
|
+SQLITE_API extern int sqlite3_io_error_pending;
|
|
+SQLITE_API extern int sqlite3_io_error_persist;
|
|
+SQLITE_API extern int sqlite3_io_error_benign;
|
|
+SQLITE_API extern int sqlite3_diskfull_pending;
|
|
+SQLITE_API extern int sqlite3_diskfull;
|
|
+#define SimulateIOErrorBenign(X) sqlite3_io_error_benign=(X)
|
|
+#define SimulateIOError(CODE) \
|
|
+ if( (sqlite3_io_error_persist && sqlite3_io_error_hit) \
|
|
+ || sqlite3_io_error_pending-- == 1 ) \
|
|
+ { local_ioerr(); CODE; }
|
|
+static void local_ioerr(){
|
|
+ IOTRACE(("IOERR\n"));
|
|
+ sqlite3_io_error_hit++;
|
|
+ if( !sqlite3_io_error_benign ) sqlite3_io_error_hardhit++;
|
|
+}
|
|
+#define SimulateDiskfullError(CODE) \
|
|
+ if( sqlite3_diskfull_pending ){ \
|
|
+ if( sqlite3_diskfull_pending == 1 ){ \
|
|
+ local_ioerr(); \
|
|
+ sqlite3_diskfull = 1; \
|
|
+ sqlite3_io_error_hit = 1; \
|
|
+ CODE; \
|
|
+ }else{ \
|
|
+ sqlite3_diskfull_pending--; \
|
|
+ } \
|
|
+ }
|
|
+#else
|
|
+#define SimulateIOErrorBenign(X)
|
|
+#define SimulateIOError(A)
|
|
+#define SimulateDiskfullError(A)
|
|
+#endif /* defined(SQLITE_TEST) */
|
|
+
|
|
+/*
|
|
+** When testing, keep a count of the number of open files.
|
|
+*/
|
|
+#if defined(SQLITE_TEST)
|
|
+SQLITE_API extern int sqlite3_open_file_count;
|
|
+#define OpenCounter(X) sqlite3_open_file_count+=(X)
|
|
+#else
|
|
+#define OpenCounter(X)
|
|
+#endif /* defined(SQLITE_TEST) */
|
|
+
|
|
+#endif /* !defined(_OS_COMMON_H_) */
|
|
+
|
|
+/************** End of os_common.h *******************************************/
|
|
+/************** Begin file ctime.c *******************************************/
|
|
+/* DO NOT EDIT!
|
|
+** This file is automatically generated by the script in the canonical
|
|
+** SQLite source tree at tool/mkctimec.tcl.
|
|
+**
|
|
+** To modify this header, edit any of the various lists in that script
|
|
+** which specify categories of generated conditionals in this file.
|
|
+*/
|
|
+
|
|
+/*
|
|
+** 2010 February 23
|
|
+**
|
|
+** The author disclaims copyright to this source code. In place of
|
|
+** a legal notice, here is a blessing:
|
|
+**
|
|
+** May you do good and not evil.
|
|
+** May you find forgiveness for yourself and forgive others.
|
|
+** May you share freely, never taking more than you give.
|
|
+**
|
|
+*************************************************************************
|
|
+**
|
|
+** This file implements routines used to report what compile-time options
|
|
+** SQLite was built with.
|
|
+*/
|
|
+#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS /* IMP: R-16824-07538 */
|
|
+
|
|
+/*
|
|
+** Include the configuration header output by 'configure' if we're using the
|
|
+** autoconf-based build
|
|
+*/
|
|
+#if defined(_HAVE_SQLITE_CONFIG_H) && !defined(SQLITECONFIG_H)
|
|
+/* #include "sqlite_cfg.h" */
|
|
+#define SQLITECONFIG_H 1
|
|
+#endif
|
|
+
|
|
+/* These macros are provided to "stringify" the value of the define
|
|
+** for those options in which the value is meaningful. */
|
|
+#define CTIMEOPT_VAL_(opt) #opt
|
|
+#define CTIMEOPT_VAL(opt) CTIMEOPT_VAL_(opt)
|
|
+
|
|
+/* Like CTIMEOPT_VAL, but especially for SQLITE_DEFAULT_LOOKASIDE. This
|
|
+** option requires a separate macro because legal values contain a single
|
|
+** comma. e.g. (-DSQLITE_DEFAULT_LOOKASIDE="100,100") */
|
|
+#define CTIMEOPT_VAL2_(opt1,opt2) #opt1 "," #opt2
|
|
+#define CTIMEOPT_VAL2(opt) CTIMEOPT_VAL2_(opt)
|
|
+/* #include "sqliteInt.h" */
|
|
+
|
|
+/*
|
|
+** An array of names of all compile-time options. This array should
|
|
+** be sorted A-Z.
|
|
+**
|
|
+** This array looks large, but in a typical installation actually uses
|
|
+** only a handful of compile-time options, so most times this array is usually
|
|
+** rather short and uses little memory space.
|
|
+*/
|
|
+static const char * const sqlite3azCompileOpt[] = {
|
|
+
|
|
+#ifdef SQLITE_32BIT_ROWID
|
|
+ "32BIT_ROWID",
|
|
+#endif
|
|
+#ifdef SQLITE_4_BYTE_ALIGNED_MALLOC
|
|
+ "4_BYTE_ALIGNED_MALLOC",
|
|
+#endif
|
|
+#ifdef SQLITE_64BIT_STATS
|
|
+ "64BIT_STATS",
|
|
+#endif
|
|
+#ifdef SQLITE_ALLOW_COVERING_INDEX_SCAN
|
|
+# if SQLITE_ALLOW_COVERING_INDEX_SCAN != 1
|
|
+ "ALLOW_COVERING_INDEX_SCAN=" CTIMEOPT_VAL(SQLITE_ALLOW_COVERING_INDEX_SCAN),
|
|
+# endif
|
|
+#endif
|
|
+#ifdef SQLITE_ALLOW_URI_AUTHORITY
|
|
+ "ALLOW_URI_AUTHORITY",
|
|
+#endif
|
|
+#ifdef SQLITE_ATOMIC_INTRINSICS
|
|
+ "ATOMIC_INTRINSICS=" CTIMEOPT_VAL(SQLITE_ATOMIC_INTRINSICS),
|
|
+#endif
|
|
+#ifdef SQLITE_BITMASK_TYPE
|
|
+ "BITMASK_TYPE=" CTIMEOPT_VAL(SQLITE_BITMASK_TYPE),
|
|
+#endif
|
|
+#ifdef SQLITE_BUG_COMPATIBLE_20160819
|
|
+ "BUG_COMPATIBLE_20160819",
|
|
+#endif
|
|
+#ifdef SQLITE_CASE_SENSITIVE_LIKE
|
|
+ "CASE_SENSITIVE_LIKE",
|
|
+#endif
|
|
+#ifdef SQLITE_CHECK_PAGES
|
|
+ "CHECK_PAGES",
|
|
+#endif
|
|
+#if defined(__clang__) && defined(__clang_major__)
|
|
+ "COMPILER=clang-" CTIMEOPT_VAL(__clang_major__) "."
|
|
+ CTIMEOPT_VAL(__clang_minor__) "."
|
|
+ CTIMEOPT_VAL(__clang_patchlevel__),
|
|
+#elif defined(_MSC_VER)
|
|
+ "COMPILER=msvc-" CTIMEOPT_VAL(_MSC_VER),
|
|
+#elif defined(__GNUC__) && defined(__VERSION__)
|
|
+ "COMPILER=gcc-" __VERSION__,
|
|
+#endif
|
|
+#ifdef SQLITE_COVERAGE_TEST
|
|
+ "COVERAGE_TEST",
|
|
+#endif
|
|
+#ifdef SQLITE_DEBUG
|
|
+ "DEBUG",
|
|
+#endif
|
|
+#ifdef SQLITE_DEFAULT_AUTOMATIC_INDEX
|
|
+ "DEFAULT_AUTOMATIC_INDEX",
|
|
+#endif
|
|
+#ifdef SQLITE_DEFAULT_AUTOVACUUM
|
|
+ "DEFAULT_AUTOVACUUM",
|
|
+#endif
|
|
+#ifdef SQLITE_DEFAULT_CACHE_SIZE
|
|
+ "DEFAULT_CACHE_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_CACHE_SIZE),
|
|
+#endif
|
|
+#ifdef SQLITE_DEFAULT_CKPTFULLFSYNC
|
|
+ "DEFAULT_CKPTFULLFSYNC",
|
|
+#endif
|
|
+#ifdef SQLITE_DEFAULT_FILE_FORMAT
|
|
+ "DEFAULT_FILE_FORMAT=" CTIMEOPT_VAL(SQLITE_DEFAULT_FILE_FORMAT),
|
|
+#endif
|
|
+#ifdef SQLITE_DEFAULT_FILE_PERMISSIONS
|
|
+ "DEFAULT_FILE_PERMISSIONS=" CTIMEOPT_VAL(SQLITE_DEFAULT_FILE_PERMISSIONS),
|
|
+#endif
|
|
+#ifdef SQLITE_DEFAULT_FOREIGN_KEYS
|
|
+ "DEFAULT_FOREIGN_KEYS",
|
|
+#endif
|
|
+#ifdef SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT
|
|
+ "DEFAULT_JOURNAL_SIZE_LIMIT=" CTIMEOPT_VAL(SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT),
|
|
+#endif
|
|
+#ifdef SQLITE_DEFAULT_LOCKING_MODE
|
|
+ "DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE),
|
|
+#endif
|
|
+#ifdef SQLITE_DEFAULT_LOOKASIDE
|
|
+ "DEFAULT_LOOKASIDE=" CTIMEOPT_VAL2(SQLITE_DEFAULT_LOOKASIDE),
|
|
+#endif
|
|
+#ifdef SQLITE_DEFAULT_MEMSTATUS
|
|
+# if SQLITE_DEFAULT_MEMSTATUS != 1
|
|
+ "DEFAULT_MEMSTATUS=" CTIMEOPT_VAL(SQLITE_DEFAULT_MEMSTATUS),
|
|
+# endif
|
|
+#endif
|
|
+#ifdef SQLITE_DEFAULT_MMAP_SIZE
|
|
+ "DEFAULT_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_MMAP_SIZE),
|
|
+#endif
|
|
+#ifdef SQLITE_DEFAULT_PAGE_SIZE
|
|
+ "DEFAULT_PAGE_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_PAGE_SIZE),
|
|
+#endif
|
|
+#ifdef SQLITE_DEFAULT_PCACHE_INITSZ
|
|
+ "DEFAULT_PCACHE_INITSZ=" CTIMEOPT_VAL(SQLITE_DEFAULT_PCACHE_INITSZ),
|
|
+#endif
|
|
+#ifdef SQLITE_DEFAULT_PROXYDIR_PERMISSIONS
|
|
+ "DEFAULT_PROXYDIR_PERMISSIONS=" CTIMEOPT_VAL(SQLITE_DEFAULT_PROXYDIR_PERMISSIONS),
|
|
+#endif
|
|
+#ifdef SQLITE_DEFAULT_RECURSIVE_TRIGGERS
|
|
+ "DEFAULT_RECURSIVE_TRIGGERS",
|
|
+#endif
|
|
+#ifdef SQLITE_DEFAULT_ROWEST
|
|
+ "DEFAULT_ROWEST=" CTIMEOPT_VAL(SQLITE_DEFAULT_ROWEST),
|
|
+#endif
|
|
+#ifdef SQLITE_DEFAULT_SECTOR_SIZE
|
|
+ "DEFAULT_SECTOR_SIZE=" CTIMEOPT_VAL(SQLITE_DEFAULT_SECTOR_SIZE),
|
|
+#endif
|
|
+#ifdef SQLITE_DEFAULT_SYNCHRONOUS
|
|
+ "DEFAULT_SYNCHRONOUS=" CTIMEOPT_VAL(SQLITE_DEFAULT_SYNCHRONOUS),
|
|
+#endif
|
|
+#ifdef SQLITE_DEFAULT_WAL_AUTOCHECKPOINT
|
|
+ "DEFAULT_WAL_AUTOCHECKPOINT=" CTIMEOPT_VAL(SQLITE_DEFAULT_WAL_AUTOCHECKPOINT),
|
|
+#endif
|
|
+#ifdef SQLITE_DEFAULT_WAL_SYNCHRONOUS
|
|
+ "DEFAULT_WAL_SYNCHRONOUS=" CTIMEOPT_VAL(SQLITE_DEFAULT_WAL_SYNCHRONOUS),
|
|
+#endif
|
|
+#ifdef SQLITE_DEFAULT_WORKER_THREADS
|
|
+ "DEFAULT_WORKER_THREADS=" CTIMEOPT_VAL(SQLITE_DEFAULT_WORKER_THREADS),
|
|
+#endif
|
|
+#ifdef SQLITE_DIRECT_OVERFLOW_READ
|
|
+ "DIRECT_OVERFLOW_READ",
|
|
+#endif
|
|
+#ifdef SQLITE_DISABLE_DIRSYNC
|
|
+ "DISABLE_DIRSYNC",
|
|
+#endif
|
|
+#ifdef SQLITE_DISABLE_FTS3_UNICODE
|
|
+ "DISABLE_FTS3_UNICODE",
|
|
+#endif
|
|
+#ifdef SQLITE_DISABLE_FTS4_DEFERRED
|
|
+ "DISABLE_FTS4_DEFERRED",
|
|
+#endif
|
|
+#ifdef SQLITE_DISABLE_INTRINSIC
|
|
+ "DISABLE_INTRINSIC",
|
|
+#endif
|
|
+#ifdef SQLITE_DISABLE_LFS
|
|
+ "DISABLE_LFS",
|
|
+#endif
|
|
+#ifdef SQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS
|
|
+ "DISABLE_PAGECACHE_OVERFLOW_STATS",
|
|
+#endif
|
|
+#ifdef SQLITE_DISABLE_SKIPAHEAD_DISTINCT
|
|
+ "DISABLE_SKIPAHEAD_DISTINCT",
|
|
+#endif
|
|
+#ifdef SQLITE_DQS
|
|
+ "DQS=" CTIMEOPT_VAL(SQLITE_DQS),
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_8_3_NAMES
|
|
+ "ENABLE_8_3_NAMES=" CTIMEOPT_VAL(SQLITE_ENABLE_8_3_NAMES),
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_API_ARMOR
|
|
+ "ENABLE_API_ARMOR",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_ATOMIC_WRITE
|
|
+ "ENABLE_ATOMIC_WRITE",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
|
|
+ "ENABLE_BATCH_ATOMIC_WRITE",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_BYTECODE_VTAB
|
|
+ "ENABLE_BYTECODE_VTAB",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_CEROD
|
|
+ "ENABLE_CEROD=" CTIMEOPT_VAL(SQLITE_ENABLE_CEROD),
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_COLUMN_METADATA
|
|
+ "ENABLE_COLUMN_METADATA",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_COLUMN_USED_MASK
|
|
+ "ENABLE_COLUMN_USED_MASK",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_COSTMULT
|
|
+ "ENABLE_COSTMULT",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_CURSOR_HINTS
|
|
+ "ENABLE_CURSOR_HINTS",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_DBPAGE_VTAB
|
|
+ "ENABLE_DBPAGE_VTAB",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_DBSTAT_VTAB
|
|
+ "ENABLE_DBSTAT_VTAB",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
|
|
+ "ENABLE_EXPENSIVE_ASSERT",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
|
|
+ "ENABLE_EXPLAIN_COMMENTS",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_FTS3
|
|
+ "ENABLE_FTS3",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_FTS3_PARENTHESIS
|
|
+ "ENABLE_FTS3_PARENTHESIS",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_FTS3_TOKENIZER
|
|
+ "ENABLE_FTS3_TOKENIZER",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_FTS4
|
|
+ "ENABLE_FTS4",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_FTS5
|
|
+ "ENABLE_FTS5",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_GEOPOLY
|
|
+ "ENABLE_GEOPOLY",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_HIDDEN_COLUMNS
|
|
+ "ENABLE_HIDDEN_COLUMNS",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_ICU
|
|
+ "ENABLE_ICU",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_IOTRACE
|
|
+ "ENABLE_IOTRACE",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_LOAD_EXTENSION
|
|
+ "ENABLE_LOAD_EXTENSION",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_LOCKING_STYLE
|
|
+ "ENABLE_LOCKING_STYLE=" CTIMEOPT_VAL(SQLITE_ENABLE_LOCKING_STYLE),
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_MATH_FUNCTIONS
|
|
+ "ENABLE_MATH_FUNCTIONS",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
|
|
+ "ENABLE_MEMORY_MANAGEMENT",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_MEMSYS3
|
|
+ "ENABLE_MEMSYS3",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_MEMSYS5
|
|
+ "ENABLE_MEMSYS5",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_MULTIPLEX
|
|
+ "ENABLE_MULTIPLEX",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_NORMALIZE
|
|
+ "ENABLE_NORMALIZE",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_NULL_TRIM
|
|
+ "ENABLE_NULL_TRIM",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
|
|
+ "ENABLE_OFFSET_SQL_FUNC",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_OVERSIZE_CELL_CHECK
|
|
+ "ENABLE_OVERSIZE_CELL_CHECK",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
|
|
+ "ENABLE_PREUPDATE_HOOK",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_QPSG
|
|
+ "ENABLE_QPSG",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_RBU
|
|
+ "ENABLE_RBU",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_RTREE
|
|
+ "ENABLE_RTREE",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_SESSION
|
|
+ "ENABLE_SESSION",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_SNAPSHOT
|
|
+ "ENABLE_SNAPSHOT",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_SORTER_REFERENCES
|
|
+ "ENABLE_SORTER_REFERENCES",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_SQLLOG
|
|
+ "ENABLE_SQLLOG",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_STAT4
|
|
+ "ENABLE_STAT4",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_STMTVTAB
|
|
+ "ENABLE_STMTVTAB",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
|
|
+ "ENABLE_STMT_SCANSTATUS",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_TREETRACE
|
|
+ "ENABLE_TREETRACE",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
|
|
+ "ENABLE_UNKNOWN_SQL_FUNCTION",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
|
|
+ "ENABLE_UNLOCK_NOTIFY",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
|
|
+ "ENABLE_UPDATE_DELETE_LIMIT",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_URI_00_ERROR
|
|
+ "ENABLE_URI_00_ERROR",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_VFSTRACE
|
|
+ "ENABLE_VFSTRACE",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_WHERETRACE
|
|
+ "ENABLE_WHERETRACE",
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_ZIPVFS
|
|
+ "ENABLE_ZIPVFS",
|
|
+#endif
|
|
+#ifdef SQLITE_EXPLAIN_ESTIMATED_ROWS
|
|
+ "EXPLAIN_ESTIMATED_ROWS",
|
|
+#endif
|
|
+#ifdef SQLITE_EXTRA_IFNULLROW
|
|
+ "EXTRA_IFNULLROW",
|
|
+#endif
|
|
+#ifdef SQLITE_EXTRA_INIT
|
|
+ "EXTRA_INIT=" CTIMEOPT_VAL(SQLITE_EXTRA_INIT),
|
|
+#endif
|
|
+#ifdef SQLITE_EXTRA_SHUTDOWN
|
|
+ "EXTRA_SHUTDOWN=" CTIMEOPT_VAL(SQLITE_EXTRA_SHUTDOWN),
|
|
+#endif
|
|
+#ifdef SQLITE_FTS3_MAX_EXPR_DEPTH
|
|
+ "FTS3_MAX_EXPR_DEPTH=" CTIMEOPT_VAL(SQLITE_FTS3_MAX_EXPR_DEPTH),
|
|
+#endif
|
|
+#ifdef SQLITE_FTS5_ENABLE_TEST_MI
|
|
+ "FTS5_ENABLE_TEST_MI",
|
|
+#endif
|
|
+#ifdef SQLITE_FTS5_NO_WITHOUT_ROWID
|
|
+ "FTS5_NO_WITHOUT_ROWID",
|
|
+#endif
|
|
+#if HAVE_ISNAN || SQLITE_HAVE_ISNAN
|
|
+ "HAVE_ISNAN",
|
|
+#endif
|
|
+#ifdef SQLITE_HOMEGROWN_RECURSIVE_MUTEX
|
|
+# if SQLITE_HOMEGROWN_RECURSIVE_MUTEX != 1
|
|
+ "HOMEGROWN_RECURSIVE_MUTEX=" CTIMEOPT_VAL(SQLITE_HOMEGROWN_RECURSIVE_MUTEX),
|
|
+# endif
|
|
+#endif
|
|
+#ifdef SQLITE_IGNORE_AFP_LOCK_ERRORS
|
|
+ "IGNORE_AFP_LOCK_ERRORS",
|
|
+#endif
|
|
+#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
|
|
+ "IGNORE_FLOCK_LOCK_ERRORS",
|
|
+#endif
|
|
+#ifdef SQLITE_INLINE_MEMCPY
|
|
+ "INLINE_MEMCPY",
|
|
+#endif
|
|
+#ifdef SQLITE_INT64_TYPE
|
|
+ "INT64_TYPE",
|
|
+#endif
|
|
+#ifdef SQLITE_INTEGRITY_CHECK_ERROR_MAX
|
|
+ "INTEGRITY_CHECK_ERROR_MAX=" CTIMEOPT_VAL(SQLITE_INTEGRITY_CHECK_ERROR_MAX),
|
|
+#endif
|
|
+#ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS
|
|
+ "LIKE_DOESNT_MATCH_BLOBS",
|
|
+#endif
|
|
+#ifdef SQLITE_LOCK_TRACE
|
|
+ "LOCK_TRACE",
|
|
+#endif
|
|
+#ifdef SQLITE_LOG_CACHE_SPILL
|
|
+ "LOG_CACHE_SPILL",
|
|
+#endif
|
|
+#ifdef SQLITE_MALLOC_SOFT_LIMIT
|
|
+ "MALLOC_SOFT_LIMIT=" CTIMEOPT_VAL(SQLITE_MALLOC_SOFT_LIMIT),
|
|
+#endif
|
|
+#ifdef SQLITE_MAX_ATTACHED
|
|
+ "MAX_ATTACHED=" CTIMEOPT_VAL(SQLITE_MAX_ATTACHED),
|
|
+#endif
|
|
+#ifdef SQLITE_MAX_COLUMN
|
|
+ "MAX_COLUMN=" CTIMEOPT_VAL(SQLITE_MAX_COLUMN),
|
|
+#endif
|
|
+#ifdef SQLITE_MAX_COMPOUND_SELECT
|
|
+ "MAX_COMPOUND_SELECT=" CTIMEOPT_VAL(SQLITE_MAX_COMPOUND_SELECT),
|
|
+#endif
|
|
+#ifdef SQLITE_MAX_DEFAULT_PAGE_SIZE
|
|
+ "MAX_DEFAULT_PAGE_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_DEFAULT_PAGE_SIZE),
|
|
+#endif
|
|
+#ifdef SQLITE_MAX_EXPR_DEPTH
|
|
+ "MAX_EXPR_DEPTH=" CTIMEOPT_VAL(SQLITE_MAX_EXPR_DEPTH),
|
|
+#endif
|
|
+#ifdef SQLITE_MAX_FUNCTION_ARG
|
|
+ "MAX_FUNCTION_ARG=" CTIMEOPT_VAL(SQLITE_MAX_FUNCTION_ARG),
|
|
+#endif
|
|
+#ifdef SQLITE_MAX_LENGTH
|
|
+ "MAX_LENGTH=" CTIMEOPT_VAL(SQLITE_MAX_LENGTH),
|
|
+#endif
|
|
+#ifdef SQLITE_MAX_LIKE_PATTERN_LENGTH
|
|
+ "MAX_LIKE_PATTERN_LENGTH=" CTIMEOPT_VAL(SQLITE_MAX_LIKE_PATTERN_LENGTH),
|
|
+#endif
|
|
+#ifdef SQLITE_MAX_MEMORY
|
|
+ "MAX_MEMORY=" CTIMEOPT_VAL(SQLITE_MAX_MEMORY),
|
|
+#endif
|
|
+#ifdef SQLITE_MAX_MMAP_SIZE
|
|
+ "MAX_MMAP_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_MMAP_SIZE),
|
|
+#endif
|
|
+#ifdef SQLITE_MAX_MMAP_SIZE_
|
|
+ "MAX_MMAP_SIZE_=" CTIMEOPT_VAL(SQLITE_MAX_MMAP_SIZE_),
|
|
+#endif
|
|
+#ifdef SQLITE_MAX_PAGE_COUNT
|
|
+ "MAX_PAGE_COUNT=" CTIMEOPT_VAL(SQLITE_MAX_PAGE_COUNT),
|
|
+#endif
|
|
+#ifdef SQLITE_MAX_PAGE_SIZE
|
|
+ "MAX_PAGE_SIZE=" CTIMEOPT_VAL(SQLITE_MAX_PAGE_SIZE),
|
|
+#endif
|
|
+#ifdef SQLITE_MAX_SCHEMA_RETRY
|
|
+ "MAX_SCHEMA_RETRY=" CTIMEOPT_VAL(SQLITE_MAX_SCHEMA_RETRY),
|
|
+#endif
|
|
+#ifdef SQLITE_MAX_SQL_LENGTH
|
|
+ "MAX_SQL_LENGTH=" CTIMEOPT_VAL(SQLITE_MAX_SQL_LENGTH),
|
|
+#endif
|
|
+#ifdef SQLITE_MAX_TRIGGER_DEPTH
|
|
+ "MAX_TRIGGER_DEPTH=" CTIMEOPT_VAL(SQLITE_MAX_TRIGGER_DEPTH),
|
|
+#endif
|
|
+#ifdef SQLITE_MAX_VARIABLE_NUMBER
|
|
+ "MAX_VARIABLE_NUMBER=" CTIMEOPT_VAL(SQLITE_MAX_VARIABLE_NUMBER),
|
|
+#endif
|
|
+#ifdef SQLITE_MAX_VDBE_OP
|
|
+ "MAX_VDBE_OP=" CTIMEOPT_VAL(SQLITE_MAX_VDBE_OP),
|
|
+#endif
|
|
+#ifdef SQLITE_MAX_WORKER_THREADS
|
|
+ "MAX_WORKER_THREADS=" CTIMEOPT_VAL(SQLITE_MAX_WORKER_THREADS),
|
|
+#endif
|
|
+#ifdef SQLITE_MEMDEBUG
|
|
+ "MEMDEBUG",
|
|
+#endif
|
|
+#ifdef SQLITE_MIXED_ENDIAN_64BIT_FLOAT
|
|
+ "MIXED_ENDIAN_64BIT_FLOAT",
|
|
+#endif
|
|
+#ifdef SQLITE_MMAP_READWRITE
|
|
+ "MMAP_READWRITE",
|
|
+#endif
|
|
+#ifdef SQLITE_MUTEX_NOOP
|
|
+ "MUTEX_NOOP",
|
|
+#endif
|
|
+#ifdef SQLITE_MUTEX_OMIT
|
|
+ "MUTEX_OMIT",
|
|
+#endif
|
|
+#ifdef SQLITE_MUTEX_PTHREADS
|
|
+ "MUTEX_PTHREADS",
|
|
+#endif
|
|
+#ifdef SQLITE_MUTEX_W32
|
|
+ "MUTEX_W32",
|
|
+#endif
|
|
+#ifdef SQLITE_NEED_ERR_NAME
|
|
+ "NEED_ERR_NAME",
|
|
+#endif
|
|
+#ifdef SQLITE_NO_SYNC
|
|
+ "NO_SYNC",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_ALTERTABLE
|
|
+ "OMIT_ALTERTABLE",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_ANALYZE
|
|
+ "OMIT_ANALYZE",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_ATTACH
|
|
+ "OMIT_ATTACH",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_AUTHORIZATION
|
|
+ "OMIT_AUTHORIZATION",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_AUTOINCREMENT
|
|
+ "OMIT_AUTOINCREMENT",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_AUTOINIT
|
|
+ "OMIT_AUTOINIT",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_AUTOMATIC_INDEX
|
|
+ "OMIT_AUTOMATIC_INDEX",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_AUTORESET
|
|
+ "OMIT_AUTORESET",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_AUTOVACUUM
|
|
+ "OMIT_AUTOVACUUM",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_BETWEEN_OPTIMIZATION
|
|
+ "OMIT_BETWEEN_OPTIMIZATION",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_BLOB_LITERAL
|
|
+ "OMIT_BLOB_LITERAL",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_CAST
|
|
+ "OMIT_CAST",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_CHECK
|
|
+ "OMIT_CHECK",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_COMPLETE
|
|
+ "OMIT_COMPLETE",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_COMPOUND_SELECT
|
|
+ "OMIT_COMPOUND_SELECT",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_CONFLICT_CLAUSE
|
|
+ "OMIT_CONFLICT_CLAUSE",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_CTE
|
|
+ "OMIT_CTE",
|
|
+#endif
|
|
+#if defined(SQLITE_OMIT_DATETIME_FUNCS) || defined(SQLITE_OMIT_FLOATING_POINT)
|
|
+ "OMIT_DATETIME_FUNCS",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_DECLTYPE
|
|
+ "OMIT_DECLTYPE",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_DEPRECATED
|
|
+ "OMIT_DEPRECATED",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_DESERIALIZE
|
|
+ "OMIT_DESERIALIZE",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_DISKIO
|
|
+ "OMIT_DISKIO",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_EXPLAIN
|
|
+ "OMIT_EXPLAIN",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_FLAG_PRAGMAS
|
|
+ "OMIT_FLAG_PRAGMAS",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_FLOATING_POINT
|
|
+ "OMIT_FLOATING_POINT",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_FOREIGN_KEY
|
|
+ "OMIT_FOREIGN_KEY",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_GET_TABLE
|
|
+ "OMIT_GET_TABLE",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_HEX_INTEGER
|
|
+ "OMIT_HEX_INTEGER",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_INCRBLOB
|
|
+ "OMIT_INCRBLOB",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_INTEGRITY_CHECK
|
|
+ "OMIT_INTEGRITY_CHECK",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_INTROSPECTION_PRAGMAS
|
|
+ "OMIT_INTROSPECTION_PRAGMAS",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_JSON
|
|
+ "OMIT_JSON",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_LIKE_OPTIMIZATION
|
|
+ "OMIT_LIKE_OPTIMIZATION",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_LOAD_EXTENSION
|
|
+ "OMIT_LOAD_EXTENSION",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_LOCALTIME
|
|
+ "OMIT_LOCALTIME",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_LOOKASIDE
|
|
+ "OMIT_LOOKASIDE",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_MEMORYDB
|
|
+ "OMIT_MEMORYDB",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_OR_OPTIMIZATION
|
|
+ "OMIT_OR_OPTIMIZATION",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_PAGER_PRAGMAS
|
|
+ "OMIT_PAGER_PRAGMAS",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_PARSER_TRACE
|
|
+ "OMIT_PARSER_TRACE",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_POPEN
|
|
+ "OMIT_POPEN",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_PRAGMA
|
|
+ "OMIT_PRAGMA",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_PROGRESS_CALLBACK
|
|
+ "OMIT_PROGRESS_CALLBACK",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_QUICKBALANCE
|
|
+ "OMIT_QUICKBALANCE",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_REINDEX
|
|
+ "OMIT_REINDEX",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_SCHEMA_PRAGMAS
|
|
+ "OMIT_SCHEMA_PRAGMAS",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS
|
|
+ "OMIT_SCHEMA_VERSION_PRAGMAS",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_SHARED_CACHE
|
|
+ "OMIT_SHARED_CACHE",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_SHUTDOWN_DIRECTORIES
|
|
+ "OMIT_SHUTDOWN_DIRECTORIES",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_SUBQUERY
|
|
+ "OMIT_SUBQUERY",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_TCL_VARIABLE
|
|
+ "OMIT_TCL_VARIABLE",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_TEMPDB
|
|
+ "OMIT_TEMPDB",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_TEST_CONTROL
|
|
+ "OMIT_TEST_CONTROL",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_TRACE
|
|
+# if SQLITE_OMIT_TRACE != 1
|
|
+ "OMIT_TRACE=" CTIMEOPT_VAL(SQLITE_OMIT_TRACE),
|
|
+# endif
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_TRIGGER
|
|
+ "OMIT_TRIGGER",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_TRUNCATE_OPTIMIZATION
|
|
+ "OMIT_TRUNCATE_OPTIMIZATION",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_UTF16
|
|
+ "OMIT_UTF16",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_VACUUM
|
|
+ "OMIT_VACUUM",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_VIEW
|
|
+ "OMIT_VIEW",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_VIRTUALTABLE
|
|
+ "OMIT_VIRTUALTABLE",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_WAL
|
|
+ "OMIT_WAL",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_WSD
|
|
+ "OMIT_WSD",
|
|
+#endif
|
|
+#ifdef SQLITE_OMIT_XFER_OPT
|
|
+ "OMIT_XFER_OPT",
|
|
+#endif
|
|
+#ifdef SQLITE_PERFORMANCE_TRACE
|
|
+ "PERFORMANCE_TRACE",
|
|
+#endif
|
|
+#ifdef SQLITE_POWERSAFE_OVERWRITE
|
|
+# if SQLITE_POWERSAFE_OVERWRITE != 1
|
|
+ "POWERSAFE_OVERWRITE=" CTIMEOPT_VAL(SQLITE_POWERSAFE_OVERWRITE),
|
|
+# endif
|
|
+#endif
|
|
+#ifdef SQLITE_PREFER_PROXY_LOCKING
|
|
+ "PREFER_PROXY_LOCKING",
|
|
+#endif
|
|
+#ifdef SQLITE_PROXY_DEBUG
|
|
+ "PROXY_DEBUG",
|
|
+#endif
|
|
+#ifdef SQLITE_REVERSE_UNORDERED_SELECTS
|
|
+ "REVERSE_UNORDERED_SELECTS",
|
|
+#endif
|
|
+#ifdef SQLITE_RTREE_INT_ONLY
|
|
+ "RTREE_INT_ONLY",
|
|
+#endif
|
|
+#ifdef SQLITE_SECURE_DELETE
|
|
+ "SECURE_DELETE",
|
|
+#endif
|
|
+#ifdef SQLITE_SMALL_STACK
|
|
+ "SMALL_STACK",
|
|
+#endif
|
|
+#ifdef SQLITE_SORTER_PMASZ
|
|
+ "SORTER_PMASZ=" CTIMEOPT_VAL(SQLITE_SORTER_PMASZ),
|
|
+#endif
|
|
+#ifdef SQLITE_SOUNDEX
|
|
+ "SOUNDEX",
|
|
+#endif
|
|
+#ifdef SQLITE_STAT4_SAMPLES
|
|
+ "STAT4_SAMPLES=" CTIMEOPT_VAL(SQLITE_STAT4_SAMPLES),
|
|
+#endif
|
|
+#ifdef SQLITE_STMTJRNL_SPILL
|
|
+ "STMTJRNL_SPILL=" CTIMEOPT_VAL(SQLITE_STMTJRNL_SPILL),
|
|
+#endif
|
|
+#ifdef SQLITE_SUBSTR_COMPATIBILITY
|
|
+ "SUBSTR_COMPATIBILITY",
|
|
+#endif
|
|
+#if (!defined(SQLITE_WIN32_MALLOC) \
|
|
+ && !defined(SQLITE_ZERO_MALLOC) \
|
|
+ && !defined(SQLITE_MEMDEBUG) \
|
|
+ ) || defined(SQLITE_SYSTEM_MALLOC)
|
|
+ "SYSTEM_MALLOC",
|
|
+#endif
|
|
+#ifdef SQLITE_TCL
|
|
+ "TCL",
|
|
+#endif
|
|
+#ifdef SQLITE_TEMP_STORE
|
|
+ "TEMP_STORE=" CTIMEOPT_VAL(SQLITE_TEMP_STORE),
|
|
+#endif
|
|
+#ifdef SQLITE_TEST
|
|
+ "TEST",
|
|
+#endif
|
|
+#if defined(SQLITE_THREADSAFE)
|
|
+ "THREADSAFE=" CTIMEOPT_VAL(SQLITE_THREADSAFE),
|
|
+#elif defined(THREADSAFE)
|
|
+ "THREADSAFE=" CTIMEOPT_VAL(THREADSAFE),
|
|
+#else
|
|
+ "THREADSAFE=1",
|
|
+#endif
|
|
+#ifdef SQLITE_UNLINK_AFTER_CLOSE
|
|
+ "UNLINK_AFTER_CLOSE",
|
|
+#endif
|
|
+#ifdef SQLITE_UNTESTABLE
|
|
+ "UNTESTABLE",
|
|
+#endif
|
|
+#ifdef SQLITE_USER_AUTHENTICATION
|
|
+ "USER_AUTHENTICATION",
|
|
+#endif
|
|
+#ifdef SQLITE_USE_ALLOCA
|
|
+ "USE_ALLOCA",
|
|
+#endif
|
|
+#ifdef SQLITE_USE_FCNTL_TRACE
|
|
+ "USE_FCNTL_TRACE",
|
|
+#endif
|
|
+#ifdef SQLITE_USE_URI
|
|
+ "USE_URI",
|
|
+#endif
|
|
+#ifdef SQLITE_VDBE_COVERAGE
|
|
+ "VDBE_COVERAGE",
|
|
+#endif
|
|
+#ifdef SQLITE_WIN32_MALLOC
|
|
+ "WIN32_MALLOC",
|
|
+#endif
|
|
+#ifdef SQLITE_ZERO_MALLOC
|
|
+ "ZERO_MALLOC",
|
|
+#endif
|
|
+
|
|
+} ;
|
|
+
|
|
+SQLITE_PRIVATE const char **sqlite3CompileOptions(int *pnOpt){
|
|
+ *pnOpt = sizeof(sqlite3azCompileOpt) / sizeof(sqlite3azCompileOpt[0]);
|
|
+ return (const char**)sqlite3azCompileOpt;
|
|
+}
|
|
+
|
|
+#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
|
|
+
|
|
+/************** End of ctime.c ***********************************************/
|
|
/************** Begin file global.c ******************************************/
|
|
/*
|
|
** 2008 June 13
|
|
@@ -20204,7 +21993,7 @@ SQLITE_PRIVATE const char **sqlite3CompileOptions(int *pnOpt);
|
|
/* #include "sqliteInt.h" */
|
|
|
|
/* An array to map all upper-case characters into their corresponding
|
|
-** lower-case character.
|
|
+** lower-case character.
|
|
**
|
|
** SQLite only considers US-ASCII (or EBCDIC) characters. We do not
|
|
** handle case conversions for the UTF character set since the tables
|
|
@@ -20226,7 +22015,7 @@ SQLITE_PRIVATE const unsigned char sqlite3UpperToLower[] = {
|
|
198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,
|
|
216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,
|
|
234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,
|
|
- 252,253,254,255
|
|
+ 252,253,254,255,
|
|
#endif
|
|
#ifdef SQLITE_EBCDIC
|
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 0x */
|
|
@@ -20246,7 +22035,35 @@ SQLITE_PRIVATE const unsigned char sqlite3UpperToLower[] = {
|
|
224,225,162,163,164,165,166,167,168,169,234,235,236,237,238,239, /* Ex */
|
|
240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255, /* Fx */
|
|
#endif
|
|
+/* All of the upper-to-lower conversion data is above. The following
|
|
+** 18 integers are completely unrelated. They are appended to the
|
|
+** sqlite3UpperToLower[] array to avoid UBSAN warnings. Here's what is
|
|
+** going on:
|
|
+**
|
|
+** The SQL comparison operators (<>, =, >, <=, <, and >=) are implemented
|
|
+** by invoking sqlite3MemCompare(A,B) which compares values A and B and
|
|
+** returns negative, zero, or positive if A is less then, equal to, or
|
|
+** greater than B, respectively. Then the true false results is found by
|
|
+** consulting sqlite3aLTb[opcode], sqlite3aEQb[opcode], or
|
|
+** sqlite3aGTb[opcode] depending on whether the result of compare(A,B)
|
|
+** is negative, zero, or positive, where opcode is the specific opcode.
|
|
+** The only works because the comparison opcodes are consecutive and in
|
|
+** this order: NE EQ GT LE LT GE. Various assert()s throughout the code
|
|
+** ensure that is the case.
|
|
+**
|
|
+** These elements must be appended to another array. Otherwise the
|
|
+** index (here shown as [256-OP_Ne]) would be out-of-bounds and thus
|
|
+** be undefined behavior. That's goofy, but the C-standards people thought
|
|
+** it was a good idea, so here we are.
|
|
+*/
|
|
+/* NE EQ GT LE LT GE */
|
|
+ 1, 0, 0, 1, 1, 0, /* aLTb[]: Use when compare(A,B) less than zero */
|
|
+ 0, 1, 0, 1, 0, 1, /* aEQb[]: Use when compare(A,B) equals zero */
|
|
+ 1, 0, 1, 0, 0, 1 /* aGTb[]: Use when compare(A,B) greater than zero*/
|
|
};
|
|
+SQLITE_PRIVATE const unsigned char *sqlite3aLTb = &sqlite3UpperToLower[256-OP_Ne];
|
|
+SQLITE_PRIVATE const unsigned char *sqlite3aEQb = &sqlite3UpperToLower[256+6-OP_Ne];
|
|
+SQLITE_PRIVATE const unsigned char *sqlite3aGTb = &sqlite3UpperToLower[256+12-OP_Ne];
|
|
|
|
/*
|
|
** The following 256 byte lookup table is used to support SQLites built-in
|
|
@@ -20271,7 +22088,7 @@ SQLITE_PRIVATE const unsigned char sqlite3UpperToLower[] = {
|
|
** The equivalent of tolower() is implemented using the sqlite3UpperToLower[]
|
|
** array. tolower() is used more often than toupper() by SQLite.
|
|
**
|
|
-** Bit 0x40 is set if the character is non-alphanumeric and can be used in an
|
|
+** Bit 0x40 is set if the character is non-alphanumeric and can be used in an
|
|
** SQLite identifier. Identifiers are alphanumerics, "_", "$", and any
|
|
** non-ASCII UTF character. Hence the test for whether or not a character is
|
|
** part of an identifier is 0x46.
|
|
@@ -20324,16 +22141,9 @@ SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = {
|
|
** EVIDENCE-OF: R-43642-56306 By default, URI handling is globally
|
|
** disabled. The default value may be changed by compiling with the
|
|
** SQLITE_USE_URI symbol defined.
|
|
-**
|
|
-** URI filenames are enabled by default if SQLITE_HAS_CODEC is
|
|
-** enabled.
|
|
*/
|
|
#ifndef SQLITE_USE_URI
|
|
-# ifdef SQLITE_HAS_CODEC
|
|
-# define SQLITE_USE_URI 1
|
|
-# else
|
|
-# define SQLITE_USE_URI 0
|
|
-# endif
|
|
+# define SQLITE_USE_URI 0
|
|
#endif
|
|
|
|
/* EVIDENCE-OF: R-38720-18127 The default setting is determined by the
|
|
@@ -20343,7 +22153,7 @@ SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = {
|
|
#if !defined(SQLITE_ALLOW_COVERING_INDEX_SCAN)
|
|
# define SQLITE_ALLOW_COVERING_INDEX_SCAN 1
|
|
#else
|
|
-# if !SQLITE_ALLOW_COVERING_INDEX_SCAN
|
|
+# if !SQLITE_ALLOW_COVERING_INDEX_SCAN
|
|
# error "Compile-time disabling of covering index scan using the\
|
|
-DSQLITE_ALLOW_COVERING_INDEX_SCAN=0 option is deprecated.\
|
|
Contact SQLite developers if this is a problem for you, and\
|
|
@@ -20366,7 +22176,7 @@ SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = {
|
|
** if journal_mode=MEMORY or if temp_store=MEMORY, regardless of this
|
|
** setting.)
|
|
*/
|
|
-#ifndef SQLITE_STMTJRNL_SPILL
|
|
+#ifndef SQLITE_STMTJRNL_SPILL
|
|
# define SQLITE_STMTJRNL_SPILL (64*1024)
|
|
#endif
|
|
|
|
@@ -20447,16 +22257,20 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
|
|
0, /* xVdbeBranch */
|
|
0, /* pVbeBranchArg */
|
|
#endif
|
|
-#ifdef SQLITE_ENABLE_DESERIALIZE
|
|
+#ifndef SQLITE_OMIT_DESERIALIZE
|
|
SQLITE_MEMDB_DEFAULT_MAXSIZE, /* mxMemdbSize */
|
|
#endif
|
|
#ifndef SQLITE_UNTESTABLE
|
|
0, /* xTestCallback */
|
|
#endif
|
|
0, /* bLocaltimeFault */
|
|
+ 0, /* xAltLocaltime */
|
|
0x7ffffffe, /* iOnceResetThreshold */
|
|
SQLITE_DEFAULT_SORTERREF_SIZE, /* szSorterRef */
|
|
0, /* iPrngSeed */
|
|
+#ifdef SQLITE_DEBUG
|
|
+ {0,0,0,0,0,0} /* aTune */
|
|
+#endif
|
|
};
|
|
|
|
/*
|
|
@@ -20466,6 +22280,18 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
|
|
*/
|
|
SQLITE_PRIVATE FuncDefHash sqlite3BuiltinFunctions;
|
|
|
|
+#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_DEBUG)
|
|
+/*
|
|
+** Counter used for coverage testing. Does not come into play for
|
|
+** release builds.
|
|
+**
|
|
+** Access to this global variable is not mutex protected. This might
|
|
+** result in TSAN warnings. But as the variable does not exist in
|
|
+** release builds, that should not be a concern.
|
|
+*/
|
|
+SQLITE_PRIVATE unsigned int sqlite3CoverageCounter;
|
|
+#endif /* SQLITE_COVERAGE_TEST || SQLITE_DEBUG */
|
|
+
|
|
#ifdef VDBE_PROFILE
|
|
/*
|
|
** The following performance counter can be used in place of
|
|
@@ -20496,12 +22322,18 @@ SQLITE_PRIVATE sqlite3_uint64 sqlite3NProfileCnt = 0;
|
|
SQLITE_PRIVATE int sqlite3PendingByte = 0x40000000;
|
|
#endif
|
|
|
|
+/*
|
|
+** Tracing flags set by SQLITE_TESTCTRL_TRACEFLAGS.
|
|
+*/
|
|
+SQLITE_PRIVATE u32 sqlite3TreeTrace = 0;
|
|
+SQLITE_PRIVATE u32 sqlite3WhereTrace = 0;
|
|
+
|
|
/* #include "opcodes.h" */
|
|
/*
|
|
** Properties of opcodes. The OPFLG_INITIALIZER macro is
|
|
** created by mkopcodeh.awk during compilation. Data is obtained
|
|
** from the comments following the "case OP_xxxx:" statements in
|
|
-** the vdbe.c file.
|
|
+** the vdbe.c file.
|
|
*/
|
|
SQLITE_PRIVATE const unsigned char sqlite3OpcodeProperty[] = OPFLG_INITIALIZER;
|
|
|
|
@@ -20510,6 +22342,36 @@ SQLITE_PRIVATE const unsigned char sqlite3OpcodeProperty[] = OPFLG_INITIALIZER;
|
|
*/
|
|
SQLITE_PRIVATE const char sqlite3StrBINARY[] = "BINARY";
|
|
|
|
+/*
|
|
+** Standard typenames. These names must match the COLTYPE_* definitions.
|
|
+** Adjust the SQLITE_N_STDTYPE value if adding or removing entries.
|
|
+**
|
|
+** sqlite3StdType[] The actual names of the datatypes.
|
|
+**
|
|
+** sqlite3StdTypeLen[] The length (in bytes) of each entry
|
|
+** in sqlite3StdType[].
|
|
+**
|
|
+** sqlite3StdTypeAffinity[] The affinity associated with each entry
|
|
+** in sqlite3StdType[].
|
|
+*/
|
|
+SQLITE_PRIVATE const unsigned char sqlite3StdTypeLen[] = { 3, 4, 3, 7, 4, 4 };
|
|
+SQLITE_PRIVATE const char sqlite3StdTypeAffinity[] = {
|
|
+ SQLITE_AFF_NUMERIC,
|
|
+ SQLITE_AFF_BLOB,
|
|
+ SQLITE_AFF_INTEGER,
|
|
+ SQLITE_AFF_INTEGER,
|
|
+ SQLITE_AFF_REAL,
|
|
+ SQLITE_AFF_TEXT
|
|
+};
|
|
+SQLITE_PRIVATE const char *sqlite3StdType[] = {
|
|
+ "ANY",
|
|
+ "BLOB",
|
|
+ "INT",
|
|
+ "INTEGER",
|
|
+ "REAL",
|
|
+ "TEXT"
|
|
+};
|
|
+
|
|
/************** End of global.c **********************************************/
|
|
/************** Begin file status.c ******************************************/
|
|
/*
|
|
@@ -20563,7 +22425,8 @@ SQLITE_PRIVATE const char sqlite3StrBINARY[] = "BINARY";
|
|
** "explain" P4 display logic is enabled.
|
|
*/
|
|
#if !defined(SQLITE_OMIT_EXPLAIN) || !defined(NDEBUG) \
|
|
- || defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
|
|
+ || defined(VDBE_PROFILE) || defined(SQLITE_DEBUG) \
|
|
+ || defined(SQLITE_ENABLE_BYTECODE_VTAB)
|
|
# define VDBE_DISPLAY_P4 1
|
|
#else
|
|
# define VDBE_DISPLAY_P4 0
|
|
@@ -20606,7 +22469,7 @@ typedef struct AuxData AuxData;
|
|
typedef struct VdbeCursor VdbeCursor;
|
|
struct VdbeCursor {
|
|
u8 eCurType; /* One of the CURTYPE_* values above */
|
|
- i8 iDb; /* Index of cursor database in db->aDb[] (or -1) */
|
|
+ i8 iDb; /* Index of cursor database in db->aDb[] */
|
|
u8 nullRow; /* True if pointing to a row with no data */
|
|
u8 deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */
|
|
u8 isTable; /* True for rowid tables. False for indexes */
|
|
@@ -20617,10 +22480,13 @@ struct VdbeCursor {
|
|
Bool isEphemeral:1; /* True for an ephemeral table */
|
|
Bool useRandomRowid:1; /* Generate new record numbers semi-randomly */
|
|
Bool isOrdered:1; /* True if the table is not BTREE_UNORDERED */
|
|
- Bool seekHit:1; /* See the OP_SeekHit and OP_IfNoHope opcodes */
|
|
- Btree *pBtx; /* Separate file holding temporary table */
|
|
+ Bool noReuse:1; /* OpenEphemeral may not reuse this cursor */
|
|
+ u16 seekHit; /* See the OP_SeekHit and OP_IfNoHope opcodes */
|
|
+ union { /* pBtx for isEphermeral. pAltMap otherwise */
|
|
+ Btree *pBtx; /* Separate file holding temporary table */
|
|
+ u32 *aAltMap; /* Mapping from table to index column numbers */
|
|
+ } ub;
|
|
i64 seqCount; /* Sequence counter */
|
|
- int *aAltMap; /* Mapping from table to index column numbers */
|
|
|
|
/* Cached OP_Column parse information is only valid if cacheStatus matches
|
|
** Vdbe.cacheCtr. Vdbe.cacheCtr will never take on the value of
|
|
@@ -20662,6 +22528,11 @@ struct VdbeCursor {
|
|
u32 aType[1]; /* Type values record decode. MUST BE LAST */
|
|
};
|
|
|
|
+/* Return true if P is a null-only cursor
|
|
+*/
|
|
+#define IsNullCursor(P) \
|
|
+ ((P)->eCurType==CURTYPE_PSEUDO && (P)->nullRow && (P)->seekResult==0)
|
|
+
|
|
|
|
/*
|
|
** A value for VdbeCursor.cacheStatus that means the cache is always invalid.
|
|
@@ -20672,7 +22543,7 @@ struct VdbeCursor {
|
|
** 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
|
|
** well as the current memory cell array and various other frame specific
|
|
-** values stored in the Vdbe struct. When the sub-program is finished,
|
|
+** values stored in the Vdbe struct. When the sub-program is finished,
|
|
** these values are copied back to the Vdbe from the VdbeFrame structure,
|
|
** restoring the state of the VM to as it was before the sub-program
|
|
** began executing.
|
|
@@ -20694,7 +22565,6 @@ struct VdbeFrame {
|
|
Vdbe *v; /* VM this frame belongs to */
|
|
VdbeFrame *pParent; /* Parent of this frame, or NULL if parent is main */
|
|
Op *aOp; /* Program instructions for parent frame */
|
|
- i64 *anExec; /* Event counters from parent frame */
|
|
Mem *aMem; /* Array of memory cells for parent frame */
|
|
VdbeCursor **apCsr; /* Array of Vdbe cursors for parent frame */
|
|
u8 *aOnce; /* Bitmask used by OP_Once */
|
|
@@ -20710,8 +22580,8 @@ struct VdbeFrame {
|
|
int nMem; /* Number of entries in aMem */
|
|
int nChildMem; /* Number of memory cells for child frame */
|
|
int nChildCsr; /* Number of cursors for child frame */
|
|
- int nChange; /* Statement changes (Vdbe.nChange) */
|
|
- int nDbChange; /* Value of db->nChange */
|
|
+ i64 nChange; /* Statement changes (Vdbe.nChange) */
|
|
+ i64 nDbChange; /* Value of db->nChange */
|
|
};
|
|
|
|
/* Magic number for sanity checking on VdbeFrame objects */
|
|
@@ -20736,16 +22606,16 @@ struct sqlite3_value {
|
|
const char *zPType; /* Pointer type when MEM_Term|MEM_Subtype|MEM_Null */
|
|
FuncDef *pDef; /* Used only when flags==MEM_Agg */
|
|
} u;
|
|
+ char *z; /* String or BLOB value */
|
|
+ int n; /* Number of characters in string value, excluding '\0' */
|
|
u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */
|
|
u8 enc; /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */
|
|
u8 eSubtype; /* Subtype for this value */
|
|
- int n; /* Number of characters in string value, excluding '\0' */
|
|
- char *z; /* String or BLOB value */
|
|
/* ShallowCopy only needs to copy the information above */
|
|
- char *zMalloc; /* Space to hold MEM_Str or MEM_Blob if szMalloc>0 */
|
|
+ sqlite3 *db; /* The associated database connection */
|
|
int szMalloc; /* Size of the zMalloc allocation */
|
|
u32 uTemp; /* Transient storage for serial_type in OP_MakeRecord */
|
|
- sqlite3 *db; /* The associated database connection */
|
|
+ char *zMalloc; /* Space to hold MEM_Str or MEM_Blob if szMalloc>0 */
|
|
void (*xDel)(void*);/* Destructor for Mem.z - only valid if MEM_Dyn */
|
|
#ifdef SQLITE_DEBUG
|
|
Mem *pScopyFrom; /* This Mem is a shallow copy of pScopyFrom */
|
|
@@ -20757,11 +22627,43 @@ struct sqlite3_value {
|
|
** Size of struct Mem not including the Mem.zMalloc member or anything that
|
|
** follows.
|
|
*/
|
|
-#define MEMCELLSIZE offsetof(Mem,zMalloc)
|
|
+#define MEMCELLSIZE offsetof(Mem,db)
|
|
|
|
-/* One or more of the following flags are set to indicate the validOK
|
|
+/* One or more of the following flags are set to indicate the
|
|
** representations of the value stored in the Mem struct.
|
|
**
|
|
+** * MEM_Null An SQL NULL value
|
|
+**
|
|
+** * MEM_Null|MEM_Zero An SQL NULL with the virtual table
|
|
+** UPDATE no-change flag set
|
|
+**
|
|
+** * MEM_Null|MEM_Term| An SQL NULL, but also contains a
|
|
+** MEM_Subtype pointer accessible using
|
|
+** sqlite3_value_pointer().
|
|
+**
|
|
+** * MEM_Null|MEM_Cleared Special SQL NULL that compares non-equal
|
|
+** to other NULLs even using the IS operator.
|
|
+**
|
|
+** * MEM_Str A string, stored in Mem.z with
|
|
+** length Mem.n. Zero-terminated if
|
|
+** MEM_Term is set. This flag is
|
|
+** incompatible with MEM_Blob and
|
|
+** MEM_Null, but can appear with MEM_Int,
|
|
+** MEM_Real, and MEM_IntReal.
|
|
+**
|
|
+** * MEM_Blob A blob, stored in Mem.z length Mem.n.
|
|
+** Incompatible with MEM_Str, MEM_Null,
|
|
+** MEM_Int, MEM_Real, and MEM_IntReal.
|
|
+**
|
|
+** * MEM_Blob|MEM_Zero A blob in Mem.z of length Mem.n plus
|
|
+** MEM.u.i extra 0x00 bytes at the end.
|
|
+**
|
|
+** * MEM_Int Integer stored in Mem.u.i.
|
|
+**
|
|
+** * MEM_Real Real stored in Mem.u.r.
|
|
+**
|
|
+** * MEM_IntReal Real stored as an integer in Mem.u.i.
|
|
+**
|
|
** If the MEM_Null flag is set, then the value is an SQL NULL value.
|
|
** For a pointer type created using sqlite3_bind_pointer() or
|
|
** sqlite3_result_pointer() the MEM_Term and MEM_Subtype flags are also set.
|
|
@@ -20769,9 +22671,10 @@ struct sqlite3_value {
|
|
** If the MEM_Str flag is set then Mem.z points at a string representation.
|
|
** Usually this is encoded in the same unicode encoding as the main
|
|
** database (see below for exceptions). If the MEM_Term flag is also
|
|
-** set, then the string is nul terminated. The MEM_Int and MEM_Real
|
|
+** set, then the string is nul terminated. The MEM_Int and MEM_Real
|
|
** flags may coexist with the MEM_Str flag.
|
|
*/
|
|
+#define MEM_Undefined 0x0000 /* Value is undefined */
|
|
#define MEM_Null 0x0001 /* Value is NULL (or a pointer) */
|
|
#define MEM_Str 0x0002 /* Value is a string */
|
|
#define MEM_Int 0x0004 /* Value is an integer */
|
|
@@ -20779,28 +22682,24 @@ struct sqlite3_value {
|
|
#define MEM_Blob 0x0010 /* Value is a BLOB */
|
|
#define MEM_IntReal 0x0020 /* MEM_Int that stringifies like MEM_Real */
|
|
#define MEM_AffMask 0x003f /* Mask of affinity bits */
|
|
+
|
|
+/* Extra bits that modify the meanings of the core datatypes above
|
|
+*/
|
|
#define MEM_FromBind 0x0040 /* Value originates from sqlite3_bind() */
|
|
-#define MEM_Undefined 0x0080 /* Value is undefined */
|
|
+ /* 0x0080 // Available */
|
|
#define MEM_Cleared 0x0100 /* NULL set by OP_Null, not from data */
|
|
-#define MEM_TypeMask 0xc1bf /* Mask of type bits */
|
|
-
|
|
+#define MEM_Term 0x0200 /* String in Mem.z is zero terminated */
|
|
+#define MEM_Zero 0x0400 /* Mem.i contains count of 0s appended to blob */
|
|
+#define MEM_Subtype 0x0800 /* Mem.eSubtype is valid */
|
|
+#define MEM_TypeMask 0x0dbf /* Mask of type bits */
|
|
|
|
-/* Whenever Mem contains a valid string or blob representation, one of
|
|
-** the following flags must be set to determine the memory management
|
|
-** policy for Mem.z. The MEM_Term flag tells us whether or not the
|
|
-** string is \000 or \u0000 terminated
|
|
+/* Bits that determine the storage for Mem.z for a string or blob or
|
|
+** aggregate accumulator.
|
|
*/
|
|
-#define MEM_Term 0x0200 /* String in Mem.z is zero terminated */
|
|
-#define MEM_Dyn 0x0400 /* Need to call Mem.xDel() on Mem.z */
|
|
-#define MEM_Static 0x0800 /* Mem.z points to a static string */
|
|
-#define MEM_Ephem 0x1000 /* Mem.z points to an ephemeral string */
|
|
-#define MEM_Agg 0x2000 /* Mem.z points to an agg function context */
|
|
-#define MEM_Zero 0x4000 /* Mem.i contains count of 0s appended to blob */
|
|
-#define MEM_Subtype 0x8000 /* Mem.eSubtype is valid */
|
|
-#ifdef SQLITE_OMIT_INCRBLOB
|
|
- #undef MEM_Zero
|
|
- #define MEM_Zero 0x0000
|
|
-#endif
|
|
+#define MEM_Dyn 0x1000 /* Need to call Mem.xDel() on Mem.z */
|
|
+#define MEM_Static 0x2000 /* Mem.z points to a static string */
|
|
+#define MEM_Ephem 0x4000 /* Mem.z points to an ephemeral string */
|
|
+#define MEM_Agg 0x8000 /* Mem.z points to an agg function context */
|
|
|
|
/* Return TRUE if Mem X contains dynamically allocated content - anything
|
|
** that needs to be deallocated to avoid a leak.
|
|
@@ -20822,15 +22721,19 @@ struct sqlite3_value {
|
|
&& (X)->n==0 && (X)->u.nZero==0)
|
|
|
|
/*
|
|
-** Return true if a memory cell is not marked as invalid. This macro
|
|
+** Return true if a memory cell has been initialized and is valid.
|
|
** is for use inside assert() statements only.
|
|
+**
|
|
+** A Memory cell is initialized if at least one of the
|
|
+** MEM_Null, MEM_Str, MEM_Int, MEM_Real, MEM_Blob, or MEM_IntReal bits
|
|
+** is set. It is "undefined" if all those bits are zero.
|
|
*/
|
|
#ifdef SQLITE_DEBUG
|
|
-#define memIsValid(M) ((M)->flags & MEM_Undefined)==0
|
|
+#define memIsValid(M) ((M)->flags & MEM_AffMask)!=0
|
|
#endif
|
|
|
|
/*
|
|
-** Each auxiliary data pointer stored by a user defined function
|
|
+** Each auxiliary data pointer stored by a user defined function
|
|
** implementation calling sqlite3_set_auxdata() is stored in an instance
|
|
** of this structure. All such structures associated with a single VM
|
|
** are stored in a linked list headed at Vdbe.pAuxData. All are destroyed
|
|
@@ -20864,6 +22767,7 @@ struct sqlite3_context {
|
|
Vdbe *pVdbe; /* The VM that owns this context */
|
|
int iOp; /* Instruction number of OP_Function */
|
|
int isError; /* Error code returned by the function. */
|
|
+ u8 enc; /* Encoding to use for results */
|
|
u8 skipFlag; /* Skip accumulator loading if true */
|
|
u8 argc; /* Number of arguments */
|
|
sqlite3_value *argv[1]; /* Argument set */
|
|
@@ -20876,10 +22780,19 @@ typedef unsigned bft; /* Bit Field Type */
|
|
|
|
/* The ScanStatus object holds a single value for the
|
|
** sqlite3_stmt_scanstatus() interface.
|
|
+**
|
|
+** aAddrRange[]:
|
|
+** This array is used by ScanStatus elements associated with EQP
|
|
+** notes that make an SQLITE_SCANSTAT_NCYCLE value available. It is
|
|
+** an array of up to 3 ranges of VM addresses for which the Vdbe.anCycle[]
|
|
+** values should be summed to calculate the NCYCLE value. Each pair of
|
|
+** integer addresses is a start and end address (both inclusive) for a range
|
|
+** instructions. A start value of 0 indicates an empty range.
|
|
*/
|
|
typedef struct ScanStatus ScanStatus;
|
|
struct ScanStatus {
|
|
int addrExplain; /* OP_Explain for loop */
|
|
+ int aAddrRange[6];
|
|
int addrLoop; /* Address of "loops" counter */
|
|
int addrVisit; /* Address of "rows visited" counter */
|
|
int iSelectID; /* The "Select-ID" for this loop */
|
|
@@ -20909,16 +22822,15 @@ struct DblquoteStr {
|
|
*/
|
|
struct Vdbe {
|
|
sqlite3 *db; /* The database connection that owns this statement */
|
|
- Vdbe *pPrev,*pNext; /* Linked list of VDBEs with the same Vdbe.db */
|
|
+ Vdbe **ppVPrev,*pVNext; /* Linked list of VDBEs with the same Vdbe.db */
|
|
Parse *pParse; /* Parsing context used to create this Vdbe */
|
|
ynVar nVar; /* Number of entries in aVar[] */
|
|
- u32 magic; /* Magic number for sanity checking */
|
|
int nMem; /* Number of memory locations currently allocated */
|
|
int nCursor; /* Number of slots in apCsr[] */
|
|
u32 cacheCtr; /* VdbeCursor row cache generation counter */
|
|
int pc; /* The program counter */
|
|
int rc; /* Value to return */
|
|
- int nChange; /* Number of db changes made since last reset */
|
|
+ i64 nChange; /* Number of db changes made since last reset */
|
|
int iStatement; /* Statement number (or 0 if has no opened stmt) */
|
|
i64 iCurrentTime; /* Value of julianday('now') for this statement */
|
|
i64 nFkConstraint; /* Number of imm. FK constraints this VM */
|
|
@@ -20936,7 +22848,7 @@ struct Vdbe {
|
|
int nOp; /* Number of instructions in the program */
|
|
int nOpAlloc; /* Slots allocated for aOp[] */
|
|
Mem *aColName; /* Column names to return */
|
|
- Mem *pResultSet; /* Pointer to an array of results */
|
|
+ Mem *pResultRow; /* Current output row */
|
|
char *zErrMsg; /* Error message written here */
|
|
VList *pVList; /* Name of variables */
|
|
#ifndef SQLITE_OMIT_TRACE
|
|
@@ -20950,17 +22862,16 @@ struct Vdbe {
|
|
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 doingRerun:1; /* True if rerunning after an auto-reprepare */
|
|
bft changeCntOn:1; /* True to update the change-counter */
|
|
- bft runOnlyOnce:1; /* Automatically expire on reset */
|
|
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 */
|
|
yDbMask btreeMask; /* Bitmask of db->aDb[] entries referenced */
|
|
yDbMask lockMask; /* Subset of btreeMask that requires a lock */
|
|
- u32 aCounter[7]; /* Counters used by sqlite3_stmt_status() */
|
|
+ u32 aCounter[9]; /* Counters used by sqlite3_stmt_status() */
|
|
char *zSql; /* Text of the SQL statement that generated this */
|
|
#ifdef SQLITE_ENABLE_NORMALIZE
|
|
char *zNormSql; /* Normalization of the associated SQL statement */
|
|
@@ -20974,23 +22885,21 @@ struct Vdbe {
|
|
SubProgram *pProgram; /* Linked list of all sub-programs used by VM */
|
|
AuxData *pAuxData; /* Linked list of auxdata allocations */
|
|
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
|
|
- i64 *anExec; /* Number of times each op has been executed */
|
|
int nScan; /* Entries in aScan[] */
|
|
ScanStatus *aScan; /* Scan definitions for sqlite3_stmt_scanstatus() */
|
|
#endif
|
|
};
|
|
|
|
/*
|
|
-** The following are allowed values for Vdbe.magic
|
|
+** The following are allowed values for Vdbe.eVdbeState
|
|
*/
|
|
-#define VDBE_MAGIC_INIT 0x16bceaa5 /* Building a VDBE program */
|
|
-#define VDBE_MAGIC_RUN 0x2df20da3 /* VDBE is ready to execute */
|
|
-#define VDBE_MAGIC_HALT 0x319c2973 /* VDBE has completed execution */
|
|
-#define VDBE_MAGIC_RESET 0x48fa9f76 /* Reset and ready to run again */
|
|
-#define VDBE_MAGIC_DEAD 0x5606c3c8 /* The VDBE has been deallocated */
|
|
+#define VDBE_INIT_STATE 0 /* Prepared statement under construction */
|
|
+#define VDBE_READY_STATE 1 /* Ready to run but not yet started */
|
|
+#define VDBE_RUN_STATE 2 /* Run in progress */
|
|
+#define VDBE_HALT_STATE 3 /* Finished. Need reset() or finalize() */
|
|
|
|
/*
|
|
-** Structure used to store the context required by the
|
|
+** Structure used to store the context required by the
|
|
** sqlite3_preupdate_*() API functions.
|
|
*/
|
|
struct PreUpdate {
|
|
@@ -21002,33 +22911,72 @@ struct PreUpdate {
|
|
UnpackedRecord *pUnpacked; /* Unpacked version of aRecord[] */
|
|
UnpackedRecord *pNewUnpacked; /* Unpacked version of new.* record */
|
|
int iNewReg; /* Register for new.* values */
|
|
+ int iBlobWrite; /* Value returned by preupdate_blobwrite() */
|
|
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 upated */
|
|
Index *pPk; /* PK index if pTab is WITHOUT ROWID */
|
|
};
|
|
|
|
+/*
|
|
+** An instance of this object is used to pass an vector of values into
|
|
+** OP_VFilter, the xFilter method of a virtual table. The vector is the
|
|
+** set of values on the right-hand side of an IN constraint.
|
|
+**
|
|
+** The value as passed into xFilter is an sqlite3_value with a "pointer"
|
|
+** type, such as is generated by sqlite3_result_pointer() and read by
|
|
+** sqlite3_value_pointer. Such values have MEM_Term|MEM_Subtype|MEM_Null
|
|
+** and a subtype of 'p'. The sqlite3_vtab_in_first() and _next() interfaces
|
|
+** know how to use this object to step through all the values in the
|
|
+** right operand of the IN constraint.
|
|
+*/
|
|
+typedef struct ValueList ValueList;
|
|
+struct ValueList {
|
|
+ BtCursor *pCsr; /* An ephemeral table holding all values */
|
|
+ sqlite3_value *pOut; /* Register to hold each decoded output value */
|
|
+};
|
|
+
|
|
+/* Size of content associated with serial types that fit into a
|
|
+** single-byte varint.
|
|
+*/
|
|
+#ifndef SQLITE_AMALGAMATION
|
|
+SQLITE_PRIVATE const u8 sqlite3SmallTypeSizes[];
|
|
+#endif
|
|
+
|
|
/*
|
|
** Function prototypes
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3VdbeError(Vdbe*, const char *, ...);
|
|
SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *, VdbeCursor*);
|
|
+SQLITE_PRIVATE void sqlite3VdbeFreeCursorNN(Vdbe*,VdbeCursor*);
|
|
void sqliteVdbePopStack(Vdbe*,int);
|
|
+SQLITE_PRIVATE int SQLITE_NOINLINE sqlite3VdbeHandleMovedCursor(VdbeCursor *p);
|
|
SQLITE_PRIVATE int SQLITE_NOINLINE sqlite3VdbeFinishMoveto(VdbeCursor*);
|
|
-SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor**, int*);
|
|
SQLITE_PRIVATE int sqlite3VdbeCursorRestore(VdbeCursor*);
|
|
SQLITE_PRIVATE u32 sqlite3VdbeSerialTypeLen(u32);
|
|
SQLITE_PRIVATE u8 sqlite3VdbeOneByteSerialTypeLen(u8);
|
|
-SQLITE_PRIVATE u32 sqlite3VdbeSerialPut(unsigned char*, Mem*, u32);
|
|
-SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
|
|
+#ifdef SQLITE_MIXED_ENDIAN_64BIT_FLOAT
|
|
+SQLITE_PRIVATE u64 sqlite3FloatSwap(u64 in);
|
|
+# define swapMixedEndianFloat(X) X = sqlite3FloatSwap(X)
|
|
+#else
|
|
+# define swapMixedEndianFloat(X)
|
|
+#endif
|
|
+SQLITE_PRIVATE void sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
|
|
SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(sqlite3*, AuxData**, int, int);
|
|
|
|
int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *);
|
|
SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(sqlite3*,VdbeCursor*,UnpackedRecord*,int*);
|
|
SQLITE_PRIVATE int sqlite3VdbeIdxRowid(sqlite3*, BtCursor*, i64*);
|
|
SQLITE_PRIVATE int sqlite3VdbeExec(Vdbe*);
|
|
-#ifndef SQLITE_OMIT_EXPLAIN
|
|
+#if !defined(SQLITE_OMIT_EXPLAIN) || defined(SQLITE_ENABLE_BYTECODE_VTAB)
|
|
+SQLITE_PRIVATE int sqlite3VdbeNextOpcode(Vdbe*,Mem*,int,int*,int*,Op**);
|
|
+SQLITE_PRIVATE char *sqlite3VdbeDisplayP4(sqlite3*,Op*);
|
|
+#endif
|
|
+#if defined(SQLITE_ENABLE_EXPLAIN_COMMENTS)
|
|
+SQLITE_PRIVATE char *sqlite3VdbeDisplayComment(sqlite3*,const Op*,const char*);
|
|
+#endif
|
|
+#if !defined(SQLITE_OMIT_EXPLAIN)
|
|
SQLITE_PRIVATE int sqlite3VdbeList(Vdbe*);
|
|
#endif
|
|
SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe*);
|
|
@@ -21038,7 +22986,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemCopy(Mem*, const Mem*);
|
|
SQLITE_PRIVATE void sqlite3VdbeMemShallowCopy(Mem*, const Mem*, int);
|
|
SQLITE_PRIVATE void sqlite3VdbeMemMove(Mem*, Mem*);
|
|
SQLITE_PRIVATE int sqlite3VdbeMemNulTerminate(Mem*);
|
|
-SQLITE_PRIVATE int sqlite3VdbeMemSetStr(Mem*, const char*, int, u8, void(*)(void*));
|
|
+SQLITE_PRIVATE int sqlite3VdbeMemSetStr(Mem*, const char*, i64, u8, void(*)(void*));
|
|
SQLITE_PRIVATE void sqlite3VdbeMemSetInt64(Mem*, i64);
|
|
#ifdef SQLITE_OMIT_FLOATING_POINT
|
|
# define sqlite3VdbeMemSetDouble sqlite3VdbeMemSetInt64
|
|
@@ -21048,14 +22996,19 @@ SQLITE_PRIVATE void sqlite3VdbeMemSetDouble(Mem*, double);
|
|
SQLITE_PRIVATE void sqlite3VdbeMemSetPointer(Mem*, void*, const char*, void(*)(void*));
|
|
SQLITE_PRIVATE void sqlite3VdbeMemInit(Mem*,sqlite3*,u16);
|
|
SQLITE_PRIVATE void sqlite3VdbeMemSetNull(Mem*);
|
|
+#ifndef SQLITE_OMIT_INCRBLOB
|
|
SQLITE_PRIVATE void sqlite3VdbeMemSetZeroBlob(Mem*,int);
|
|
+#else
|
|
+SQLITE_PRIVATE int sqlite3VdbeMemSetZeroBlob(Mem*,int);
|
|
+#endif
|
|
#ifdef SQLITE_DEBUG
|
|
SQLITE_PRIVATE int sqlite3VdbeMemIsRowSet(const Mem*);
|
|
#endif
|
|
SQLITE_PRIVATE int sqlite3VdbeMemSetRowSet(Mem*);
|
|
SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem*);
|
|
SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem*, u8, u8);
|
|
-SQLITE_PRIVATE i64 sqlite3VdbeIntValue(Mem*);
|
|
+SQLITE_PRIVATE int sqlite3IntFloatCompare(i64,double);
|
|
+SQLITE_PRIVATE i64 sqlite3VdbeIntValue(const Mem*);
|
|
SQLITE_PRIVATE int sqlite3VdbeMemIntegerify(Mem*);
|
|
SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem*);
|
|
SQLITE_PRIVATE int sqlite3VdbeBooleanValue(Mem*, int ifNull);
|
|
@@ -21064,12 +23017,14 @@ SQLITE_PRIVATE int sqlite3VdbeMemRealify(Mem*);
|
|
SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem*);
|
|
SQLITE_PRIVATE int sqlite3VdbeMemCast(Mem*,u8,u8);
|
|
SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(BtCursor*,u32,u32,Mem*);
|
|
+SQLITE_PRIVATE int sqlite3VdbeMemFromBtreeZeroOffset(BtCursor*,u32,Mem*);
|
|
SQLITE_PRIVATE void sqlite3VdbeMemRelease(Mem *p);
|
|
+SQLITE_PRIVATE void sqlite3VdbeMemReleaseMalloc(Mem*p);
|
|
SQLITE_PRIVATE int sqlite3VdbeMemFinalize(Mem*, FuncDef*);
|
|
#ifndef SQLITE_OMIT_WINDOWFUNC
|
|
SQLITE_PRIVATE int sqlite3VdbeMemAggValue(Mem*, Mem*, FuncDef*);
|
|
#endif
|
|
-#ifndef SQLITE_OMIT_EXPLAIN
|
|
+#if !defined(SQLITE_OMIT_EXPLAIN) || defined(SQLITE_ENABLE_BYTECODE_VTAB)
|
|
SQLITE_PRIVATE const char *sqlite3OpcodeName(int);
|
|
#endif
|
|
SQLITE_PRIVATE int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve);
|
|
@@ -21082,7 +23037,8 @@ SQLITE_PRIVATE void sqlite3VdbeFrameMemDel(void*); /* Destructor on Mem */
|
|
SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame*); /* Actually deletes the Frame */
|
|
SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *);
|
|
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
|
|
-SQLITE_PRIVATE void sqlite3VdbePreUpdateHook(Vdbe*,VdbeCursor*,int,const char*,Table*,i64,int);
|
|
+SQLITE_PRIVATE void sqlite3VdbePreUpdateHook(
|
|
+ Vdbe*,VdbeCursor*,int,const char*,Table*,i64,int,int);
|
|
#endif
|
|
SQLITE_PRIVATE int sqlite3VdbeTransferError(Vdbe *p);
|
|
|
|
@@ -21095,6 +23051,8 @@ SQLITE_PRIVATE int sqlite3VdbeSorterRewind(const VdbeCursor *, int *);
|
|
SQLITE_PRIVATE int sqlite3VdbeSorterWrite(const VdbeCursor *, Mem *);
|
|
SQLITE_PRIVATE int sqlite3VdbeSorterCompare(const VdbeCursor *, Mem *, int, int *);
|
|
|
|
+SQLITE_PRIVATE void sqlite3VdbeValueListFree(void*);
|
|
+
|
|
#ifdef SQLITE_DEBUG
|
|
SQLITE_PRIVATE void sqlite3VdbeIncrWriteCounter(Vdbe*, VdbeCursor*);
|
|
SQLITE_PRIVATE void sqlite3VdbeAssertAbortable(Vdbe*);
|
|
@@ -21103,7 +23061,7 @@ SQLITE_PRIVATE void sqlite3VdbeAssertAbortable(Vdbe*);
|
|
# define sqlite3VdbeAssertAbortable(V)
|
|
#endif
|
|
|
|
-#if !defined(SQLITE_OMIT_SHARED_CACHE)
|
|
+#if !defined(SQLITE_OMIT_SHARED_CACHE)
|
|
SQLITE_PRIVATE void sqlite3VdbeEnter(Vdbe*);
|
|
#else
|
|
# define sqlite3VdbeEnter(X)
|
|
@@ -21385,7 +23343,7 @@ SQLITE_API int sqlite3_db_status(
|
|
break;
|
|
}
|
|
|
|
- /*
|
|
+ /*
|
|
** Return an approximation for the amount of memory currently used
|
|
** by all pagers associated with the given database connection. The
|
|
** highwater mark is meaningless and is returned as zero.
|
|
@@ -21423,13 +23381,15 @@ SQLITE_API int sqlite3_db_status(
|
|
|
|
sqlite3BtreeEnterAll(db);
|
|
db->pnBytesFreed = &nByte;
|
|
+ assert( db->lookaside.pEnd==db->lookaside.pTrueEnd );
|
|
+ db->lookaside.pEnd = db->lookaside.pStart;
|
|
for(i=0; i<db->nDb; i++){
|
|
Schema *pSchema = db->aDb[i].pSchema;
|
|
if( ALWAYS(pSchema!=0) ){
|
|
HashElem *p;
|
|
|
|
nByte += sqlite3GlobalConfig.m.xRoundup(sizeof(HashElem)) * (
|
|
- pSchema->tblHash.count
|
|
+ pSchema->tblHash.count
|
|
+ pSchema->trigHash.count
|
|
+ pSchema->idxHash.count
|
|
+ pSchema->fkeyHash.count
|
|
@@ -21448,6 +23408,7 @@ SQLITE_API int sqlite3_db_status(
|
|
}
|
|
}
|
|
db->pnBytesFreed = 0;
|
|
+ db->lookaside.pEnd = db->lookaside.pTrueEnd;
|
|
sqlite3BtreeLeaveAll(db);
|
|
|
|
*pHighwater = 0;
|
|
@@ -21465,10 +23426,12 @@ SQLITE_API int sqlite3_db_status(
|
|
int nByte = 0; /* Used to accumulate return value */
|
|
|
|
db->pnBytesFreed = &nByte;
|
|
- for(pVdbe=db->pVdbe; pVdbe; pVdbe=pVdbe->pNext){
|
|
- sqlite3VdbeClearObject(db, pVdbe);
|
|
- sqlite3DbFree(db, pVdbe);
|
|
+ assert( db->lookaside.pEnd==db->lookaside.pTrueEnd );
|
|
+ db->lookaside.pEnd = db->lookaside.pStart;
|
|
+ for(pVdbe=db->pVdbe; pVdbe; pVdbe=pVdbe->pVNext){
|
|
+ sqlite3VdbeDelete(pVdbe);
|
|
}
|
|
+ db->lookaside.pEnd = db->lookaside.pTrueEnd;
|
|
db->pnBytesFreed = 0;
|
|
|
|
*pHighwater = 0; /* IMP: R-64479-57858 */
|
|
@@ -21479,12 +23442,12 @@ SQLITE_API int sqlite3_db_status(
|
|
|
|
/*
|
|
** Set *pCurrent to the total cache hits or misses encountered by all
|
|
- ** pagers the database handle is connected to. *pHighwater is always set
|
|
+ ** pagers the database handle is connected to. *pHighwater is always set
|
|
** to zero.
|
|
*/
|
|
case SQLITE_DBSTATUS_CACHE_SPILL:
|
|
op = SQLITE_DBSTATUS_CACHE_WRITE+1;
|
|
- /* Fall through into the next case */
|
|
+ /* no break */ deliberate_fall_through
|
|
case SQLITE_DBSTATUS_CACHE_HIT:
|
|
case SQLITE_DBSTATUS_CACHE_MISS:
|
|
case SQLITE_DBSTATUS_CACHE_WRITE:{
|
|
@@ -21538,7 +23501,7 @@ SQLITE_API int sqlite3_db_status(
|
|
**
|
|
*************************************************************************
|
|
** This file contains the C functions that implement date and time
|
|
-** functions for SQLite.
|
|
+** functions for SQLite.
|
|
**
|
|
** There is only one exported symbol in this file - the function
|
|
** sqlite3RegisterDateTimeFunctions() found at the bottom of the file.
|
|
@@ -21547,7 +23510,7 @@ SQLITE_API int sqlite3_db_status(
|
|
** SQLite processes all times and dates as julian day numbers. The
|
|
** dates and times are stored as the number of days since noon
|
|
** in Greenwich on November 24, 4714 B.C. according to the Gregorian
|
|
-** calendar system.
|
|
+** calendar system.
|
|
**
|
|
** 1970-01-01 00:00:00 is JD 2440587.5
|
|
** 2000-01-01 00:00:00 is JD 2451544.5
|
|
@@ -21804,7 +23767,7 @@ static void computeJD(DateTime *p){
|
|
p->iJD = (sqlite3_int64)((X1 + X2 + D + B - 1524.5 ) * 86400000);
|
|
p->validJD = 1;
|
|
if( p->validHMS ){
|
|
- p->iJD += p->h*3600000 + p->m*60000 + (sqlite3_int64)(p->s*1000);
|
|
+ p->iJD += p->h*3600000 + p->m*60000 + (sqlite3_int64)(p->s*1000 + 0.5);
|
|
if( p->validTZ ){
|
|
p->iJD -= p->tz*60000;
|
|
p->validYMD = 0;
|
|
@@ -21895,7 +23858,7 @@ static void setRawDateNumber(DateTime *p, double r){
|
|
** The following are acceptable forms for the input string:
|
|
**
|
|
** YYYY-MM-DD HH:MM:SS.FFF +/-HH:MM
|
|
-** DDDD.DD
|
|
+** DDDD.DD
|
|
** now
|
|
**
|
|
** In the first form, the +/-HH:MM is always optional. The fractional
|
|
@@ -21905,8 +23868,8 @@ static void setRawDateNumber(DateTime *p, double r){
|
|
** as there is a year and date.
|
|
*/
|
|
static int parseDateOrTime(
|
|
- sqlite3_context *context,
|
|
- const char *zDate,
|
|
+ sqlite3_context *context,
|
|
+ const char *zDate,
|
|
DateTime *p
|
|
){
|
|
double r;
|
|
@@ -21927,7 +23890,7 @@ static int parseDateOrTime(
|
|
** Multiplying this by 86400000 gives 464269060799999 as the maximum value
|
|
** for DateTime.iJD.
|
|
**
|
|
-** But some older compilers (ex: gcc 4.2.1 on older Macs) cannot deal with
|
|
+** But some older compilers (ex: gcc 4.2.1 on older Macs) cannot deal with
|
|
** such a large integer literal, so we have to encode it.
|
|
*/
|
|
#define INT_464269060799999 ((((i64)0x1a640)<<32)|0x1072fdff)
|
|
@@ -22009,14 +23972,14 @@ static void clearYMD_HMS_TZ(DateTime *p){
|
|
#ifndef SQLITE_OMIT_LOCALTIME
|
|
/*
|
|
** On recent Windows platforms, the localtime_s() function is available
|
|
-** as part of the "Secure CRT". It is essentially equivalent to
|
|
-** localtime_r() available under most POSIX platforms, except that the
|
|
+** as part of the "Secure CRT". It is essentially equivalent to
|
|
+** localtime_r() available under most POSIX platforms, except that the
|
|
** order of the parameters is reversed.
|
|
**
|
|
** See http://msdn.microsoft.com/en-us/library/a442x3ye(VS.80).aspx.
|
|
**
|
|
** If the user has not indicated to use localtime_r() or localtime_s()
|
|
-** already, check for an MSVC build environment that provides
|
|
+** already, check for an MSVC build environment that provides
|
|
** localtime_s().
|
|
*/
|
|
#if !HAVE_LOCALTIME_R && !HAVE_LOCALTIME_S \
|
|
@@ -22031,8 +23994,10 @@ static void clearYMD_HMS_TZ(DateTime *p){
|
|
** is available. This routine returns 0 on success and
|
|
** non-zero on any kind of error.
|
|
**
|
|
-** If the sqlite3GlobalConfig.bLocaltimeFault variable is true then this
|
|
-** routine will always fail.
|
|
+** If the sqlite3GlobalConfig.bLocaltimeFault variable is non-zero then this
|
|
+** routine will always fail. If bLocaltimeFault is nonzero and
|
|
+** sqlite3GlobalConfig.xAltLocaltime is not NULL, then xAltLocaltime() is
|
|
+** invoked in place of the OS-defined localtime() function.
|
|
**
|
|
** EVIDENCE-OF: R-62172-00036 In this implementation, the standard C
|
|
** library function localtime_r() is used to assist in the calculation of
|
|
@@ -22043,19 +24008,35 @@ static int osLocaltime(time_t *t, struct tm *pTm){
|
|
#if !HAVE_LOCALTIME_R && !HAVE_LOCALTIME_S
|
|
struct tm *pX;
|
|
#if SQLITE_THREADSAFE>0
|
|
- sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
|
|
+ sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN);
|
|
#endif
|
|
sqlite3_mutex_enter(mutex);
|
|
pX = localtime(t);
|
|
#ifndef SQLITE_UNTESTABLE
|
|
- if( sqlite3GlobalConfig.bLocaltimeFault ) pX = 0;
|
|
+ if( sqlite3GlobalConfig.bLocaltimeFault ){
|
|
+ if( sqlite3GlobalConfig.xAltLocaltime!=0
|
|
+ && 0==sqlite3GlobalConfig.xAltLocaltime((const void*)t,(void*)pTm)
|
|
+ ){
|
|
+ pX = pTm;
|
|
+ }else{
|
|
+ pX = 0;
|
|
+ }
|
|
+ }
|
|
#endif
|
|
if( pX ) *pTm = *pX;
|
|
+#if SQLITE_THREADSAFE>0
|
|
sqlite3_mutex_leave(mutex);
|
|
+#endif
|
|
rc = pX==0;
|
|
#else
|
|
#ifndef SQLITE_UNTESTABLE
|
|
- if( sqlite3GlobalConfig.bLocaltimeFault ) return 1;
|
|
+ if( sqlite3GlobalConfig.bLocaltimeFault ){
|
|
+ if( sqlite3GlobalConfig.xAltLocaltime!=0 ){
|
|
+ return sqlite3GlobalConfig.xAltLocaltime((const void*)t,(void*)pTm);
|
|
+ }else{
|
|
+ return 1;
|
|
+ }
|
|
+ }
|
|
#endif
|
|
#if HAVE_LOCALTIME_R
|
|
rc = localtime_r(t, pTm)==0;
|
|
@@ -22070,67 +24051,56 @@ static int osLocaltime(time_t *t, struct tm *pTm){
|
|
|
|
#ifndef SQLITE_OMIT_LOCALTIME
|
|
/*
|
|
-** Compute the difference (in milliseconds) between localtime and UTC
|
|
-** (a.k.a. GMT) for the time value p where p is in UTC. If no error occurs,
|
|
-** return this value and set *pRc to SQLITE_OK.
|
|
-**
|
|
-** Or, if an error does occur, set *pRc to SQLITE_ERROR. The returned value
|
|
-** is undefined in this case.
|
|
+** Assuming the input DateTime is UTC, move it to its localtime equivalent.
|
|
*/
|
|
-static sqlite3_int64 localtimeOffset(
|
|
- DateTime *p, /* Date at which to calculate offset */
|
|
- sqlite3_context *pCtx, /* Write error here if one occurs */
|
|
- int *pRc /* OUT: Error code. SQLITE_OK or ERROR */
|
|
+static int toLocaltime(
|
|
+ DateTime *p, /* Date at which to calculate offset */
|
|
+ sqlite3_context *pCtx /* Write error here if one occurs */
|
|
){
|
|
- DateTime x, y;
|
|
time_t t;
|
|
struct tm sLocal;
|
|
+ int iYearDiff;
|
|
|
|
/* Initialize the contents of sLocal to avoid a compiler warning. */
|
|
memset(&sLocal, 0, sizeof(sLocal));
|
|
|
|
- x = *p;
|
|
- computeYMD_HMS(&x);
|
|
- if( x.Y<1971 || x.Y>=2038 ){
|
|
+ computeJD(p);
|
|
+ if( p->iJD<2108667600*(i64)100000 /* 1970-01-01 */
|
|
+ || p->iJD>2130141456*(i64)100000 /* 2038-01-18 */
|
|
+ ){
|
|
/* EVIDENCE-OF: R-55269-29598 The localtime_r() C function normally only
|
|
** works for years between 1970 and 2037. For dates outside this range,
|
|
** SQLite attempts to map the year into an equivalent year within this
|
|
** range, do the calculation, then map the year back.
|
|
*/
|
|
- x.Y = 2000;
|
|
- x.M = 1;
|
|
- x.D = 1;
|
|
- x.h = 0;
|
|
- x.m = 0;
|
|
- x.s = 0.0;
|
|
- } else {
|
|
- int s = (int)(x.s + 0.5);
|
|
- x.s = s;
|
|
+ DateTime x = *p;
|
|
+ computeYMD_HMS(&x);
|
|
+ iYearDiff = (2000 + x.Y%4) - x.Y;
|
|
+ x.Y += iYearDiff;
|
|
+ x.validJD = 0;
|
|
+ computeJD(&x);
|
|
+ t = (time_t)(x.iJD/1000 - 21086676*(i64)10000);
|
|
+ }else{
|
|
+ iYearDiff = 0;
|
|
+ t = (time_t)(p->iJD/1000 - 21086676*(i64)10000);
|
|
}
|
|
- x.tz = 0;
|
|
- x.validJD = 0;
|
|
- computeJD(&x);
|
|
- t = (time_t)(x.iJD/1000 - 21086676*(i64)10000);
|
|
if( osLocaltime(&t, &sLocal) ){
|
|
sqlite3_result_error(pCtx, "local time unavailable", -1);
|
|
- *pRc = SQLITE_ERROR;
|
|
- return 0;
|
|
+ return SQLITE_ERROR;
|
|
}
|
|
- y.Y = sLocal.tm_year + 1900;
|
|
- y.M = sLocal.tm_mon + 1;
|
|
- y.D = sLocal.tm_mday;
|
|
- y.h = sLocal.tm_hour;
|
|
- y.m = sLocal.tm_min;
|
|
- y.s = sLocal.tm_sec;
|
|
- y.validYMD = 1;
|
|
- y.validHMS = 1;
|
|
- y.validJD = 0;
|
|
- y.rawS = 0;
|
|
- y.validTZ = 0;
|
|
- y.isError = 0;
|
|
- computeJD(&y);
|
|
- *pRc = SQLITE_OK;
|
|
- return y.iJD - x.iJD;
|
|
+ p->Y = sLocal.tm_year + 1900 - iYearDiff;
|
|
+ p->M = sLocal.tm_mon + 1;
|
|
+ p->D = sLocal.tm_mday;
|
|
+ p->h = sLocal.tm_hour;
|
|
+ p->m = sLocal.tm_min;
|
|
+ p->s = sLocal.tm_sec + (p->iJD%1000)*0.001;
|
|
+ p->validYMD = 1;
|
|
+ p->validHMS = 1;
|
|
+ p->validJD = 0;
|
|
+ p->rawS = 0;
|
|
+ p->validTZ = 0;
|
|
+ p->isError = 0;
|
|
+ return SQLITE_OK;
|
|
}
|
|
#endif /* SQLITE_OMIT_LOCALTIME */
|
|
|
|
@@ -22143,18 +24113,17 @@ static sqlite3_int64 localtimeOffset(
|
|
** of several units of time.
|
|
*/
|
|
static const struct {
|
|
- u8 eType; /* Transformation type code */
|
|
- u8 nName; /* Length of th name */
|
|
- char *zName; /* Name of the transformation */
|
|
- double rLimit; /* Maximum NNN value for this transform */
|
|
- double rXform; /* Constant used for this transform */
|
|
+ u8 nName; /* Length of the name */
|
|
+ char zName[7]; /* Name of the transformation */
|
|
+ float rLimit; /* Maximum NNN value for this transform */
|
|
+ float rXform; /* Constant used for this transform */
|
|
} aXformType[] = {
|
|
- { 0, 6, "second", 464269060800.0, 86400000.0/(24.0*60.0*60.0) },
|
|
- { 0, 6, "minute", 7737817680.0, 86400000.0/(24.0*60.0) },
|
|
- { 0, 4, "hour", 128963628.0, 86400000.0/24.0 },
|
|
- { 0, 3, "day", 5373485.0, 86400000.0 },
|
|
- { 1, 5, "month", 176546.0, 30.0*86400000.0 },
|
|
- { 2, 4, "year", 14713.0, 365.0*86400000.0 },
|
|
+ { 6, "second", 4.6427e+14, 1.0 },
|
|
+ { 6, "minute", 7.7379e+12, 60.0 },
|
|
+ { 4, "hour", 1.2897e+11, 3600.0 },
|
|
+ { 3, "day", 5373485.0, 86400.0 },
|
|
+ { 5, "month", 176546.0, 2592000.0 },
|
|
+ { 4, "year", 14713.0, 31536000.0 },
|
|
};
|
|
|
|
/*
|
|
@@ -22185,11 +24154,55 @@ static int parseModifier(
|
|
sqlite3_context *pCtx, /* Function context */
|
|
const char *z, /* The text of the modifier */
|
|
int n, /* Length of zMod in bytes */
|
|
- DateTime *p /* The date/time value to be modified */
|
|
+ DateTime *p, /* The date/time value to be modified */
|
|
+ int idx /* Parameter index of the modifier */
|
|
){
|
|
int rc = 1;
|
|
double r;
|
|
switch(sqlite3UpperToLower[(u8)z[0]] ){
|
|
+ case 'a': {
|
|
+ /*
|
|
+ ** auto
|
|
+ **
|
|
+ ** If rawS is available, then interpret as a julian day number, or
|
|
+ ** a unix timestamp, depending on its magnitude.
|
|
+ */
|
|
+ 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;
|
|
+ }
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+ case 'j': {
|
|
+ /*
|
|
+ ** julianday
|
|
+ **
|
|
+ ** Always interpret the prior number as a julian-day value. If this
|
|
+ ** is not the first modifier, or if the prior argument is not a numeric
|
|
+ ** value in the allowed range of julian day numbers understood by
|
|
+ ** SQLite (0..5373484.5) then the result will be NULL.
|
|
+ */
|
|
+ if( sqlite3_stricmp(z, "julianday")==0 ){
|
|
+ if( idx>1 ) return 1; /* IMP: R-31176-64601 */
|
|
+ if( p->validJD && p->rawS ){
|
|
+ rc = 0;
|
|
+ p->rawS = 0;
|
|
+ }
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
#ifndef SQLITE_OMIT_LOCALTIME
|
|
case 'l': {
|
|
/* localtime
|
|
@@ -22198,9 +24211,7 @@ static int parseModifier(
|
|
** show local time.
|
|
*/
|
|
if( sqlite3_stricmp(z, "localtime")==0 && sqlite3NotPureFunc(pCtx) ){
|
|
- computeJD(p);
|
|
- p->iJD += localtimeOffset(p, pCtx, &rc);
|
|
- clearYMD_HMS_TZ(p);
|
|
+ rc = toLocaltime(p, pCtx);
|
|
}
|
|
break;
|
|
}
|
|
@@ -22213,6 +24224,7 @@ static int parseModifier(
|
|
** seconds since 1970. Convert to a real julian day number.
|
|
*/
|
|
if( sqlite3_stricmp(z, "unixepoch")==0 && p->rawS ){
|
|
+ if( idx>1 ) return 1; /* IMP: R-49255-55373 */
|
|
r = p->s*1000.0 + 210866760000000.0;
|
|
if( r>=0.0 && r<464269060800000.0 ){
|
|
clearYMD_HMS_TZ(p);
|
|
@@ -22225,18 +24237,31 @@ static int parseModifier(
|
|
#ifndef SQLITE_OMIT_LOCALTIME
|
|
else if( sqlite3_stricmp(z, "utc")==0 && sqlite3NotPureFunc(pCtx) ){
|
|
if( p->tzSet==0 ){
|
|
- sqlite3_int64 c1;
|
|
+ i64 iOrigJD; /* Original localtime */
|
|
+ i64 iGuess; /* Guess at the corresponding utc time */
|
|
+ int cnt = 0; /* Safety to prevent infinite loop */
|
|
+ i64 iErr; /* Guess is off by this much */
|
|
+
|
|
computeJD(p);
|
|
- c1 = localtimeOffset(p, pCtx, &rc);
|
|
- if( rc==SQLITE_OK ){
|
|
- p->iJD -= c1;
|
|
- clearYMD_HMS_TZ(p);
|
|
- p->iJD += c1 - localtimeOffset(p, pCtx, &rc);
|
|
- }
|
|
+ iGuess = iOrigJD = p->iJD;
|
|
+ iErr = 0;
|
|
+ do{
|
|
+ DateTime new;
|
|
+ memset(&new, 0, sizeof(new));
|
|
+ iGuess -= iErr;
|
|
+ new.iJD = iGuess;
|
|
+ new.validJD = 1;
|
|
+ rc = toLocaltime(&new, pCtx);
|
|
+ if( rc ) return rc;
|
|
+ computeJD(&new);
|
|
+ iErr = new.iJD - iOrigJD;
|
|
+ }while( iErr && cnt++<3 );
|
|
+ memset(p, 0, sizeof(*p));
|
|
+ p->iJD = iGuess;
|
|
+ p->validJD = 1;
|
|
p->tzSet = 1;
|
|
- }else{
|
|
- rc = SQLITE_OK;
|
|
}
|
|
+ rc = SQLITE_OK;
|
|
}
|
|
#endif
|
|
break;
|
|
@@ -22251,7 +24276,7 @@ static int parseModifier(
|
|
*/
|
|
if( sqlite3_strnicmp(z, "weekday ", 8)==0
|
|
&& sqlite3AtoF(&z[8], &r, sqlite3Strlen30(&z[8]), SQLITE_UTF8)>0
|
|
- && (n=(int)r)==r && n>=0 && r<7 ){
|
|
+ && r>=0.0 && r<7.0 && (n=(int)r)==r ){
|
|
sqlite3_int64 Z;
|
|
computeYMD_HMS(p);
|
|
p->validTZ = 0;
|
|
@@ -22352,9 +24377,10 @@ static int parseModifier(
|
|
&& sqlite3_strnicmp(aXformType[i].zName, z, n)==0
|
|
&& r>-aXformType[i].rLimit && r<aXformType[i].rLimit
|
|
){
|
|
- switch( aXformType[i].eType ){
|
|
- case 1: { /* Special processing to add months */
|
|
+ switch( i ){
|
|
+ case 4: { /* Special processing to add months */
|
|
int x;
|
|
+ assert( strcmp(aXformType[i].zName,"month")==0 );
|
|
computeYMD_HMS(p);
|
|
p->M += (int)r;
|
|
x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12;
|
|
@@ -22364,8 +24390,9 @@ static int parseModifier(
|
|
r -= (int)r;
|
|
break;
|
|
}
|
|
- case 2: { /* Special processing to add years */
|
|
+ case 5: { /* Special processing to add years */
|
|
int y = (int)r;
|
|
+ assert( strcmp(aXformType[i].zName,"year")==0 );
|
|
computeYMD_HMS(p);
|
|
p->Y += y;
|
|
p->validJD = 0;
|
|
@@ -22374,7 +24401,7 @@ static int parseModifier(
|
|
}
|
|
}
|
|
computeJD(p);
|
|
- p->iJD += (sqlite3_int64)(r*aXformType[i].rXform + rRounder);
|
|
+ p->iJD += (sqlite3_int64)(r*1000.0*aXformType[i].rXform + rRounder);
|
|
rc = 0;
|
|
break;
|
|
}
|
|
@@ -22399,9 +24426,9 @@ static int parseModifier(
|
|
** then assume a default value of "now" for argv[0].
|
|
*/
|
|
static int isDate(
|
|
- sqlite3_context *context,
|
|
- int argc,
|
|
- sqlite3_value **argv,
|
|
+ sqlite3_context *context,
|
|
+ int argc,
|
|
+ sqlite3_value **argv,
|
|
DateTime *p
|
|
){
|
|
int i, n;
|
|
@@ -22409,6 +24436,7 @@ static int isDate(
|
|
int eType;
|
|
memset(p, 0, sizeof(*p));
|
|
if( argc==0 ){
|
|
+ if( !sqlite3NotPureFunc(context) ) return 1;
|
|
return setDateTimeToCurrent(context, p);
|
|
}
|
|
if( (eType = sqlite3_value_type(argv[0]))==SQLITE_FLOAT
|
|
@@ -22423,7 +24451,7 @@ static int isDate(
|
|
for(i=1; i<argc; i++){
|
|
z = sqlite3_value_text(argv[i]);
|
|
n = sqlite3_value_bytes(argv[i]);
|
|
- if( z==0 || parseModifier(context, (char*)z, n, p) ) return 1;
|
|
+ if( z==0 || parseModifier(context, (char*)z, n, p, i) ) return 1;
|
|
}
|
|
computeJD(p);
|
|
if( p->isError || !validJulianDay(p->iJD) ) return 1;
|
|
@@ -22453,6 +24481,24 @@ static void juliandayFunc(
|
|
}
|
|
}
|
|
|
|
+/*
|
|
+** unixepoch( TIMESTRING, MOD, MOD, ...)
|
|
+**
|
|
+** Return the number of seconds (including fractional seconds) since
|
|
+** the unix epoch of 1970-01-01 00:00:00 GMT.
|
|
+*/
|
|
+static void unixepochFunc(
|
|
+ sqlite3_context *context,
|
|
+ int argc,
|
|
+ sqlite3_value **argv
|
|
+){
|
|
+ DateTime x;
|
|
+ if( isDate(context, argc, argv, &x)==0 ){
|
|
+ computeJD(&x);
|
|
+ sqlite3_result_int64(context, x.iJD/1000 - 21086676*(i64)10000);
|
|
+ }
|
|
+}
|
|
+
|
|
/*
|
|
** datetime( TIMESTRING, MOD, MOD, ...)
|
|
**
|
|
@@ -22465,11 +24511,38 @@ static void datetimeFunc(
|
|
){
|
|
DateTime x;
|
|
if( isDate(context, argc, argv, &x)==0 ){
|
|
- char zBuf[100];
|
|
+ int Y, s;
|
|
+ char zBuf[24];
|
|
computeYMD_HMS(&x);
|
|
- sqlite3_snprintf(sizeof(zBuf), zBuf, "%04d-%02d-%02d %02d:%02d:%02d",
|
|
- x.Y, x.M, x.D, x.h, x.m, (int)(x.s));
|
|
- sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
|
|
+ Y = x.Y;
|
|
+ if( Y<0 ) Y = -Y;
|
|
+ zBuf[1] = '0' + (Y/1000)%10;
|
|
+ zBuf[2] = '0' + (Y/100)%10;
|
|
+ zBuf[3] = '0' + (Y/10)%10;
|
|
+ zBuf[4] = '0' + (Y)%10;
|
|
+ zBuf[5] = '-';
|
|
+ zBuf[6] = '0' + (x.M/10)%10;
|
|
+ zBuf[7] = '0' + (x.M)%10;
|
|
+ zBuf[8] = '-';
|
|
+ zBuf[9] = '0' + (x.D/10)%10;
|
|
+ zBuf[10] = '0' + (x.D)%10;
|
|
+ zBuf[11] = ' ';
|
|
+ zBuf[12] = '0' + (x.h/10)%10;
|
|
+ zBuf[13] = '0' + (x.h)%10;
|
|
+ zBuf[14] = ':';
|
|
+ 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.Y<0 ){
|
|
+ zBuf[0] = '-';
|
|
+ sqlite3_result_text(context, zBuf, 20, SQLITE_TRANSIENT);
|
|
+ }else{
|
|
+ sqlite3_result_text(context, &zBuf[1], 19, SQLITE_TRANSIENT);
|
|
+ }
|
|
}
|
|
}
|
|
|
|
@@ -22485,10 +24558,20 @@ static void timeFunc(
|
|
){
|
|
DateTime x;
|
|
if( isDate(context, argc, argv, &x)==0 ){
|
|
- char zBuf[100];
|
|
+ int s;
|
|
+ char zBuf[16];
|
|
computeHMS(&x);
|
|
- sqlite3_snprintf(sizeof(zBuf), zBuf, "%02d:%02d:%02d", x.h, x.m, (int)x.s);
|
|
- sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
|
|
+ zBuf[0] = '0' + (x.h/10)%10;
|
|
+ zBuf[1] = '0' + (x.h)%10;
|
|
+ zBuf[2] = ':';
|
|
+ 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);
|
|
}
|
|
}
|
|
|
|
@@ -22504,10 +24587,28 @@ static void dateFunc(
|
|
){
|
|
DateTime x;
|
|
if( isDate(context, argc, argv, &x)==0 ){
|
|
- char zBuf[100];
|
|
+ int Y;
|
|
+ char zBuf[16];
|
|
computeYMD(&x);
|
|
- sqlite3_snprintf(sizeof(zBuf), zBuf, "%04d-%02d-%02d", x.Y, x.M, x.D);
|
|
- sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
|
|
+ Y = x.Y;
|
|
+ if( Y<0 ) Y = -Y;
|
|
+ zBuf[1] = '0' + (Y/1000)%10;
|
|
+ zBuf[2] = '0' + (Y/100)%10;
|
|
+ zBuf[3] = '0' + (Y/10)%10;
|
|
+ zBuf[4] = '0' + (Y)%10;
|
|
+ zBuf[5] = '-';
|
|
+ zBuf[6] = '0' + (x.M/10)%10;
|
|
+ zBuf[7] = '0' + (x.M)%10;
|
|
+ zBuf[8] = '-';
|
|
+ zBuf[9] = '0' + (x.D/10)%10;
|
|
+ zBuf[10] = '0' + (x.D)%10;
|
|
+ zBuf[11] = 0;
|
|
+ if( x.Y<0 ){
|
|
+ zBuf[0] = '-';
|
|
+ sqlite3_result_text(context, zBuf, 11, SQLITE_TRANSIENT);
|
|
+ }else{
|
|
+ sqlite3_result_text(context, &zBuf[1], 10, SQLITE_TRANSIENT);
|
|
+ }
|
|
}
|
|
}
|
|
|
|
@@ -22536,131 +24637,100 @@ static void strftimeFunc(
|
|
sqlite3_value **argv
|
|
){
|
|
DateTime x;
|
|
- u64 n;
|
|
size_t i,j;
|
|
- char *z;
|
|
sqlite3 *db;
|
|
const char *zFmt;
|
|
- char zBuf[100];
|
|
+ sqlite3_str sRes;
|
|
+
|
|
+
|
|
if( argc==0 ) return;
|
|
zFmt = (const char*)sqlite3_value_text(argv[0]);
|
|
if( zFmt==0 || isDate(context, argc-1, argv+1, &x) ) return;
|
|
db = sqlite3_context_db_handle(context);
|
|
- for(i=0, n=1; zFmt[i]; i++, n++){
|
|
- if( zFmt[i]=='%' ){
|
|
- switch( zFmt[i+1] ){
|
|
- case 'd':
|
|
- case 'H':
|
|
- case 'm':
|
|
- case 'M':
|
|
- case 'S':
|
|
- case 'W':
|
|
- n++;
|
|
- /* fall thru */
|
|
- case 'w':
|
|
- case '%':
|
|
- break;
|
|
- case 'f':
|
|
- n += 8;
|
|
- break;
|
|
- case 'j':
|
|
- n += 3;
|
|
- break;
|
|
- case 'Y':
|
|
- n += 8;
|
|
- break;
|
|
- case 's':
|
|
- case 'J':
|
|
- n += 50;
|
|
- break;
|
|
- default:
|
|
- return; /* ERROR. return a NULL */
|
|
- }
|
|
- i++;
|
|
- }
|
|
- }
|
|
- testcase( n==sizeof(zBuf)-1 );
|
|
- testcase( n==sizeof(zBuf) );
|
|
- testcase( n==(u64)db->aLimit[SQLITE_LIMIT_LENGTH]+1 );
|
|
- testcase( n==(u64)db->aLimit[SQLITE_LIMIT_LENGTH] );
|
|
- if( n<sizeof(zBuf) ){
|
|
- z = zBuf;
|
|
- }else if( n>(u64)db->aLimit[SQLITE_LIMIT_LENGTH] ){
|
|
- sqlite3_result_error_toobig(context);
|
|
- return;
|
|
- }else{
|
|
- z = sqlite3DbMallocRawNN(db, (int)n);
|
|
- if( z==0 ){
|
|
- sqlite3_result_error_nomem(context);
|
|
- return;
|
|
- }
|
|
- }
|
|
+ sqlite3StrAccumInit(&sRes, 0, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]);
|
|
+
|
|
computeJD(&x);
|
|
computeYMD_HMS(&x);
|
|
for(i=j=0; zFmt[i]; i++){
|
|
- if( zFmt[i]!='%' ){
|
|
- z[j++] = zFmt[i];
|
|
- }else{
|
|
- i++;
|
|
- switch( zFmt[i] ){
|
|
- case 'd': sqlite3_snprintf(3, &z[j],"%02d",x.D); j+=2; break;
|
|
- case 'f': {
|
|
- double s = x.s;
|
|
- if( s>59.999 ) s = 59.999;
|
|
- sqlite3_snprintf(7, &z[j],"%06.3f", s);
|
|
- j += sqlite3Strlen30(&z[j]);
|
|
- break;
|
|
- }
|
|
- case 'H': sqlite3_snprintf(3, &z[j],"%02d",x.h); j+=2; break;
|
|
- case 'W': /* Fall thru */
|
|
- case 'j': {
|
|
- int nDay; /* Number of days since 1st day of year */
|
|
- DateTime y = x;
|
|
- y.validJD = 0;
|
|
- y.M = 1;
|
|
- y.D = 1;
|
|
- computeJD(&y);
|
|
- nDay = (int)((x.iJD-y.iJD+43200000)/86400000);
|
|
- if( zFmt[i]=='W' ){
|
|
- int wd; /* 0=Monday, 1=Tuesday, ... 6=Sunday */
|
|
- wd = (int)(((x.iJD+43200000)/86400000)%7);
|
|
- sqlite3_snprintf(3, &z[j],"%02d",(nDay+7-wd)/7);
|
|
- j += 2;
|
|
- }else{
|
|
- sqlite3_snprintf(4, &z[j],"%03d",nDay+1);
|
|
- j += 3;
|
|
- }
|
|
- break;
|
|
- }
|
|
- case 'J': {
|
|
- sqlite3_snprintf(20, &z[j],"%.16g",x.iJD/86400000.0);
|
|
- j+=sqlite3Strlen30(&z[j]);
|
|
- break;
|
|
- }
|
|
- case 'm': sqlite3_snprintf(3, &z[j],"%02d",x.M); j+=2; break;
|
|
- case 'M': sqlite3_snprintf(3, &z[j],"%02d",x.m); j+=2; break;
|
|
- case 's': {
|
|
- sqlite3_snprintf(30,&z[j],"%lld",
|
|
- (i64)(x.iJD/1000 - 21086676*(i64)10000));
|
|
- j += sqlite3Strlen30(&z[j]);
|
|
- break;
|
|
- }
|
|
- case 'S': sqlite3_snprintf(3,&z[j],"%02d",(int)x.s); j+=2; break;
|
|
- case 'w': {
|
|
- z[j++] = (char)(((x.iJD+129600000)/86400000) % 7) + '0';
|
|
- break;
|
|
- }
|
|
- case 'Y': {
|
|
- sqlite3_snprintf(5,&z[j],"%04d",x.Y); j+=sqlite3Strlen30(&z[j]);
|
|
- break;
|
|
+ if( zFmt[i]!='%' ) continue;
|
|
+ if( j<i ) sqlite3_str_append(&sRes, zFmt+j, (int)(i-j));
|
|
+ i++;
|
|
+ j = i + 1;
|
|
+ switch( zFmt[i] ){
|
|
+ case 'd': {
|
|
+ sqlite3_str_appendf(&sRes, "%02d", x.D);
|
|
+ break;
|
|
+ }
|
|
+ case 'f': {
|
|
+ double s = x.s;
|
|
+ if( s>59.999 ) s = 59.999;
|
|
+ sqlite3_str_appendf(&sRes, "%06.3f", s);
|
|
+ break;
|
|
+ }
|
|
+ case 'H': {
|
|
+ sqlite3_str_appendf(&sRes, "%02d", x.h);
|
|
+ break;
|
|
+ }
|
|
+ case 'W': /* Fall thru */
|
|
+ case 'j': {
|
|
+ int nDay; /* Number of days since 1st day of year */
|
|
+ DateTime y = x;
|
|
+ y.validJD = 0;
|
|
+ y.M = 1;
|
|
+ y.D = 1;
|
|
+ computeJD(&y);
|
|
+ nDay = (int)((x.iJD-y.iJD+43200000)/86400000);
|
|
+ if( zFmt[i]=='W' ){
|
|
+ int wd; /* 0=Monday, 1=Tuesday, ... 6=Sunday */
|
|
+ wd = (int)(((x.iJD+43200000)/86400000)%7);
|
|
+ sqlite3_str_appendf(&sRes,"%02d",(nDay+7-wd)/7);
|
|
+ }else{
|
|
+ sqlite3_str_appendf(&sRes,"%03d",nDay+1);
|
|
}
|
|
- default: z[j++] = '%'; break;
|
|
+ break;
|
|
+ }
|
|
+ case 'J': {
|
|
+ sqlite3_str_appendf(&sRes,"%.16g",x.iJD/86400000.0);
|
|
+ break;
|
|
+ }
|
|
+ case 'm': {
|
|
+ sqlite3_str_appendf(&sRes,"%02d",x.M);
|
|
+ break;
|
|
+ }
|
|
+ case 'M': {
|
|
+ sqlite3_str_appendf(&sRes,"%02d",x.m);
|
|
+ break;
|
|
+ }
|
|
+ case 's': {
|
|
+ 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 'w': {
|
|
+ sqlite3_str_appendchar(&sRes, 1,
|
|
+ (char)(((x.iJD+129600000)/86400000) % 7) + '0');
|
|
+ break;
|
|
+ }
|
|
+ case 'Y': {
|
|
+ sqlite3_str_appendf(&sRes,"%04d",x.Y);
|
|
+ break;
|
|
+ }
|
|
+ case '%': {
|
|
+ sqlite3_str_appendchar(&sRes, 1, '%');
|
|
+ break;
|
|
+ }
|
|
+ default: {
|
|
+ sqlite3_str_reset(&sRes);
|
|
+ return;
|
|
}
|
|
}
|
|
}
|
|
- z[j] = 0;
|
|
- sqlite3_result_text(context, z, -1,
|
|
- z==zBuf ? SQLITE_TRANSIENT : SQLITE_DYNAMIC);
|
|
+ if( j<i ) sqlite3_str_append(&sRes, zFmt+j, (int)(i-j));
|
|
+ sqlite3ResultStrAccum(context, &sRes);
|
|
}
|
|
|
|
/*
|
|
@@ -22739,10 +24809,10 @@ static void currentTimeFunc(
|
|
#if HAVE_GMTIME_R
|
|
pTm = gmtime_r(&t, &sNow);
|
|
#else
|
|
- sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
|
|
+ sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN));
|
|
pTm = gmtime(&t);
|
|
if( pTm ) memcpy(&sNow, pTm, sizeof(sNow));
|
|
- sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
|
|
+ sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN));
|
|
#endif
|
|
if( pTm ){
|
|
strftime(zBuf, 20, zFormat, &sNow);
|
|
@@ -22760,6 +24830,7 @@ SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void){
|
|
static FuncDef aDateTimeFuncs[] = {
|
|
#ifndef SQLITE_OMIT_DATETIME_FUNCS
|
|
PURE_DATE(julianday, -1, 0, 0, juliandayFunc ),
|
|
+ PURE_DATE(unixepoch, -1, 0, 0, unixepochFunc ),
|
|
PURE_DATE(date, -1, 0, 0, dateFunc ),
|
|
PURE_DATE(time, -1, 0, 0, timeFunc ),
|
|
PURE_DATE(datetime, -1, 0, 0, datetimeFunc ),
|
|
@@ -22886,9 +24957,11 @@ SQLITE_PRIVATE int sqlite3OsFileSize(sqlite3_file *id, i64 *pSize){
|
|
}
|
|
SQLITE_PRIVATE int sqlite3OsLock(sqlite3_file *id, int lockType){
|
|
DO_OS_MALLOC_TEST(id);
|
|
+ assert( lockType>=SQLITE_LOCK_SHARED && lockType<=SQLITE_LOCK_EXCLUSIVE );
|
|
return id->pMethods->xLock(id, lockType);
|
|
}
|
|
SQLITE_PRIVATE int sqlite3OsUnlock(sqlite3_file *id, int lockType){
|
|
+ assert( lockType==SQLITE_LOCK_NONE || lockType==SQLITE_LOCK_SHARED );
|
|
return id->pMethods->xUnlock(id, lockType);
|
|
}
|
|
SQLITE_PRIVATE int sqlite3OsCheckReservedLock(sqlite3_file *id, int *pResOut){
|
|
@@ -22909,6 +24982,8 @@ SQLITE_PRIVATE int sqlite3OsFileControl(sqlite3_file *id, int op, void *pArg){
|
|
#ifdef SQLITE_TEST
|
|
if( op!=SQLITE_FCNTL_COMMIT_PHASETWO
|
|
&& op!=SQLITE_FCNTL_LOCK_TIMEOUT
|
|
+ && op!=SQLITE_FCNTL_CKPT_DONE
|
|
+ && op!=SQLITE_FCNTL_CKPT_START
|
|
){
|
|
/* Faults are not injected into COMMIT_PHASETWO because, assuming SQLite
|
|
** is using a regular VFS, it is called after the corresponding
|
|
@@ -22919,7 +24994,12 @@ SQLITE_PRIVATE int sqlite3OsFileControl(sqlite3_file *id, int op, void *pArg){
|
|
** The core must call OsFileControl() though, not OsFileControlHint(),
|
|
** as if a custom VFS (e.g. zipvfs) returns an error here, it probably
|
|
** means the commit really has failed and an error should be returned
|
|
- ** to the user. */
|
|
+ ** to the user.
|
|
+ **
|
|
+ ** The CKPT_DONE and CKPT_START file-controls are write-only signals
|
|
+ ** to the cksumvfs. Their return code is meaningless and is ignored
|
|
+ ** by the SQLite core, so there is no point in simulating OOMs for them.
|
|
+ */
|
|
DO_OS_MALLOC_TEST(id);
|
|
}
|
|
#endif
|
|
@@ -22934,6 +25014,7 @@ SQLITE_PRIVATE int sqlite3OsSectorSize(sqlite3_file *id){
|
|
return (xSectorSize ? xSectorSize(id) : SQLITE_DEFAULT_SECTOR_SIZE);
|
|
}
|
|
SQLITE_PRIVATE int sqlite3OsDeviceCharacteristics(sqlite3_file *id){
|
|
+ if( NEVER(id->pMethods==0) ) return 0;
|
|
return id->pMethods->xDeviceCharacteristics(id);
|
|
}
|
|
#ifndef SQLITE_OMIT_WAL
|
|
@@ -22995,6 +25076,7 @@ SQLITE_PRIVATE int sqlite3OsOpen(
|
|
** down into the VFS layer. Some SQLITE_OPEN_ flags (for example,
|
|
** SQLITE_OPEN_FULLMUTEX or SQLITE_OPEN_SHAREDCACHE) are blocked before
|
|
** reaching the VFS. */
|
|
+ assert( zPath || (flags & SQLITE_OPEN_EXCLUSIVE) );
|
|
rc = pVfs->xOpen(pVfs, zPath, pFile, flags & 0x1087f7f, pFlagsOut);
|
|
assert( rc==SQLITE_OK || pFile->pMethods==0 );
|
|
return rc;
|
|
@@ -23002,7 +25084,7 @@ SQLITE_PRIVATE int sqlite3OsOpen(
|
|
SQLITE_PRIVATE int sqlite3OsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
|
|
DO_OS_MALLOC_TEST(0);
|
|
assert( dirSync==0 || dirSync==1 );
|
|
- return pVfs->xDelete(pVfs, zPath, dirSync);
|
|
+ return pVfs->xDelete!=0 ? pVfs->xDelete(pVfs, zPath, dirSync) : SQLITE_OK;
|
|
}
|
|
SQLITE_PRIVATE int sqlite3OsAccess(
|
|
sqlite3_vfs *pVfs,
|
|
@@ -23025,6 +25107,8 @@ SQLITE_PRIVATE int sqlite3OsFullPathname(
|
|
}
|
|
#ifndef SQLITE_OMIT_LOAD_EXTENSION
|
|
SQLITE_PRIVATE void *sqlite3OsDlOpen(sqlite3_vfs *pVfs, const char *zPath){
|
|
+ assert( zPath!=0 );
|
|
+ assert( strlen(zPath)<=SQLITE_MAX_PATHLEN ); /* tag-20210611-1 */
|
|
return pVfs->xDlOpen(pVfs, zPath);
|
|
}
|
|
SQLITE_PRIVATE void sqlite3OsDlError(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
|
|
@@ -23046,7 +25130,7 @@ SQLITE_PRIVATE int sqlite3OsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufO
|
|
}else{
|
|
return pVfs->xRandomness(pVfs, nByte, zBufOut);
|
|
}
|
|
-
|
|
+
|
|
}
|
|
SQLITE_PRIVATE int sqlite3OsSleep(sqlite3_vfs *pVfs, int nMicro){
|
|
return pVfs->xSleep(pVfs, nMicro);
|
|
@@ -23086,12 +25170,15 @@ SQLITE_PRIVATE int sqlite3OsOpenMalloc(
|
|
rc = sqlite3OsOpen(pVfs, zFile, pFile, flags, pOutFlags);
|
|
if( rc!=SQLITE_OK ){
|
|
sqlite3_free(pFile);
|
|
+ *ppFile = 0;
|
|
}else{
|
|
*ppFile = pFile;
|
|
}
|
|
}else{
|
|
+ *ppFile = 0;
|
|
rc = SQLITE_NOMEM_BKPT;
|
|
}
|
|
+ assert( *ppFile!=0 || rc!=SQLITE_OK );
|
|
return rc;
|
|
}
|
|
SQLITE_PRIVATE void sqlite3OsCloseFree(sqlite3_file *pFile){
|
|
@@ -23133,7 +25220,7 @@ SQLITE_API sqlite3_vfs *sqlite3_vfs_find(const char *zVfs){
|
|
if( rc ) return 0;
|
|
#endif
|
|
#if SQLITE_THREADSAFE
|
|
- mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
|
|
+ mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN);
|
|
#endif
|
|
sqlite3_mutex_enter(mutex);
|
|
for(pVfs = vfsList; pVfs; pVfs=pVfs->pNext){
|
|
@@ -23148,7 +25235,7 @@ SQLITE_API sqlite3_vfs *sqlite3_vfs_find(const char *zVfs){
|
|
** Unlink a VFS from the linked list
|
|
*/
|
|
static void vfsUnlink(sqlite3_vfs *pVfs){
|
|
- assert( sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)) );
|
|
+ assert( sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN)) );
|
|
if( pVfs==0 ){
|
|
/* No-op */
|
|
}else if( vfsList==pVfs ){
|
|
@@ -23179,7 +25266,7 @@ SQLITE_API int sqlite3_vfs_register(sqlite3_vfs *pVfs, int makeDflt){
|
|
if( pVfs==0 ) return SQLITE_MISUSE_BKPT;
|
|
#endif
|
|
|
|
- MUTEX_LOGIC( mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); )
|
|
+ MUTEX_LOGIC( mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); )
|
|
sqlite3_mutex_enter(mutex);
|
|
vfsUnlink(pVfs);
|
|
if( makeDflt || vfsList==0 ){
|
|
@@ -23203,7 +25290,7 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs *pVfs){
|
|
int rc = sqlite3_initialize();
|
|
if( rc ) return rc;
|
|
#endif
|
|
- MUTEX_LOGIC( mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); )
|
|
+ MUTEX_LOGIC( mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); )
|
|
sqlite3_mutex_enter(mutex);
|
|
vfsUnlink(pVfs);
|
|
sqlite3_mutex_leave(mutex);
|
|
@@ -23224,17 +25311,17 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs *pVfs){
|
|
**
|
|
*************************************************************************
|
|
**
|
|
-** This file contains code to support the concept of "benign"
|
|
+** This file contains code to support the concept of "benign"
|
|
** malloc failures (when the xMalloc() or xRealloc() method of the
|
|
** sqlite3_mem_methods structure fails to allocate a block of memory
|
|
-** and returns 0).
|
|
+** and returns 0).
|
|
**
|
|
** Most malloc failures are non-benign. After they occur, SQLite
|
|
** abandons the current operation and returns an error code (usually
|
|
** SQLITE_NOMEM) to the user. However, sometimes a fault is not necessarily
|
|
-** fatal. For example, if a malloc fails while resizing a hash table, this
|
|
-** is completely recoverable simply by not carrying out the resize. The
|
|
-** hash table will continue to function normally. So a malloc failure
|
|
+** fatal. For example, if a malloc fails while resizing a hash table, this
|
|
+** is completely recoverable simply by not carrying out the resize. The
|
|
+** hash table will continue to function normally. So a malloc failure
|
|
** during a hash table resize is a benign fault.
|
|
*/
|
|
|
|
@@ -23436,7 +25523,7 @@ static malloc_zone_t* _sqliteZone_;
|
|
#else /* if not __APPLE__ */
|
|
|
|
/*
|
|
-** Use standard C library malloc and free on non-Apple systems.
|
|
+** Use standard C library malloc and free on non-Apple systems.
|
|
** Also used by Apple systems if SQLITE_WITHOUT_ZONEMALLOC is defined.
|
|
*/
|
|
#define SQLITE_MALLOC(x) malloc(x)
|
|
@@ -23578,13 +25665,11 @@ static void *sqlite3MemRealloc(void *pPrior, int nByte){
|
|
assert( pPrior!=0 && nByte>0 );
|
|
assert( nByte==ROUND8(nByte) ); /* EV: R-46199-30249 */
|
|
p--;
|
|
- void *new_p = SQLITE_REALLOC(p, nByte+8 );
|
|
- if( new_p ){
|
|
- p = (sqlite3_int64 *)new_p;
|
|
+ p = SQLITE_REALLOC(p, nByte+8 );
|
|
+ if( p ){
|
|
p[0] = nByte;
|
|
p++;
|
|
}else{
|
|
- SQLITE_FREE(p);
|
|
testcase( sqlite3GlobalConfig.xLog!=0 );
|
|
sqlite3_log(SQLITE_NOMEM,
|
|
"failed memory resize %u to %u bytes",
|
|
@@ -23618,7 +25703,7 @@ static int sqlite3MemInit(void *NotUsed){
|
|
/* defer MT decisions to system malloc */
|
|
_sqliteZone_ = malloc_default_zone();
|
|
}else{
|
|
- /* only 1 core, use our own zone to contention over global locks,
|
|
+ /* only 1 core, use our own zone to contention over global locks,
|
|
** e.g. we have our own dedicated locks */
|
|
_sqliteZone_ = malloc_create_zone(4096, 0);
|
|
malloc_set_zone_name(_sqliteZone_, "Sqlite_Heap");
|
|
@@ -23742,7 +25827,7 @@ struct MemBlockHdr {
|
|
** when this module is combined with other in the amalgamation.
|
|
*/
|
|
static struct {
|
|
-
|
|
+
|
|
/*
|
|
** Mutex to control access to the memory allocation subsystem.
|
|
*/
|
|
@@ -23753,7 +25838,7 @@ static struct {
|
|
*/
|
|
struct MemBlockHdr *pFirst;
|
|
struct MemBlockHdr *pLast;
|
|
-
|
|
+
|
|
/*
|
|
** The number of levels of backtrace to save in new allocations.
|
|
*/
|
|
@@ -23766,7 +25851,7 @@ static struct {
|
|
int nTitle; /* Bytes of zTitle to save. Includes '\0' and padding */
|
|
char zTitle[100]; /* The title text */
|
|
|
|
- /*
|
|
+ /*
|
|
** sqlite3MallocDisallow() increments the following counter.
|
|
** sqlite3MallocAllow() decrements it.
|
|
*/
|
|
@@ -23811,7 +25896,7 @@ static void adjustStats(int iSize, int increment){
|
|
** This routine checks the guards at either end of the allocation and
|
|
** if they are incorrect it asserts.
|
|
*/
|
|
-static struct MemBlockHdr *sqlite3MemsysGetHeader(void *pAllocation){
|
|
+static struct MemBlockHdr *sqlite3MemsysGetHeader(const void *pAllocation){
|
|
struct MemBlockHdr *p;
|
|
int *pInt;
|
|
u8 *pU8;
|
|
@@ -23825,7 +25910,7 @@ static struct MemBlockHdr *sqlite3MemsysGetHeader(void *pAllocation){
|
|
pU8 = (u8*)pAllocation;
|
|
assert( pInt[nReserve/sizeof(int)]==(int)REARGUARD );
|
|
/* This checks any of the "extra" bytes allocated due
|
|
- ** to rounding up to an 8 byte boundary to ensure
|
|
+ ** to rounding up to an 8 byte boundary to ensure
|
|
** they haven't been overwritten.
|
|
*/
|
|
while( nReserve-- > p->iSize ) assert( pU8[nReserve]==0x65 );
|
|
@@ -23954,7 +26039,7 @@ static void *sqlite3MemMalloc(int nByte){
|
|
p = (void*)pInt;
|
|
}
|
|
sqlite3_mutex_leave(mem.mutex);
|
|
- return p;
|
|
+ return p;
|
|
}
|
|
|
|
/*
|
|
@@ -23964,7 +26049,7 @@ static void sqlite3MemFree(void *pPrior){
|
|
struct MemBlockHdr *pHdr;
|
|
void **pBt;
|
|
char *z;
|
|
- assert( sqlite3GlobalConfig.bMemstat || sqlite3GlobalConfig.bCoreMutex==0
|
|
+ assert( sqlite3GlobalConfig.bMemstat || sqlite3GlobalConfig.bCoreMutex==0
|
|
|| mem.mutex!=0 );
|
|
pHdr = sqlite3MemsysGetHeader(pPrior);
|
|
pBt = (void**)pHdr;
|
|
@@ -23990,15 +26075,15 @@ static void sqlite3MemFree(void *pPrior){
|
|
randomFill(z, sizeof(void*)*pHdr->nBacktraceSlots + sizeof(*pHdr) +
|
|
(int)pHdr->iSize + sizeof(int) + pHdr->nTitle);
|
|
free(z);
|
|
- sqlite3_mutex_leave(mem.mutex);
|
|
+ sqlite3_mutex_leave(mem.mutex);
|
|
}
|
|
|
|
/*
|
|
** Change the size of an existing memory allocation.
|
|
**
|
|
** For this debugging implementation, we *always* make a copy of the
|
|
-** allocation into a new place in memory. In this way, if the
|
|
-** higher level code is using pointer to the old allocation, it is
|
|
+** allocation into a new place in memory. In this way, if the
|
|
+** higher level code is using pointer to the old allocation, it is
|
|
** much more likely to break and we are much more liking to find
|
|
** the error.
|
|
*/
|
|
@@ -24041,7 +26126,7 @@ SQLITE_PRIVATE void sqlite3MemSetDefault(void){
|
|
** Set the "type" of an allocation.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3MemdebugSetType(void *p, u8 eType){
|
|
- if( p && sqlite3GlobalConfig.m.xMalloc==sqlite3MemMalloc ){
|
|
+ if( p && sqlite3GlobalConfig.m.xFree==sqlite3MemFree ){
|
|
struct MemBlockHdr *pHdr;
|
|
pHdr = sqlite3MemsysGetHeader(p);
|
|
assert( pHdr->iForeGuard==FOREGUARD );
|
|
@@ -24058,9 +26143,9 @@ SQLITE_PRIVATE void sqlite3MemdebugSetType(void *p, u8 eType){
|
|
**
|
|
** assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
|
|
*/
|
|
-SQLITE_PRIVATE int sqlite3MemdebugHasType(void *p, u8 eType){
|
|
+SQLITE_PRIVATE int sqlite3MemdebugHasType(const void *p, u8 eType){
|
|
int rc = 1;
|
|
- if( p && sqlite3GlobalConfig.m.xMalloc==sqlite3MemMalloc ){
|
|
+ if( p && sqlite3GlobalConfig.m.xFree==sqlite3MemFree ){
|
|
struct MemBlockHdr *pHdr;
|
|
pHdr = sqlite3MemsysGetHeader(p);
|
|
assert( pHdr->iForeGuard==FOREGUARD ); /* Allocation is valid */
|
|
@@ -24080,9 +26165,9 @@ SQLITE_PRIVATE int sqlite3MemdebugHasType(void *p, u8 eType){
|
|
**
|
|
** assert( sqlite3MemdebugNoType(p, MEMTYPE_LOOKASIDE) );
|
|
*/
|
|
-SQLITE_PRIVATE int sqlite3MemdebugNoType(void *p, u8 eType){
|
|
+SQLITE_PRIVATE int sqlite3MemdebugNoType(const void *p, u8 eType){
|
|
int rc = 1;
|
|
- if( p && sqlite3GlobalConfig.m.xMalloc==sqlite3MemMalloc ){
|
|
+ if( p && sqlite3GlobalConfig.m.xFree==sqlite3MemFree ){
|
|
struct MemBlockHdr *pHdr;
|
|
pHdr = sqlite3MemsysGetHeader(p);
|
|
assert( pHdr->iForeGuard==FOREGUARD ); /* Allocation is valid */
|
|
@@ -24132,7 +26217,7 @@ SQLITE_PRIVATE void sqlite3MemdebugSync(){
|
|
}
|
|
|
|
/*
|
|
-** Open the file indicated and write a log of all unfreed memory
|
|
+** Open the file indicated and write a log of all unfreed memory
|
|
** allocations into that log.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3MemdebugDump(const char *zFilename){
|
|
@@ -24149,7 +26234,7 @@ SQLITE_PRIVATE void sqlite3MemdebugDump(const char *zFilename){
|
|
for(pHdr=mem.pFirst; pHdr; pHdr=pHdr->pNext){
|
|
char *z = (char*)pHdr;
|
|
z -= pHdr->nBacktraceSlots*sizeof(void*) + pHdr->nTitle;
|
|
- fprintf(out, "**** %lld bytes at %p from %s ****\n",
|
|
+ fprintf(out, "**** %lld bytes at %p from %s ****\n",
|
|
pHdr->iSize, &pHdr[1], pHdr->nTitle ? z : "???");
|
|
if( pHdr->nBacktrace ){
|
|
fflush(out);
|
|
@@ -24162,7 +26247,7 @@ SQLITE_PRIVATE void sqlite3MemdebugDump(const char *zFilename){
|
|
fprintf(out, "COUNTS:\n");
|
|
for(i=0; i<NCSIZE-1; i++){
|
|
if( mem.nAlloc[i] ){
|
|
- fprintf(out, " %5d: %10d %10d %10d\n",
|
|
+ fprintf(out, " %5d: %10d %10d %10d\n",
|
|
i*8, mem.nAlloc[i], mem.nCurrent[i], mem.mxCurrent[i]);
|
|
}
|
|
}
|
|
@@ -24203,12 +26288,12 @@ SQLITE_PRIVATE int sqlite3MemdebugMallocCount(){
|
|
**
|
|
*************************************************************************
|
|
** This file contains the C functions that implement a memory
|
|
-** allocation subsystem for use by SQLite.
|
|
+** allocation subsystem for use by SQLite.
|
|
**
|
|
** This version of the memory allocation subsystem omits all
|
|
** use of malloc(). The SQLite user supplies a block of memory
|
|
** before calling sqlite3_initialize() from which allocations
|
|
-** are made and returned by the xMalloc() and xRealloc()
|
|
+** are made and returned by the xMalloc() and xRealloc()
|
|
** implementations. Once sqlite3_initialize() has been called,
|
|
** the amount of memory available to SQLite is fixed and cannot
|
|
** be changed.
|
|
@@ -24239,8 +26324,8 @@ SQLITE_PRIVATE int sqlite3MemdebugMallocCount(){
|
|
#define N_HASH 61
|
|
|
|
/*
|
|
-** A memory allocation (also called a "chunk") consists of two or
|
|
-** more blocks where each block is 8 bytes. The first 8 bytes are
|
|
+** A memory allocation (also called a "chunk") consists of two or
|
|
+** more blocks where each block is 8 bytes. The first 8 bytes are
|
|
** a header that is not returned to the user.
|
|
**
|
|
** A chunk is two or more blocks that is either checked out or
|
|
@@ -24263,10 +26348,10 @@ SQLITE_PRIVATE int sqlite3MemdebugMallocCount(){
|
|
**
|
|
** The second block of free chunks is of the form u.list. The
|
|
** two fields form a double-linked list of chunks of related sizes.
|
|
-** Pointers to the head of the list are stored in mem3.aiSmall[]
|
|
+** Pointers to the head of the list are stored in mem3.aiSmall[]
|
|
** for smaller chunks and mem3.aiHash[] for larger chunks.
|
|
**
|
|
-** The second block of a chunk is user data if the chunk is checked
|
|
+** The second block of a chunk is user data if the chunk is checked
|
|
** out. If a chunk is checked out, the user data may extend into
|
|
** the u.hdr.prevSize value of the following chunk.
|
|
*/
|
|
@@ -24302,28 +26387,28 @@ static SQLITE_WSD struct Mem3Global {
|
|
** True if we are evaluating an out-of-memory callback.
|
|
*/
|
|
int alarmBusy;
|
|
-
|
|
+
|
|
/*
|
|
** Mutex to control access to the memory allocation subsystem.
|
|
*/
|
|
sqlite3_mutex *mutex;
|
|
-
|
|
+
|
|
/*
|
|
** The minimum amount of free space that we have seen.
|
|
*/
|
|
- u32 mnMaster;
|
|
+ u32 mnKeyBlk;
|
|
|
|
/*
|
|
- ** iMaster is the index of the master chunk. Most new allocations
|
|
- ** occur off of this chunk. szMaster is the size (in Mem3Blocks)
|
|
- ** of the current master. iMaster is 0 if there is not master chunk.
|
|
- ** The master chunk is not in either the aiHash[] or aiSmall[].
|
|
+ ** iKeyBlk is the index of the key chunk. Most new allocations
|
|
+ ** occur off of this chunk. szKeyBlk is the size (in Mem3Blocks)
|
|
+ ** of the current key chunk. iKeyBlk is 0 if there is no key chunk.
|
|
+ ** The key chunk is not in either the aiHash[] or aiSmall[].
|
|
*/
|
|
- u32 iMaster;
|
|
- u32 szMaster;
|
|
+ u32 iKeyBlk;
|
|
+ u32 szKeyBlk;
|
|
|
|
/*
|
|
- ** Array of lists of free blocks according to the block size
|
|
+ ** Array of lists of free blocks according to the block size
|
|
** for smaller chunks, or a hash on the block size for larger
|
|
** chunks.
|
|
*/
|
|
@@ -24354,7 +26439,7 @@ static void memsys3UnlinkFromList(u32 i, u32 *pRoot){
|
|
}
|
|
|
|
/*
|
|
-** Unlink the chunk at index i from
|
|
+** Unlink the chunk at index i from
|
|
** whatever list is currently a member of.
|
|
*/
|
|
static void memsys3Unlink(u32 i){
|
|
@@ -24438,8 +26523,8 @@ static void memsys3OutOfMemory(int nByte){
|
|
|
|
|
|
/*
|
|
-** Chunk i is a free chunk that has been unlinked. Adjust its
|
|
-** size parameters for check-out and return a pointer to the
|
|
+** Chunk i is a free chunk that has been unlinked. Adjust its
|
|
+** size parameters for check-out and return a pointer to the
|
|
** user portion of the chunk.
|
|
*/
|
|
static void *memsys3Checkout(u32 i, u32 nBlock){
|
|
@@ -24456,34 +26541,34 @@ static void *memsys3Checkout(u32 i, u32 nBlock){
|
|
}
|
|
|
|
/*
|
|
-** Carve a piece off of the end of the mem3.iMaster free chunk.
|
|
-** Return a pointer to the new allocation. Or, if the master chunk
|
|
+** Carve a piece off of the end of the mem3.iKeyBlk free chunk.
|
|
+** Return a pointer to the new allocation. Or, if the key chunk
|
|
** is not large enough, return 0.
|
|
*/
|
|
-static void *memsys3FromMaster(u32 nBlock){
|
|
+static void *memsys3FromKeyBlk(u32 nBlock){
|
|
assert( sqlite3_mutex_held(mem3.mutex) );
|
|
- assert( mem3.szMaster>=nBlock );
|
|
- if( nBlock>=mem3.szMaster-1 ){
|
|
- /* Use the entire master */
|
|
- void *p = memsys3Checkout(mem3.iMaster, mem3.szMaster);
|
|
- mem3.iMaster = 0;
|
|
- mem3.szMaster = 0;
|
|
- mem3.mnMaster = 0;
|
|
+ assert( mem3.szKeyBlk>=nBlock );
|
|
+ if( nBlock>=mem3.szKeyBlk-1 ){
|
|
+ /* Use the entire key chunk */
|
|
+ void *p = memsys3Checkout(mem3.iKeyBlk, mem3.szKeyBlk);
|
|
+ mem3.iKeyBlk = 0;
|
|
+ mem3.szKeyBlk = 0;
|
|
+ mem3.mnKeyBlk = 0;
|
|
return p;
|
|
}else{
|
|
- /* Split the master block. Return the tail. */
|
|
+ /* Split the key block. Return the tail. */
|
|
u32 newi, x;
|
|
- newi = mem3.iMaster + mem3.szMaster - nBlock;
|
|
- assert( newi > mem3.iMaster+1 );
|
|
- mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.prevSize = nBlock;
|
|
- mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.size4x |= 2;
|
|
+ newi = mem3.iKeyBlk + mem3.szKeyBlk - nBlock;
|
|
+ assert( newi > mem3.iKeyBlk+1 );
|
|
+ mem3.aPool[mem3.iKeyBlk+mem3.szKeyBlk-1].u.hdr.prevSize = nBlock;
|
|
+ mem3.aPool[mem3.iKeyBlk+mem3.szKeyBlk-1].u.hdr.size4x |= 2;
|
|
mem3.aPool[newi-1].u.hdr.size4x = nBlock*4 + 1;
|
|
- mem3.szMaster -= nBlock;
|
|
- mem3.aPool[newi-1].u.hdr.prevSize = mem3.szMaster;
|
|
- x = mem3.aPool[mem3.iMaster-1].u.hdr.size4x & 2;
|
|
- mem3.aPool[mem3.iMaster-1].u.hdr.size4x = mem3.szMaster*4 | x;
|
|
- if( mem3.szMaster < mem3.mnMaster ){
|
|
- mem3.mnMaster = mem3.szMaster;
|
|
+ mem3.szKeyBlk -= nBlock;
|
|
+ mem3.aPool[newi-1].u.hdr.prevSize = mem3.szKeyBlk;
|
|
+ x = mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x & 2;
|
|
+ mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x = mem3.szKeyBlk*4 | x;
|
|
+ if( mem3.szKeyBlk < mem3.mnKeyBlk ){
|
|
+ mem3.mnKeyBlk = mem3.szKeyBlk;
|
|
}
|
|
return (void*)&mem3.aPool[newi];
|
|
}
|
|
@@ -24492,18 +26577,18 @@ static void *memsys3FromMaster(u32 nBlock){
|
|
/*
|
|
** *pRoot is the head of a list of free chunks of the same size
|
|
** or same size hash. In other words, *pRoot is an entry in either
|
|
-** mem3.aiSmall[] or mem3.aiHash[].
|
|
+** mem3.aiSmall[] or mem3.aiHash[].
|
|
**
|
|
** This routine examines all entries on the given list and tries
|
|
-** to coalesce each entries with adjacent free chunks.
|
|
+** to coalesce each entries with adjacent free chunks.
|
|
**
|
|
-** If it sees a chunk that is larger than mem3.iMaster, it replaces
|
|
-** the current mem3.iMaster with the new larger chunk. In order for
|
|
-** this mem3.iMaster replacement to work, the master chunk must be
|
|
+** If it sees a chunk that is larger than mem3.iKeyBlk, it replaces
|
|
+** the current mem3.iKeyBlk with the new larger chunk. In order for
|
|
+** this mem3.iKeyBlk replacement to work, the key chunk must be
|
|
** linked into the hash tables. That is not the normal state of
|
|
-** affairs, of course. The calling routine must link the master
|
|
+** affairs, of course. The calling routine must link the key
|
|
** chunk before invoking this routine, then must unlink the (possibly
|
|
-** changed) master chunk once this routine has finished.
|
|
+** changed) key chunk once this routine has finished.
|
|
*/
|
|
static void memsys3Merge(u32 *pRoot){
|
|
u32 iNext, prev, size, i, x;
|
|
@@ -24530,9 +26615,9 @@ static void memsys3Merge(u32 *pRoot){
|
|
}else{
|
|
size /= 4;
|
|
}
|
|
- if( size>mem3.szMaster ){
|
|
- mem3.iMaster = i;
|
|
- mem3.szMaster = size;
|
|
+ if( size>mem3.szKeyBlk ){
|
|
+ mem3.iKeyBlk = i;
|
|
+ mem3.szKeyBlk = size;
|
|
}
|
|
}
|
|
}
|
|
@@ -24581,26 +26666,26 @@ static void *memsys3MallocUnsafe(int nByte){
|
|
|
|
/* STEP 2:
|
|
** Try to satisfy the allocation by carving a piece off of the end
|
|
- ** of the master chunk. This step usually works if step 1 fails.
|
|
+ ** of the key chunk. This step usually works if step 1 fails.
|
|
*/
|
|
- if( mem3.szMaster>=nBlock ){
|
|
- return memsys3FromMaster(nBlock);
|
|
+ if( mem3.szKeyBlk>=nBlock ){
|
|
+ return memsys3FromKeyBlk(nBlock);
|
|
}
|
|
|
|
|
|
- /* STEP 3:
|
|
+ /* STEP 3:
|
|
** Loop through the entire memory pool. Coalesce adjacent free
|
|
- ** chunks. Recompute the master chunk as the largest free chunk.
|
|
+ ** chunks. Recompute the key chunk as the largest free chunk.
|
|
** Then try again to satisfy the allocation by carving a piece off
|
|
- ** of the end of the master chunk. This step happens very
|
|
+ ** of the end of the key chunk. This step happens very
|
|
** rarely (we hope!)
|
|
*/
|
|
for(toFree=nBlock*16; toFree<(mem3.nPool*16); toFree *= 2){
|
|
memsys3OutOfMemory(toFree);
|
|
- if( mem3.iMaster ){
|
|
- memsys3Link(mem3.iMaster);
|
|
- mem3.iMaster = 0;
|
|
- mem3.szMaster = 0;
|
|
+ if( mem3.iKeyBlk ){
|
|
+ memsys3Link(mem3.iKeyBlk);
|
|
+ mem3.iKeyBlk = 0;
|
|
+ mem3.szKeyBlk = 0;
|
|
}
|
|
for(i=0; i<N_HASH; i++){
|
|
memsys3Merge(&mem3.aiHash[i]);
|
|
@@ -24608,10 +26693,10 @@ static void *memsys3MallocUnsafe(int nByte){
|
|
for(i=0; i<MX_SMALL-1; i++){
|
|
memsys3Merge(&mem3.aiSmall[i]);
|
|
}
|
|
- if( mem3.szMaster ){
|
|
- memsys3Unlink(mem3.iMaster);
|
|
- if( mem3.szMaster>=nBlock ){
|
|
- return memsys3FromMaster(nBlock);
|
|
+ if( mem3.szKeyBlk ){
|
|
+ memsys3Unlink(mem3.iKeyBlk);
|
|
+ if( mem3.szKeyBlk>=nBlock ){
|
|
+ return memsys3FromKeyBlk(nBlock);
|
|
}
|
|
}
|
|
}
|
|
@@ -24641,23 +26726,23 @@ static void memsys3FreeUnsafe(void *pOld){
|
|
mem3.aPool[i+size-1].u.hdr.size4x &= ~2;
|
|
memsys3Link(i);
|
|
|
|
- /* Try to expand the master using the newly freed chunk */
|
|
- if( mem3.iMaster ){
|
|
- while( (mem3.aPool[mem3.iMaster-1].u.hdr.size4x&2)==0 ){
|
|
- size = mem3.aPool[mem3.iMaster-1].u.hdr.prevSize;
|
|
- mem3.iMaster -= size;
|
|
- mem3.szMaster += size;
|
|
- memsys3Unlink(mem3.iMaster);
|
|
- x = mem3.aPool[mem3.iMaster-1].u.hdr.size4x & 2;
|
|
- mem3.aPool[mem3.iMaster-1].u.hdr.size4x = mem3.szMaster*4 | x;
|
|
- mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.prevSize = mem3.szMaster;
|
|
+ /* Try to expand the key using the newly freed chunk */
|
|
+ if( mem3.iKeyBlk ){
|
|
+ while( (mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x&2)==0 ){
|
|
+ size = mem3.aPool[mem3.iKeyBlk-1].u.hdr.prevSize;
|
|
+ mem3.iKeyBlk -= size;
|
|
+ mem3.szKeyBlk += size;
|
|
+ memsys3Unlink(mem3.iKeyBlk);
|
|
+ x = mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x & 2;
|
|
+ mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x = mem3.szKeyBlk*4 | x;
|
|
+ mem3.aPool[mem3.iKeyBlk+mem3.szKeyBlk-1].u.hdr.prevSize = mem3.szKeyBlk;
|
|
}
|
|
- x = mem3.aPool[mem3.iMaster-1].u.hdr.size4x & 2;
|
|
- while( (mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.size4x&1)==0 ){
|
|
- memsys3Unlink(mem3.iMaster+mem3.szMaster);
|
|
- mem3.szMaster += mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.size4x/4;
|
|
- mem3.aPool[mem3.iMaster-1].u.hdr.size4x = mem3.szMaster*4 | x;
|
|
- mem3.aPool[mem3.iMaster+mem3.szMaster-1].u.hdr.prevSize = mem3.szMaster;
|
|
+ x = mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x & 2;
|
|
+ while( (mem3.aPool[mem3.iKeyBlk+mem3.szKeyBlk-1].u.hdr.size4x&1)==0 ){
|
|
+ memsys3Unlink(mem3.iKeyBlk+mem3.szKeyBlk);
|
|
+ mem3.szKeyBlk += mem3.aPool[mem3.iKeyBlk+mem3.szKeyBlk-1].u.hdr.size4x/4;
|
|
+ mem3.aPool[mem3.iKeyBlk-1].u.hdr.size4x = mem3.szKeyBlk*4 | x;
|
|
+ mem3.aPool[mem3.iKeyBlk+mem3.szKeyBlk-1].u.hdr.prevSize = mem3.szKeyBlk;
|
|
}
|
|
}
|
|
}
|
|
@@ -24695,7 +26780,7 @@ static void *memsys3Malloc(int nBytes){
|
|
memsys3Enter();
|
|
p = memsys3MallocUnsafe(nBytes);
|
|
memsys3Leave();
|
|
- return (void*)p;
|
|
+ return (void*)p;
|
|
}
|
|
|
|
/*
|
|
@@ -24753,11 +26838,11 @@ static int memsys3Init(void *NotUsed){
|
|
mem3.aPool = (Mem3Block *)sqlite3GlobalConfig.pHeap;
|
|
mem3.nPool = (sqlite3GlobalConfig.nHeap / sizeof(Mem3Block)) - 2;
|
|
|
|
- /* Initialize the master block. */
|
|
- mem3.szMaster = mem3.nPool;
|
|
- mem3.mnMaster = mem3.szMaster;
|
|
- mem3.iMaster = 1;
|
|
- mem3.aPool[0].u.hdr.size4x = (mem3.szMaster<<2) + 2;
|
|
+ /* Initialize the key block. */
|
|
+ mem3.szKeyBlk = mem3.nPool;
|
|
+ mem3.mnKeyBlk = mem3.szKeyBlk;
|
|
+ mem3.iKeyBlk = 1;
|
|
+ mem3.aPool[0].u.hdr.size4x = (mem3.szKeyBlk<<2) + 2;
|
|
mem3.aPool[mem3.nPool].u.hdr.prevSize = mem3.nPool;
|
|
mem3.aPool[mem3.nPool].u.hdr.size4x = 1;
|
|
|
|
@@ -24776,7 +26861,7 @@ static void memsys3Shutdown(void *NotUsed){
|
|
|
|
|
|
/*
|
|
-** Open the file indicated and write a log of all unfreed memory
|
|
+** Open the file indicated and write a log of all unfreed memory
|
|
** allocations into that log.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3Memsys3Dump(const char *zFilename){
|
|
@@ -24817,7 +26902,7 @@ SQLITE_PRIVATE void sqlite3Memsys3Dump(const char *zFilename){
|
|
fprintf(out, "%p %6d bytes checked out\n", &mem3.aPool[i], (size/4)*8-8);
|
|
}else{
|
|
fprintf(out, "%p %6d bytes free%s\n", &mem3.aPool[i], (size/4)*8-8,
|
|
- i==mem3.iMaster ? " **master**" : "");
|
|
+ i==mem3.iKeyBlk ? " **key**" : "");
|
|
}
|
|
}
|
|
for(i=0; i<MX_SMALL-1; i++){
|
|
@@ -24827,7 +26912,7 @@ SQLITE_PRIVATE void sqlite3Memsys3Dump(const char *zFilename){
|
|
fprintf(out, " %p(%d)", &mem3.aPool[j],
|
|
(mem3.aPool[j-1].u.hdr.size4x/4)*8-8);
|
|
}
|
|
- fprintf(out, "\n");
|
|
+ fprintf(out, "\n");
|
|
}
|
|
for(i=0; i<N_HASH; i++){
|
|
if( mem3.aiHash[i]==0 ) continue;
|
|
@@ -24836,11 +26921,11 @@ SQLITE_PRIVATE void sqlite3Memsys3Dump(const char *zFilename){
|
|
fprintf(out, " %p(%d)", &mem3.aPool[j],
|
|
(mem3.aPool[j-1].u.hdr.size4x/4)*8-8);
|
|
}
|
|
- fprintf(out, "\n");
|
|
+ fprintf(out, "\n");
|
|
}
|
|
- fprintf(out, "master=%d\n", mem3.iMaster);
|
|
- fprintf(out, "nowUsed=%d\n", mem3.nPool*8 - mem3.szMaster*8);
|
|
- fprintf(out, "mxUsed=%d\n", mem3.nPool*8 - mem3.mnMaster*8);
|
|
+ fprintf(out, "key=%d\n", mem3.iKeyBlk);
|
|
+ fprintf(out, "nowUsed=%d\n", mem3.nPool*8 - mem3.szKeyBlk*8);
|
|
+ fprintf(out, "mxUsed=%d\n", mem3.nPool*8 - mem3.mnKeyBlk*8);
|
|
sqlite3_mutex_leave(mem3.mutex);
|
|
if( out==stdout ){
|
|
fflush(stdout);
|
|
@@ -24853,7 +26938,7 @@ SQLITE_PRIVATE void sqlite3Memsys3Dump(const char *zFilename){
|
|
}
|
|
|
|
/*
|
|
-** This routine is the only routine in this file with external
|
|
+** This routine is the only routine in this file with external
|
|
** linkage.
|
|
**
|
|
** Populate the low-level memory allocation function pointers in
|
|
@@ -24893,12 +26978,12 @@ SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys3(void){
|
|
**
|
|
*************************************************************************
|
|
** This file contains the C functions that implement a memory
|
|
-** allocation subsystem for use by SQLite.
|
|
+** allocation subsystem for use by SQLite.
|
|
**
|
|
** This version of the memory allocation subsystem omits all
|
|
** use of malloc(). The application gives SQLite a block of memory
|
|
** before calling sqlite3_initialize() from which allocations
|
|
-** are made and returned by the xMalloc() and xRealloc()
|
|
+** are made and returned by the xMalloc() and xRealloc()
|
|
** implementations. Once sqlite3_initialize() has been called,
|
|
** the amount of memory available to SQLite is fixed and cannot
|
|
** be changed.
|
|
@@ -24918,12 +27003,12 @@ SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys3(void){
|
|
** This algorithm is described in: J. M. Robson. "Bounds for Some Functions
|
|
** Concerning Dynamic Storage Allocation". Journal of the Association for
|
|
** Computing Machinery, Volume 21, Number 8, July 1974, pages 491-499.
|
|
-**
|
|
+**
|
|
** Let n be the size of the largest allocation divided by the minimum
|
|
** allocation size (after rounding all sizes up to a power of 2.) Let M
|
|
** be the maximum amount of memory ever outstanding at one time. Let
|
|
** N be the total amount of memory available for allocation. Robson
|
|
-** proved that this memory allocator will never breakdown due to
|
|
+** proved that this memory allocator will never breakdown due to
|
|
** fragmentation as long as the following constraint holds:
|
|
**
|
|
** N >= M*(1 + log2(n)/2) - n + 1
|
|
@@ -24934,7 +27019,7 @@ SQLITE_PRIVATE const sqlite3_mem_methods *sqlite3MemGetMemsys3(void){
|
|
/* #include "sqliteInt.h" */
|
|
|
|
/*
|
|
-** This version of the memory allocator is used only when
|
|
+** This version of the memory allocator is used only when
|
|
** SQLITE_ENABLE_MEMSYS5 is defined.
|
|
*/
|
|
#ifdef SQLITE_ENABLE_MEMSYS5
|
|
@@ -24979,7 +27064,7 @@ static SQLITE_WSD struct Mem5Global {
|
|
int szAtom; /* Smallest possible allocation in bytes */
|
|
int nBlock; /* Number of szAtom sized blocks in zPool */
|
|
u8 *zPool; /* Memory available to be allocated */
|
|
-
|
|
+
|
|
/*
|
|
** Mutex to control access to the memory allocation subsystem.
|
|
*/
|
|
@@ -24998,7 +27083,7 @@ static SQLITE_WSD struct Mem5Global {
|
|
u32 maxCount; /* Maximum instantaneous currentCount */
|
|
u32 maxRequest; /* Largest allocation (exclusive of internal frag) */
|
|
#endif
|
|
-
|
|
+
|
|
/*
|
|
** Lists of free blocks. aiFreelist[0] is a list of free blocks of
|
|
** size mem5.szAtom. aiFreelist[1] holds blocks of size szAtom*2.
|
|
@@ -25174,7 +27259,7 @@ static void memsys5FreeUnsafe(void *pOld){
|
|
u32 size, iLogsize;
|
|
int iBlock;
|
|
|
|
- /* Set iBlock to the index of the block pointed to by pOld in
|
|
+ /* Set iBlock to the index of the block pointed to by pOld in
|
|
** the array of mem5.szAtom byte blocks pointed to by mem5.zPool.
|
|
*/
|
|
iBlock = (int)(((u8 *)pOld-mem5.zPool)/mem5.szAtom);
|
|
@@ -25243,7 +27328,7 @@ static void *memsys5Malloc(int nBytes){
|
|
p = memsys5MallocUnsafe(nBytes);
|
|
memsys5Leave();
|
|
}
|
|
- return (void*)p;
|
|
+ return (void*)p;
|
|
}
|
|
|
|
/*
|
|
@@ -25256,14 +27341,14 @@ static void memsys5Free(void *pPrior){
|
|
assert( pPrior!=0 );
|
|
memsys5Enter();
|
|
memsys5FreeUnsafe(pPrior);
|
|
- memsys5Leave();
|
|
+ memsys5Leave();
|
|
}
|
|
|
|
/*
|
|
** Change the size of an existing memory allocation.
|
|
**
|
|
** The outer layer memory allocator prevents this routine from
|
|
-** being called with pPrior==0.
|
|
+** being called with pPrior==0.
|
|
**
|
|
** nBytes is always a value obtained from a prior call to
|
|
** memsys5Round(). Hence nBytes is always a non-negative power
|
|
@@ -25303,8 +27388,17 @@ static void *memsys5Realloc(void *pPrior, int nBytes){
|
|
*/
|
|
static int memsys5Roundup(int n){
|
|
int iFullSz;
|
|
- if( n > 0x40000000 ) return 0;
|
|
- for(iFullSz=mem5.szAtom; iFullSz<n; iFullSz *= 2);
|
|
+ if( n<=mem5.szAtom*2 ){
|
|
+ if( n<=mem5.szAtom ) return mem5.szAtom;
|
|
+ return mem5.szAtom*2;
|
|
+ }
|
|
+ if( n>0x10000000 ){
|
|
+ if( n>0x40000000 ) return 0;
|
|
+ if( n>0x20000000 ) return 0x40000000;
|
|
+ return 0x20000000;
|
|
+ }
|
|
+ for(iFullSz=mem5.szAtom*8; iFullSz<n; iFullSz *= 4);
|
|
+ if( (iFullSz/2)>=(i64)n ) return iFullSz/2;
|
|
return iFullSz;
|
|
}
|
|
|
|
@@ -25396,7 +27490,7 @@ static void memsys5Shutdown(void *NotUsed){
|
|
|
|
#ifdef SQLITE_TEST
|
|
/*
|
|
-** Open the file indicated and write a log of all unfreed memory
|
|
+** Open the file indicated and write a log of all unfreed memory
|
|
** allocations into that log.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3Memsys5Dump(const char *zFilename){
|
|
@@ -25438,7 +27532,7 @@ SQLITE_PRIVATE void sqlite3Memsys5Dump(const char *zFilename){
|
|
#endif
|
|
|
|
/*
|
|
-** This routine is the only routine in this file with external
|
|
+** This routine is the only routine in this file with external
|
|
** linkage. It returns a pointer to a static sqlite3_mem_methods
|
|
** struct populated with the memsys5 methods.
|
|
*/
|
|
@@ -25493,7 +27587,7 @@ static SQLITE_WSD int mutexIsInit = 0;
|
|
/*
|
|
** This block (enclosed by SQLITE_ENABLE_MULTITHREADED_CHECKS) contains
|
|
** the implementation of a wrapper around the system default mutex
|
|
-** implementation (sqlite3DefaultMutex()).
|
|
+** implementation (sqlite3DefaultMutex()).
|
|
**
|
|
** Most calls are passed directly through to the underlying default
|
|
** mutex implementation. Except, if a mutex is configured by calling
|
|
@@ -25504,7 +27598,7 @@ static SQLITE_WSD int mutexIsInit = 0;
|
|
** apps that usually use SQLITE_CONFIG_MULTITHREAD mode.
|
|
*/
|
|
|
|
-/*
|
|
+/*
|
|
** Type for all mutexes used when SQLITE_ENABLE_MULTITHREADED_CHECKS
|
|
** is defined. Variable CheckMutex.mutex is a pointer to the real mutex
|
|
** allocated by the system mutex implementation. Variable iType is usually set
|
|
@@ -25521,9 +27615,9 @@ struct CheckMutex {
|
|
|
|
#define SQLITE_MUTEX_WARNONCONTENTION (-1)
|
|
|
|
-/*
|
|
+/*
|
|
** Pointer to real mutex methods object used by the CheckMutex
|
|
-** implementation. Set by checkMutexInit().
|
|
+** implementation. Set by checkMutexInit().
|
|
*/
|
|
static SQLITE_WSD const sqlite3_mutex_methods *pGlobalMutexMethods;
|
|
|
|
@@ -25539,13 +27633,13 @@ static int checkMutexNotheld(sqlite3_mutex *p){
|
|
/*
|
|
** Initialize and deinitialize the mutex subsystem.
|
|
*/
|
|
-static int checkMutexInit(void){
|
|
+static int checkMutexInit(void){
|
|
pGlobalMutexMethods = sqlite3DefaultMutex();
|
|
- return SQLITE_OK;
|
|
+ return SQLITE_OK;
|
|
}
|
|
-static int checkMutexEnd(void){
|
|
+static int checkMutexEnd(void){
|
|
pGlobalMutexMethods = 0;
|
|
- return SQLITE_OK;
|
|
+ return SQLITE_OK;
|
|
}
|
|
|
|
/*
|
|
@@ -25619,7 +27713,7 @@ static void checkMutexEnter(sqlite3_mutex *p){
|
|
if( SQLITE_OK==pGlobalMutexMethods->xMutexTry(pCheck->mutex) ){
|
|
return;
|
|
}
|
|
- sqlite3_log(SQLITE_MISUSE,
|
|
+ sqlite3_log(SQLITE_MISUSE,
|
|
"illegal multi-threaded access to database connection"
|
|
);
|
|
}
|
|
@@ -25678,11 +27772,11 @@ SQLITE_PRIVATE void sqlite3MutexWarnOnContention(sqlite3_mutex *p){
|
|
/*
|
|
** Initialize the mutex system.
|
|
*/
|
|
-SQLITE_PRIVATE int sqlite3MutexInit(void){
|
|
+SQLITE_PRIVATE int sqlite3MutexInit(void){
|
|
int rc = SQLITE_OK;
|
|
if( !sqlite3GlobalConfig.mutex.xMutexAlloc ){
|
|
/* If the xMutexAlloc method has not been set, then the user did not
|
|
- ** install a mutex implementation via sqlite3_config() prior to
|
|
+ ** install a mutex implementation via sqlite3_config() prior to
|
|
** sqlite3_initialize() being called. This block copies pointers to
|
|
** the default implementation into the sqlite3GlobalConfig structure.
|
|
*/
|
|
@@ -25716,6 +27810,7 @@ SQLITE_PRIVATE int sqlite3MutexInit(void){
|
|
GLOBAL(int, mutexIsInit) = 1;
|
|
#endif
|
|
|
|
+ sqlite3MemoryBarrier();
|
|
return rc;
|
|
}
|
|
|
|
@@ -25793,7 +27888,7 @@ SQLITE_API int sqlite3_mutex_try(sqlite3_mutex *p){
|
|
|
|
/*
|
|
** The sqlite3_mutex_leave() routine exits a mutex that was previously
|
|
-** entered by the same thread. The behavior is undefined if the mutex
|
|
+** entered by the same thread. The behavior is undefined if the mutex
|
|
** is not currently entered. If a NULL pointer is passed as an argument
|
|
** this function is a no-op.
|
|
*/
|
|
@@ -25862,9 +27957,9 @@ SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex *p){
|
|
*/
|
|
static int noopMutexInit(void){ return SQLITE_OK; }
|
|
static int noopMutexEnd(void){ return SQLITE_OK; }
|
|
-static sqlite3_mutex *noopMutexAlloc(int id){
|
|
+static sqlite3_mutex *noopMutexAlloc(int id){
|
|
UNUSED_PARAMETER(id);
|
|
- return (sqlite3_mutex*)8;
|
|
+ return (sqlite3_mutex*)8;
|
|
}
|
|
static void noopMutexFree(sqlite3_mutex *p){ UNUSED_PARAMETER(p); return; }
|
|
static void noopMutexEnter(sqlite3_mutex *p){ UNUSED_PARAMETER(p); return; }
|
|
@@ -25929,7 +28024,7 @@ static int debugMutexEnd(void){ return SQLITE_OK; }
|
|
/*
|
|
** The sqlite3_mutex_alloc() routine allocates a new
|
|
** mutex and returns a pointer to it. If it returns NULL
|
|
-** that means that a mutex could not be allocated.
|
|
+** that means that a mutex could not be allocated.
|
|
*/
|
|
static sqlite3_mutex *debugMutexAlloc(int id){
|
|
static sqlite3_debug_mutex aStatic[SQLITE_MUTEX_STATIC_VFS3 - 1];
|
|
@@ -26107,7 +28202,7 @@ struct sqlite3_mutex {
|
|
** there might be race conditions that can cause these routines to
|
|
** deliver incorrect results. In particular, if pthread_equal() is
|
|
** not an atomic operation, then these routines might delivery
|
|
-** incorrect results. On most platforms, pthread_equal() is a
|
|
+** incorrect results. On most platforms, pthread_equal() is a
|
|
** comparison of two integers and is therefore atomic. But we are
|
|
** told that HPUX is not such a platform. If so, then these routines
|
|
** will not always work correctly on HPUX.
|
|
@@ -26155,7 +28250,7 @@ static int pthreadMutexEnd(void){ return SQLITE_OK; }
|
|
** <ul>
|
|
** <li> SQLITE_MUTEX_FAST
|
|
** <li> SQLITE_MUTEX_RECURSIVE
|
|
-** <li> SQLITE_MUTEX_STATIC_MASTER
|
|
+** <li> SQLITE_MUTEX_STATIC_MAIN
|
|
** <li> SQLITE_MUTEX_STATIC_MEM
|
|
** <li> SQLITE_MUTEX_STATIC_OPEN
|
|
** <li> SQLITE_MUTEX_STATIC_PRNG
|
|
@@ -26189,7 +28284,7 @@ static int pthreadMutexEnd(void){ return SQLITE_OK; }
|
|
**
|
|
** Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST
|
|
** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc()
|
|
-** returns a different mutex on every call. But for the static
|
|
+** returns a different mutex on every call. But for the static
|
|
** mutex types, the same mutex is returned on every call that has
|
|
** the same type number.
|
|
*/
|
|
@@ -26300,7 +28395,7 @@ static void pthreadMutexEnter(sqlite3_mutex *p){
|
|
** is atomic - that it cannot be deceived into thinking self
|
|
** and p->owner are equal if p->owner changes between two values
|
|
** that are not equal to self while the comparison is taking place.
|
|
- ** This implementation also assumes a coherent cache - that
|
|
+ ** This implementation also assumes a coherent cache - that
|
|
** separate processes cannot read different values from the same
|
|
** address at the same time. If either of these two conditions
|
|
** are not met, then the mutexes will fail and problems will result.
|
|
@@ -26343,7 +28438,7 @@ static int pthreadMutexTry(sqlite3_mutex *p){
|
|
** is atomic - that it cannot be deceived into thinking self
|
|
** and p->owner are equal if p->owner changes between two values
|
|
** that are not equal to self while the comparison is taking place.
|
|
- ** This implementation also assumes a coherent cache - that
|
|
+ ** This implementation also assumes a coherent cache - that
|
|
** separate processes cannot read different values from the same
|
|
** address at the same time. If either of these two conditions
|
|
** are not met, then the mutexes will fail and problems will result.
|
|
@@ -26457,205 +28552,7 @@ SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
|
|
/*
|
|
** Include code that is common to all os_*.c files
|
|
*/
|
|
-/************** Include os_common.h in the middle of mutex_w32.c *************/
|
|
-/************** Begin file os_common.h ***************************************/
|
|
-/*
|
|
-** 2004 May 22
|
|
-**
|
|
-** The author disclaims copyright to this source code. In place of
|
|
-** a legal notice, here is a blessing:
|
|
-**
|
|
-** May you do good and not evil.
|
|
-** May you find forgiveness for yourself and forgive others.
|
|
-** May you share freely, never taking more than you give.
|
|
-**
|
|
-******************************************************************************
|
|
-**
|
|
-** This file contains macros and a little bit of code that is common to
|
|
-** all of the platform-specific files (os_*.c) and is #included into those
|
|
-** files.
|
|
-**
|
|
-** This file should be #included by the os_*.c files only. It is not a
|
|
-** general purpose header file.
|
|
-*/
|
|
-#ifndef _OS_COMMON_H_
|
|
-#define _OS_COMMON_H_
|
|
-
|
|
-/*
|
|
-** At least two bugs have slipped in because we changed the MEMORY_DEBUG
|
|
-** macro to SQLITE_DEBUG and some older makefiles have not yet made the
|
|
-** switch. The following code should catch this problem at compile-time.
|
|
-*/
|
|
-#ifdef MEMORY_DEBUG
|
|
-# error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead."
|
|
-#endif
|
|
-
|
|
-/*
|
|
-** Macros for performance tracing. Normally turned off. Only works
|
|
-** on i486 hardware.
|
|
-*/
|
|
-#ifdef SQLITE_PERFORMANCE_TRACE
|
|
-
|
|
-/*
|
|
-** hwtime.h contains inline assembler code for implementing
|
|
-** high-performance timing routines.
|
|
-*/
|
|
-/************** Include hwtime.h in the middle of os_common.h ****************/
|
|
-/************** Begin file hwtime.h ******************************************/
|
|
-/*
|
|
-** 2008 May 27
|
|
-**
|
|
-** The author disclaims copyright to this source code. In place of
|
|
-** a legal notice, here is a blessing:
|
|
-**
|
|
-** May you do good and not evil.
|
|
-** May you find forgiveness for yourself and forgive others.
|
|
-** May you share freely, never taking more than you give.
|
|
-**
|
|
-******************************************************************************
|
|
-**
|
|
-** This file contains inline asm code for retrieving "high-performance"
|
|
-** counters for x86 and x86_64 class CPUs.
|
|
-*/
|
|
-#ifndef SQLITE_HWTIME_H
|
|
-#define SQLITE_HWTIME_H
|
|
-
|
|
-/*
|
|
-** The following routine only works on pentium-class (or newer) processors.
|
|
-** It uses the RDTSC opcode to read the cycle count value out of the
|
|
-** processor and returns that value. This can be used for high-res
|
|
-** profiling.
|
|
-*/
|
|
-#if !defined(__STRICT_ANSI__) && \
|
|
- (defined(__GNUC__) || defined(_MSC_VER)) && \
|
|
- (defined(i386) || defined(__i386__) || defined(_M_IX86))
|
|
-
|
|
- #if defined(__GNUC__)
|
|
-
|
|
- __inline__ sqlite_uint64 sqlite3Hwtime(void){
|
|
- unsigned int lo, hi;
|
|
- __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
|
|
- return (sqlite_uint64)hi << 32 | lo;
|
|
- }
|
|
-
|
|
- #elif defined(_MSC_VER)
|
|
-
|
|
- __declspec(naked) __inline sqlite_uint64 __cdecl sqlite3Hwtime(void){
|
|
- __asm {
|
|
- rdtsc
|
|
- ret ; return value at EDX:EAX
|
|
- }
|
|
- }
|
|
-
|
|
- #endif
|
|
-
|
|
-#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__x86_64__))
|
|
-
|
|
- __inline__ sqlite_uint64 sqlite3Hwtime(void){
|
|
- unsigned long val;
|
|
- __asm__ __volatile__ ("rdtsc" : "=A" (val));
|
|
- return val;
|
|
- }
|
|
-
|
|
-#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__ppc__))
|
|
-
|
|
- __inline__ sqlite_uint64 sqlite3Hwtime(void){
|
|
- unsigned long long retval;
|
|
- unsigned long junk;
|
|
- __asm__ __volatile__ ("\n\
|
|
- 1: mftbu %1\n\
|
|
- mftb %L0\n\
|
|
- mftbu %0\n\
|
|
- cmpw %0,%1\n\
|
|
- bne 1b"
|
|
- : "=r" (retval), "=r" (junk));
|
|
- return retval;
|
|
- }
|
|
-
|
|
-#else
|
|
-
|
|
- /*
|
|
- ** asm() is needed for hardware timing support. Without asm(),
|
|
- ** disable the sqlite3Hwtime() routine.
|
|
- **
|
|
- ** sqlite3Hwtime() is only used for some obscure debugging
|
|
- ** and analysis configurations, not in any deliverable, so this
|
|
- ** should not be a great loss.
|
|
- */
|
|
-SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); }
|
|
-
|
|
-#endif
|
|
-
|
|
-#endif /* !defined(SQLITE_HWTIME_H) */
|
|
-
|
|
-/************** End of hwtime.h **********************************************/
|
|
-/************** Continuing where we left off in os_common.h ******************/
|
|
-
|
|
-static sqlite_uint64 g_start;
|
|
-static sqlite_uint64 g_elapsed;
|
|
-#define TIMER_START g_start=sqlite3Hwtime()
|
|
-#define TIMER_END g_elapsed=sqlite3Hwtime()-g_start
|
|
-#define TIMER_ELAPSED g_elapsed
|
|
-#else
|
|
-#define TIMER_START
|
|
-#define TIMER_END
|
|
-#define TIMER_ELAPSED ((sqlite_uint64)0)
|
|
-#endif
|
|
-
|
|
-/*
|
|
-** If we compile with the SQLITE_TEST macro set, then the following block
|
|
-** of code will give us the ability to simulate a disk I/O error. This
|
|
-** is used for testing the I/O recovery logic.
|
|
-*/
|
|
-#if defined(SQLITE_TEST)
|
|
-SQLITE_API extern int sqlite3_io_error_hit;
|
|
-SQLITE_API extern int sqlite3_io_error_hardhit;
|
|
-SQLITE_API extern int sqlite3_io_error_pending;
|
|
-SQLITE_API extern int sqlite3_io_error_persist;
|
|
-SQLITE_API extern int sqlite3_io_error_benign;
|
|
-SQLITE_API extern int sqlite3_diskfull_pending;
|
|
-SQLITE_API extern int sqlite3_diskfull;
|
|
-#define SimulateIOErrorBenign(X) sqlite3_io_error_benign=(X)
|
|
-#define SimulateIOError(CODE) \
|
|
- if( (sqlite3_io_error_persist && sqlite3_io_error_hit) \
|
|
- || sqlite3_io_error_pending-- == 1 ) \
|
|
- { local_ioerr(); CODE; }
|
|
-static void local_ioerr(){
|
|
- IOTRACE(("IOERR\n"));
|
|
- sqlite3_io_error_hit++;
|
|
- if( !sqlite3_io_error_benign ) sqlite3_io_error_hardhit++;
|
|
-}
|
|
-#define SimulateDiskfullError(CODE) \
|
|
- if( sqlite3_diskfull_pending ){ \
|
|
- if( sqlite3_diskfull_pending == 1 ){ \
|
|
- local_ioerr(); \
|
|
- sqlite3_diskfull = 1; \
|
|
- sqlite3_io_error_hit = 1; \
|
|
- CODE; \
|
|
- }else{ \
|
|
- sqlite3_diskfull_pending--; \
|
|
- } \
|
|
- }
|
|
-#else
|
|
-#define SimulateIOErrorBenign(X)
|
|
-#define SimulateIOError(A)
|
|
-#define SimulateDiskfullError(A)
|
|
-#endif /* defined(SQLITE_TEST) */
|
|
-
|
|
-/*
|
|
-** When testing, keep a count of the number of open files.
|
|
-*/
|
|
-#if defined(SQLITE_TEST)
|
|
-SQLITE_API extern int sqlite3_open_file_count;
|
|
-#define OpenCounter(X) sqlite3_open_file_count+=(X)
|
|
-#else
|
|
-#define OpenCounter(X)
|
|
-#endif /* defined(SQLITE_TEST) */
|
|
-
|
|
-#endif /* !defined(_OS_COMMON_H_) */
|
|
-
|
|
-/************** End of os_common.h *******************************************/
|
|
-/************** Continuing where we left off in mutex_w32.c ******************/
|
|
+/* #include "os_common.h" */
|
|
|
|
/*
|
|
** Include the header file for the Windows VFS.
|
|
@@ -26901,7 +28798,7 @@ static int winMutexEnd(void){
|
|
** <ul>
|
|
** <li> SQLITE_MUTEX_FAST
|
|
** <li> SQLITE_MUTEX_RECURSIVE
|
|
-** <li> SQLITE_MUTEX_STATIC_MASTER
|
|
+** <li> SQLITE_MUTEX_STATIC_MAIN
|
|
** <li> SQLITE_MUTEX_STATIC_MEM
|
|
** <li> SQLITE_MUTEX_STATIC_OPEN
|
|
** <li> SQLITE_MUTEX_STATIC_PRNG
|
|
@@ -27243,7 +29140,7 @@ SQLITE_API sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 n){
|
|
}
|
|
mem0.alarmThreshold = n;
|
|
nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
|
|
- mem0.nearlyFull = (n>0 && n<=nUsed);
|
|
+ AtomicStore(&mem0.nearlyFull, n>0 && n<=nUsed);
|
|
sqlite3_mutex_leave(mem0.mutex);
|
|
excess = sqlite3_memory_used() - n;
|
|
if( excess>0 ) sqlite3_release_memory((int)(excess & 0x7fffffff));
|
|
@@ -27293,7 +29190,6 @@ SQLITE_PRIVATE int sqlite3MallocInit(void){
|
|
if( sqlite3GlobalConfig.m.xMalloc==0 ){
|
|
sqlite3MemSetDefault();
|
|
}
|
|
- memset(&mem0, 0, sizeof(mem0));
|
|
mem0.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM);
|
|
if( sqlite3GlobalConfig.pPage==0 || sqlite3GlobalConfig.szPage<512
|
|
|| sqlite3GlobalConfig.nPage<=0 ){
|
|
@@ -27311,7 +29207,7 @@ SQLITE_PRIVATE int sqlite3MallocInit(void){
|
|
** sqlite3_soft_heap_limit().
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3HeapNearlyFull(void){
|
|
- return mem0.nearlyFull;
|
|
+ return AtomicLoad(&mem0.nearlyFull);
|
|
}
|
|
|
|
/*
|
|
@@ -27345,7 +29241,7 @@ SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag){
|
|
}
|
|
|
|
/*
|
|
-** Trigger the alarm
|
|
+** Trigger the alarm
|
|
*/
|
|
static void sqlite3MallocAlarm(int nByte){
|
|
if( mem0.alarmThreshold<=0 ) return;
|
|
@@ -27375,7 +29271,7 @@ static void mallocWithAlarm(int n, void **pp){
|
|
if( mem0.alarmThreshold>0 ){
|
|
sqlite3_int64 nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
|
|
if( nUsed >= mem0.alarmThreshold - nFull ){
|
|
- mem0.nearlyFull = 1;
|
|
+ AtomicStore(&mem0.nearlyFull, 1);
|
|
sqlite3MallocAlarm(nFull);
|
|
if( mem0.hardLimit ){
|
|
nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
|
|
@@ -27385,7 +29281,7 @@ static void mallocWithAlarm(int n, void **pp){
|
|
}
|
|
}
|
|
}else{
|
|
- mem0.nearlyFull = 0;
|
|
+ AtomicStore(&mem0.nearlyFull, 0);
|
|
}
|
|
}
|
|
p = sqlite3GlobalConfig.m.xMalloc(nFull);
|
|
@@ -27403,18 +29299,34 @@ static void mallocWithAlarm(int n, void **pp){
|
|
*pp = p;
|
|
}
|
|
|
|
+/*
|
|
+** Maximum size of any single memory allocation.
|
|
+**
|
|
+** This is not a limit on the total amount of memory used. This is
|
|
+** a limit on the size parameter to sqlite3_malloc() and sqlite3_realloc().
|
|
+**
|
|
+** The upper bound is slightly less than 2GiB: 0x7ffffeff == 2,147,483,391
|
|
+** This provides a 256-byte safety margin for defense against 32-bit
|
|
+** signed integer overflow bugs when computing memory allocation sizes.
|
|
+** Paranoid applications might want to reduce the maximum allocation size
|
|
+** further for an even larger safety margin. 0x3fffffff or 0x0fffffff
|
|
+** or even smaller would be reasonable upper bounds on the size of a memory
|
|
+** allocations for most applications.
|
|
+*/
|
|
+#ifndef SQLITE_MAX_ALLOCATION_SIZE
|
|
+# define SQLITE_MAX_ALLOCATION_SIZE 2147483391
|
|
+#endif
|
|
+#if SQLITE_MAX_ALLOCATION_SIZE>2147483391
|
|
+# error Maximum size for SQLITE_MAX_ALLOCATION_SIZE is 2147483391
|
|
+#endif
|
|
+
|
|
/*
|
|
** Allocate memory. This routine is like sqlite3_malloc() except that it
|
|
** assumes the memory subsystem has already been initialized.
|
|
*/
|
|
SQLITE_PRIVATE void *sqlite3Malloc(u64 n){
|
|
void *p;
|
|
- if( n==0 || n>=0x7fffff00 ){
|
|
- /* A memory allocation of a number of bytes which is near the maximum
|
|
- ** signed integer value might cause an integer overflow inside of the
|
|
- ** xMalloc(). Hence we limit the maximum size to 0x7fffff00, giving
|
|
- ** 255 bytes of overhead. SQLite itself will never use anything near
|
|
- ** this amount. The only way to reach the limit is with sqlite3_malloc() */
|
|
+ if( n==0 || n>SQLITE_MAX_ALLOCATION_SIZE ){
|
|
p = 0;
|
|
}else if( sqlite3GlobalConfig.bMemstat ){
|
|
sqlite3_mutex_enter(mem0.mutex);
|
|
@@ -27449,8 +29361,8 @@ SQLITE_API void *sqlite3_malloc64(sqlite3_uint64 n){
|
|
** TRUE if p is a lookaside memory allocation from db
|
|
*/
|
|
#ifndef SQLITE_OMIT_LOOKASIDE
|
|
-static int isLookaside(sqlite3 *db, void *p){
|
|
- return SQLITE_WITHIN(p, db->lookaside.pStart, db->lookaside.pEnd);
|
|
+static int isLookaside(sqlite3 *db, const void *p){
|
|
+ return SQLITE_WITHIN(p, db->lookaside.pStart, db->lookaside.pTrueEnd);
|
|
}
|
|
#else
|
|
#define isLookaside(A,B) 0
|
|
@@ -27460,32 +29372,30 @@ static int isLookaside(sqlite3 *db, void *p){
|
|
** Return the size of a memory allocation previously obtained from
|
|
** sqlite3Malloc() or sqlite3_malloc().
|
|
*/
|
|
-SQLITE_PRIVATE int sqlite3MallocSize(void *p){
|
|
+SQLITE_PRIVATE int sqlite3MallocSize(const void *p){
|
|
assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
|
|
- return sqlite3GlobalConfig.m.xSize(p);
|
|
+ return sqlite3GlobalConfig.m.xSize((void*)p);
|
|
}
|
|
-static int lookasideMallocSize(sqlite3 *db, void *p){
|
|
-#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
|
|
+static int lookasideMallocSize(sqlite3 *db, const void *p){
|
|
+#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
|
|
return p<db->lookaside.pMiddle ? db->lookaside.szTrue : LOOKASIDE_SMALL;
|
|
#else
|
|
return db->lookaside.szTrue;
|
|
-#endif
|
|
+#endif
|
|
}
|
|
-SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3 *db, void *p){
|
|
+SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3 *db, const void *p){
|
|
assert( p!=0 );
|
|
#ifdef SQLITE_DEBUG
|
|
- if( db==0 || !isLookaside(db,p) ){
|
|
- if( db==0 ){
|
|
- assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );
|
|
- assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
|
|
- }else{
|
|
- assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
|
|
- assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
|
|
- }
|
|
+ if( db==0 ){
|
|
+ assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );
|
|
+ assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
|
|
+ }else if( !isLookaside(db,p) ){
|
|
+ assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
|
|
+ assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
|
|
}
|
|
#endif
|
|
if( db ){
|
|
- if( ((uptr)p)<(uptr)(db->lookaside.pEnd) ){
|
|
+ if( ((uptr)p)<(uptr)(db->lookaside.pTrueEnd) ){
|
|
#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
|
|
if( ((uptr)p)>=(uptr)(db->lookaside.pMiddle) ){
|
|
assert( sqlite3_mutex_held(db->mutex) );
|
|
@@ -27498,7 +29408,7 @@ SQLITE_PRIVATE int sqlite3DbMallocSize(sqlite3 *db, void *p){
|
|
}
|
|
}
|
|
}
|
|
- return sqlite3GlobalConfig.m.xSize(p);
|
|
+ return sqlite3GlobalConfig.m.xSize((void*)p);
|
|
}
|
|
SQLITE_API sqlite3_uint64 sqlite3_msize(void *p){
|
|
assert( sqlite3MemdebugNoType(p, (u8)~MEMTYPE_HEAP) );
|
|
@@ -27541,14 +29451,11 @@ SQLITE_PRIVATE void sqlite3DbFreeNN(sqlite3 *db, void *p){
|
|
assert( db==0 || sqlite3_mutex_held(db->mutex) );
|
|
assert( p!=0 );
|
|
if( db ){
|
|
- if( db->pnBytesFreed ){
|
|
- measureAllocationSize(db, p);
|
|
- return;
|
|
- }
|
|
if( ((uptr)p)<(uptr)(db->lookaside.pEnd) ){
|
|
#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
|
|
if( ((uptr)p)>=(uptr)(db->lookaside.pMiddle) ){
|
|
LookasideSlot *pBuf = (LookasideSlot*)p;
|
|
+ assert( db->pnBytesFreed==0 );
|
|
#ifdef SQLITE_DEBUG
|
|
memset(p, 0xaa, LOOKASIDE_SMALL); /* Trash freed content */
|
|
#endif
|
|
@@ -27559,6 +29466,7 @@ SQLITE_PRIVATE void sqlite3DbFreeNN(sqlite3 *db, void *p){
|
|
#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
|
|
if( ((uptr)p)>=(uptr)(db->lookaside.pStart) ){
|
|
LookasideSlot *pBuf = (LookasideSlot*)p;
|
|
+ assert( db->pnBytesFreed==0 );
|
|
#ifdef SQLITE_DEBUG
|
|
memset(p, 0xaa, db->lookaside.szTrue); /* Trash freed content */
|
|
#endif
|
|
@@ -27567,6 +29475,10 @@ SQLITE_PRIVATE void sqlite3DbFreeNN(sqlite3 *db, void *p){
|
|
return;
|
|
}
|
|
}
|
|
+ if( db->pnBytesFreed ){
|
|
+ measureAllocationSize(db, p);
|
|
+ return;
|
|
+ }
|
|
}
|
|
assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
|
|
assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
|
|
@@ -27574,6 +29486,43 @@ SQLITE_PRIVATE void sqlite3DbFreeNN(sqlite3 *db, void *p){
|
|
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
|
|
sqlite3_free(p);
|
|
}
|
|
+SQLITE_PRIVATE void sqlite3DbNNFreeNN(sqlite3 *db, void *p){
|
|
+ assert( db!=0 );
|
|
+ assert( sqlite3_mutex_held(db->mutex) );
|
|
+ assert( p!=0 );
|
|
+ if( ((uptr)p)<(uptr)(db->lookaside.pEnd) ){
|
|
+#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
|
|
+ if( ((uptr)p)>=(uptr)(db->lookaside.pMiddle) ){
|
|
+ LookasideSlot *pBuf = (LookasideSlot*)p;
|
|
+ assert( db->pnBytesFreed==0 );
|
|
+#ifdef SQLITE_DEBUG
|
|
+ memset(p, 0xaa, LOOKASIDE_SMALL); /* Trash freed content */
|
|
+#endif
|
|
+ pBuf->pNext = db->lookaside.pSmallFree;
|
|
+ db->lookaside.pSmallFree = pBuf;
|
|
+ return;
|
|
+ }
|
|
+#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
|
|
+ if( ((uptr)p)>=(uptr)(db->lookaside.pStart) ){
|
|
+ LookasideSlot *pBuf = (LookasideSlot*)p;
|
|
+ assert( db->pnBytesFreed==0 );
|
|
+#ifdef SQLITE_DEBUG
|
|
+ memset(p, 0xaa, db->lookaside.szTrue); /* Trash freed content */
|
|
+#endif
|
|
+ pBuf->pNext = db->lookaside.pFree;
|
|
+ db->lookaside.pFree = pBuf;
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+ if( db->pnBytesFreed ){
|
|
+ measureAllocationSize(db, p);
|
|
+ return;
|
|
+ }
|
|
+ assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
|
|
+ assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
|
|
+ sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
|
|
+ sqlite3_free(p);
|
|
+}
|
|
SQLITE_PRIVATE void sqlite3DbFree(sqlite3 *db, void *p){
|
|
assert( db==0 || sqlite3_mutex_held(db->mutex) );
|
|
if( p ) sqlite3DbFreeNN(db, p);
|
|
@@ -27606,18 +29555,25 @@ SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, u64 nBytes){
|
|
if( nOld==nNew ){
|
|
pNew = pOld;
|
|
}else if( sqlite3GlobalConfig.bMemstat ){
|
|
+ sqlite3_int64 nUsed;
|
|
sqlite3_mutex_enter(mem0.mutex);
|
|
sqlite3StatusHighwater(SQLITE_STATUS_MALLOC_SIZE, (int)nBytes);
|
|
nDiff = nNew - nOld;
|
|
- if( nDiff>0 && sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED) >=
|
|
+ if( nDiff>0 && (nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED)) >=
|
|
mem0.alarmThreshold-nDiff ){
|
|
sqlite3MallocAlarm(nDiff);
|
|
+ if( mem0.hardLimit>0 && nUsed >= mem0.hardLimit - nDiff ){
|
|
+ sqlite3_mutex_leave(mem0.mutex);
|
|
+ return 0;
|
|
+ }
|
|
}
|
|
pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
|
|
+#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
|
|
if( pNew==0 && mem0.alarmThreshold>0 ){
|
|
sqlite3MallocAlarm((int)nBytes);
|
|
pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
|
|
}
|
|
+#endif
|
|
if( pNew ){
|
|
nNew = sqlite3MallocSize(pNew);
|
|
sqlite3StatusUp(SQLITE_STATUS_MEMORY_USED, nNew-nOld);
|
|
@@ -27651,7 +29607,7 @@ SQLITE_API void *sqlite3_realloc64(void *pOld, sqlite3_uint64 n){
|
|
|
|
/*
|
|
** Allocate and zero memory.
|
|
-*/
|
|
+*/
|
|
SQLITE_PRIVATE void *sqlite3MallocZero(u64 n){
|
|
void *p = sqlite3Malloc(n);
|
|
if( p ){
|
|
@@ -27681,13 +29637,13 @@ static SQLITE_NOINLINE void *dbMallocRawFinish(sqlite3 *db, u64 n){
|
|
assert( db!=0 );
|
|
p = sqlite3Malloc(n);
|
|
if( !p ) sqlite3OomFault(db);
|
|
- sqlite3MemdebugSetType(p,
|
|
+ sqlite3MemdebugSetType(p,
|
|
(db->lookaside.bDisable==0) ? MEMTYPE_LOOKASIDE : MEMTYPE_HEAP);
|
|
return p;
|
|
}
|
|
|
|
/*
|
|
-** Allocate memory, either lookaside (if possible) or heap.
|
|
+** Allocate memory, either lookaside (if possible) or heap.
|
|
** If the allocation fails, set the mallocFailed flag in
|
|
** the connection pointer.
|
|
**
|
|
@@ -27723,7 +29679,7 @@ SQLITE_PRIVATE void *sqlite3DbMallocRawNN(sqlite3 *db, u64 n){
|
|
assert( db->pnBytesFreed==0 );
|
|
if( n>db->lookaside.sz ){
|
|
if( !db->lookaside.bDisable ){
|
|
- db->lookaside.anStat[1]++;
|
|
+ db->lookaside.anStat[1]++;
|
|
}else if( db->mallocFailed ){
|
|
return 0;
|
|
}
|
|
@@ -27802,7 +29758,7 @@ static SQLITE_NOINLINE void *dbReallocFinish(sqlite3 *db, void *p, u64 n){
|
|
assert( sqlite3MemdebugHasType(p, (MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
|
|
assert( sqlite3MemdebugNoType(p, (u8)~(MEMTYPE_LOOKASIDE|MEMTYPE_HEAP)) );
|
|
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
|
|
- pNew = sqlite3_realloc64(p, n);
|
|
+ pNew = sqlite3Realloc(p, n);
|
|
if( !pNew ){
|
|
sqlite3OomFault(db);
|
|
}
|
|
@@ -27827,9 +29783,9 @@ SQLITE_PRIVATE void *sqlite3DbReallocOrFree(sqlite3 *db, void *p, u64 n){
|
|
}
|
|
|
|
/*
|
|
-** Make a copy of a string in memory obtained from sqliteMalloc(). These
|
|
+** Make a copy of a string in memory obtained from sqliteMalloc(). These
|
|
** functions call sqlite3MallocRaw() directly instead of sqliteMalloc(). This
|
|
-** is because when memory debugging is turned on, these two functions are
|
|
+** is because when memory debugging is turned on, these two functions are
|
|
** called via macros that record the current file and line number in the
|
|
** ThreadData structure.
|
|
*/
|
|
@@ -27849,11 +29805,9 @@ SQLITE_PRIVATE char *sqlite3DbStrDup(sqlite3 *db, const char *z){
|
|
SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3 *db, const char *z, u64 n){
|
|
char *zNew;
|
|
assert( db!=0 );
|
|
- if( z==0 ){
|
|
- return 0;
|
|
- }
|
|
+ assert( z!=0 || n==0 );
|
|
assert( (n&0x7fffffff)==n );
|
|
- zNew = sqlite3DbMallocRawNN(db, n+1);
|
|
+ zNew = z ? sqlite3DbMallocRawNN(db, n+1) : 0;
|
|
if( zNew ){
|
|
memcpy(zNew, z, (size_t)n);
|
|
zNew[n] = 0;
|
|
@@ -27868,9 +29822,14 @@ SQLITE_PRIVATE char *sqlite3DbStrNDup(sqlite3 *db, const char *z, u64 n){
|
|
*/
|
|
SQLITE_PRIVATE char *sqlite3DbSpanDup(sqlite3 *db, const char *zStart, const char *zEnd){
|
|
int n;
|
|
+#ifdef SQLITE_DEBUG
|
|
+ /* Because of the way the parser works, the span is guaranteed to contain
|
|
+ ** at least one non-space character */
|
|
+ for(n=0; sqlite3Isspace(zStart[n]); n++){ assert( &zStart[n]<zEnd ); }
|
|
+#endif
|
|
while( sqlite3Isspace(zStart[0]) ) zStart++;
|
|
n = (int)(zEnd - zStart);
|
|
- while( ALWAYS(n>0) && sqlite3Isspace(zStart[n-1]) ) n--;
|
|
+ while( sqlite3Isspace(zStart[n-1]) ) n--;
|
|
return sqlite3DbStrNDup(db, zStart, n);
|
|
}
|
|
|
|
@@ -27878,8 +29837,9 @@ SQLITE_PRIVATE char *sqlite3DbSpanDup(sqlite3 *db, const char *zStart, const cha
|
|
** Free any prior content in *pz and replace it with a copy of zNew.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3SetString(char **pz, sqlite3 *db, const char *zNew){
|
|
+ char *z = sqlite3DbStrDup(db, zNew);
|
|
sqlite3DbFree(db, *pz);
|
|
- *pz = sqlite3DbStrDup(db, zNew);
|
|
+ *pz = z;
|
|
}
|
|
|
|
/*
|
|
@@ -27887,18 +29847,32 @@ SQLITE_PRIVATE void sqlite3SetString(char **pz, sqlite3 *db, const char *zNew){
|
|
** has happened. This routine will set db->mallocFailed, and also
|
|
** temporarily disable the lookaside memory allocator and interrupt
|
|
** any running VDBEs.
|
|
+**
|
|
+** Always return a NULL pointer so that this routine can be invoked using
|
|
+**
|
|
+** return sqlite3OomFault(db);
|
|
+**
|
|
+** and thereby avoid unnecessary stack frame allocations for the overwhelmingly
|
|
+** common case where no OOM occurs.
|
|
*/
|
|
-SQLITE_PRIVATE void sqlite3OomFault(sqlite3 *db){
|
|
+SQLITE_PRIVATE void *sqlite3OomFault(sqlite3 *db){
|
|
if( db->mallocFailed==0 && db->bBenignMalloc==0 ){
|
|
db->mallocFailed = 1;
|
|
if( db->nVdbeExec>0 ){
|
|
- db->u1.isInterrupted = 1;
|
|
+ AtomicStore(&db->u1.isInterrupted, 1);
|
|
}
|
|
DisableLookaside;
|
|
if( db->pParse ){
|
|
+ Parse *pParse;
|
|
+ sqlite3ErrorMsg(db->pParse, "out of memory");
|
|
db->pParse->rc = SQLITE_NOMEM_BKPT;
|
|
+ for(pParse=db->pParse->pOuterParse; pParse; pParse = pParse->pOuterParse){
|
|
+ pParse->nErr++;
|
|
+ pParse->rc = SQLITE_NOMEM;
|
|
+ }
|
|
}
|
|
}
|
|
+ return 0;
|
|
}
|
|
|
|
/*
|
|
@@ -27911,42 +29885,45 @@ SQLITE_PRIVATE void sqlite3OomFault(sqlite3 *db){
|
|
SQLITE_PRIVATE void sqlite3OomClear(sqlite3 *db){
|
|
if( db->mallocFailed && db->nVdbeExec==0 ){
|
|
db->mallocFailed = 0;
|
|
- db->u1.isInterrupted = 0;
|
|
+ AtomicStore(&db->u1.isInterrupted, 0);
|
|
assert( db->lookaside.bDisable>0 );
|
|
EnableLookaside;
|
|
}
|
|
}
|
|
|
|
/*
|
|
-** Take actions at the end of an API call to indicate an OOM error
|
|
+** Take actions at the end of an API call to deal with error codes.
|
|
*/
|
|
-static SQLITE_NOINLINE int apiOomError(sqlite3 *db){
|
|
- sqlite3OomClear(db);
|
|
- sqlite3Error(db, SQLITE_NOMEM);
|
|
- return SQLITE_NOMEM_BKPT;
|
|
+static SQLITE_NOINLINE int apiHandleError(sqlite3 *db, int rc){
|
|
+ if( db->mallocFailed || rc==SQLITE_IOERR_NOMEM ){
|
|
+ sqlite3OomClear(db);
|
|
+ sqlite3Error(db, SQLITE_NOMEM);
|
|
+ return SQLITE_NOMEM_BKPT;
|
|
+ }
|
|
+ return rc & db->errMask;
|
|
}
|
|
|
|
/*
|
|
-** This function must be called before exiting any API function (i.e.
|
|
+** This function must be called before exiting any API function (i.e.
|
|
** returning control to the user) that has called sqlite3_malloc or
|
|
** sqlite3_realloc.
|
|
**
|
|
** The returned value is normally a copy of the second argument to this
|
|
** function. However, if a malloc() failure has occurred since the previous
|
|
-** invocation SQLITE_NOMEM is returned instead.
|
|
+** invocation SQLITE_NOMEM is returned instead.
|
|
**
|
|
** If an OOM as occurred, then the connection error-code (the value
|
|
** returned by sqlite3_errcode()) is set to SQLITE_NOMEM.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3ApiExit(sqlite3* db, int rc){
|
|
/* If the db handle must hold the connection handle mutex here.
|
|
- ** Otherwise the read (and possible write) of db->mallocFailed
|
|
+ ** Otherwise the read (and possible write) of db->mallocFailed
|
|
** is unsafe, as is the call to sqlite3Error().
|
|
*/
|
|
assert( db!=0 );
|
|
assert( sqlite3_mutex_held(db->mutex) );
|
|
- if( db->mallocFailed || rc==SQLITE_IOERR_NOMEM ){
|
|
- return apiOomError(db);
|
|
+ if( db->mallocFailed || rc ){
|
|
+ return apiHandleError(db, rc);
|
|
}
|
|
return rc & db->errMask;
|
|
}
|
|
@@ -27955,7 +29932,7 @@ SQLITE_PRIVATE int sqlite3ApiExit(sqlite3* db, int rc){
|
|
/************** Begin file printf.c ******************************************/
|
|
/*
|
|
** The "printf" code that follows dates from the 1980's. It is in
|
|
-** the public domain.
|
|
+** the public domain.
|
|
**
|
|
**************************************************************************
|
|
**
|
|
@@ -27984,7 +29961,7 @@ SQLITE_PRIVATE int sqlite3ApiExit(sqlite3* db, int rc){
|
|
#define etSQLESCAPE2 10 /* Strings with '\'' doubled and enclosed in '',
|
|
NULL pointers replaced by SQL NULL. %Q */
|
|
#define etTOKEN 11 /* a pointer to a Token structure */
|
|
-#define etSRCLIST 12 /* a pointer to a SrcList */
|
|
+#define etSRCITEM 12 /* a pointer to a SrcItem */
|
|
#define etPOINTER 13 /* The %p conversion */
|
|
#define etSQLESCAPE3 14 /* %w -> Strings with '\"' doubled */
|
|
#define etORDINAL 15 /* %r -> 1st, 2nd, 3rd, 4th, etc. English only */
|
|
@@ -28050,10 +30027,16 @@ static const et_info fmtinfo[] = {
|
|
|
|
/* All the rest are undocumented and are for internal use only */
|
|
{ 'T', 0, 0, etTOKEN, 0, 0 },
|
|
- { 'S', 0, 0, etSRCLIST, 0, 0 },
|
|
+ { 'S', 0, 0, etSRCITEM, 0, 0 },
|
|
{ 'r', 10, 1, etORDINAL, 0, 0 },
|
|
};
|
|
|
|
+/* Notes:
|
|
+**
|
|
+** %S Takes a pointer to SrcItem. Shows name or database.name
|
|
+** %!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,
|
|
@@ -28094,7 +30077,7 @@ static char et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){
|
|
/*
|
|
** Set the StrAccum object to an error mode.
|
|
*/
|
|
-static void setStrAccumError(StrAccum *p, u8 eError){
|
|
+SQLITE_PRIVATE void sqlite3StrAccumSetError(StrAccum *p, u8 eError){
|
|
assert( eError==SQLITE_NOMEM || eError==SQLITE_TOOBIG );
|
|
p->accError = eError;
|
|
if( p->mxAlloc ) sqlite3_str_reset(p);
|
|
@@ -28130,12 +30113,12 @@ static char *printfTempBuf(sqlite3_str *pAccum, sqlite3_int64 n){
|
|
char *z;
|
|
if( pAccum->accError ) return 0;
|
|
if( n>pAccum->nAlloc && n>pAccum->mxAlloc ){
|
|
- setStrAccumError(pAccum, SQLITE_TOOBIG);
|
|
+ sqlite3StrAccumSetError(pAccum, SQLITE_TOOBIG);
|
|
return 0;
|
|
}
|
|
z = sqlite3DbMallocRaw(pAccum->db, n);
|
|
if( z==0 ){
|
|
- setStrAccumError(pAccum, SQLITE_NOMEM);
|
|
+ sqlite3StrAccumSetError(pAccum, SQLITE_NOMEM);
|
|
}
|
|
return z;
|
|
}
|
|
@@ -28149,6 +30132,13 @@ static char *printfTempBuf(sqlite3_str *pAccum, sqlite3_int64 n){
|
|
#endif
|
|
#define etBUFSIZE SQLITE_PRINT_BUF_SIZE /* Size of the output buffer */
|
|
|
|
+/*
|
|
+** Hard limit on the precision of floating-point conversions.
|
|
+*/
|
|
+#ifndef SQLITE_PRINTF_PRECISION_LIMIT
|
|
+# define SQLITE_FP_PRECISION_LIMIT 100000000
|
|
+#endif
|
|
+
|
|
/*
|
|
** Render a string given by "fmt" into the StrAccum object.
|
|
*/
|
|
@@ -28190,7 +30180,7 @@ SQLITE_API void sqlite3_str_vappendf(
|
|
PrintfArguments *pArgList = 0; /* Arguments for SQLITE_PRINTF_SQLFUNC */
|
|
char buf[etBUFSIZE]; /* Conversion buffer */
|
|
|
|
- /* pAccum never starts out with an empty buffer that was obtained from
|
|
+ /* pAccum never starts out with an empty buffer that was obtained from
|
|
** malloc(). This precondition is required by the mprintf("%z...")
|
|
** optimization. */
|
|
assert( pAccum->nChar>0 || (pAccum->printfFlags&SQLITE_PRINTF_MALLOCED)==0 );
|
|
@@ -28349,15 +30339,17 @@ SQLITE_API void sqlite3_str_vappendf(
|
|
** xtype The class of the conversion.
|
|
** infop Pointer to the appropriate info struct.
|
|
*/
|
|
+ assert( width>=0 );
|
|
+ assert( precision>=(-1) );
|
|
switch( xtype ){
|
|
case etPOINTER:
|
|
flag_long = sizeof(char*)==sizeof(i64) ? 2 :
|
|
sizeof(char*)==sizeof(long int) ? 1 : 0;
|
|
- /* Fall through into the next case */
|
|
+ /* no break */ deliberate_fall_through
|
|
case etORDINAL:
|
|
- case etRADIX:
|
|
+ case etRADIX:
|
|
cThousand = 0;
|
|
- /* Fall through into the next case */
|
|
+ /* no break */ deliberate_fall_through
|
|
case etDECIMAL:
|
|
if( infop->flags & FLAG_SIGNED ){
|
|
i64 v;
|
|
@@ -28373,11 +30365,10 @@ SQLITE_API void sqlite3_str_vappendf(
|
|
v = va_arg(ap,int);
|
|
}
|
|
if( v<0 ){
|
|
- if( v==SMALLEST_INT64 ){
|
|
- longvalue = ((u64)1)<<63;
|
|
- }else{
|
|
- longvalue = -v;
|
|
- }
|
|
+ testcase( v==SMALLEST_INT64 );
|
|
+ testcase( v==(-1) );
|
|
+ longvalue = ~v;
|
|
+ longvalue++;
|
|
prefix = '-';
|
|
}else{
|
|
longvalue = v;
|
|
@@ -28470,6 +30461,11 @@ SQLITE_API void sqlite3_str_vappendf(
|
|
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 = '-';
|
|
@@ -28672,13 +30668,26 @@ SQLITE_API void sqlite3_str_vappendf(
|
|
}
|
|
}
|
|
if( precision>1 ){
|
|
+ i64 nPrior = 1;
|
|
width -= precision-1;
|
|
if( width>1 && !flag_leftjustify ){
|
|
sqlite3_str_appendchar(pAccum, width-1, ' ');
|
|
width = 0;
|
|
}
|
|
- while( precision-- > 1 ){
|
|
- sqlite3_str_append(pAccum, buf, length);
|
|
+ sqlite3_str_append(pAccum, buf, length);
|
|
+ precision--;
|
|
+ while( precision > 1 ){
|
|
+ i64 nCopyBytes;
|
|
+ if( nPrior > precision-1 ) nPrior = precision - 1;
|
|
+ nCopyBytes = length*nPrior;
|
|
+ if( nCopyBytes + pAccum->nChar >= pAccum->nAlloc ){
|
|
+ sqlite3StrAccumEnlarge(pAccum, nCopyBytes);
|
|
+ }
|
|
+ if( pAccum->accError ) break;
|
|
+ sqlite3_str_append(pAccum,
|
|
+ &pAccum->zText[pAccum->nChar-nCopyBytes], nCopyBytes);
|
|
+ precision -= nPrior;
|
|
+ nPrior *= 2;
|
|
}
|
|
}
|
|
bufpt = buf;
|
|
@@ -28739,8 +30748,8 @@ SQLITE_API void sqlite3_str_vappendf(
|
|
case etSQLESCAPE: /* %q: Escape ' characters */
|
|
case etSQLESCAPE2: /* %Q: Escape ' and enclose in '...' */
|
|
case etSQLESCAPE3: { /* %w: Escape " characters */
|
|
- int i, j, k, n, isnull;
|
|
- int needQuote;
|
|
+ i64 i, j, k, n;
|
|
+ int needQuote, isnull;
|
|
char ch;
|
|
char q = ((xtype==etSQLESCAPE3)?'"':'\''); /* Quote character */
|
|
char *escarg;
|
|
@@ -28752,7 +30761,7 @@ SQLITE_API void sqlite3_str_vappendf(
|
|
}
|
|
isnull = escarg==0;
|
|
if( isnull ) escarg = (xtype==etSQLESCAPE2 ? "NULL" : "(NULL)");
|
|
- /* For %q, %Q, and %w, the precision is the number of byte (or
|
|
+ /* For %q, %Q, and %w, the precision is the number of bytes (or
|
|
** characters if the ! flags is present) to use from the input.
|
|
** Because of the extra quoting characters inserted, the number
|
|
** of output characters may be larger than the precision.
|
|
@@ -28785,31 +30794,50 @@ SQLITE_API void sqlite3_str_vappendf(
|
|
goto adjust_width_for_utf8;
|
|
}
|
|
case etTOKEN: {
|
|
- Token *pToken;
|
|
if( (pAccum->printfFlags & SQLITE_PRINTF_INTERNAL)==0 ) return;
|
|
- pToken = va_arg(ap, Token*);
|
|
- assert( bArgList==0 );
|
|
- if( pToken && pToken->n ){
|
|
- sqlite3_str_append(pAccum, (const char*)pToken->z, pToken->n);
|
|
+ if( flag_alternateform ){
|
|
+ /* %#T means an Expr pointer that uses Expr.u.zToken */
|
|
+ Expr *pExpr = va_arg(ap,Expr*);
|
|
+ if( ALWAYS(pExpr) && ALWAYS(!ExprHasProperty(pExpr,EP_IntValue)) ){
|
|
+ sqlite3_str_appendall(pAccum, (const char*)pExpr->u.zToken);
|
|
+ sqlite3RecordErrorOffsetOfExpr(pAccum->db, pExpr);
|
|
+ }
|
|
+ }else{
|
|
+ /* %T means a Token pointer */
|
|
+ Token *pToken = va_arg(ap, Token*);
|
|
+ assert( bArgList==0 );
|
|
+ if( pToken && pToken->n ){
|
|
+ sqlite3_str_append(pAccum, (const char*)pToken->z, pToken->n);
|
|
+ sqlite3RecordErrorByteOffset(pAccum->db, pToken->z);
|
|
+ }
|
|
}
|
|
length = width = 0;
|
|
break;
|
|
}
|
|
- case etSRCLIST: {
|
|
- SrcList *pSrc;
|
|
- int k;
|
|
- struct SrcList_item *pItem;
|
|
+ case etSRCITEM: {
|
|
+ SrcItem *pItem;
|
|
if( (pAccum->printfFlags & SQLITE_PRINTF_INTERNAL)==0 ) return;
|
|
- pSrc = va_arg(ap, SrcList*);
|
|
- k = va_arg(ap, int);
|
|
- pItem = &pSrc->a[k];
|
|
+ pItem = va_arg(ap, SrcItem*);
|
|
assert( bArgList==0 );
|
|
- assert( k>=0 && k<pSrc->nSrc );
|
|
- if( pItem->zDatabase ){
|
|
- sqlite3_str_appendall(pAccum, pItem->zDatabase);
|
|
- sqlite3_str_append(pAccum, ".", 1);
|
|
+ if( pItem->zAlias && !flag_altform2 ){
|
|
+ sqlite3_str_appendall(pAccum, pItem->zAlias);
|
|
+ }else if( pItem->zName ){
|
|
+ if( pItem->zDatabase ){
|
|
+ sqlite3_str_appendall(pAccum, pItem->zDatabase);
|
|
+ sqlite3_str_append(pAccum, ".", 1);
|
|
+ }
|
|
+ sqlite3_str_appendall(pAccum, pItem->zName);
|
|
+ }else if( pItem->zAlias ){
|
|
+ sqlite3_str_appendall(pAccum, pItem->zAlias);
|
|
+ }else{
|
|
+ Select *pSel = pItem->pSelect;
|
|
+ assert( pSel!=0 );
|
|
+ if( pSel->selFlags & SF_NestedFrom ){
|
|
+ sqlite3_str_appendf(pAccum, "(join-%u)", pSel->selId);
|
|
+ }else{
|
|
+ sqlite3_str_appendf(pAccum, "(subquery-%u)", pSel->selId);
|
|
+ }
|
|
}
|
|
- sqlite3_str_appendall(pAccum, pItem->zName);
|
|
length = width = 0;
|
|
break;
|
|
}
|
|
@@ -28842,6 +30870,44 @@ SQLITE_API void sqlite3_str_vappendf(
|
|
}/* End for loop over the format string */
|
|
} /* End of function */
|
|
|
|
+
|
|
+/*
|
|
+** The z string points to the first character of a token that is
|
|
+** associated with an error. If db does not already have an error
|
|
+** byte offset recorded, try to compute the error byte offset for
|
|
+** z and set the error byte offset in db.
|
|
+*/
|
|
+SQLITE_PRIVATE void sqlite3RecordErrorByteOffset(sqlite3 *db, const char *z){
|
|
+ const Parse *pParse;
|
|
+ const char *zText;
|
|
+ const char *zEnd;
|
|
+ assert( z!=0 );
|
|
+ if( NEVER(db==0) ) return;
|
|
+ if( db->errByteOffset!=(-2) ) return;
|
|
+ pParse = db->pParse;
|
|
+ if( NEVER(pParse==0) ) return;
|
|
+ zText =pParse->zTail;
|
|
+ if( NEVER(zText==0) ) return;
|
|
+ zEnd = &zText[strlen(zText)];
|
|
+ if( SQLITE_WITHIN(z,zText,zEnd) ){
|
|
+ db->errByteOffset = (int)(z-zText);
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+** If pExpr has a byte offset for the start of a token, record that as
|
|
+** as the error offset.
|
|
+*/
|
|
+SQLITE_PRIVATE void sqlite3RecordErrorOffsetOfExpr(sqlite3 *db, const Expr *pExpr){
|
|
+ while( pExpr
|
|
+ && (ExprHasProperty(pExpr,EP_OuterON|EP_InnerON) || pExpr->w.iOfst<=0)
|
|
+ ){
|
|
+ pExpr = pExpr->pLeft;
|
|
+ }
|
|
+ if( pExpr==0 ) return;
|
|
+ db->errByteOffset = pExpr->w.iOfst;
|
|
+}
|
|
+
|
|
/*
|
|
** Enlarge the memory allocation on a StrAccum object so that it is
|
|
** able to accept at least N more bytes of text.
|
|
@@ -28849,21 +30915,20 @@ SQLITE_API void sqlite3_str_vappendf(
|
|
** Return the number of bytes of text that StrAccum is able to accept
|
|
** after the attempted enlargement. The value returned might be zero.
|
|
*/
|
|
-static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
|
|
+SQLITE_PRIVATE int sqlite3StrAccumEnlarge(StrAccum *p, i64 N){
|
|
char *zNew;
|
|
- assert( p->nChar+(i64)N >= p->nAlloc ); /* Only called if really needed */
|
|
+ assert( p->nChar+N >= p->nAlloc ); /* Only called if really needed */
|
|
if( p->accError ){
|
|
testcase(p->accError==SQLITE_TOOBIG);
|
|
testcase(p->accError==SQLITE_NOMEM);
|
|
return 0;
|
|
}
|
|
if( p->mxAlloc==0 ){
|
|
- setStrAccumError(p, SQLITE_TOOBIG);
|
|
+ sqlite3StrAccumSetError(p, SQLITE_TOOBIG);
|
|
return p->nAlloc - p->nChar - 1;
|
|
}else{
|
|
char *zOld = isMalloced(p) ? p->zText : 0;
|
|
- i64 szNew = p->nChar;
|
|
- szNew += N + 1;
|
|
+ i64 szNew = p->nChar + N + 1;
|
|
if( szNew+p->nChar<=p->mxAlloc ){
|
|
/* Force exponential buffer size growth as long as it does not overflow,
|
|
** to avoid having to call this routine too often */
|
|
@@ -28871,7 +30936,7 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
|
|
}
|
|
if( szNew > p->mxAlloc ){
|
|
sqlite3_str_reset(p);
|
|
- setStrAccumError(p, SQLITE_TOOBIG);
|
|
+ sqlite3StrAccumSetError(p, SQLITE_TOOBIG);
|
|
return 0;
|
|
}else{
|
|
p->nAlloc = (int)szNew;
|
|
@@ -28879,7 +30944,7 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
|
|
if( p->db ){
|
|
zNew = sqlite3DbRealloc(p->db, zOld, p->nAlloc);
|
|
}else{
|
|
- zNew = sqlite3_realloc64(zOld, p->nAlloc);
|
|
+ zNew = sqlite3Realloc(zOld, p->nAlloc);
|
|
}
|
|
if( zNew ){
|
|
assert( p->zText!=0 || p->nChar==0 );
|
|
@@ -28889,11 +30954,12 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
|
|
p->printfFlags |= SQLITE_PRINTF_MALLOCED;
|
|
}else{
|
|
sqlite3_str_reset(p);
|
|
- setStrAccumError(p, SQLITE_NOMEM);
|
|
+ sqlite3StrAccumSetError(p, SQLITE_NOMEM);
|
|
return 0;
|
|
}
|
|
}
|
|
- return N;
|
|
+ assert( N>=0 && N<=0x7fffffff );
|
|
+ return (int)N;
|
|
}
|
|
|
|
/*
|
|
@@ -28962,7 +31028,7 @@ static SQLITE_NOINLINE char *strAccumFinishRealloc(StrAccum *p){
|
|
memcpy(zText, p->zText, p->nChar+1);
|
|
p->printfFlags |= SQLITE_PRINTF_MALLOCED;
|
|
}else{
|
|
- setStrAccumError(p, SQLITE_NOMEM);
|
|
+ sqlite3StrAccumSetError(p, SQLITE_NOMEM);
|
|
}
|
|
p->zText = zText;
|
|
return zText;
|
|
@@ -28977,6 +31043,22 @@ SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum *p){
|
|
return p->zText;
|
|
}
|
|
|
|
+/*
|
|
+** Use the content of the StrAccum passed as the second argument
|
|
+** as the result of an SQL function.
|
|
+*/
|
|
+SQLITE_PRIVATE void sqlite3ResultStrAccum(sqlite3_context *pCtx, StrAccum *p){
|
|
+ if( p->accError ){
|
|
+ sqlite3_result_error_code(pCtx, p->accError);
|
|
+ sqlite3_str_reset(p);
|
|
+ }else if( isMalloced(p) ){
|
|
+ sqlite3_result_text(pCtx, p->zText, p->nChar, SQLITE_DYNAMIC);
|
|
+ }else{
|
|
+ sqlite3_result_text(pCtx, "", 0, SQLITE_STATIC);
|
|
+ sqlite3_str_reset(p);
|
|
+ }
|
|
+}
|
|
+
|
|
/*
|
|
** This singleton is an sqlite3_str object that is returned if
|
|
** sqlite3_malloc() fails to provide space for a real one. This
|
|
@@ -29108,7 +31190,7 @@ SQLITE_API char *sqlite3_vmprintf(const char *zFormat, va_list ap){
|
|
char zBase[SQLITE_PRINT_BUF_SIZE];
|
|
StrAccum acc;
|
|
|
|
-#ifdef SQLITE_ENABLE_API_ARMOR
|
|
+#ifdef SQLITE_ENABLE_API_ARMOR
|
|
if( zFormat==0 ){
|
|
(void)SQLITE_MISUSE_BKPT;
|
|
return 0;
|
|
@@ -29221,7 +31303,7 @@ SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...){
|
|
SQLITE_PRIVATE void sqlite3DebugPrintf(const char *zFormat, ...){
|
|
va_list ap;
|
|
StrAccum acc;
|
|
- char zBuf[500];
|
|
+ char zBuf[SQLITE_PRINT_BUF_SIZE*10];
|
|
sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0);
|
|
va_start(ap,zFormat);
|
|
sqlite3_str_vappendf(&acc, zFormat, ap);
|
|
@@ -29267,7 +31349,7 @@ SQLITE_API void sqlite3_str_appendf(StrAccum *p, const char *zFormat, ...){
|
|
**
|
|
** This file contains C code to implement the TreeView debugging routines.
|
|
** These routines print a parse tree to standard output for debugging and
|
|
-** analysis.
|
|
+** analysis.
|
|
**
|
|
** The interfaces in this file is only available when compiling
|
|
** with SQLITE_DEBUG.
|
|
@@ -29279,40 +31361,44 @@ SQLITE_API void sqlite3_str_appendf(StrAccum *p, const char *zFormat, ...){
|
|
** Add a new subitem to the tree. The moreToFollow flag indicates that this
|
|
** is not the last item in the tree.
|
|
*/
|
|
-static TreeView *sqlite3TreeViewPush(TreeView *p, u8 moreToFollow){
|
|
+static void sqlite3TreeViewPush(TreeView **pp, u8 moreToFollow){
|
|
+ TreeView *p = *pp;
|
|
if( p==0 ){
|
|
- p = sqlite3_malloc64( sizeof(*p) );
|
|
- if( p==0 ) return 0;
|
|
+ *pp = p = sqlite3_malloc64( sizeof(*p) );
|
|
+ if( p==0 ) return;
|
|
memset(p, 0, sizeof(*p));
|
|
}else{
|
|
p->iLevel++;
|
|
}
|
|
assert( moreToFollow==0 || moreToFollow==1 );
|
|
- if( p->iLevel<sizeof(p->bLine) ) p->bLine[p->iLevel] = moreToFollow;
|
|
- return p;
|
|
+ if( p->iLevel<(int)sizeof(p->bLine) ) p->bLine[p->iLevel] = moreToFollow;
|
|
}
|
|
|
|
/*
|
|
** Finished with one layer of the tree
|
|
*/
|
|
-static void sqlite3TreeViewPop(TreeView *p){
|
|
+static void sqlite3TreeViewPop(TreeView **pp){
|
|
+ TreeView *p = *pp;
|
|
if( p==0 ) return;
|
|
p->iLevel--;
|
|
- if( p->iLevel<0 ) sqlite3_free(p);
|
|
+ if( p->iLevel<0 ){
|
|
+ sqlite3_free(p);
|
|
+ *pp = 0;
|
|
+ }
|
|
}
|
|
|
|
/*
|
|
** Generate a single line of output for the tree, with a prefix that contains
|
|
** all the appropriate tree lines
|
|
*/
|
|
-static void sqlite3TreeViewLine(TreeView *p, const char *zFormat, ...){
|
|
+SQLITE_PRIVATE void sqlite3TreeViewLine(TreeView *p, const char *zFormat, ...){
|
|
va_list ap;
|
|
int i;
|
|
StrAccum acc;
|
|
- char zBuf[500];
|
|
+ char zBuf[1000];
|
|
sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0);
|
|
if( p ){
|
|
- for(i=0; i<p->iLevel && i<sizeof(p->bLine)-1; i++){
|
|
+ for(i=0; i<p->iLevel && i<(int)sizeof(p->bLine)-1; i++){
|
|
sqlite3_str_append(&acc, p->bLine[i] ? "| " : " ", 4);
|
|
}
|
|
sqlite3_str_append(&acc, p->bLine[i] ? "|-- " : "'-- ", 4);
|
|
@@ -29333,10 +31419,57 @@ static void sqlite3TreeViewLine(TreeView *p, const char *zFormat, ...){
|
|
** Shorthand for starting a new tree item that consists of a single label
|
|
*/
|
|
static void sqlite3TreeViewItem(TreeView *p, const char *zLabel,u8 moreFollows){
|
|
- p = sqlite3TreeViewPush(p, moreFollows);
|
|
+ sqlite3TreeViewPush(&p, moreFollows);
|
|
sqlite3TreeViewLine(p, "%s", zLabel);
|
|
}
|
|
|
|
+/*
|
|
+** Show a list of Column objects in tree format.
|
|
+*/
|
|
+SQLITE_PRIVATE void sqlite3TreeViewColumnList(
|
|
+ TreeView *pView,
|
|
+ const Column *aCol,
|
|
+ int nCol,
|
|
+ u8 moreToFollow
|
|
+){
|
|
+ int i;
|
|
+ sqlite3TreeViewPush(&pView, moreToFollow);
|
|
+ sqlite3TreeViewLine(pView, "COLUMNS");
|
|
+ for(i=0; i<nCol; i++){
|
|
+ u16 flg = aCol[i].colFlags;
|
|
+ int colMoreToFollow = i<(nCol - 1);
|
|
+ sqlite3TreeViewPush(&pView, colMoreToFollow);
|
|
+ sqlite3TreeViewLine(pView, 0);
|
|
+ printf(" %s", aCol[i].zCnName);
|
|
+ switch( aCol[i].eCType ){
|
|
+ case COLTYPE_ANY: printf(" ANY"); break;
|
|
+ case COLTYPE_BLOB: printf(" BLOB"); break;
|
|
+ case COLTYPE_INT: printf(" INT"); break;
|
|
+ case COLTYPE_INTEGER: printf(" INTEGER"); break;
|
|
+ case COLTYPE_REAL: printf(" REAL"); break;
|
|
+ case COLTYPE_TEXT: printf(" TEXT"); break;
|
|
+ case COLTYPE_CUSTOM: {
|
|
+ if( flg & COLFLAG_HASTYPE ){
|
|
+ const char *z = aCol[i].zCnName;
|
|
+ z += strlen(z)+1;
|
|
+ printf(" X-%s", z);
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ if( flg & COLFLAG_PRIMKEY ) printf(" PRIMARY KEY");
|
|
+ if( flg & COLFLAG_HIDDEN ) printf(" HIDDEN");
|
|
+#ifdef COLFLAG_NOEXPAND
|
|
+ if( flg & COLFLAG_NOEXPAND ) printf(" NO-EXPAND");
|
|
+#endif
|
|
+ if( flg ) printf(" flags=%04x", flg);
|
|
+ printf("\n");
|
|
+ fflush(stdout);
|
|
+ sqlite3TreeViewPop(&pView);
|
|
+ }
|
|
+ sqlite3TreeViewPop(&pView);
|
|
+}
|
|
+
|
|
/*
|
|
** Generate a human-readable description of a WITH clause.
|
|
*/
|
|
@@ -29350,7 +31483,7 @@ SQLITE_PRIVATE void sqlite3TreeViewWith(TreeView *pView, const With *pWith, u8 m
|
|
sqlite3TreeViewLine(pView, "WITH (0x%p)", pWith);
|
|
}
|
|
if( pWith->nCte>0 ){
|
|
- pView = sqlite3TreeViewPush(pView, 1);
|
|
+ sqlite3TreeViewPush(&pView, moreToFollow);
|
|
for(i=0; i<pWith->nCte; i++){
|
|
StrAccum x;
|
|
char zLine[1000];
|
|
@@ -29366,13 +31499,20 @@ SQLITE_PRIVATE void sqlite3TreeViewWith(TreeView *pView, const With *pWith, u8 m
|
|
}
|
|
sqlite3_str_appendf(&x, ")");
|
|
}
|
|
- sqlite3_str_appendf(&x, " AS");
|
|
+ if( pCte->eM10d!=M10d_Any ){
|
|
+ sqlite3_str_appendf(&x, " %sMATERIALIZED",
|
|
+ pCte->eM10d==M10d_No ? "NOT " : "");
|
|
+ }
|
|
+ if( pCte->pUse ){
|
|
+ sqlite3_str_appendf(&x, " (pUse=0x%p, nUse=%d)", pCte->pUse,
|
|
+ pCte->pUse->nUse);
|
|
+ }
|
|
sqlite3StrAccumFinish(&x);
|
|
sqlite3TreeViewItem(pView, zLine, i<pWith->nCte-1);
|
|
sqlite3TreeViewSelect(pView, pCte->pSelect, 0);
|
|
- sqlite3TreeViewPop(pView);
|
|
+ sqlite3TreeViewPop(&pView);
|
|
}
|
|
- sqlite3TreeViewPop(pView);
|
|
+ sqlite3TreeViewPop(&pView);
|
|
}
|
|
}
|
|
|
|
@@ -29381,39 +31521,68 @@ SQLITE_PRIVATE void sqlite3TreeViewWith(TreeView *pView, const With *pWith, u8 m
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3TreeViewSrcList(TreeView *pView, const SrcList *pSrc){
|
|
int i;
|
|
+ if( pSrc==0 ) return;
|
|
for(i=0; i<pSrc->nSrc; i++){
|
|
- const struct SrcList_item *pItem = &pSrc->a[i];
|
|
+ const SrcItem *pItem = &pSrc->a[i];
|
|
StrAccum x;
|
|
- char zLine[100];
|
|
+ int n = 0;
|
|
+ char zLine[1000];
|
|
sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0);
|
|
- sqlite3_str_appendf(&x, "{%d:*}", pItem->iCursor);
|
|
- if( pItem->zDatabase ){
|
|
- sqlite3_str_appendf(&x, " %s.%s", pItem->zDatabase, pItem->zName);
|
|
- }else if( pItem->zName ){
|
|
- sqlite3_str_appendf(&x, " %s", pItem->zName);
|
|
- }
|
|
+ x.printfFlags |= SQLITE_PRINTF_INTERNAL;
|
|
+ sqlite3_str_appendf(&x, "{%d:*} %!S", pItem->iCursor, pItem);
|
|
if( pItem->pTab ){
|
|
- sqlite3_str_appendf(&x, " tab=%Q nCol=%d ptr=%p",
|
|
- pItem->pTab->zName, pItem->pTab->nCol, pItem->pTab);
|
|
+ sqlite3_str_appendf(&x, " tab=%Q nCol=%d ptr=%p used=%llx",
|
|
+ pItem->pTab->zName, pItem->pTab->nCol, pItem->pTab, pItem->colUsed);
|
|
}
|
|
- if( pItem->zAlias ){
|
|
- sqlite3_str_appendf(&x, " (AS %s)", pItem->zAlias);
|
|
- }
|
|
- if( pItem->fg.jointype & JT_LEFT ){
|
|
+ if( (pItem->fg.jointype & (JT_LEFT|JT_RIGHT))==(JT_LEFT|JT_RIGHT) ){
|
|
+ sqlite3_str_appendf(&x, " FULL-OUTER-JOIN");
|
|
+ }else if( pItem->fg.jointype & JT_LEFT ){
|
|
sqlite3_str_appendf(&x, " LEFT-JOIN");
|
|
+ }else if( pItem->fg.jointype & JT_RIGHT ){
|
|
+ sqlite3_str_appendf(&x, " RIGHT-JOIN");
|
|
+ }else if( pItem->fg.jointype & JT_CROSS ){
|
|
+ sqlite3_str_appendf(&x, " CROSS-JOIN");
|
|
+ }
|
|
+ if( pItem->fg.jointype & JT_LTORJ ){
|
|
+ sqlite3_str_appendf(&x, " LTORJ");
|
|
}
|
|
if( pItem->fg.fromDDL ){
|
|
sqlite3_str_appendf(&x, " DDL");
|
|
}
|
|
+ if( pItem->fg.isCte ){
|
|
+ sqlite3_str_appendf(&x, " CteUse=0x%p", pItem->u2.pCteUse);
|
|
+ }
|
|
+ if( pItem->fg.isOn || (pItem->fg.isUsing==0 && pItem->u3.pOn!=0) ){
|
|
+ sqlite3_str_appendf(&x, " ON");
|
|
+ }
|
|
+ if( pItem->fg.isTabFunc ) sqlite3_str_appendf(&x, " isTabFunc");
|
|
+ if( pItem->fg.isCorrelated ) sqlite3_str_appendf(&x, " isCorrelated");
|
|
+ if( pItem->fg.isMaterialized ) sqlite3_str_appendf(&x, " isMaterialized");
|
|
+ if( pItem->fg.viaCoroutine ) sqlite3_str_appendf(&x, " viaCoroutine");
|
|
+ if( pItem->fg.notCte ) sqlite3_str_appendf(&x, " notCte");
|
|
+ if( pItem->fg.isNestedFrom ) sqlite3_str_appendf(&x, " isNestedFrom");
|
|
+
|
|
sqlite3StrAccumFinish(&x);
|
|
- sqlite3TreeViewItem(pView, zLine, i<pSrc->nSrc-1);
|
|
+ sqlite3TreeViewItem(pView, zLine, i<pSrc->nSrc-1);
|
|
+ n = 0;
|
|
+ if( pItem->pSelect ) n++;
|
|
+ if( pItem->fg.isTabFunc ) n++;
|
|
+ if( pItem->fg.isUsing ) n++;
|
|
+ if( pItem->fg.isUsing ){
|
|
+ sqlite3TreeViewIdList(pView, pItem->u3.pUsing, (--n)>0, "USING");
|
|
+ }
|
|
if( pItem->pSelect ){
|
|
- sqlite3TreeViewSelect(pView, pItem->pSelect, 0);
|
|
+ if( pItem->pTab ){
|
|
+ Table *pTab = pItem->pTab;
|
|
+ sqlite3TreeViewColumnList(pView, pTab->aCol, pTab->nCol, 1);
|
|
+ }
|
|
+ assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem->pSelect) );
|
|
+ sqlite3TreeViewSelect(pView, pItem->pSelect, (--n)>0);
|
|
}
|
|
if( pItem->fg.isTabFunc ){
|
|
sqlite3TreeViewExprList(pView, pItem->u1.pFuncArg, 0, "func-args:");
|
|
}
|
|
- sqlite3TreeViewPop(pView);
|
|
+ sqlite3TreeViewPop(&pView);
|
|
}
|
|
}
|
|
|
|
@@ -29426,12 +31595,12 @@ SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 m
|
|
if( p==0 ){
|
|
sqlite3TreeViewLine(pView, "nil-SELECT");
|
|
return;
|
|
- }
|
|
- pView = sqlite3TreeViewPush(pView, moreToFollow);
|
|
+ }
|
|
+ sqlite3TreeViewPush(&pView, moreToFollow);
|
|
if( p->pWith ){
|
|
sqlite3TreeViewWith(pView, p->pWith, 1);
|
|
cnt = 1;
|
|
- sqlite3TreeViewPush(pView, 1);
|
|
+ sqlite3TreeViewPush(&pView, 1);
|
|
}
|
|
do{
|
|
if( p->selFlags & SF_WhereBegin ){
|
|
@@ -29445,7 +31614,7 @@ SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 m
|
|
(int)p->nSelectRow
|
|
);
|
|
}
|
|
- if( cnt++ ) sqlite3TreeViewPop(pView);
|
|
+ if( cnt++ ) sqlite3TreeViewPop(&pView);
|
|
if( p->pPrior ){
|
|
n = 1000;
|
|
}else{
|
|
@@ -29468,24 +31637,24 @@ SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 m
|
|
#ifndef SQLITE_OMIT_WINDOWFUNC
|
|
if( p->pWin ){
|
|
Window *pX;
|
|
- pView = sqlite3TreeViewPush(pView, (n--)>0);
|
|
+ sqlite3TreeViewPush(&pView, (n--)>0);
|
|
sqlite3TreeViewLine(pView, "window-functions");
|
|
for(pX=p->pWin; pX; pX=pX->pNextWin){
|
|
sqlite3TreeViewWinFunc(pView, pX, pX->pNextWin!=0);
|
|
}
|
|
- sqlite3TreeViewPop(pView);
|
|
+ sqlite3TreeViewPop(&pView);
|
|
}
|
|
#endif
|
|
if( p->pSrc && p->pSrc->nSrc ){
|
|
- pView = sqlite3TreeViewPush(pView, (n--)>0);
|
|
+ sqlite3TreeViewPush(&pView, (n--)>0);
|
|
sqlite3TreeViewLine(pView, "FROM");
|
|
sqlite3TreeViewSrcList(pView, p->pSrc);
|
|
- sqlite3TreeViewPop(pView);
|
|
+ sqlite3TreeViewPop(&pView);
|
|
}
|
|
if( p->pWhere ){
|
|
sqlite3TreeViewItem(pView, "WHERE", (n--)>0);
|
|
sqlite3TreeViewExpr(pView, p->pWhere, 0);
|
|
- sqlite3TreeViewPop(pView);
|
|
+ sqlite3TreeViewPop(&pView);
|
|
}
|
|
if( p->pGroupBy ){
|
|
sqlite3TreeViewExprList(pView, p->pGroupBy, (n--)>0, "GROUPBY");
|
|
@@ -29493,7 +31662,7 @@ SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 m
|
|
if( p->pHaving ){
|
|
sqlite3TreeViewItem(pView, "HAVING", (n--)>0);
|
|
sqlite3TreeViewExpr(pView, p->pHaving, 0);
|
|
- sqlite3TreeViewPop(pView);
|
|
+ sqlite3TreeViewPop(&pView);
|
|
}
|
|
#ifndef SQLITE_OMIT_WINDOWFUNC
|
|
if( p->pWinDefn ){
|
|
@@ -29502,7 +31671,7 @@ SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 m
|
|
for(pX=p->pWinDefn; pX; pX=pX->pNextWin){
|
|
sqlite3TreeViewWindow(pView, pX, pX->pNextWin!=0);
|
|
}
|
|
- sqlite3TreeViewPop(pView);
|
|
+ sqlite3TreeViewPop(&pView);
|
|
}
|
|
#endif
|
|
if( p->pOrderBy ){
|
|
@@ -29514,9 +31683,9 @@ SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 m
|
|
if( p->pLimit->pRight ){
|
|
sqlite3TreeViewItem(pView, "OFFSET", (n--)>0);
|
|
sqlite3TreeViewExpr(pView, p->pLimit->pRight, 0);
|
|
- sqlite3TreeViewPop(pView);
|
|
+ sqlite3TreeViewPop(&pView);
|
|
}
|
|
- sqlite3TreeViewPop(pView);
|
|
+ sqlite3TreeViewPop(&pView);
|
|
}
|
|
if( p->pPrior ){
|
|
const char *zOp = "UNION";
|
|
@@ -29529,7 +31698,7 @@ SQLITE_PRIVATE void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 m
|
|
}
|
|
p = p->pPrior;
|
|
}while( p!=0 );
|
|
- sqlite3TreeViewPop(pView);
|
|
+ sqlite3TreeViewPop(&pView);
|
|
}
|
|
|
|
#ifndef SQLITE_OMIT_WINDOWFUNC
|
|
@@ -29545,24 +31714,24 @@ SQLITE_PRIVATE void sqlite3TreeViewBound(
|
|
switch( eBound ){
|
|
case TK_UNBOUNDED: {
|
|
sqlite3TreeViewItem(pView, "UNBOUNDED", moreToFollow);
|
|
- sqlite3TreeViewPop(pView);
|
|
+ sqlite3TreeViewPop(&pView);
|
|
break;
|
|
}
|
|
case TK_CURRENT: {
|
|
sqlite3TreeViewItem(pView, "CURRENT", moreToFollow);
|
|
- sqlite3TreeViewPop(pView);
|
|
+ sqlite3TreeViewPop(&pView);
|
|
break;
|
|
}
|
|
case TK_PRECEDING: {
|
|
sqlite3TreeViewItem(pView, "PRECEDING", moreToFollow);
|
|
sqlite3TreeViewExpr(pView, pExpr, 0);
|
|
- sqlite3TreeViewPop(pView);
|
|
+ sqlite3TreeViewPop(&pView);
|
|
break;
|
|
}
|
|
case TK_FOLLOWING: {
|
|
sqlite3TreeViewItem(pView, "FOLLOWING", moreToFollow);
|
|
sqlite3TreeViewExpr(pView, pExpr, 0);
|
|
- sqlite3TreeViewPop(pView);
|
|
+ sqlite3TreeViewPop(&pView);
|
|
break;
|
|
}
|
|
}
|
|
@@ -29575,12 +31744,13 @@ SQLITE_PRIVATE void sqlite3TreeViewBound(
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3TreeViewWindow(TreeView *pView, const Window *pWin, u8 more){
|
|
int nElement = 0;
|
|
+ if( pWin==0 ) return;
|
|
if( pWin->pFilter ){
|
|
sqlite3TreeViewItem(pView, "FILTER", 1);
|
|
sqlite3TreeViewExpr(pView, pWin->pFilter, 0);
|
|
- sqlite3TreeViewPop(pView);
|
|
+ sqlite3TreeViewPop(&pView);
|
|
}
|
|
- pView = sqlite3TreeViewPush(pView, more);
|
|
+ sqlite3TreeViewPush(&pView, more);
|
|
if( pWin->zName ){
|
|
sqlite3TreeViewLine(pView, "OVER %s (%p)", pWin->zName, pWin);
|
|
}else{
|
|
@@ -29591,9 +31761,9 @@ SQLITE_PRIVATE void sqlite3TreeViewWindow(TreeView *pView, const Window *pWin, u
|
|
if( pWin->eFrmType ) nElement++;
|
|
if( pWin->eExclude ) nElement++;
|
|
if( pWin->zBase ){
|
|
- sqlite3TreeViewPush(pView, (--nElement)>0);
|
|
+ sqlite3TreeViewPush(&pView, (--nElement)>0);
|
|
sqlite3TreeViewLine(pView, "window: %s", pWin->zBase);
|
|
- sqlite3TreeViewPop(pView);
|
|
+ sqlite3TreeViewPop(&pView);
|
|
}
|
|
if( pWin->pPartition ){
|
|
sqlite3TreeViewExprList(pView, pWin->pPartition, nElement>0,"PARTITION-BY");
|
|
@@ -29611,7 +31781,7 @@ SQLITE_PRIVATE void sqlite3TreeViewWindow(TreeView *pView, const Window *pWin, u
|
|
sqlite3TreeViewItem(pView, zBuf, (--nElement)>0);
|
|
sqlite3TreeViewBound(pView, pWin->eStart, pWin->pStart, 1);
|
|
sqlite3TreeViewBound(pView, pWin->eEnd, pWin->pEnd, 0);
|
|
- sqlite3TreeViewPop(pView);
|
|
+ sqlite3TreeViewPop(&pView);
|
|
}
|
|
if( pWin->eExclude ){
|
|
char zBuf[30];
|
|
@@ -29626,11 +31796,11 @@ SQLITE_PRIVATE void sqlite3TreeViewWindow(TreeView *pView, const Window *pWin, u
|
|
zExclude = zBuf;
|
|
break;
|
|
}
|
|
- sqlite3TreeViewPush(pView, 0);
|
|
+ sqlite3TreeViewPush(&pView, 0);
|
|
sqlite3TreeViewLine(pView, "EXCLUDE %s", zExclude);
|
|
- sqlite3TreeViewPop(pView);
|
|
+ sqlite3TreeViewPop(&pView);
|
|
}
|
|
- sqlite3TreeViewPop(pView);
|
|
+ sqlite3TreeViewPop(&pView);
|
|
}
|
|
#endif /* SQLITE_OMIT_WINDOWFUNC */
|
|
|
|
@@ -29639,11 +31809,12 @@ SQLITE_PRIVATE void sqlite3TreeViewWindow(TreeView *pView, const Window *pWin, u
|
|
** Generate a human-readable explanation for a Window Function object
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3TreeViewWinFunc(TreeView *pView, const Window *pWin, u8 more){
|
|
- pView = sqlite3TreeViewPush(pView, more);
|
|
+ if( pWin==0 ) return;
|
|
+ sqlite3TreeViewPush(&pView, more);
|
|
sqlite3TreeViewLine(pView, "WINFUNC %s(%d)",
|
|
- pWin->pFunc->zName, pWin->pFunc->nArg);
|
|
+ pWin->pWFunc->zName, pWin->pWFunc->nArg);
|
|
sqlite3TreeViewWindow(pView, pWin, 0);
|
|
- sqlite3TreeViewPop(pView);
|
|
+ sqlite3TreeViewPop(&pView);
|
|
}
|
|
#endif /* SQLITE_OMIT_WINDOWFUNC */
|
|
|
|
@@ -29653,24 +31824,33 @@ SQLITE_PRIVATE void sqlite3TreeViewWinFunc(TreeView *pView, const Window *pWin,
|
|
SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
|
|
const char *zBinOp = 0; /* Binary operator */
|
|
const char *zUniOp = 0; /* Unary operator */
|
|
- char zFlgs[60];
|
|
- pView = sqlite3TreeViewPush(pView, moreToFollow);
|
|
+ char zFlgs[200];
|
|
+ sqlite3TreeViewPush(&pView, moreToFollow);
|
|
if( pExpr==0 ){
|
|
sqlite3TreeViewLine(pView, "nil");
|
|
- sqlite3TreeViewPop(pView);
|
|
+ sqlite3TreeViewPop(&pView);
|
|
return;
|
|
}
|
|
- if( pExpr->flags || pExpr->affExpr ){
|
|
+ if( pExpr->flags || pExpr->affExpr || pExpr->vvaFlags || pExpr->pAggInfo ){
|
|
StrAccum x;
|
|
sqlite3StrAccumInit(&x, 0, zFlgs, sizeof(zFlgs), 0);
|
|
sqlite3_str_appendf(&x, " fg.af=%x.%c",
|
|
pExpr->flags, pExpr->affExpr ? pExpr->affExpr : 'n');
|
|
- if( ExprHasProperty(pExpr, EP_FromJoin) ){
|
|
- sqlite3_str_appendf(&x, " iRJT=%d", pExpr->iRightJoinTable);
|
|
+ if( ExprHasProperty(pExpr, EP_OuterON) ){
|
|
+ sqlite3_str_appendf(&x, " outer.iJoin=%d", pExpr->w.iJoin);
|
|
+ }
|
|
+ if( ExprHasProperty(pExpr, EP_InnerON) ){
|
|
+ sqlite3_str_appendf(&x, " inner.iJoin=%d", pExpr->w.iJoin);
|
|
}
|
|
if( ExprHasProperty(pExpr, EP_FromDDL) ){
|
|
sqlite3_str_appendf(&x, " DDL");
|
|
}
|
|
+ if( ExprHasVVAProperty(pExpr, EP_Immutable) ){
|
|
+ sqlite3_str_appendf(&x, " IMMUTABLE");
|
|
+ }
|
|
+ if( pExpr->pAggInfo!=0 ){
|
|
+ sqlite3_str_appendf(&x, " agg-column[%d]", pExpr->iAgg);
|
|
+ }
|
|
sqlite3StrAccumFinish(&x);
|
|
}else{
|
|
zFlgs[0] = 0;
|
|
@@ -29693,6 +31873,7 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
|
|
sqlite3TreeViewLine(pView, "COLUMN(%d)%s%s",
|
|
pExpr->iColumn, zFlgs, zOp2);
|
|
}else{
|
|
+ assert( ExprUseYTab(pExpr) );
|
|
sqlite3TreeViewLine(pView, "{%d:%d} pTab=%p%s",
|
|
pExpr->iTable, pExpr->iColumn,
|
|
pExpr->y.pTab, zFlgs);
|
|
@@ -29712,11 +31893,13 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
|
|
}
|
|
#ifndef SQLITE_OMIT_FLOATING_POINT
|
|
case TK_FLOAT: {
|
|
+ assert( !ExprHasProperty(pExpr, EP_IntValue) );
|
|
sqlite3TreeViewLine(pView,"%s", pExpr->u.zToken);
|
|
break;
|
|
}
|
|
#endif
|
|
case TK_STRING: {
|
|
+ assert( !ExprHasProperty(pExpr, EP_IntValue) );
|
|
sqlite3TreeViewLine(pView,"%Q", pExpr->u.zToken);
|
|
break;
|
|
}
|
|
@@ -29725,17 +31908,19 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
|
|
break;
|
|
}
|
|
case TK_TRUEFALSE: {
|
|
- sqlite3TreeViewLine(pView,
|
|
- sqlite3ExprTruthValue(pExpr) ? "TRUE" : "FALSE");
|
|
+ sqlite3TreeViewLine(pView,"%s%s",
|
|
+ sqlite3ExprTruthValue(pExpr) ? "TRUE" : "FALSE", zFlgs);
|
|
break;
|
|
}
|
|
#ifndef SQLITE_OMIT_BLOB_LITERAL
|
|
case TK_BLOB: {
|
|
+ assert( !ExprHasProperty(pExpr, EP_IntValue) );
|
|
sqlite3TreeViewLine(pView,"%s", pExpr->u.zToken);
|
|
break;
|
|
}
|
|
#endif
|
|
case TK_VARIABLE: {
|
|
+ assert( !ExprHasProperty(pExpr, EP_IntValue) );
|
|
sqlite3TreeViewLine(pView,"VARIABLE(%s,%d)",
|
|
pExpr->u.zToken, pExpr->iColumn);
|
|
break;
|
|
@@ -29745,12 +31930,14 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
|
|
break;
|
|
}
|
|
case TK_ID: {
|
|
+ assert( !ExprHasProperty(pExpr, EP_IntValue) );
|
|
sqlite3TreeViewLine(pView,"ID \"%w\"", pExpr->u.zToken);
|
|
break;
|
|
}
|
|
#ifndef SQLITE_OMIT_CAST
|
|
case TK_CAST: {
|
|
/* Expressions of the form: CAST(pLeft AS token) */
|
|
+ assert( !ExprHasProperty(pExpr, EP_IntValue) );
|
|
sqlite3TreeViewLine(pView,"CAST %Q", pExpr->u.zToken);
|
|
sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
|
|
break;
|
|
@@ -29777,6 +31964,7 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
|
|
case TK_RSHIFT: zBinOp = "RSHIFT"; break;
|
|
case TK_CONCAT: zBinOp = "CONCAT"; break;
|
|
case TK_DOT: zBinOp = "DOT"; break;
|
|
+ case TK_LIMIT: zBinOp = "LIMIT"; break;
|
|
|
|
case TK_UMINUS: zUniOp = "UMINUS"; break;
|
|
case TK_UPLUS: zUniOp = "UPLUS"; break;
|
|
@@ -29799,6 +31987,7 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
|
|
}
|
|
|
|
case TK_SPAN: {
|
|
+ assert( !ExprHasProperty(pExpr, EP_IntValue) );
|
|
sqlite3TreeViewLine(pView, "SPAN %Q", pExpr->u.zToken);
|
|
sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
|
|
break;
|
|
@@ -29810,6 +31999,7 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
|
|
** up in the treeview output as "SOFT-COLLATE". Explicit COLLATE
|
|
** operators that appear in the original SQL always have the
|
|
** EP_Collate bit set and appear in treeview output as just "COLLATE" */
|
|
+ assert( !ExprHasProperty(pExpr, EP_IntValue) );
|
|
sqlite3TreeViewLine(pView, "%sCOLLATE %Q%s",
|
|
!ExprHasProperty(pExpr, EP_Collate) ? "SOFT-" : "",
|
|
pExpr->u.zToken, zFlgs);
|
|
@@ -29825,16 +32015,20 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
|
|
pFarg = 0;
|
|
pWin = 0;
|
|
}else{
|
|
+ assert( ExprUseXList(pExpr) );
|
|
pFarg = pExpr->x.pList;
|
|
#ifndef SQLITE_OMIT_WINDOWFUNC
|
|
pWin = ExprHasProperty(pExpr, EP_WinFunc) ? pExpr->y.pWin : 0;
|
|
#else
|
|
pWin = 0;
|
|
-#endif
|
|
+#endif
|
|
}
|
|
+ assert( !ExprHasProperty(pExpr, EP_IntValue) );
|
|
if( pExpr->op==TK_AGG_FUNCTION ){
|
|
- sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q%s",
|
|
- pExpr->op2, pExpr->u.zToken, zFlgs);
|
|
+ sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q%s agg=%d[%d]/%p",
|
|
+ pExpr->op2, pExpr->u.zToken, zFlgs,
|
|
+ pExpr->pAggInfo ? pExpr->pAggInfo->selId : 0,
|
|
+ pExpr->iAgg, pExpr->pAggInfo);
|
|
}else if( pExpr->op2!=0 ){
|
|
const char *zOp2;
|
|
char zBuf[8];
|
|
@@ -29861,19 +32055,31 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
|
|
}
|
|
#ifndef SQLITE_OMIT_SUBQUERY
|
|
case TK_EXISTS: {
|
|
+ assert( ExprUseXSelect(pExpr) );
|
|
sqlite3TreeViewLine(pView, "EXISTS-expr flags=0x%x", pExpr->flags);
|
|
sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0);
|
|
break;
|
|
}
|
|
case TK_SELECT: {
|
|
- sqlite3TreeViewLine(pView, "SELECT-expr flags=0x%x", pExpr->flags);
|
|
+ assert( ExprUseXSelect(pExpr) );
|
|
+ sqlite3TreeViewLine(pView, "subquery-expr flags=0x%x", pExpr->flags);
|
|
sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0);
|
|
break;
|
|
}
|
|
case TK_IN: {
|
|
- sqlite3TreeViewLine(pView, "IN flags=0x%x", pExpr->flags);
|
|
+ sqlite3_str *pStr = sqlite3_str_new(0);
|
|
+ char *z;
|
|
+ sqlite3_str_appendf(pStr, "IN flags=0x%x", pExpr->flags);
|
|
+ if( pExpr->iTable ) sqlite3_str_appendf(pStr, " iTable=%d",pExpr->iTable);
|
|
+ if( ExprHasProperty(pExpr, EP_Subrtn) ){
|
|
+ sqlite3_str_appendf(pStr, " subrtn(%d,%d)",
|
|
+ pExpr->y.sub.regReturn, pExpr->y.sub.iAddr);
|
|
+ }
|
|
+ z = sqlite3_str_finish(pStr);
|
|
+ sqlite3TreeViewLine(pView, z);
|
|
+ sqlite3_free(z);
|
|
sqlite3TreeViewExpr(pView, pExpr->pLeft, 1);
|
|
- if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
|
+ if( ExprUseXSelect(pExpr) ){
|
|
sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0);
|
|
}else{
|
|
sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, 0);
|
|
@@ -29894,9 +32100,12 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
|
|
** Z is stored in pExpr->pList->a[1].pExpr.
|
|
*/
|
|
case TK_BETWEEN: {
|
|
- Expr *pX = pExpr->pLeft;
|
|
- Expr *pY = pExpr->x.pList->a[0].pExpr;
|
|
- Expr *pZ = pExpr->x.pList->a[1].pExpr;
|
|
+ const Expr *pX, *pY, *pZ;
|
|
+ pX = pExpr->pLeft;
|
|
+ assert( ExprUseXList(pExpr) );
|
|
+ assert( pExpr->x.pList->nExpr==2 );
|
|
+ pY = pExpr->x.pList->a[0].pExpr;
|
|
+ pZ = pExpr->x.pList->a[1].pExpr;
|
|
sqlite3TreeViewLine(pView, "BETWEEN");
|
|
sqlite3TreeViewExpr(pView, pX, 1);
|
|
sqlite3TreeViewExpr(pView, pY, 1);
|
|
@@ -29911,13 +32120,14 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
|
|
** is set to the column of the pseudo-table to read, or to -1 to
|
|
** read the rowid field.
|
|
*/
|
|
- sqlite3TreeViewLine(pView, "%s(%d)",
|
|
+ sqlite3TreeViewLine(pView, "%s(%d)",
|
|
pExpr->iTable ? "NEW" : "OLD", pExpr->iColumn);
|
|
break;
|
|
}
|
|
case TK_CASE: {
|
|
sqlite3TreeViewLine(pView, "CASE");
|
|
sqlite3TreeViewExpr(pView, pExpr->pLeft, 1);
|
|
+ assert( ExprUseXList(pExpr) );
|
|
sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, 0);
|
|
break;
|
|
}
|
|
@@ -29930,6 +32140,7 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
|
|
case OE_Fail: zType = "fail"; break;
|
|
case OE_Ignore: zType = "ignore"; break;
|
|
}
|
|
+ assert( !ExprHasProperty(pExpr, EP_IntValue) );
|
|
sqlite3TreeViewLine(pView, "RAISE %s(%Q)", zType, pExpr->u.zToken);
|
|
break;
|
|
}
|
|
@@ -29942,12 +32153,16 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
|
|
}
|
|
case TK_VECTOR: {
|
|
char *z = sqlite3_mprintf("VECTOR%s",zFlgs);
|
|
+ assert( ExprUseXList(pExpr) );
|
|
sqlite3TreeViewBareExprList(pView, pExpr->x.pList, z);
|
|
sqlite3_free(z);
|
|
break;
|
|
}
|
|
case TK_SELECT_COLUMN: {
|
|
- sqlite3TreeViewLine(pView, "SELECT-COLUMN %d", pExpr->iColumn);
|
|
+ sqlite3TreeViewLine(pView, "SELECT-COLUMN %d of [0..%d]%s",
|
|
+ pExpr->iColumn, pExpr->iTable-1,
|
|
+ pExpr->pRight==pExpr->pLeft ? " (SELECT-owner)" : "");
|
|
+ assert( ExprUseXSelect(pExpr->pLeft) );
|
|
sqlite3TreeViewSelect(pView, pExpr->pLeft->x.pSelect, 0);
|
|
break;
|
|
}
|
|
@@ -29956,6 +32171,23 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
|
|
sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
|
|
break;
|
|
}
|
|
+ case TK_ERROR: {
|
|
+ Expr tmp;
|
|
+ sqlite3TreeViewLine(pView, "ERROR");
|
|
+ tmp = *pExpr;
|
|
+ tmp.op = pExpr->op2;
|
|
+ sqlite3TreeViewExpr(pView, &tmp, 0);
|
|
+ break;
|
|
+ }
|
|
+ case TK_ROW: {
|
|
+ if( pExpr->iColumn<=0 ){
|
|
+ sqlite3TreeViewLine(pView, "First FROM table rowid");
|
|
+ }else{
|
|
+ sqlite3TreeViewLine(pView, "First FROM table column %d",
|
|
+ pExpr->iColumn-1);
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
default: {
|
|
sqlite3TreeViewLine(pView, "op=%d", pExpr->op);
|
|
break;
|
|
@@ -29969,7 +32201,7 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
|
|
sqlite3TreeViewLine(pView, "%s%s", zUniOp, zFlgs);
|
|
sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
|
|
}
|
|
- sqlite3TreeViewPop(pView);
|
|
+ sqlite3TreeViewPop(&pView);
|
|
}
|
|
|
|
|
|
@@ -29991,13 +32223,25 @@ SQLITE_PRIVATE void sqlite3TreeViewBareExprList(
|
|
int j = pList->a[i].u.x.iOrderByCol;
|
|
char *zName = pList->a[i].zEName;
|
|
int moreToFollow = i<pList->nExpr - 1;
|
|
- if( pList->a[i].eEName!=ENAME_NAME ) zName = 0;
|
|
if( j || zName ){
|
|
- sqlite3TreeViewPush(pView, moreToFollow);
|
|
+ sqlite3TreeViewPush(&pView, moreToFollow);
|
|
moreToFollow = 0;
|
|
sqlite3TreeViewLine(pView, 0);
|
|
if( zName ){
|
|
- fprintf(stdout, "AS %s ", zName);
|
|
+ switch( pList->a[i].fg.eEName ){
|
|
+ default:
|
|
+ fprintf(stdout, "AS %s ", zName);
|
|
+ break;
|
|
+ case ENAME_TAB:
|
|
+ fprintf(stdout, "TABLE-ALIAS-NAME(\"%s\") ", zName);
|
|
+ if( pList->a[i].fg.bUsed ) fprintf(stdout, "(used) ");
|
|
+ if( pList->a[i].fg.bUsingTerm ) fprintf(stdout, "(USING-term) ");
|
|
+ if( pList->a[i].fg.bNoExpand ) fprintf(stdout, "(NoExpand) ");
|
|
+ break;
|
|
+ case ENAME_SPAN:
|
|
+ fprintf(stdout, "SPAN(\"%s\") ", zName);
|
|
+ break;
|
|
+ }
|
|
}
|
|
if( j ){
|
|
fprintf(stdout, "iOrderByCol=%d", j);
|
|
@@ -30007,7 +32251,7 @@ SQLITE_PRIVATE void sqlite3TreeViewBareExprList(
|
|
}
|
|
sqlite3TreeViewExpr(pView, pList->a[i].pExpr, moreToFollow);
|
|
if( j || zName ){
|
|
- sqlite3TreeViewPop(pView);
|
|
+ sqlite3TreeViewPop(&pView);
|
|
}
|
|
}
|
|
}
|
|
@@ -30018,11 +32262,378 @@ SQLITE_PRIVATE void sqlite3TreeViewExprList(
|
|
u8 moreToFollow,
|
|
const char *zLabel
|
|
){
|
|
- pView = sqlite3TreeViewPush(pView, moreToFollow);
|
|
+ sqlite3TreeViewPush(&pView, moreToFollow);
|
|
sqlite3TreeViewBareExprList(pView, pList, zLabel);
|
|
- sqlite3TreeViewPop(pView);
|
|
+ sqlite3TreeViewPop(&pView);
|
|
+}
|
|
+
|
|
+/*
|
|
+** Generate a human-readable explanation of an id-list.
|
|
+*/
|
|
+SQLITE_PRIVATE void sqlite3TreeViewBareIdList(
|
|
+ TreeView *pView,
|
|
+ const IdList *pList,
|
|
+ const char *zLabel
|
|
+){
|
|
+ if( zLabel==0 || zLabel[0]==0 ) zLabel = "LIST";
|
|
+ if( pList==0 ){
|
|
+ sqlite3TreeViewLine(pView, "%s (empty)", zLabel);
|
|
+ }else{
|
|
+ int i;
|
|
+ sqlite3TreeViewLine(pView, "%s", zLabel);
|
|
+ for(i=0; i<pList->nId; i++){
|
|
+ char *zName = pList->a[i].zName;
|
|
+ int moreToFollow = i<pList->nId - 1;
|
|
+ if( zName==0 ) zName = "(null)";
|
|
+ sqlite3TreeViewPush(&pView, moreToFollow);
|
|
+ sqlite3TreeViewLine(pView, 0);
|
|
+ if( pList->eU4==EU4_NONE ){
|
|
+ fprintf(stdout, "%s\n", zName);
|
|
+ }else if( pList->eU4==EU4_IDX ){
|
|
+ fprintf(stdout, "%s (%d)\n", zName, pList->a[i].u4.idx);
|
|
+ }else{
|
|
+ assert( pList->eU4==EU4_EXPR );
|
|
+ if( pList->a[i].u4.pExpr==0 ){
|
|
+ fprintf(stdout, "%s (pExpr=NULL)\n", zName);
|
|
+ }else{
|
|
+ fprintf(stdout, "%s\n", zName);
|
|
+ sqlite3TreeViewPush(&pView, i<pList->nId-1);
|
|
+ sqlite3TreeViewExpr(pView, pList->a[i].u4.pExpr, 0);
|
|
+ sqlite3TreeViewPop(&pView);
|
|
+ }
|
|
+ }
|
|
+ sqlite3TreeViewPop(&pView);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+SQLITE_PRIVATE void sqlite3TreeViewIdList(
|
|
+ TreeView *pView,
|
|
+ const IdList *pList,
|
|
+ u8 moreToFollow,
|
|
+ const char *zLabel
|
|
+){
|
|
+ sqlite3TreeViewPush(&pView, moreToFollow);
|
|
+ sqlite3TreeViewBareIdList(pView, pList, zLabel);
|
|
+ sqlite3TreeViewPop(&pView);
|
|
+}
|
|
+
|
|
+/*
|
|
+** Generate a human-readable explanation of a list of Upsert objects
|
|
+*/
|
|
+SQLITE_PRIVATE void sqlite3TreeViewUpsert(
|
|
+ TreeView *pView,
|
|
+ const Upsert *pUpsert,
|
|
+ u8 moreToFollow
|
|
+){
|
|
+ if( pUpsert==0 ) return;
|
|
+ sqlite3TreeViewPush(&pView, moreToFollow);
|
|
+ while( pUpsert ){
|
|
+ int n;
|
|
+ sqlite3TreeViewPush(&pView, pUpsert->pNextUpsert!=0 || moreToFollow);
|
|
+ sqlite3TreeViewLine(pView, "ON CONFLICT DO %s",
|
|
+ pUpsert->isDoUpdate ? "UPDATE" : "NOTHING");
|
|
+ n = (pUpsert->pUpsertSet!=0) + (pUpsert->pUpsertWhere!=0);
|
|
+ sqlite3TreeViewExprList(pView, pUpsert->pUpsertTarget, (n--)>0, "TARGET");
|
|
+ sqlite3TreeViewExprList(pView, pUpsert->pUpsertSet, (n--)>0, "SET");
|
|
+ if( pUpsert->pUpsertWhere ){
|
|
+ sqlite3TreeViewItem(pView, "WHERE", (n--)>0);
|
|
+ sqlite3TreeViewExpr(pView, pUpsert->pUpsertWhere, 0);
|
|
+ sqlite3TreeViewPop(&pView);
|
|
+ }
|
|
+ sqlite3TreeViewPop(&pView);
|
|
+ pUpsert = pUpsert->pNextUpsert;
|
|
+ }
|
|
+ sqlite3TreeViewPop(&pView);
|
|
+}
|
|
+
|
|
+#if TREETRACE_ENABLED
|
|
+/*
|
|
+** Generate a human-readable diagram of the data structure that go
|
|
+** into generating an DELETE statement.
|
|
+*/
|
|
+SQLITE_PRIVATE void sqlite3TreeViewDelete(
|
|
+ const With *pWith,
|
|
+ const SrcList *pTabList,
|
|
+ const Expr *pWhere,
|
|
+ const ExprList *pOrderBy,
|
|
+ const Expr *pLimit,
|
|
+ const Trigger *pTrigger
|
|
+){
|
|
+ int n = 0;
|
|
+ TreeView *pView = 0;
|
|
+ sqlite3TreeViewPush(&pView, 0);
|
|
+ sqlite3TreeViewLine(pView, "DELETE");
|
|
+ if( pWith ) n++;
|
|
+ if( pTabList ) n++;
|
|
+ if( pWhere ) n++;
|
|
+ if( pOrderBy ) n++;
|
|
+ if( pLimit ) n++;
|
|
+ if( pTrigger ) n++;
|
|
+ if( pWith ){
|
|
+ sqlite3TreeViewPush(&pView, (--n)>0);
|
|
+ sqlite3TreeViewWith(pView, pWith, 0);
|
|
+ sqlite3TreeViewPop(&pView);
|
|
+ }
|
|
+ if( pTabList ){
|
|
+ sqlite3TreeViewPush(&pView, (--n)>0);
|
|
+ sqlite3TreeViewLine(pView, "FROM");
|
|
+ sqlite3TreeViewSrcList(pView, pTabList);
|
|
+ sqlite3TreeViewPop(&pView);
|
|
+ }
|
|
+ if( pWhere ){
|
|
+ sqlite3TreeViewPush(&pView, (--n)>0);
|
|
+ sqlite3TreeViewLine(pView, "WHERE");
|
|
+ sqlite3TreeViewExpr(pView, pWhere, 0);
|
|
+ sqlite3TreeViewPop(&pView);
|
|
+ }
|
|
+ if( pOrderBy ){
|
|
+ sqlite3TreeViewExprList(pView, pOrderBy, (--n)>0, "ORDER-BY");
|
|
+ }
|
|
+ if( pLimit ){
|
|
+ sqlite3TreeViewPush(&pView, (--n)>0);
|
|
+ sqlite3TreeViewLine(pView, "LIMIT");
|
|
+ sqlite3TreeViewExpr(pView, pLimit, 0);
|
|
+ sqlite3TreeViewPop(&pView);
|
|
+ }
|
|
+ if( pTrigger ){
|
|
+ sqlite3TreeViewTrigger(pView, pTrigger, (--n)>0, 1);
|
|
+ }
|
|
+ sqlite3TreeViewPop(&pView);
|
|
+}
|
|
+#endif /* TREETRACE_ENABLED */
|
|
+
|
|
+#if TREETRACE_ENABLED
|
|
+/*
|
|
+** Generate a human-readable diagram of the data structure that go
|
|
+** into generating an INSERT statement.
|
|
+*/
|
|
+SQLITE_PRIVATE void sqlite3TreeViewInsert(
|
|
+ const With *pWith,
|
|
+ const SrcList *pTabList,
|
|
+ const IdList *pColumnList,
|
|
+ const Select *pSelect,
|
|
+ const ExprList *pExprList,
|
|
+ int onError,
|
|
+ const Upsert *pUpsert,
|
|
+ const Trigger *pTrigger
|
|
+){
|
|
+ TreeView *pView = 0;
|
|
+ int n = 0;
|
|
+ const char *zLabel = "INSERT";
|
|
+ switch( onError ){
|
|
+ case OE_Replace: zLabel = "REPLACE"; break;
|
|
+ case OE_Ignore: zLabel = "INSERT OR IGNORE"; break;
|
|
+ case OE_Rollback: zLabel = "INSERT OR ROLLBACK"; break;
|
|
+ case OE_Abort: zLabel = "INSERT OR ABORT"; break;
|
|
+ case OE_Fail: zLabel = "INSERT OR FAIL"; break;
|
|
+ }
|
|
+ sqlite3TreeViewPush(&pView, 0);
|
|
+ sqlite3TreeViewLine(pView, zLabel);
|
|
+ if( pWith ) n++;
|
|
+ if( pTabList ) n++;
|
|
+ if( pColumnList ) n++;
|
|
+ if( pSelect ) n++;
|
|
+ if( pExprList ) n++;
|
|
+ if( pUpsert ) n++;
|
|
+ if( pTrigger ) n++;
|
|
+ if( pWith ){
|
|
+ sqlite3TreeViewPush(&pView, (--n)>0);
|
|
+ sqlite3TreeViewWith(pView, pWith, 0);
|
|
+ sqlite3TreeViewPop(&pView);
|
|
+ }
|
|
+ if( pTabList ){
|
|
+ sqlite3TreeViewPush(&pView, (--n)>0);
|
|
+ sqlite3TreeViewLine(pView, "INTO");
|
|
+ sqlite3TreeViewSrcList(pView, pTabList);
|
|
+ sqlite3TreeViewPop(&pView);
|
|
+ }
|
|
+ if( pColumnList ){
|
|
+ sqlite3TreeViewIdList(pView, pColumnList, (--n)>0, "COLUMNS");
|
|
+ }
|
|
+ if( pSelect ){
|
|
+ sqlite3TreeViewPush(&pView, (--n)>0);
|
|
+ sqlite3TreeViewLine(pView, "DATA-SOURCE");
|
|
+ sqlite3TreeViewSelect(pView, pSelect, 0);
|
|
+ sqlite3TreeViewPop(&pView);
|
|
+ }
|
|
+ if( pExprList ){
|
|
+ sqlite3TreeViewExprList(pView, pExprList, (--n)>0, "VALUES");
|
|
+ }
|
|
+ if( pUpsert ){
|
|
+ sqlite3TreeViewPush(&pView, (--n)>0);
|
|
+ sqlite3TreeViewLine(pView, "UPSERT");
|
|
+ sqlite3TreeViewUpsert(pView, pUpsert, 0);
|
|
+ sqlite3TreeViewPop(&pView);
|
|
+ }
|
|
+ if( pTrigger ){
|
|
+ sqlite3TreeViewTrigger(pView, pTrigger, (--n)>0, 1);
|
|
+ }
|
|
+ sqlite3TreeViewPop(&pView);
|
|
+}
|
|
+#endif /* TREETRACE_ENABLED */
|
|
+
|
|
+#if TREETRACE_ENABLED
|
|
+/*
|
|
+** Generate a human-readable diagram of the data structure that go
|
|
+** into generating an UPDATE statement.
|
|
+*/
|
|
+SQLITE_PRIVATE void sqlite3TreeViewUpdate(
|
|
+ const With *pWith,
|
|
+ const SrcList *pTabList,
|
|
+ const ExprList *pChanges,
|
|
+ const Expr *pWhere,
|
|
+ int onError,
|
|
+ const ExprList *pOrderBy,
|
|
+ const Expr *pLimit,
|
|
+ const Upsert *pUpsert,
|
|
+ const Trigger *pTrigger
|
|
+){
|
|
+ int n = 0;
|
|
+ TreeView *pView = 0;
|
|
+ const char *zLabel = "UPDATE";
|
|
+ switch( onError ){
|
|
+ case OE_Replace: zLabel = "UPDATE OR REPLACE"; break;
|
|
+ case OE_Ignore: zLabel = "UPDATE OR IGNORE"; break;
|
|
+ case OE_Rollback: zLabel = "UPDATE OR ROLLBACK"; break;
|
|
+ case OE_Abort: zLabel = "UPDATE OR ABORT"; break;
|
|
+ case OE_Fail: zLabel = "UPDATE OR FAIL"; break;
|
|
+ }
|
|
+ sqlite3TreeViewPush(&pView, 0);
|
|
+ sqlite3TreeViewLine(pView, zLabel);
|
|
+ if( pWith ) n++;
|
|
+ if( pTabList ) n++;
|
|
+ if( pChanges ) n++;
|
|
+ if( pWhere ) n++;
|
|
+ if( pOrderBy ) n++;
|
|
+ if( pLimit ) n++;
|
|
+ if( pUpsert ) n++;
|
|
+ if( pTrigger ) n++;
|
|
+ if( pWith ){
|
|
+ sqlite3TreeViewPush(&pView, (--n)>0);
|
|
+ sqlite3TreeViewWith(pView, pWith, 0);
|
|
+ sqlite3TreeViewPop(&pView);
|
|
+ }
|
|
+ if( pTabList ){
|
|
+ sqlite3TreeViewPush(&pView, (--n)>0);
|
|
+ sqlite3TreeViewLine(pView, "FROM");
|
|
+ sqlite3TreeViewSrcList(pView, pTabList);
|
|
+ sqlite3TreeViewPop(&pView);
|
|
+ }
|
|
+ if( pChanges ){
|
|
+ sqlite3TreeViewExprList(pView, pChanges, (--n)>0, "SET");
|
|
+ }
|
|
+ if( pWhere ){
|
|
+ sqlite3TreeViewPush(&pView, (--n)>0);
|
|
+ sqlite3TreeViewLine(pView, "WHERE");
|
|
+ sqlite3TreeViewExpr(pView, pWhere, 0);
|
|
+ sqlite3TreeViewPop(&pView);
|
|
+ }
|
|
+ if( pOrderBy ){
|
|
+ sqlite3TreeViewExprList(pView, pOrderBy, (--n)>0, "ORDER-BY");
|
|
+ }
|
|
+ if( pLimit ){
|
|
+ sqlite3TreeViewPush(&pView, (--n)>0);
|
|
+ sqlite3TreeViewLine(pView, "LIMIT");
|
|
+ sqlite3TreeViewExpr(pView, pLimit, 0);
|
|
+ sqlite3TreeViewPop(&pView);
|
|
+ }
|
|
+ if( pUpsert ){
|
|
+ sqlite3TreeViewPush(&pView, (--n)>0);
|
|
+ sqlite3TreeViewLine(pView, "UPSERT");
|
|
+ sqlite3TreeViewUpsert(pView, pUpsert, 0);
|
|
+ sqlite3TreeViewPop(&pView);
|
|
+ }
|
|
+ if( pTrigger ){
|
|
+ sqlite3TreeViewTrigger(pView, pTrigger, (--n)>0, 1);
|
|
+ }
|
|
+ sqlite3TreeViewPop(&pView);
|
|
+}
|
|
+#endif /* TREETRACE_ENABLED */
|
|
+
|
|
+#ifndef SQLITE_OMIT_TRIGGER
|
|
+/*
|
|
+** Show a human-readable graph of a TriggerStep
|
|
+*/
|
|
+SQLITE_PRIVATE void sqlite3TreeViewTriggerStep(
|
|
+ TreeView *pView,
|
|
+ const TriggerStep *pStep,
|
|
+ u8 moreToFollow,
|
|
+ u8 showFullList
|
|
+){
|
|
+ int cnt = 0;
|
|
+ if( pStep==0 ) return;
|
|
+ sqlite3TreeViewPush(&pView,
|
|
+ moreToFollow || (showFullList && pStep->pNext!=0));
|
|
+ do{
|
|
+ if( cnt++ && pStep->pNext==0 ){
|
|
+ sqlite3TreeViewPop(&pView);
|
|
+ sqlite3TreeViewPush(&pView, 0);
|
|
+ }
|
|
+ sqlite3TreeViewLine(pView, "%s", pStep->zSpan ? pStep->zSpan : "RETURNING");
|
|
+ }while( showFullList && (pStep = pStep->pNext)!=0 );
|
|
+ sqlite3TreeViewPop(&pView);
|
|
}
|
|
|
|
+/*
|
|
+** Show a human-readable graph of a Trigger
|
|
+*/
|
|
+SQLITE_PRIVATE void sqlite3TreeViewTrigger(
|
|
+ TreeView *pView,
|
|
+ const Trigger *pTrigger,
|
|
+ u8 moreToFollow,
|
|
+ u8 showFullList
|
|
+){
|
|
+ int cnt = 0;
|
|
+ if( pTrigger==0 ) return;
|
|
+ sqlite3TreeViewPush(&pView,
|
|
+ moreToFollow || (showFullList && pTrigger->pNext!=0));
|
|
+ do{
|
|
+ if( cnt++ && pTrigger->pNext==0 ){
|
|
+ sqlite3TreeViewPop(&pView);
|
|
+ sqlite3TreeViewPush(&pView, 0);
|
|
+ }
|
|
+ sqlite3TreeViewLine(pView, "TRIGGER %s", pTrigger->zName);
|
|
+ sqlite3TreeViewPush(&pView, 0);
|
|
+ sqlite3TreeViewTriggerStep(pView, pTrigger->step_list, 0, 1);
|
|
+ sqlite3TreeViewPop(&pView);
|
|
+ }while( showFullList && (pTrigger = pTrigger->pNext)!=0 );
|
|
+ sqlite3TreeViewPop(&pView);
|
|
+}
|
|
+#endif /* SQLITE_OMIT_TRIGGER */
|
|
+
|
|
+
|
|
+/*
|
|
+** These simplified versions of the tree-view routines omit unnecessary
|
|
+** parameters. These variants are intended to be used from a symbolic
|
|
+** debugger, such as "gdb", during interactive debugging sessions.
|
|
+**
|
|
+** This routines are given external linkage so that they will always be
|
|
+** accessible to the debugging, and to avoid warnings about unused
|
|
+** functions. But these routines only exist in debugging builds, so they
|
|
+** do not contaminate the interface.
|
|
+*/
|
|
+SQLITE_PRIVATE void sqlite3ShowExpr(const Expr *p){ sqlite3TreeViewExpr(0,p,0); }
|
|
+SQLITE_PRIVATE void sqlite3ShowExprList(const ExprList *p){ sqlite3TreeViewExprList(0,p,0,0);}
|
|
+SQLITE_PRIVATE void sqlite3ShowIdList(const IdList *p){ sqlite3TreeViewIdList(0,p,0,0); }
|
|
+SQLITE_PRIVATE void sqlite3ShowSrcList(const SrcList *p){ sqlite3TreeViewSrcList(0,p); }
|
|
+SQLITE_PRIVATE void sqlite3ShowSelect(const Select *p){ sqlite3TreeViewSelect(0,p,0); }
|
|
+SQLITE_PRIVATE void sqlite3ShowWith(const With *p){ sqlite3TreeViewWith(0,p,0); }
|
|
+SQLITE_PRIVATE void sqlite3ShowUpsert(const Upsert *p){ sqlite3TreeViewUpsert(0,p,0); }
|
|
+#ifndef SQLITE_OMIT_TRIGGER
|
|
+SQLITE_PRIVATE void sqlite3ShowTriggerStep(const TriggerStep *p){
|
|
+ sqlite3TreeViewTriggerStep(0,p,0,0);
|
|
+}
|
|
+SQLITE_PRIVATE void sqlite3ShowTriggerStepList(const TriggerStep *p){
|
|
+ sqlite3TreeViewTriggerStep(0,p,0,1);
|
|
+}
|
|
+SQLITE_PRIVATE void sqlite3ShowTrigger(const Trigger *p){ sqlite3TreeViewTrigger(0,p,0,0); }
|
|
+SQLITE_PRIVATE void sqlite3ShowTriggerList(const Trigger *p){ sqlite3TreeViewTrigger(0,p,0,1);}
|
|
+#endif
|
|
+#ifndef SQLITE_OMIT_WINDOWFUNC
|
|
+SQLITE_PRIVATE void sqlite3ShowWindow(const Window *p){ sqlite3TreeViewWindow(0,p,0); }
|
|
+SQLITE_PRIVATE void sqlite3ShowWinFunc(const Window *p){ sqlite3TreeViewWinFunc(0,p,0); }
|
|
+#endif
|
|
+
|
|
#endif /* SQLITE_DEBUG */
|
|
|
|
/************** End of treeview.c ********************************************/
|
|
@@ -30051,16 +32662,41 @@ SQLITE_PRIVATE void sqlite3TreeViewExprList(
|
|
** This structure is the current state of the generator.
|
|
*/
|
|
static SQLITE_WSD struct sqlite3PrngType {
|
|
- unsigned char isInit; /* True if initialized */
|
|
- unsigned char i, j; /* State variables */
|
|
- unsigned char s[256]; /* State variables */
|
|
+ u32 s[16]; /* 64 bytes of chacha20 state */
|
|
+ u8 out[64]; /* Output bytes */
|
|
+ u8 n; /* Output bytes remaining */
|
|
} sqlite3Prng;
|
|
|
|
+
|
|
+/* The RFC-7539 ChaCha20 block function
|
|
+*/
|
|
+#define ROTL(a,b) (((a) << (b)) | ((a) >> (32 - (b))))
|
|
+#define QR(a, b, c, d) ( \
|
|
+ a += b, d ^= a, d = ROTL(d,16), \
|
|
+ c += d, b ^= c, b = ROTL(b,12), \
|
|
+ a += b, d ^= a, d = ROTL(d, 8), \
|
|
+ c += d, b ^= c, b = ROTL(b, 7))
|
|
+static void chacha_block(u32 *out, const u32 *in){
|
|
+ int i;
|
|
+ u32 x[16];
|
|
+ memcpy(x, in, 64);
|
|
+ for(i=0; i<10; i++){
|
|
+ QR(x[0], x[4], x[ 8], x[12]);
|
|
+ QR(x[1], x[5], x[ 9], x[13]);
|
|
+ QR(x[2], x[6], x[10], x[14]);
|
|
+ QR(x[3], x[7], x[11], x[15]);
|
|
+ QR(x[0], x[5], x[10], x[15]);
|
|
+ QR(x[1], x[6], x[11], x[12]);
|
|
+ QR(x[2], x[7], x[ 8], x[13]);
|
|
+ QR(x[3], x[4], x[ 9], x[14]);
|
|
+ }
|
|
+ for(i=0; i<16; i++) out[i] = x[i]+in[i];
|
|
+}
|
|
+
|
|
/*
|
|
** Return N random bytes.
|
|
*/
|
|
SQLITE_API void sqlite3_randomness(int N, void *pBuf){
|
|
- unsigned char t;
|
|
unsigned char *zBuf = pBuf;
|
|
|
|
/* The "wsdPrng" macro will resolve to the pseudo-random number generator
|
|
@@ -30090,48 +32726,46 @@ SQLITE_API void sqlite3_randomness(int N, void *pBuf){
|
|
|
|
sqlite3_mutex_enter(mutex);
|
|
if( N<=0 || pBuf==0 ){
|
|
- wsdPrng.isInit = 0;
|
|
+ wsdPrng.s[0] = 0;
|
|
sqlite3_mutex_leave(mutex);
|
|
return;
|
|
}
|
|
|
|
/* Initialize the state of the random number generator once,
|
|
- ** the first time this routine is called. The seed value does
|
|
- ** not need to contain a lot of randomness since we are not
|
|
- ** trying to do secure encryption or anything like that...
|
|
- **
|
|
- ** Nothing in this file or anywhere else in SQLite does any kind of
|
|
- ** encryption. The RC4 algorithm is being used as a PRNG (pseudo-random
|
|
- ** number generator) not as an encryption device.
|
|
+ ** the first time this routine is called.
|
|
*/
|
|
- if( !wsdPrng.isInit ){
|
|
- int i;
|
|
- char k[256];
|
|
- wsdPrng.j = 0;
|
|
- wsdPrng.i = 0;
|
|
- sqlite3OsRandomness(sqlite3_vfs_find(0), 256, k);
|
|
- for(i=0; i<256; i++){
|
|
- wsdPrng.s[i] = (u8)i;
|
|
- }
|
|
- for(i=0; i<256; i++){
|
|
- wsdPrng.j += wsdPrng.s[i] + k[i];
|
|
- t = wsdPrng.s[wsdPrng.j];
|
|
- wsdPrng.s[wsdPrng.j] = wsdPrng.s[i];
|
|
- wsdPrng.s[i] = t;
|
|
+ if( wsdPrng.s[0]==0 ){
|
|
+ sqlite3_vfs *pVfs = sqlite3_vfs_find(0);
|
|
+ static const u32 chacha20_init[] = {
|
|
+ 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574
|
|
+ };
|
|
+ memcpy(&wsdPrng.s[0], chacha20_init, 16);
|
|
+ if( NEVER(pVfs==0) ){
|
|
+ memset(&wsdPrng.s[4], 0, 44);
|
|
+ }else{
|
|
+ sqlite3OsRandomness(pVfs, 44, (char*)&wsdPrng.s[4]);
|
|
}
|
|
- wsdPrng.isInit = 1;
|
|
+ wsdPrng.s[15] = wsdPrng.s[12];
|
|
+ wsdPrng.s[12] = 0;
|
|
+ wsdPrng.n = 0;
|
|
}
|
|
|
|
assert( N>0 );
|
|
- do{
|
|
- wsdPrng.i++;
|
|
- t = wsdPrng.s[wsdPrng.i];
|
|
- wsdPrng.j += t;
|
|
- wsdPrng.s[wsdPrng.i] = wsdPrng.s[wsdPrng.j];
|
|
- wsdPrng.s[wsdPrng.j] = t;
|
|
- t += wsdPrng.s[wsdPrng.i];
|
|
- *(zBuf++) = wsdPrng.s[t];
|
|
- }while( --N );
|
|
+ while( 1 /* exit by break */ ){
|
|
+ if( N<=wsdPrng.n ){
|
|
+ memcpy(zBuf, &wsdPrng.out[wsdPrng.n-N], N);
|
|
+ wsdPrng.n -= N;
|
|
+ break;
|
|
+ }
|
|
+ if( wsdPrng.n>0 ){
|
|
+ memcpy(zBuf, wsdPrng.out, wsdPrng.n);
|
|
+ N -= wsdPrng.n;
|
|
+ zBuf += wsdPrng.n;
|
|
+ }
|
|
+ wsdPrng.s[12]++;
|
|
+ chacha_block((u32*)wsdPrng.out, wsdPrng.s);
|
|
+ wsdPrng.n = 64;
|
|
+ }
|
|
sqlite3_mutex_leave(mutex);
|
|
}
|
|
|
|
@@ -30233,13 +32867,13 @@ SQLITE_PRIVATE int sqlite3ThreadCreate(
|
|
memset(p, 0, sizeof(*p));
|
|
p->xTask = xTask;
|
|
p->pIn = pIn;
|
|
- /* If the SQLITE_TESTCTRL_FAULT_INSTALL callback is registered to a
|
|
+ /* If the SQLITE_TESTCTRL_FAULT_INSTALL callback is registered to a
|
|
** function that returns SQLITE_ERROR when passed the argument 200, that
|
|
- ** forces worker threads to run sequentially and deterministically
|
|
+ ** forces worker threads to run sequentially and deterministically
|
|
** for testing purposes. */
|
|
if( sqlite3FaultSim(200) ){
|
|
rc = 1;
|
|
- }else{
|
|
+ }else{
|
|
rc = pthread_create(&p->tid, 0, xTask, pIn);
|
|
}
|
|
if( rc ){
|
|
@@ -30321,9 +32955,9 @@ SQLITE_PRIVATE int sqlite3ThreadCreate(
|
|
*ppThread = 0;
|
|
p = sqlite3Malloc(sizeof(*p));
|
|
if( p==0 ) return SQLITE_NOMEM_BKPT;
|
|
- /* If the SQLITE_TESTCTRL_FAULT_INSTALL callback is registered to a
|
|
+ /* If the SQLITE_TESTCTRL_FAULT_INSTALL callback is registered to a
|
|
** function that returns SQLITE_ERROR when passed the argument 200, that
|
|
- ** forces worker threads to run sequentially and deterministically
|
|
+ ** forces worker threads to run sequentially and deterministically
|
|
** (via the sqlite3FaultSim() term of the conditional) for testing
|
|
** purposes. */
|
|
if( sqlite3GlobalConfig.bCoreMutex==0 || sqlite3FaultSim(200) ){
|
|
@@ -30452,7 +33086,7 @@ SQLITE_PRIVATE int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
|
|
** May you share freely, never taking more than you give.
|
|
**
|
|
*************************************************************************
|
|
-** This file contains routines used to translate between UTF-8,
|
|
+** This file contains routines used to translate between UTF-8,
|
|
** UTF-16, UTF-16BE, and UTF-16LE.
|
|
**
|
|
** Notes on UTF-8:
|
|
@@ -30548,26 +33182,6 @@ static const unsigned char sqlite3Utf8Trans1[] = {
|
|
} \
|
|
}
|
|
|
|
-#define READ_UTF16LE(zIn, TERM, c){ \
|
|
- c = (*zIn++); \
|
|
- c += ((*zIn++)<<8); \
|
|
- if( c>=0xD800 && c<0xE000 && TERM ){ \
|
|
- int c2 = (*zIn++); \
|
|
- c2 += ((*zIn++)<<8); \
|
|
- c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10); \
|
|
- } \
|
|
-}
|
|
-
|
|
-#define READ_UTF16BE(zIn, TERM, c){ \
|
|
- c = ((*zIn++)<<8); \
|
|
- c += (*zIn++); \
|
|
- if( c>=0xD800 && c<0xE000 && TERM ){ \
|
|
- int c2 = ((*zIn++)<<8); \
|
|
- c2 += (*zIn++); \
|
|
- c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10); \
|
|
- } \
|
|
-}
|
|
-
|
|
/*
|
|
** Translate a single UTF-8 character. Return the unicode value.
|
|
**
|
|
@@ -30633,7 +33247,7 @@ SQLITE_PRIVATE u32 sqlite3Utf8Read(
|
|
/*
|
|
** If the TRANSLATE_TRACE macro is defined, the value of each Mem is
|
|
** printed on stderr on the way into and out of sqlite3VdbeMemTranslate().
|
|
-*/
|
|
+*/
|
|
/* #define TRANSLATE_TRACE 1 */
|
|
|
|
#ifndef SQLITE_OMIT_UTF16
|
|
@@ -30660,13 +33274,13 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desired
|
|
{
|
|
StrAccum acc;
|
|
char zBuf[1000];
|
|
- sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0);
|
|
+ sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0);
|
|
sqlite3VdbeMemPrettyPrint(pMem, &acc);
|
|
fprintf(stderr, "INPUT: %s\n", sqlite3StrAccumFinish(&acc));
|
|
}
|
|
#endif
|
|
|
|
- /* If the translation is between UTF-16 little and big endian, then
|
|
+ /* If the translation is between UTF-16 little and big endian, then
|
|
** all that is required is to swap the byte order. This case is handled
|
|
** differently from the others.
|
|
*/
|
|
@@ -30744,13 +33358,59 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desired
|
|
if( pMem->enc==SQLITE_UTF16LE ){
|
|
/* UTF-16 Little-endian -> UTF-8 */
|
|
while( zIn<zTerm ){
|
|
- READ_UTF16LE(zIn, zIn<zTerm, c);
|
|
+ c = *(zIn++);
|
|
+ c += (*(zIn++))<<8;
|
|
+ if( c>=0xd800 && c<0xe000 ){
|
|
+#ifdef SQLITE_REPLACE_INVALID_UTF
|
|
+ if( c>=0xdc00 || zIn>=zTerm ){
|
|
+ c = 0xfffd;
|
|
+ }else{
|
|
+ int c2 = *(zIn++);
|
|
+ c2 += (*(zIn++))<<8;
|
|
+ if( c2<0xdc00 || c2>=0xe000 ){
|
|
+ zIn -= 2;
|
|
+ c = 0xfffd;
|
|
+ }else{
|
|
+ c = ((c&0x3ff)<<10) + (c2&0x3ff) + 0x10000;
|
|
+ }
|
|
+ }
|
|
+#else
|
|
+ if( zIn<zTerm ){
|
|
+ int c2 = (*zIn++);
|
|
+ c2 += ((*zIn++)<<8);
|
|
+ c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10);
|
|
+ }
|
|
+#endif
|
|
+ }
|
|
WRITE_UTF8(z, c);
|
|
}
|
|
}else{
|
|
/* UTF-16 Big-endian -> UTF-8 */
|
|
while( zIn<zTerm ){
|
|
- READ_UTF16BE(zIn, zIn<zTerm, c);
|
|
+ c = (*(zIn++))<<8;
|
|
+ c += *(zIn++);
|
|
+ if( c>=0xd800 && c<0xe000 ){
|
|
+#ifdef SQLITE_REPLACE_INVALID_UTF
|
|
+ if( c>=0xdc00 || zIn>=zTerm ){
|
|
+ c = 0xfffd;
|
|
+ }else{
|
|
+ int c2 = (*(zIn++))<<8;
|
|
+ c2 += *(zIn++);
|
|
+ if( c2<0xdc00 || c2>=0xe000 ){
|
|
+ zIn -= 2;
|
|
+ c = 0xfffd;
|
|
+ }else{
|
|
+ c = ((c&0x3ff)<<10) + (c2&0x3ff) + 0x10000;
|
|
+ }
|
|
+ }
|
|
+#else
|
|
+ if( zIn<zTerm ){
|
|
+ int c2 = ((*zIn++)<<8);
|
|
+ c2 += (*zIn++);
|
|
+ c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10);
|
|
+ }
|
|
+#endif
|
|
+ }
|
|
WRITE_UTF8(z, c);
|
|
}
|
|
}
|
|
@@ -30759,9 +33419,9 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desired
|
|
*z = 0;
|
|
assert( (pMem->n+(desiredEnc==SQLITE_UTF8?1:2))<=len );
|
|
|
|
- c = pMem->flags;
|
|
+ c = MEM_Str|MEM_Term|(pMem->flags&(MEM_AffMask|MEM_Subtype));
|
|
sqlite3VdbeMemRelease(pMem);
|
|
- pMem->flags = MEM_Str|MEM_Term|(c&(MEM_AffMask|MEM_Subtype));
|
|
+ pMem->flags = c;
|
|
pMem->enc = desiredEnc;
|
|
pMem->z = (char*)zOut;
|
|
pMem->zMalloc = pMem->z;
|
|
@@ -30772,7 +33432,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desired
|
|
{
|
|
StrAccum acc;
|
|
char zBuf[1000];
|
|
- sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0);
|
|
+ sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 0);
|
|
sqlite3VdbeMemPrettyPrint(pMem, &acc);
|
|
fprintf(stderr, "OUTPUT: %s\n", sqlite3StrAccumFinish(&acc));
|
|
}
|
|
@@ -30783,7 +33443,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemTranslate(Mem *pMem, u8 desired
|
|
|
|
#ifndef SQLITE_OMIT_UTF16
|
|
/*
|
|
-** This routine checks for a byte-order mark at the beginning of the
|
|
+** This routine checks for a byte-order mark at the beginning of the
|
|
** UTF-16 string stored in *pMem. If one is present, it is removed and
|
|
** the encoding of the Mem adjusted. This routine does not do any
|
|
** byte-swapping, it just sets Mem.enc appropriately.
|
|
@@ -30806,7 +33466,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemHandleBom(Mem *pMem){
|
|
bom = SQLITE_UTF16LE;
|
|
}
|
|
}
|
|
-
|
|
+
|
|
if( bom ){
|
|
rc = sqlite3VdbeMemMakeWriteable(pMem);
|
|
if( rc==SQLITE_OK ){
|
|
@@ -30826,7 +33486,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemHandleBom(Mem *pMem){
|
|
** pZ is a UTF-8 encoded unicode string. If nByte is less than zero,
|
|
** return the number of unicode characters in pZ up to (but not including)
|
|
** the first 0x00 byte. If nByte is not less than zero, return the
|
|
-** number of unicode characters in the first nByte of pZ (or up to
|
|
+** number of unicode characters in the first nByte of pZ (or up to
|
|
** the first 0x00, whichever comes first).
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3Utf8CharLen(const char *zIn, int nByte){
|
|
@@ -30846,7 +33506,7 @@ SQLITE_PRIVATE int sqlite3Utf8CharLen(const char *zIn, int nByte){
|
|
return r;
|
|
}
|
|
|
|
-/* This test function is not currently used by the automated test-suite.
|
|
+/* This test function is not currently used by the automated test-suite.
|
|
** Hence it is only available in debug builds.
|
|
*/
|
|
#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
|
|
@@ -30908,19 +33568,16 @@ SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *zIn, int nChar){
|
|
int c;
|
|
unsigned char const *z = zIn;
|
|
int n = 0;
|
|
-
|
|
- if( SQLITE_UTF16NATIVE==SQLITE_UTF16BE ){
|
|
- while( n<nChar ){
|
|
- READ_UTF16BE(z, 1, c);
|
|
- n++;
|
|
- }
|
|
- }else{
|
|
- while( n<nChar ){
|
|
- READ_UTF16LE(z, 1, c);
|
|
- n++;
|
|
- }
|
|
+
|
|
+ if( SQLITE_UTF16NATIVE==SQLITE_UTF16LE ) z++;
|
|
+ while( n<nChar ){
|
|
+ c = z[0];
|
|
+ z += 2;
|
|
+ if( c>=0xd8 && c<0xdc && z[0]>=0xdc && z[0]<0xe0 ) z += 2;
|
|
+ n++;
|
|
}
|
|
- return (int)(z-(unsigned char const *)zIn);
|
|
+ return (int)(z-(unsigned char const *)zIn)
|
|
+ - (SQLITE_UTF16NATIVE==SQLITE_UTF16LE);
|
|
}
|
|
|
|
#if defined(SQLITE_TEST)
|
|
@@ -30950,30 +33607,6 @@ SQLITE_PRIVATE void sqlite3UtfSelfTest(void){
|
|
assert( c==t );
|
|
assert( (z-zBuf)==n );
|
|
}
|
|
- for(i=0; i<0x00110000; i++){
|
|
- if( i>=0xD800 && i<0xE000 ) continue;
|
|
- z = zBuf;
|
|
- WRITE_UTF16LE(z, i);
|
|
- n = (int)(z-zBuf);
|
|
- assert( n>0 && n<=4 );
|
|
- z[0] = 0;
|
|
- z = zBuf;
|
|
- READ_UTF16LE(z, 1, c);
|
|
- assert( c==i );
|
|
- assert( (z-zBuf)==n );
|
|
- }
|
|
- for(i=0; i<0x00110000; i++){
|
|
- if( i>=0xD800 && i<0xE000 ) continue;
|
|
- z = zBuf;
|
|
- WRITE_UTF16BE(z, i);
|
|
- n = (int)(z-zBuf);
|
|
- assert( n>0 && n<=4 );
|
|
- z[0] = 0;
|
|
- z = zBuf;
|
|
- READ_UTF16BE(z, 1, c);
|
|
- assert( c==i );
|
|
- assert( (z-zBuf)==n );
|
|
- }
|
|
}
|
|
#endif /* SQLITE_TEST */
|
|
#endif /* SQLITE_OMIT_UTF16 */
|
|
@@ -31003,19 +33636,9 @@ SQLITE_PRIVATE void sqlite3UtfSelfTest(void){
|
|
#include <math.h>
|
|
#endif
|
|
|
|
-/*
|
|
-** Routine needed to support the testcase() macro.
|
|
-*/
|
|
-#ifdef SQLITE_COVERAGE_TEST
|
|
-SQLITE_PRIVATE void sqlite3Coverage(int x){
|
|
- static unsigned dummy = 0;
|
|
- dummy += (unsigned)x;
|
|
-}
|
|
-#endif
|
|
-
|
|
/*
|
|
** Calls to sqlite3FaultSim() are used to simulate a failure during testing,
|
|
-** or to bypass normal error detection during testing in order to let
|
|
+** or to bypass normal error detection during testing in order to let
|
|
** execute proceed futher downstream.
|
|
**
|
|
** In deployment, sqlite3FaultSim() *always* return SQLITE_OK (0). The
|
|
@@ -31042,11 +33665,21 @@ SQLITE_PRIVATE int sqlite3FaultSim(int iTest){
|
|
#ifndef SQLITE_OMIT_FLOATING_POINT
|
|
/*
|
|
** Return true if the floating point value is Not a Number (NaN).
|
|
+**
|
|
+** Use the math library isnan() function if compiled with SQLITE_HAVE_ISNAN.
|
|
+** Otherwise, we have our own implementation that works on most systems.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3IsNaN(double x){
|
|
+ int rc; /* The value return */
|
|
+#if !SQLITE_HAVE_ISNAN && !HAVE_ISNAN
|
|
u64 y;
|
|
memcpy(&y,&x,sizeof(y));
|
|
- return IsNaN(y);
|
|
+ rc = IsNaN(y);
|
|
+#else
|
|
+ rc = isnan(x);
|
|
+#endif /* HAVE_ISNAN */
|
|
+ testcase( rc );
|
|
+ return rc;
|
|
}
|
|
#endif /* SQLITE_OMIT_FLOATING_POINT */
|
|
|
|
@@ -31064,15 +33697,21 @@ SQLITE_PRIVATE int sqlite3Strlen30(const char *z){
|
|
}
|
|
|
|
/*
|
|
-** Return the declared type of a column. Or return zDflt if the column
|
|
+** Return the declared type of a column. Or return zDflt if the column
|
|
** has no declared type.
|
|
**
|
|
** The column type is an extra string stored after the zero-terminator on
|
|
** the column name if and only if the COLFLAG_HASTYPE flag is set.
|
|
*/
|
|
SQLITE_PRIVATE char *sqlite3ColumnType(Column *pCol, char *zDflt){
|
|
- if( (pCol->colFlags & COLFLAG_HASTYPE)==0 ) return zDflt;
|
|
- return pCol->zName + strlen(pCol->zName) + 1;
|
|
+ if( pCol->colFlags & COLFLAG_HASTYPE ){
|
|
+ return pCol->zCnName + strlen(pCol->zCnName) + 1;
|
|
+ }else if( pCol->eCType ){
|
|
+ assert( pCol->eCType<=SQLITE_N_STDTYPE );
|
|
+ return (char*)sqlite3StdType[pCol->eCType-1];
|
|
+ }else{
|
|
+ return zDflt;
|
|
+ }
|
|
}
|
|
|
|
/*
|
|
@@ -31093,7 +33732,22 @@ static SQLITE_NOINLINE void sqlite3ErrorFinish(sqlite3 *db, int err_code){
|
|
SQLITE_PRIVATE void sqlite3Error(sqlite3 *db, int err_code){
|
|
assert( db!=0 );
|
|
db->errCode = err_code;
|
|
- if( err_code || db->pErr ) sqlite3ErrorFinish(db, err_code);
|
|
+ if( err_code || db->pErr ){
|
|
+ sqlite3ErrorFinish(db, err_code);
|
|
+ }else{
|
|
+ db->errByteOffset = -1;
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+** The equivalent of sqlite3Error(db, SQLITE_OK). Clear the error state
|
|
+** and error message.
|
|
+*/
|
|
+SQLITE_PRIVATE void sqlite3ErrorClear(sqlite3 *db){
|
|
+ assert( db!=0 );
|
|
+ db->errCode = SQLITE_OK;
|
|
+ db->errByteOffset = -1;
|
|
+ if( db->pErr ) sqlite3ValueSetNull(db->pErr);
|
|
}
|
|
|
|
/*
|
|
@@ -31113,17 +33767,8 @@ SQLITE_PRIVATE void sqlite3SystemError(sqlite3 *db, int rc){
|
|
** handle "db". The error code is set to "err_code".
|
|
**
|
|
** If it is not NULL, string zFormat specifies the format of the
|
|
-** error string in the style of the printf functions: The following
|
|
-** format characters are allowed:
|
|
-**
|
|
-** %s Insert a string
|
|
-** %z A string that should be freed after use
|
|
-** %d Insert an integer
|
|
-** %T Insert a token
|
|
-** %S Insert the first element of a SrcList
|
|
-**
|
|
-** zFormat and any string tokens that follow it are assumed to be
|
|
-** encoded in UTF-8.
|
|
+** error string. zFormat and any string tokens that follow it are
|
|
+** assumed to be encoded in UTF-8.
|
|
**
|
|
** To clear the most recent error for sqlite handle "db", sqlite3Error
|
|
** should be called with err_code set to SQLITE_OK and zFormat set
|
|
@@ -31145,15 +33790,28 @@ SQLITE_PRIVATE void sqlite3ErrorWithMsg(sqlite3 *db, int err_code, const char *z
|
|
}
|
|
}
|
|
|
|
+/*
|
|
+** Check for interrupts and invoke progress callback.
|
|
+*/
|
|
+SQLITE_PRIVATE void sqlite3ProgressCheck(Parse *p){
|
|
+ sqlite3 *db = p->db;
|
|
+ if( AtomicLoad(&db->u1.isInterrupted) ){
|
|
+ p->nErr++;
|
|
+ p->rc = SQLITE_INTERRUPT;
|
|
+ }
|
|
+#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
|
|
+ if( db->xProgress && (++p->nProgressSteps)>=db->nProgressOps ){
|
|
+ if( db->xProgress(db->pProgressArg) ){
|
|
+ p->nErr++;
|
|
+ p->rc = SQLITE_INTERRUPT;
|
|
+ }
|
|
+ p->nProgressSteps = 0;
|
|
+ }
|
|
+#endif
|
|
+}
|
|
+
|
|
/*
|
|
** Add an error message to pParse->zErrMsg and increment pParse->nErr.
|
|
-** The following formatting characters are allowed:
|
|
-**
|
|
-** %s Insert a string
|
|
-** %z A string that should be freed after use
|
|
-** %d Insert an integer
|
|
-** %T Insert a token
|
|
-** %S Insert the first element of a SrcList
|
|
**
|
|
** This function should be used to report any error that occurs while
|
|
** compiling an SQL statement (i.e. within sqlite3_prepare()). The
|
|
@@ -31166,11 +33824,19 @@ SQLITE_PRIVATE void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){
|
|
char *zMsg;
|
|
va_list ap;
|
|
sqlite3 *db = pParse->db;
|
|
+ assert( db!=0 );
|
|
+ assert( db->pParse==pParse || db->pParse->pToplevel==pParse );
|
|
+ db->errByteOffset = -2;
|
|
va_start(ap, zFormat);
|
|
zMsg = sqlite3VMPrintf(db, zFormat, ap);
|
|
va_end(ap);
|
|
+ if( db->errByteOffset<-1 ) db->errByteOffset = -1;
|
|
if( db->suppressErr ){
|
|
sqlite3DbFree(db, zMsg);
|
|
+ if( db->mallocFailed ){
|
|
+ pParse->nErr++;
|
|
+ pParse->rc = SQLITE_NOMEM;
|
|
+ }
|
|
}else{
|
|
pParse->nErr++;
|
|
sqlite3DbFree(db, pParse->zErrMsg);
|
|
@@ -31233,11 +33899,34 @@ SQLITE_PRIVATE void sqlite3Dequote(char *z){
|
|
z[j] = 0;
|
|
}
|
|
SQLITE_PRIVATE void sqlite3DequoteExpr(Expr *p){
|
|
+ assert( !ExprHasProperty(p, EP_IntValue) );
|
|
assert( sqlite3Isquote(p->u.zToken[0]) );
|
|
p->flags |= p->u.zToken[0]=='"' ? EP_Quoted|EP_DblQuoted : EP_Quoted;
|
|
sqlite3Dequote(p->u.zToken);
|
|
}
|
|
|
|
+/*
|
|
+** If the input token p is quoted, try to adjust the token to remove
|
|
+** the quotes. This is not always possible:
|
|
+**
|
|
+** "abc" -> abc
|
|
+** "ab""cd" -> (not possible because of the interior "")
|
|
+**
|
|
+** Remove the quotes if possible. This is a optimization. The overall
|
|
+** system should still return the correct answer even if this routine
|
|
+** is always a no-op.
|
|
+*/
|
|
+SQLITE_PRIVATE void sqlite3DequoteToken(Token *p){
|
|
+ unsigned int i;
|
|
+ if( p->n<2 ) return;
|
|
+ if( !sqlite3Isquote(p->z[0]) ) return;
|
|
+ for(i=1; i<p->n-1; i++){
|
|
+ if( sqlite3Isquote(p->z[i]) ) return;
|
|
+ }
|
|
+ p->n -= 2;
|
|
+ p->z++;
|
|
+}
|
|
+
|
|
/*
|
|
** Generate a Token object from a string
|
|
*/
|
|
@@ -31299,6 +33988,19 @@ SQLITE_API int sqlite3_strnicmp(const char *zLeft, const char *zRight, int N){
|
|
return N<0 ? 0 : UpperToLower[*a] - UpperToLower[*b];
|
|
}
|
|
|
|
+/*
|
|
+** Compute an 8-bit hash on a string that is insensitive to case differences
|
|
+*/
|
|
+SQLITE_PRIVATE u8 sqlite3StrIHash(const char *z){
|
|
+ u8 h = 0;
|
|
+ if( z==0 ) return 0;
|
|
+ while( z[0] ){
|
|
+ h += UpperToLower[(unsigned char)z[0]];
|
|
+ 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.
|
|
@@ -31334,7 +34036,7 @@ static LONGDOUBLE_TYPE sqlite3Pow10(int E){
|
|
if( E==0 ) break;
|
|
x *= x;
|
|
}
|
|
- return r;
|
|
+ return r;
|
|
#endif
|
|
}
|
|
|
|
@@ -31351,7 +34053,7 @@ static LONGDOUBLE_TYPE sqlite3Pow10(int E){
|
|
** 1 => The input string is a pure integer
|
|
** 2 or more => The input has a decimal point or eNNN clause
|
|
** 0 or less => The input string is not a valid number
|
|
-** -1 => Not a valid number, but has a valid prefix which
|
|
+** -1 => Not a valid number, but has a valid prefix which
|
|
** includes a decimal point and/or an eNNN clause
|
|
**
|
|
** Valid numbers are in one of these formats:
|
|
@@ -31452,7 +34154,7 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en
|
|
eValid = 0;
|
|
eType++;
|
|
|
|
- /* This branch is needed to avoid a (harmless) buffer overread. The
|
|
+ /* This branch is needed to avoid a (harmless) buffer overread. The
|
|
** special comment alerts the mutation tester that the correct answer
|
|
** is obtained even if the branch is omitted */
|
|
if( z>=zEnd ) goto do_atof_calc; /*PREVENTS-HARMLESS-OVERREAD*/
|
|
@@ -31564,6 +34266,34 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en
|
|
#pragma warning(default : 4756)
|
|
#endif
|
|
|
|
+/*
|
|
+** Render an signed 64-bit integer as text. Store the result in zOut[] and
|
|
+** return the length of the string that was stored, in bytes. The value
|
|
+** returned does not include the zero terminator at the end of the output
|
|
+** string.
|
|
+**
|
|
+** The caller must ensure that zOut[] is at least 21 bytes in size.
|
|
+*/
|
|
+SQLITE_PRIVATE int sqlite3Int64ToText(i64 v, char *zOut){
|
|
+ int i;
|
|
+ u64 x;
|
|
+ char zTemp[22];
|
|
+ if( v<0 ){
|
|
+ x = (v==SMALLEST_INT64) ? ((u64)1)<<63 : (u64)-v;
|
|
+ }else{
|
|
+ x = v;
|
|
+ }
|
|
+ i = sizeof(zTemp)-2;
|
|
+ zTemp[sizeof(zTemp)-1] = 0;
|
|
+ do{
|
|
+ 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;
|
|
+}
|
|
+
|
|
/*
|
|
** Compare the 19-character string zNum against the text representation
|
|
** value 2^63: 9223372036854775808. Return negative, zero, or positive
|
|
@@ -31626,6 +34356,7 @@ SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc
|
|
incr = 1;
|
|
}else{
|
|
incr = 2;
|
|
+ length &= ~1;
|
|
assert( SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 );
|
|
for(i=3-enc; i<length && zNum[i]==0; i+=2){}
|
|
nonNum = i<length;
|
|
@@ -31804,10 +34535,28 @@ SQLITE_PRIVATE int sqlite3GetInt32(const char *zNum, int *pValue){
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3Atoi(const char *z){
|
|
int x = 0;
|
|
- if( z ) sqlite3GetInt32(z, &x);
|
|
+ sqlite3GetInt32(z, &x);
|
|
return x;
|
|
}
|
|
|
|
+/*
|
|
+** Try to convert z into an unsigned 32-bit integer. Return true on
|
|
+** success and false if there is an error.
|
|
+**
|
|
+** Only decimal notation is accepted.
|
|
+*/
|
|
+SQLITE_PRIVATE int sqlite3GetUInt32(const char *z, u32 *pI){
|
|
+ u64 v = 0;
|
|
+ int i;
|
|
+ for(i=0; sqlite3Isdigit(z[i]); i++){
|
|
+ v = v*10 + z[i] - '0';
|
|
+ if( v>4294967296LL ){ *pI = 0; return 0; }
|
|
+ }
|
|
+ if( i==0 || z[i]!=0 ){ *pI = 0; return 0; }
|
|
+ *pI = (u32)v;
|
|
+ return 1;
|
|
+}
|
|
+
|
|
/*
|
|
** The variable-length integer encoding is as follows:
|
|
**
|
|
@@ -31848,7 +34597,7 @@ static int SQLITE_NOINLINE putVarint64(unsigned char *p, u64 v){
|
|
v >>= 7;
|
|
}
|
|
return 9;
|
|
- }
|
|
+ }
|
|
n = 0;
|
|
do{
|
|
buf[n++] = (u8)((v & 0x7f) | 0x80);
|
|
@@ -32048,8 +34797,8 @@ SQLITE_PRIVATE u8 sqlite3GetVarint(const unsigned char *p, u64 *v){
|
|
** If the varint stored in p[0] is larger than can fit in a 32-bit unsigned
|
|
** integer, then set *v to 0xffffffff.
|
|
**
|
|
-** A MACRO version, getVarint32, is provided which inlines the
|
|
-** single-byte case. All code should use the MACRO version as
|
|
+** A MACRO version, getVarint32, is provided which inlines the
|
|
+** single-byte case. All code should use the MACRO version as
|
|
** this function assumes the single-byte case has already been handled.
|
|
*/
|
|
SQLITE_PRIVATE u8 sqlite3GetVarint32(const unsigned char *p, u32 *v){
|
|
@@ -32110,8 +34859,7 @@ SQLITE_PRIVATE u8 sqlite3GetVarint32(const unsigned char *p, u32 *v){
|
|
u64 v64;
|
|
u8 n;
|
|
|
|
- p -= 2;
|
|
- n = sqlite3GetVarint(p, &v64);
|
|
+ n = sqlite3GetVarint(p-2, &v64);
|
|
assert( n>3 && n<=9 );
|
|
if( (v64 & SQLITE_MAX_U32)!=v64 ){
|
|
*v = 0xffffffff;
|
|
@@ -32238,7 +34986,7 @@ SQLITE_PRIVATE u8 sqlite3HexToInt(int h){
|
|
return (u8)(h & 0xf);
|
|
}
|
|
|
|
-#if !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC)
|
|
+#if !defined(SQLITE_OMIT_BLOB_LITERAL)
|
|
/*
|
|
** Convert a BLOB literal of the form "x'hhhhhh'" into its binary
|
|
** value. Return a pointer to its binary value. Space to hold the
|
|
@@ -32259,7 +35007,7 @@ SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3 *db, const char *z, int n){
|
|
}
|
|
return zBlob;
|
|
}
|
|
-#endif /* !SQLITE_OMIT_BLOB_LITERAL || SQLITE_HAS_CODEC */
|
|
+#endif /* !SQLITE_OMIT_BLOB_LITERAL */
|
|
|
|
/*
|
|
** Log an error that is an API call on a connection pointer that should
|
|
@@ -32267,7 +35015,7 @@ SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3 *db, const char *z, int n){
|
|
** argument. The zType is a word like "NULL" or "closed" or "invalid".
|
|
*/
|
|
static void logBadConnection(const char *zType){
|
|
- sqlite3_log(SQLITE_MISUSE,
|
|
+ sqlite3_log(SQLITE_MISUSE,
|
|
"API call with %s database connection pointer",
|
|
zType
|
|
);
|
|
@@ -32288,13 +35036,13 @@ static void logBadConnection(const char *zType){
|
|
** used as an argument to sqlite3_errmsg() or sqlite3_close().
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3SafetyCheckOk(sqlite3 *db){
|
|
- u32 magic;
|
|
+ u8 eOpenState;
|
|
if( db==0 ){
|
|
logBadConnection("NULL");
|
|
return 0;
|
|
}
|
|
- magic = db->magic;
|
|
- if( magic!=SQLITE_MAGIC_OPEN ){
|
|
+ eOpenState = db->eOpenState;
|
|
+ if( eOpenState!=SQLITE_STATE_OPEN ){
|
|
if( sqlite3SafetyCheckSickOrOk(db) ){
|
|
testcase( sqlite3GlobalConfig.xLog!=0 );
|
|
logBadConnection("unopened");
|
|
@@ -32305,11 +35053,11 @@ SQLITE_PRIVATE int sqlite3SafetyCheckOk(sqlite3 *db){
|
|
}
|
|
}
|
|
SQLITE_PRIVATE int sqlite3SafetyCheckSickOrOk(sqlite3 *db){
|
|
- u32 magic;
|
|
- magic = db->magic;
|
|
- if( magic!=SQLITE_MAGIC_SICK &&
|
|
- magic!=SQLITE_MAGIC_OPEN &&
|
|
- magic!=SQLITE_MAGIC_BUSY ){
|
|
+ u8 eOpenState;
|
|
+ eOpenState = db->eOpenState;
|
|
+ if( eOpenState!=SQLITE_STATE_SICK &&
|
|
+ eOpenState!=SQLITE_STATE_OPEN &&
|
|
+ eOpenState!=SQLITE_STATE_BUSY ){
|
|
testcase( sqlite3GlobalConfig.xLog!=0 );
|
|
logBadConnection("invalid");
|
|
return 0;
|
|
@@ -32341,7 +35089,7 @@ SQLITE_PRIVATE int sqlite3AddInt64(i64 *pA, i64 iB){
|
|
if( iA<0 && -(iA + LARGEST_INT64) > iB + 1 ) return 1;
|
|
}
|
|
*pA += iB;
|
|
- return 0;
|
|
+ return 0;
|
|
#endif
|
|
}
|
|
SQLITE_PRIVATE int sqlite3SubInt64(i64 *pA, i64 iB){
|
|
@@ -32382,7 +35130,7 @@ SQLITE_PRIVATE int sqlite3MulInt64(i64 *pA, i64 iB){
|
|
}
|
|
|
|
/*
|
|
-** Compute the absolute value of a 32-bit signed integer, of possible. Or
|
|
+** Compute the absolute value of a 32-bit signed integer, of possible. Or
|
|
** if the integer has a value of -2147483648, return +2147483647
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3AbsInt32(int x){
|
|
@@ -32422,11 +35170,11 @@ SQLITE_PRIVATE void sqlite3FileSuffix3(const char *zBaseFilename, char *z){
|
|
}
|
|
#endif
|
|
|
|
-/*
|
|
+/*
|
|
** Find (an approximate) sum of two LogEst values. This computation is
|
|
** not a simple "+" operator because LogEst is stored as a logarithmic
|
|
** value.
|
|
-**
|
|
+**
|
|
*/
|
|
SQLITE_PRIVATE LogEst sqlite3LogEstAdd(LogEst a, LogEst b){
|
|
static const unsigned char x[] = {
|
|
@@ -32474,7 +35222,6 @@ SQLITE_PRIVATE LogEst sqlite3LogEst(u64 x){
|
|
return a[x&7] + y - 10;
|
|
}
|
|
|
|
-#ifndef SQLITE_OMIT_VIRTUALTABLE
|
|
/*
|
|
** Convert a double into a LogEst
|
|
** In other words, compute an approximation for 10*log2(x).
|
|
@@ -32489,16 +35236,9 @@ SQLITE_PRIVATE LogEst sqlite3LogEstFromDouble(double x){
|
|
e = (a>>52) - 1022;
|
|
return e*10;
|
|
}
|
|
-#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
|
|
|
-#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || \
|
|
- defined(SQLITE_ENABLE_STAT4) || \
|
|
- defined(SQLITE_EXPLAIN_ESTIMATED_ROWS)
|
|
/*
|
|
** Convert a LogEst into an integer.
|
|
-**
|
|
-** Note that this routine is only used when one or more of various
|
|
-** non-standard compile-time options is enabled.
|
|
*/
|
|
SQLITE_PRIVATE u64 sqlite3LogEstToInt(LogEst x){
|
|
u64 n;
|
|
@@ -32506,17 +35246,9 @@ SQLITE_PRIVATE u64 sqlite3LogEstToInt(LogEst x){
|
|
x /= 10;
|
|
if( n>=5 ) n -= 2;
|
|
else if( n>=1 ) n -= 1;
|
|
-#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || \
|
|
- defined(SQLITE_EXPLAIN_ESTIMATED_ROWS)
|
|
if( x>60 ) return (u64)LARGEST_INT64;
|
|
-#else
|
|
- /* If only SQLITE_ENABLE_STAT4 is on, then the largest input
|
|
- ** possible to this routine is 310, resulting in a maximum x of 31 */
|
|
- assert( x<=60 );
|
|
-#endif
|
|
return x>=3 ? (n+8)<<(x-3) : (n+8)>>(3-x);
|
|
}
|
|
-#endif /* defined SCANSTAT or STAT4 or ESTIMATED_ROWS */
|
|
|
|
/*
|
|
** Add a new name/number pair to a VList. This might require that the
|
|
@@ -32540,8 +35272,8 @@ SQLITE_PRIVATE u64 sqlite3LogEstToInt(LogEst x){
|
|
** Conceptually:
|
|
**
|
|
** struct VList {
|
|
-** int nAlloc; // Number of allocated slots
|
|
-** int nUsed; // Number of used slots
|
|
+** int nAlloc; // Number of allocated slots
|
|
+** int nUsed; // Number of used slots
|
|
** struct VListEntry {
|
|
** int iValue; // Value for this entry
|
|
** int nSlot; // Slots used by this entry
|
|
@@ -32550,7 +35282,7 @@ SQLITE_PRIVATE u64 sqlite3LogEstToInt(LogEst x){
|
|
** }
|
|
**
|
|
** During code generation, pointers to the variable names within the
|
|
-** VList are taken. When that happens, nAlloc is set to zero as an
|
|
+** VList are taken. When that happens, nAlloc is set to zero as an
|
|
** indication that the VList may never again be enlarged, since the
|
|
** accompanying realloc() would invalidate the pointers.
|
|
*/
|
|
@@ -32621,6 +35353,104 @@ SQLITE_PRIVATE int sqlite3VListNameToNum(VList *pIn, const char *zName, int nNam
|
|
return 0;
|
|
}
|
|
|
|
+/*
|
|
+** High-resolution hardware timer used for debugging and testing only.
|
|
+*/
|
|
+#if defined(VDBE_PROFILE) \
|
|
+ || defined(SQLITE_PERFORMANCE_TRACE) \
|
|
+ || defined(SQLITE_ENABLE_STMT_SCANSTATUS)
|
|
+/************** Include hwtime.h in the middle of util.c *********************/
|
|
+/************** Begin file hwtime.h ******************************************/
|
|
+/*
|
|
+** 2008 May 27
|
|
+**
|
|
+** The author disclaims copyright to this source code. In place of
|
|
+** a legal notice, here is a blessing:
|
|
+**
|
|
+** May you do good and not evil.
|
|
+** May you find forgiveness for yourself and forgive others.
|
|
+** May you share freely, never taking more than you give.
|
|
+**
|
|
+******************************************************************************
|
|
+**
|
|
+** This file contains inline asm code for retrieving "high-performance"
|
|
+** counters for x86 and x86_64 class CPUs.
|
|
+*/
|
|
+#ifndef SQLITE_HWTIME_H
|
|
+#define SQLITE_HWTIME_H
|
|
+
|
|
+/*
|
|
+** The following routine only works on pentium-class (or newer) processors.
|
|
+** It uses the RDTSC opcode to read the cycle count value out of the
|
|
+** processor and returns that value. This can be used for high-res
|
|
+** profiling.
|
|
+*/
|
|
+#if !defined(__STRICT_ANSI__) && \
|
|
+ (defined(__GNUC__) || defined(_MSC_VER)) && \
|
|
+ (defined(i386) || defined(__i386__) || defined(_M_IX86))
|
|
+
|
|
+ #if defined(__GNUC__)
|
|
+
|
|
+ __inline__ sqlite_uint64 sqlite3Hwtime(void){
|
|
+ unsigned int lo, hi;
|
|
+ __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
|
|
+ return (sqlite_uint64)hi << 32 | lo;
|
|
+ }
|
|
+
|
|
+ #elif defined(_MSC_VER)
|
|
+
|
|
+ __declspec(naked) __inline sqlite_uint64 __cdecl sqlite3Hwtime(void){
|
|
+ __asm {
|
|
+ rdtsc
|
|
+ ret ; return value at EDX:EAX
|
|
+ }
|
|
+ }
|
|
+
|
|
+ #endif
|
|
+
|
|
+#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__x86_64__))
|
|
+
|
|
+ __inline__ sqlite_uint64 sqlite3Hwtime(void){
|
|
+ unsigned int lo, hi;
|
|
+ __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
|
|
+ return (sqlite_uint64)hi << 32 | lo;
|
|
+ }
|
|
+
|
|
+#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__ppc__))
|
|
+
|
|
+ __inline__ sqlite_uint64 sqlite3Hwtime(void){
|
|
+ unsigned long long retval;
|
|
+ unsigned long junk;
|
|
+ __asm__ __volatile__ ("\n\
|
|
+ 1: mftbu %1\n\
|
|
+ mftb %L0\n\
|
|
+ mftbu %0\n\
|
|
+ cmpw %0,%1\n\
|
|
+ bne 1b"
|
|
+ : "=r" (retval), "=r" (junk));
|
|
+ return retval;
|
|
+ }
|
|
+
|
|
+#else
|
|
+
|
|
+ /*
|
|
+ ** asm() is needed for hardware timing support. Without asm(),
|
|
+ ** disable the sqlite3Hwtime() routine.
|
|
+ **
|
|
+ ** sqlite3Hwtime() is only used for some obscure debugging
|
|
+ ** and analysis configurations, not in any deliverable, so this
|
|
+ ** should not be a great loss.
|
|
+ */
|
|
+SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); }
|
|
+
|
|
+#endif
|
|
+
|
|
+#endif /* !defined(SQLITE_HWTIME_H) */
|
|
+
|
|
+/************** End of hwtime.h **********************************************/
|
|
+/************** Continuing where we left off in util.c ***********************/
|
|
+#endif
|
|
+
|
|
/************** End of util.c ************************************************/
|
|
/************** Begin file hash.c ********************************************/
|
|
/*
|
|
@@ -32741,7 +35571,7 @@ static int rehash(Hash *pH, unsigned int new_size){
|
|
|
|
/* The inability to allocates space for a larger hash table is
|
|
** a performance hit but it is not a fatal error. So mark the
|
|
- ** allocation as a benign. Use sqlite3Malloc()/memset(0) instead of
|
|
+ ** allocation as a benign. Use sqlite3Malloc()/memset(0) instead of
|
|
** sqlite3MallocZero() to make the allocation, as sqlite3MallocZero()
|
|
** only zeroes the requested number of bytes whereas this module will
|
|
** use the actual amount of space allocated for the hash table (which
|
|
@@ -32791,12 +35621,13 @@ static HashElem *findElementWithHash(
|
|
count = pH->count;
|
|
}
|
|
if( pHash ) *pHash = h;
|
|
- while( count-- ){
|
|
+ while( count ){
|
|
assert( elem!=0 );
|
|
- if( sqlite3StrICmp(elem->pKey,pKey)==0 ){
|
|
+ if( sqlite3StrICmp(elem->pKey,pKey)==0 ){
|
|
return elem;
|
|
}
|
|
elem = elem->next;
|
|
+ count--;
|
|
}
|
|
return &nullElement;
|
|
}
|
|
@@ -32811,7 +35642,7 @@ static void removeElementGivenHash(
|
|
){
|
|
struct _ht *pEntry;
|
|
if( elem->prev ){
|
|
- elem->prev->next = elem->next;
|
|
+ elem->prev->next = elem->next;
|
|
}else{
|
|
pH->first = elem->next;
|
|
}
|
|
@@ -32910,53 +35741,53 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
|
|
/* 0 */ "Savepoint" OpHelp(""),
|
|
/* 1 */ "AutoCommit" OpHelp(""),
|
|
/* 2 */ "Transaction" OpHelp(""),
|
|
- /* 3 */ "SorterNext" OpHelp(""),
|
|
- /* 4 */ "Prev" OpHelp(""),
|
|
- /* 5 */ "Next" OpHelp(""),
|
|
- /* 6 */ "Checkpoint" OpHelp(""),
|
|
- /* 7 */ "JournalMode" OpHelp(""),
|
|
- /* 8 */ "Vacuum" OpHelp(""),
|
|
- /* 9 */ "VFilter" OpHelp("iplan=r[P3] zplan='P4'"),
|
|
- /* 10 */ "VUpdate" OpHelp("data=r[P3@P2]"),
|
|
- /* 11 */ "Goto" OpHelp(""),
|
|
- /* 12 */ "Gosub" OpHelp(""),
|
|
- /* 13 */ "InitCoroutine" OpHelp(""),
|
|
- /* 14 */ "Yield" OpHelp(""),
|
|
- /* 15 */ "MustBeInt" OpHelp(""),
|
|
- /* 16 */ "Jump" OpHelp(""),
|
|
- /* 17 */ "Once" OpHelp(""),
|
|
- /* 18 */ "If" OpHelp(""),
|
|
+ /* 3 */ "Checkpoint" OpHelp(""),
|
|
+ /* 4 */ "JournalMode" OpHelp(""),
|
|
+ /* 5 */ "Vacuum" OpHelp(""),
|
|
+ /* 6 */ "VFilter" OpHelp("iplan=r[P3] zplan='P4'"),
|
|
+ /* 7 */ "VUpdate" OpHelp("data=r[P3@P2]"),
|
|
+ /* 8 */ "Init" OpHelp("Start at P2"),
|
|
+ /* 9 */ "Goto" OpHelp(""),
|
|
+ /* 10 */ "Gosub" OpHelp(""),
|
|
+ /* 11 */ "InitCoroutine" OpHelp(""),
|
|
+ /* 12 */ "Yield" OpHelp(""),
|
|
+ /* 13 */ "MustBeInt" OpHelp(""),
|
|
+ /* 14 */ "Jump" OpHelp(""),
|
|
+ /* 15 */ "Once" OpHelp(""),
|
|
+ /* 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 */ "IfNot" OpHelp(""),
|
|
- /* 21 */ "IfNullRow" OpHelp("if P1.nullRow then r[P3]=NULL, goto P2"),
|
|
- /* 22 */ "SeekLT" OpHelp("key=r[P3@P4]"),
|
|
- /* 23 */ "SeekLE" OpHelp("key=r[P3@P4]"),
|
|
- /* 24 */ "SeekGE" OpHelp("key=r[P3@P4]"),
|
|
- /* 25 */ "SeekGT" OpHelp("key=r[P3@P4]"),
|
|
- /* 26 */ "IfNotOpen" OpHelp("if( !csr[P1] ) goto P2"),
|
|
- /* 27 */ "IfNoHope" OpHelp("key=r[P3@P4]"),
|
|
- /* 28 */ "NoConflict" OpHelp("key=r[P3@P4]"),
|
|
- /* 29 */ "NotFound" OpHelp("key=r[P3@P4]"),
|
|
- /* 30 */ "Found" OpHelp("key=r[P3@P4]"),
|
|
- /* 31 */ "SeekRowid" OpHelp("intkey=r[P3]"),
|
|
- /* 32 */ "NotExists" OpHelp("intkey=r[P3]"),
|
|
- /* 33 */ "Last" OpHelp(""),
|
|
- /* 34 */ "IfSmaller" OpHelp(""),
|
|
- /* 35 */ "SorterSort" OpHelp(""),
|
|
- /* 36 */ "Sort" OpHelp(""),
|
|
- /* 37 */ "Rewind" OpHelp(""),
|
|
- /* 38 */ "IdxLE" OpHelp("key=r[P3@P4]"),
|
|
- /* 39 */ "IdxGT" OpHelp("key=r[P3@P4]"),
|
|
- /* 40 */ "IdxLT" OpHelp("key=r[P3@P4]"),
|
|
- /* 41 */ "IdxGE" OpHelp("key=r[P3@P4]"),
|
|
- /* 42 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"),
|
|
+ /* 20 */ "IfNullRow" OpHelp("if P1.nullRow then r[P3]=NULL, goto P2"),
|
|
+ /* 21 */ "SeekLT" OpHelp("key=r[P3@P4]"),
|
|
+ /* 22 */ "SeekLE" OpHelp("key=r[P3@P4]"),
|
|
+ /* 23 */ "SeekGE" OpHelp("key=r[P3@P4]"),
|
|
+ /* 24 */ "SeekGT" OpHelp("key=r[P3@P4]"),
|
|
+ /* 25 */ "IfNotOpen" OpHelp("if( !csr[P1] ) goto P2"),
|
|
+ /* 26 */ "IfNoHope" OpHelp("key=r[P3@P4]"),
|
|
+ /* 27 */ "NoConflict" OpHelp("key=r[P3@P4]"),
|
|
+ /* 28 */ "NotFound" OpHelp("key=r[P3@P4]"),
|
|
+ /* 29 */ "Found" OpHelp("key=r[P3@P4]"),
|
|
+ /* 30 */ "SeekRowid" OpHelp("intkey=r[P3]"),
|
|
+ /* 31 */ "NotExists" OpHelp("intkey=r[P3]"),
|
|
+ /* 32 */ "Last" OpHelp(""),
|
|
+ /* 33 */ "IfSmaller" OpHelp(""),
|
|
+ /* 34 */ "SorterSort" OpHelp(""),
|
|
+ /* 35 */ "Sort" OpHelp(""),
|
|
+ /* 36 */ "Rewind" OpHelp(""),
|
|
+ /* 37 */ "SorterNext" OpHelp(""),
|
|
+ /* 38 */ "Prev" OpHelp(""),
|
|
+ /* 39 */ "Next" OpHelp(""),
|
|
+ /* 40 */ "IdxLE" OpHelp("key=r[P3@P4]"),
|
|
+ /* 41 */ "IdxGT" OpHelp("key=r[P3@P4]"),
|
|
+ /* 42 */ "IdxLT" OpHelp("key=r[P3@P4]"),
|
|
/* 43 */ "Or" OpHelp("r[P3]=(r[P1] || r[P2])"),
|
|
/* 44 */ "And" OpHelp("r[P3]=(r[P1] && r[P2])"),
|
|
- /* 45 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"),
|
|
- /* 46 */ "Program" OpHelp(""),
|
|
- /* 47 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"),
|
|
- /* 48 */ "IfPos" OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"),
|
|
- /* 49 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]--, goto P2"),
|
|
+ /* 45 */ "IdxGE" OpHelp("key=r[P3@P4]"),
|
|
+ /* 46 */ "RowSetRead" OpHelp("r[P3]=rowset(P1)"),
|
|
+ /* 47 */ "RowSetTest" OpHelp("if r[P3] in rowset(P1) goto P2"),
|
|
+ /* 48 */ "Program" OpHelp(""),
|
|
+ /* 49 */ "FkIfZero" OpHelp("if fkctr[P1]==0 goto P2"),
|
|
/* 50 */ "IsNull" OpHelp("if r[P1]==NULL goto P2"),
|
|
/* 51 */ "NotNull" OpHelp("if r[P1]!=NULL goto P2"),
|
|
/* 52 */ "Ne" OpHelp("IF r[P3]!=r[P1]"),
|
|
@@ -32965,130 +35796,1123 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
|
|
/* 55 */ "Le" OpHelp("IF r[P3]<=r[P1]"),
|
|
/* 56 */ "Lt" OpHelp("IF r[P3]<r[P1]"),
|
|
/* 57 */ "Ge" OpHelp("IF r[P3]>=r[P1]"),
|
|
- /* 58 */ "ElseNotEq" OpHelp(""),
|
|
- /* 59 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"),
|
|
- /* 60 */ "IncrVacuum" OpHelp(""),
|
|
- /* 61 */ "VNext" OpHelp(""),
|
|
- /* 62 */ "Init" OpHelp("Start at P2"),
|
|
- /* 63 */ "PureFunc" OpHelp("r[P3]=func(r[P2@P5])"),
|
|
- /* 64 */ "Function" OpHelp("r[P3]=func(r[P2@P5])"),
|
|
- /* 65 */ "Return" OpHelp(""),
|
|
- /* 66 */ "EndCoroutine" OpHelp(""),
|
|
- /* 67 */ "HaltIfNull" OpHelp("if r[P3]=null halt"),
|
|
- /* 68 */ "Halt" OpHelp(""),
|
|
- /* 69 */ "Integer" OpHelp("r[P2]=P1"),
|
|
- /* 70 */ "Int64" OpHelp("r[P2]=P4"),
|
|
- /* 71 */ "String" OpHelp("r[P2]='P4' (len=P1)"),
|
|
- /* 72 */ "Null" OpHelp("r[P2..P3]=NULL"),
|
|
- /* 73 */ "SoftNull" OpHelp("r[P1]=NULL"),
|
|
- /* 74 */ "Blob" OpHelp("r[P2]=P4 (len=P1)"),
|
|
- /* 75 */ "Variable" OpHelp("r[P2]=parameter(P1,P4)"),
|
|
- /* 76 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"),
|
|
- /* 77 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"),
|
|
- /* 78 */ "SCopy" OpHelp("r[P2]=r[P1]"),
|
|
- /* 79 */ "IntCopy" OpHelp("r[P2]=r[P1]"),
|
|
- /* 80 */ "ResultRow" OpHelp("output=r[P1@P2]"),
|
|
- /* 81 */ "CollSeq" OpHelp(""),
|
|
- /* 82 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"),
|
|
- /* 83 */ "RealAffinity" OpHelp(""),
|
|
- /* 84 */ "Cast" OpHelp("affinity(r[P1])"),
|
|
- /* 85 */ "Permutation" OpHelp(""),
|
|
- /* 86 */ "Compare" OpHelp("r[P1@P3] <-> r[P2@P3]"),
|
|
- /* 87 */ "IsTrue" OpHelp("r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4"),
|
|
- /* 88 */ "Offset" OpHelp("r[P3] = sqlite_offset(P1)"),
|
|
- /* 89 */ "Column" OpHelp("r[P3]=PX"),
|
|
- /* 90 */ "Affinity" OpHelp("affinity(r[P1@P2])"),
|
|
- /* 91 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"),
|
|
- /* 92 */ "Count" OpHelp("r[P2]=count()"),
|
|
- /* 93 */ "ReadCookie" OpHelp(""),
|
|
- /* 94 */ "SetCookie" OpHelp(""),
|
|
- /* 95 */ "ReopenIdx" OpHelp("root=P2 iDb=P3"),
|
|
- /* 96 */ "OpenRead" OpHelp("root=P2 iDb=P3"),
|
|
- /* 97 */ "OpenWrite" OpHelp("root=P2 iDb=P3"),
|
|
- /* 98 */ "OpenDup" OpHelp(""),
|
|
- /* 99 */ "OpenAutoindex" OpHelp("nColumn=P2"),
|
|
- /* 100 */ "OpenEphemeral" OpHelp("nColumn=P2"),
|
|
- /* 101 */ "BitAnd" OpHelp("r[P3]=r[P1]&r[P2]"),
|
|
- /* 102 */ "BitOr" OpHelp("r[P3]=r[P1]|r[P2]"),
|
|
- /* 103 */ "ShiftLeft" OpHelp("r[P3]=r[P2]<<r[P1]"),
|
|
- /* 104 */ "ShiftRight" OpHelp("r[P3]=r[P2]>>r[P1]"),
|
|
- /* 105 */ "Add" OpHelp("r[P3]=r[P1]+r[P2]"),
|
|
- /* 106 */ "Subtract" OpHelp("r[P3]=r[P2]-r[P1]"),
|
|
- /* 107 */ "Multiply" OpHelp("r[P3]=r[P1]*r[P2]"),
|
|
- /* 108 */ "Divide" OpHelp("r[P3]=r[P2]/r[P1]"),
|
|
- /* 109 */ "Remainder" OpHelp("r[P3]=r[P2]%r[P1]"),
|
|
- /* 110 */ "Concat" OpHelp("r[P3]=r[P2]+r[P1]"),
|
|
- /* 111 */ "SorterOpen" OpHelp(""),
|
|
- /* 112 */ "BitNot" OpHelp("r[P2]= ~r[P1]"),
|
|
- /* 113 */ "SequenceTest" OpHelp("if( cursor[P1].ctr++ ) pc = P2"),
|
|
- /* 114 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"),
|
|
- /* 115 */ "String8" OpHelp("r[P2]='P4'"),
|
|
- /* 116 */ "Close" OpHelp(""),
|
|
- /* 117 */ "ColumnsUsed" OpHelp(""),
|
|
- /* 118 */ "SeekHit" OpHelp("seekHit=P2"),
|
|
- /* 119 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"),
|
|
- /* 120 */ "NewRowid" OpHelp("r[P2]=rowid"),
|
|
- /* 121 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"),
|
|
- /* 122 */ "Delete" OpHelp(""),
|
|
- /* 123 */ "ResetCount" OpHelp(""),
|
|
- /* 124 */ "SorterCompare" OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"),
|
|
- /* 125 */ "SorterData" OpHelp("r[P2]=data"),
|
|
- /* 126 */ "RowData" OpHelp("r[P2]=data"),
|
|
- /* 127 */ "Rowid" OpHelp("r[P2]=rowid"),
|
|
- /* 128 */ "NullRow" OpHelp(""),
|
|
- /* 129 */ "SeekEnd" OpHelp(""),
|
|
- /* 130 */ "SorterInsert" OpHelp("key=r[P2]"),
|
|
- /* 131 */ "IdxInsert" OpHelp("key=r[P2]"),
|
|
- /* 132 */ "IdxDelete" OpHelp("key=r[P2@P3]"),
|
|
- /* 133 */ "DeferredSeek" OpHelp("Move P3 to P1.rowid if needed"),
|
|
- /* 134 */ "IdxRowid" OpHelp("r[P2]=rowid"),
|
|
- /* 135 */ "FinishSeek" OpHelp(""),
|
|
- /* 136 */ "Destroy" OpHelp(""),
|
|
- /* 137 */ "Clear" OpHelp(""),
|
|
- /* 138 */ "ResetSorter" OpHelp(""),
|
|
- /* 139 */ "CreateBtree" OpHelp("r[P2]=root iDb=P1 flags=P3"),
|
|
- /* 140 */ "SqlExec" OpHelp(""),
|
|
- /* 141 */ "ParseSchema" OpHelp(""),
|
|
- /* 142 */ "LoadAnalysis" OpHelp(""),
|
|
- /* 143 */ "DropTable" OpHelp(""),
|
|
- /* 144 */ "DropIndex" OpHelp(""),
|
|
- /* 145 */ "DropTrigger" OpHelp(""),
|
|
- /* 146 */ "IntegrityCk" OpHelp(""),
|
|
- /* 147 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"),
|
|
- /* 148 */ "Param" OpHelp(""),
|
|
- /* 149 */ "FkCounter" OpHelp("fkctr[P1]+=P2"),
|
|
- /* 150 */ "Real" OpHelp("r[P2]=P4"),
|
|
- /* 151 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"),
|
|
- /* 152 */ "OffsetLimit" OpHelp("if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"),
|
|
- /* 153 */ "AggInverse" OpHelp("accum=r[P3] inverse(r[P2@P5])"),
|
|
- /* 154 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@P5])"),
|
|
- /* 155 */ "AggStep1" OpHelp("accum=r[P3] step(r[P2@P5])"),
|
|
- /* 156 */ "AggValue" OpHelp("r[P3]=value N=P2"),
|
|
- /* 157 */ "AggFinal" OpHelp("accum=r[P1] N=P2"),
|
|
- /* 158 */ "Expire" OpHelp(""),
|
|
- /* 159 */ "CursorLock" OpHelp(""),
|
|
- /* 160 */ "CursorUnlock" OpHelp(""),
|
|
- /* 161 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"),
|
|
- /* 162 */ "VBegin" OpHelp(""),
|
|
- /* 163 */ "VCreate" OpHelp(""),
|
|
- /* 164 */ "VDestroy" OpHelp(""),
|
|
- /* 165 */ "VOpen" OpHelp(""),
|
|
- /* 166 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"),
|
|
- /* 167 */ "VRename" OpHelp(""),
|
|
- /* 168 */ "Pagecount" OpHelp(""),
|
|
- /* 169 */ "MaxPgcnt" OpHelp(""),
|
|
- /* 170 */ "Trace" OpHelp(""),
|
|
- /* 171 */ "CursorHint" OpHelp(""),
|
|
- /* 172 */ "ReleaseReg" OpHelp("release r[P1@P2] mask P3"),
|
|
- /* 173 */ "Noop" OpHelp(""),
|
|
- /* 174 */ "Explain" OpHelp(""),
|
|
- /* 175 */ "Abortable" OpHelp(""),
|
|
+ /* 58 */ "ElseEq" OpHelp(""),
|
|
+ /* 59 */ "IfPos" OpHelp("if r[P1]>0 then r[P1]-=P3, goto P2"),
|
|
+ /* 60 */ "IfNotZero" OpHelp("if r[P1]!=0 then r[P1]--, goto P2"),
|
|
+ /* 61 */ "DecrJumpZero" OpHelp("if (--r[P1])==0 goto P2"),
|
|
+ /* 62 */ "IncrVacuum" 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])"),
|
|
+ /* 66 */ "Function" OpHelp("r[P3]=func(r[P2@NP])"),
|
|
+ /* 67 */ "Return" OpHelp(""),
|
|
+ /* 68 */ "EndCoroutine" OpHelp(""),
|
|
+ /* 69 */ "HaltIfNull" OpHelp("if r[P3]=null halt"),
|
|
+ /* 70 */ "Halt" OpHelp(""),
|
|
+ /* 71 */ "Integer" OpHelp("r[P2]=P1"),
|
|
+ /* 72 */ "Int64" OpHelp("r[P2]=P4"),
|
|
+ /* 73 */ "String" OpHelp("r[P2]='P4' (len=P1)"),
|
|
+ /* 74 */ "BeginSubrtn" OpHelp("r[P2]=NULL"),
|
|
+ /* 75 */ "Null" OpHelp("r[P2..P3]=NULL"),
|
|
+ /* 76 */ "SoftNull" OpHelp("r[P1]=NULL"),
|
|
+ /* 77 */ "Blob" OpHelp("r[P2]=P4 (len=P1)"),
|
|
+ /* 78 */ "Variable" OpHelp("r[P2]=parameter(P1,P4)"),
|
|
+ /* 79 */ "Move" OpHelp("r[P2@P3]=r[P1@P3]"),
|
|
+ /* 80 */ "Copy" OpHelp("r[P2@P3+1]=r[P1@P3+1]"),
|
|
+ /* 81 */ "SCopy" OpHelp("r[P2]=r[P1]"),
|
|
+ /* 82 */ "IntCopy" OpHelp("r[P2]=r[P1]"),
|
|
+ /* 83 */ "FkCheck" OpHelp(""),
|
|
+ /* 84 */ "ResultRow" OpHelp("output=r[P1@P2]"),
|
|
+ /* 85 */ "CollSeq" OpHelp(""),
|
|
+ /* 86 */ "AddImm" OpHelp("r[P1]=r[P1]+P2"),
|
|
+ /* 87 */ "RealAffinity" OpHelp(""),
|
|
+ /* 88 */ "Cast" OpHelp("affinity(r[P1])"),
|
|
+ /* 89 */ "Permutation" OpHelp(""),
|
|
+ /* 90 */ "Compare" OpHelp("r[P1@P3] <-> r[P2@P3]"),
|
|
+ /* 91 */ "IsTrue" OpHelp("r[P2] = coalesce(r[P1]==TRUE,P3) ^ P4"),
|
|
+ /* 92 */ "ZeroOrNull" OpHelp("r[P2] = 0 OR NULL"),
|
|
+ /* 93 */ "Offset" OpHelp("r[P3] = sqlite_offset(P1)"),
|
|
+ /* 94 */ "Column" OpHelp("r[P3]=PX cursor P1 column P2"),
|
|
+ /* 95 */ "TypeCheck" OpHelp("typecheck(r[P1@P2])"),
|
|
+ /* 96 */ "Affinity" OpHelp("affinity(r[P1@P2])"),
|
|
+ /* 97 */ "MakeRecord" OpHelp("r[P3]=mkrec(r[P1@P2])"),
|
|
+ /* 98 */ "Count" OpHelp("r[P2]=count()"),
|
|
+ /* 99 */ "ReadCookie" OpHelp(""),
|
|
+ /* 100 */ "SetCookie" OpHelp(""),
|
|
+ /* 101 */ "ReopenIdx" OpHelp("root=P2 iDb=P3"),
|
|
+ /* 102 */ "BitAnd" OpHelp("r[P3]=r[P1]&r[P2]"),
|
|
+ /* 103 */ "BitOr" OpHelp("r[P3]=r[P1]|r[P2]"),
|
|
+ /* 104 */ "ShiftLeft" OpHelp("r[P3]=r[P2]<<r[P1]"),
|
|
+ /* 105 */ "ShiftRight" OpHelp("r[P3]=r[P2]>>r[P1]"),
|
|
+ /* 106 */ "Add" OpHelp("r[P3]=r[P1]+r[P2]"),
|
|
+ /* 107 */ "Subtract" OpHelp("r[P3]=r[P2]-r[P1]"),
|
|
+ /* 108 */ "Multiply" OpHelp("r[P3]=r[P1]*r[P2]"),
|
|
+ /* 109 */ "Divide" OpHelp("r[P3]=r[P2]/r[P1]"),
|
|
+ /* 110 */ "Remainder" OpHelp("r[P3]=r[P2]%r[P1]"),
|
|
+ /* 111 */ "Concat" OpHelp("r[P3]=r[P2]+r[P1]"),
|
|
+ /* 112 */ "OpenRead" OpHelp("root=P2 iDb=P3"),
|
|
+ /* 113 */ "OpenWrite" OpHelp("root=P2 iDb=P3"),
|
|
+ /* 114 */ "BitNot" OpHelp("r[P2]= ~r[P1]"),
|
|
+ /* 115 */ "OpenDup" OpHelp(""),
|
|
+ /* 116 */ "OpenAutoindex" OpHelp("nColumn=P2"),
|
|
+ /* 117 */ "String8" OpHelp("r[P2]='P4'"),
|
|
+ /* 118 */ "OpenEphemeral" OpHelp("nColumn=P2"),
|
|
+ /* 119 */ "SorterOpen" OpHelp(""),
|
|
+ /* 120 */ "SequenceTest" OpHelp("if( cursor[P1].ctr++ ) pc = P2"),
|
|
+ /* 121 */ "OpenPseudo" OpHelp("P3 columns in r[P2]"),
|
|
+ /* 122 */ "Close" OpHelp(""),
|
|
+ /* 123 */ "ColumnsUsed" OpHelp(""),
|
|
+ /* 124 */ "SeekScan" OpHelp("Scan-ahead up to P1 rows"),
|
|
+ /* 125 */ "SeekHit" OpHelp("set P2<=seekHit<=P3"),
|
|
+ /* 126 */ "Sequence" OpHelp("r[P2]=cursor[P1].ctr++"),
|
|
+ /* 127 */ "NewRowid" OpHelp("r[P2]=rowid"),
|
|
+ /* 128 */ "Insert" OpHelp("intkey=r[P3] data=r[P2]"),
|
|
+ /* 129 */ "RowCell" OpHelp(""),
|
|
+ /* 130 */ "Delete" OpHelp(""),
|
|
+ /* 131 */ "ResetCount" OpHelp(""),
|
|
+ /* 132 */ "SorterCompare" OpHelp("if key(P1)!=trim(r[P3],P4) goto P2"),
|
|
+ /* 133 */ "SorterData" OpHelp("r[P2]=data"),
|
|
+ /* 134 */ "RowData" OpHelp("r[P2]=data"),
|
|
+ /* 135 */ "Rowid" OpHelp("r[P2]=PX rowid of P1"),
|
|
+ /* 136 */ "NullRow" OpHelp(""),
|
|
+ /* 137 */ "SeekEnd" OpHelp(""),
|
|
+ /* 138 */ "IdxInsert" OpHelp("key=r[P2]"),
|
|
+ /* 139 */ "SorterInsert" OpHelp("key=r[P2]"),
|
|
+ /* 140 */ "IdxDelete" OpHelp("key=r[P2@P3]"),
|
|
+ /* 141 */ "DeferredSeek" OpHelp("Move P3 to P1.rowid if needed"),
|
|
+ /* 142 */ "IdxRowid" OpHelp("r[P2]=rowid"),
|
|
+ /* 143 */ "FinishSeek" OpHelp(""),
|
|
+ /* 144 */ "Destroy" OpHelp(""),
|
|
+ /* 145 */ "Clear" OpHelp(""),
|
|
+ /* 146 */ "ResetSorter" OpHelp(""),
|
|
+ /* 147 */ "CreateBtree" OpHelp("r[P2]=root iDb=P1 flags=P3"),
|
|
+ /* 148 */ "SqlExec" OpHelp(""),
|
|
+ /* 149 */ "ParseSchema" OpHelp(""),
|
|
+ /* 150 */ "LoadAnalysis" OpHelp(""),
|
|
+ /* 151 */ "DropTable" OpHelp(""),
|
|
+ /* 152 */ "DropIndex" OpHelp(""),
|
|
+ /* 153 */ "Real" OpHelp("r[P2]=P4"),
|
|
+ /* 154 */ "DropTrigger" OpHelp(""),
|
|
+ /* 155 */ "IntegrityCk" OpHelp(""),
|
|
+ /* 156 */ "RowSetAdd" OpHelp("rowset(P1)=r[P2]"),
|
|
+ /* 157 */ "Param" OpHelp(""),
|
|
+ /* 158 */ "FkCounter" OpHelp("fkctr[P1]+=P2"),
|
|
+ /* 159 */ "MemMax" OpHelp("r[P1]=max(r[P1],r[P2])"),
|
|
+ /* 160 */ "OffsetLimit" OpHelp("if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)"),
|
|
+ /* 161 */ "AggInverse" OpHelp("accum=r[P3] inverse(r[P2@P5])"),
|
|
+ /* 162 */ "AggStep" OpHelp("accum=r[P3] step(r[P2@P5])"),
|
|
+ /* 163 */ "AggStep1" OpHelp("accum=r[P3] step(r[P2@P5])"),
|
|
+ /* 164 */ "AggValue" OpHelp("r[P3]=value N=P2"),
|
|
+ /* 165 */ "AggFinal" OpHelp("accum=r[P1] N=P2"),
|
|
+ /* 166 */ "Expire" OpHelp(""),
|
|
+ /* 167 */ "CursorLock" OpHelp(""),
|
|
+ /* 168 */ "CursorUnlock" OpHelp(""),
|
|
+ /* 169 */ "TableLock" OpHelp("iDb=P1 root=P2 write=P3"),
|
|
+ /* 170 */ "VBegin" OpHelp(""),
|
|
+ /* 171 */ "VCreate" OpHelp(""),
|
|
+ /* 172 */ "VDestroy" OpHelp(""),
|
|
+ /* 173 */ "VOpen" OpHelp(""),
|
|
+ /* 174 */ "VInitIn" OpHelp("r[P2]=ValueList(P1,P3)"),
|
|
+ /* 175 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"),
|
|
+ /* 176 */ "VRename" OpHelp(""),
|
|
+ /* 177 */ "Pagecount" OpHelp(""),
|
|
+ /* 178 */ "MaxPgcnt" OpHelp(""),
|
|
+ /* 179 */ "ClrSubtype" OpHelp("r[P1].subtype = 0"),
|
|
+ /* 180 */ "FilterAdd" OpHelp("filter(P1) += key(P3@P4)"),
|
|
+ /* 181 */ "Trace" OpHelp(""),
|
|
+ /* 182 */ "CursorHint" OpHelp(""),
|
|
+ /* 183 */ "ReleaseReg" OpHelp("release r[P1@P2] mask P3"),
|
|
+ /* 184 */ "Noop" OpHelp(""),
|
|
+ /* 185 */ "Explain" OpHelp(""),
|
|
+ /* 186 */ "Abortable" OpHelp(""),
|
|
};
|
|
return azName[i];
|
|
}
|
|
#endif
|
|
|
|
/************** End of opcodes.c *********************************************/
|
|
+/************** Begin file os_kv.c *******************************************/
|
|
+/*
|
|
+** 2022-09-06
|
|
+**
|
|
+** The author disclaims copyright to this source code. In place of
|
|
+** a legal notice, here is a blessing:
|
|
+**
|
|
+** May you do good and not evil.
|
|
+** May you find forgiveness for yourself and forgive others.
|
|
+** May you share freely, never taking more than you give.
|
|
+**
|
|
+******************************************************************************
|
|
+**
|
|
+** This file contains an experimental VFS layer that operates on a
|
|
+** Key/Value storage engine where both keys and values must be pure
|
|
+** text.
|
|
+*/
|
|
+/* #include <sqliteInt.h> */
|
|
+#if SQLITE_OS_KV || (SQLITE_OS_UNIX && defined(SQLITE_OS_KV_OPTIONAL))
|
|
+
|
|
+/*****************************************************************************
|
|
+** Debugging logic
|
|
+*/
|
|
+
|
|
+/* SQLITE_KV_TRACE() is used for tracing calls to kvstorage routines. */
|
|
+#if 0
|
|
+#define SQLITE_KV_TRACE(X) printf X
|
|
+#else
|
|
+#define SQLITE_KV_TRACE(X)
|
|
+#endif
|
|
+
|
|
+/* SQLITE_KV_LOG() is used for tracing calls to the VFS interface */
|
|
+#if 0
|
|
+#define SQLITE_KV_LOG(X) printf X
|
|
+#else
|
|
+#define SQLITE_KV_LOG(X)
|
|
+#endif
|
|
+
|
|
+
|
|
+/*
|
|
+** Forward declaration of objects used by this VFS implementation
|
|
+*/
|
|
+typedef struct KVVfsFile KVVfsFile;
|
|
+
|
|
+/* A single open file. There are only two files represented by this
|
|
+** VFS - the database and the rollback journal.
|
|
+*/
|
|
+struct KVVfsFile {
|
|
+ sqlite3_file base; /* IO methods */
|
|
+ const char *zClass; /* Storage class */
|
|
+ int isJournal; /* True if this is a journal file */
|
|
+ unsigned int nJrnl; /* Space allocated for aJrnl[] */
|
|
+ char *aJrnl; /* Journal content */
|
|
+ int szPage; /* Last known page size */
|
|
+ sqlite3_int64 szDb; /* Database file size. -1 means unknown */
|
|
+ char *aData; /* Buffer to hold page data */
|
|
+};
|
|
+#define SQLITE_KVOS_SZ 133073
|
|
+
|
|
+/*
|
|
+** Methods for KVVfsFile
|
|
+*/
|
|
+static int kvvfsClose(sqlite3_file*);
|
|
+static int kvvfsReadDb(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
|
|
+static int kvvfsReadJrnl(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
|
|
+static int kvvfsWriteDb(sqlite3_file*,const void*,int iAmt, sqlite3_int64);
|
|
+static int kvvfsWriteJrnl(sqlite3_file*,const void*,int iAmt, sqlite3_int64);
|
|
+static int kvvfsTruncateDb(sqlite3_file*, sqlite3_int64 size);
|
|
+static int kvvfsTruncateJrnl(sqlite3_file*, sqlite3_int64 size);
|
|
+static int kvvfsSyncDb(sqlite3_file*, int flags);
|
|
+static int kvvfsSyncJrnl(sqlite3_file*, int flags);
|
|
+static int kvvfsFileSizeDb(sqlite3_file*, sqlite3_int64 *pSize);
|
|
+static int kvvfsFileSizeJrnl(sqlite3_file*, sqlite3_int64 *pSize);
|
|
+static int kvvfsLock(sqlite3_file*, int);
|
|
+static int kvvfsUnlock(sqlite3_file*, int);
|
|
+static int kvvfsCheckReservedLock(sqlite3_file*, int *pResOut);
|
|
+static int kvvfsFileControlDb(sqlite3_file*, int op, void *pArg);
|
|
+static int kvvfsFileControlJrnl(sqlite3_file*, int op, void *pArg);
|
|
+static int kvvfsSectorSize(sqlite3_file*);
|
|
+static int kvvfsDeviceCharacteristics(sqlite3_file*);
|
|
+
|
|
+/*
|
|
+** Methods for sqlite3_vfs
|
|
+*/
|
|
+static int kvvfsOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
|
|
+static int kvvfsDelete(sqlite3_vfs*, const char *zName, int syncDir);
|
|
+static int kvvfsAccess(sqlite3_vfs*, const char *zName, int flags, int *);
|
|
+static int kvvfsFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
|
|
+static void *kvvfsDlOpen(sqlite3_vfs*, const char *zFilename);
|
|
+static int kvvfsRandomness(sqlite3_vfs*, int nByte, char *zOut);
|
|
+static int kvvfsSleep(sqlite3_vfs*, int microseconds);
|
|
+static int kvvfsCurrentTime(sqlite3_vfs*, double*);
|
|
+static int kvvfsCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
|
|
+
|
|
+static sqlite3_vfs sqlite3OsKvvfsObject = {
|
|
+ 1, /* iVersion */
|
|
+ sizeof(KVVfsFile), /* szOsFile */
|
|
+ 1024, /* mxPathname */
|
|
+ 0, /* pNext */
|
|
+ "kvvfs", /* zName */
|
|
+ 0, /* pAppData */
|
|
+ kvvfsOpen, /* xOpen */
|
|
+ kvvfsDelete, /* xDelete */
|
|
+ kvvfsAccess, /* xAccess */
|
|
+ kvvfsFullPathname, /* xFullPathname */
|
|
+ kvvfsDlOpen, /* xDlOpen */
|
|
+ 0, /* xDlError */
|
|
+ 0, /* xDlSym */
|
|
+ 0, /* xDlClose */
|
|
+ kvvfsRandomness, /* xRandomness */
|
|
+ kvvfsSleep, /* xSleep */
|
|
+ kvvfsCurrentTime, /* xCurrentTime */
|
|
+ 0, /* xGetLastError */
|
|
+ kvvfsCurrentTimeInt64 /* xCurrentTimeInt64 */
|
|
+};
|
|
+
|
|
+/* Methods for sqlite3_file objects referencing a database file
|
|
+*/
|
|
+static sqlite3_io_methods kvvfs_db_io_methods = {
|
|
+ 1, /* iVersion */
|
|
+ kvvfsClose, /* xClose */
|
|
+ kvvfsReadDb, /* xRead */
|
|
+ kvvfsWriteDb, /* xWrite */
|
|
+ kvvfsTruncateDb, /* xTruncate */
|
|
+ kvvfsSyncDb, /* xSync */
|
|
+ kvvfsFileSizeDb, /* xFileSize */
|
|
+ kvvfsLock, /* xLock */
|
|
+ kvvfsUnlock, /* xUnlock */
|
|
+ kvvfsCheckReservedLock, /* xCheckReservedLock */
|
|
+ kvvfsFileControlDb, /* xFileControl */
|
|
+ kvvfsSectorSize, /* xSectorSize */
|
|
+ kvvfsDeviceCharacteristics, /* xDeviceCharacteristics */
|
|
+ 0, /* xShmMap */
|
|
+ 0, /* xShmLock */
|
|
+ 0, /* xShmBarrier */
|
|
+ 0, /* xShmUnmap */
|
|
+ 0, /* xFetch */
|
|
+ 0 /* xUnfetch */
|
|
+};
|
|
+
|
|
+/* Methods for sqlite3_file objects referencing a rollback journal
|
|
+*/
|
|
+static sqlite3_io_methods kvvfs_jrnl_io_methods = {
|
|
+ 1, /* iVersion */
|
|
+ kvvfsClose, /* xClose */
|
|
+ kvvfsReadJrnl, /* xRead */
|
|
+ kvvfsWriteJrnl, /* xWrite */
|
|
+ kvvfsTruncateJrnl, /* xTruncate */
|
|
+ kvvfsSyncJrnl, /* xSync */
|
|
+ kvvfsFileSizeJrnl, /* xFileSize */
|
|
+ kvvfsLock, /* xLock */
|
|
+ kvvfsUnlock, /* xUnlock */
|
|
+ kvvfsCheckReservedLock, /* xCheckReservedLock */
|
|
+ kvvfsFileControlJrnl, /* xFileControl */
|
|
+ kvvfsSectorSize, /* xSectorSize */
|
|
+ kvvfsDeviceCharacteristics, /* xDeviceCharacteristics */
|
|
+ 0, /* xShmMap */
|
|
+ 0, /* xShmLock */
|
|
+ 0, /* xShmBarrier */
|
|
+ 0, /* xShmUnmap */
|
|
+ 0, /* xFetch */
|
|
+ 0 /* xUnfetch */
|
|
+};
|
|
+
|
|
+/****** Storage subsystem **************************************************/
|
|
+#include <sys/types.h>
|
|
+#include <sys/stat.h>
|
|
+#include <unistd.h>
|
|
+
|
|
+/* Forward declarations for the low-level storage engine
|
|
+*/
|
|
+static int kvstorageWrite(const char*, const char *zKey, const char *zData);
|
|
+static int kvstorageDelete(const char*, const char *zKey);
|
|
+static int kvstorageRead(const char*, const char *zKey, char *zBuf, int nBuf);
|
|
+#define KVSTORAGE_KEY_SZ 32
|
|
+
|
|
+/* Expand the key name with an appropriate prefix and put the result
|
|
+** zKeyOut[]. The zKeyOut[] buffer is assumed to hold at least
|
|
+** KVSTORAGE_KEY_SZ bytes.
|
|
+*/
|
|
+static void kvstorageMakeKey(
|
|
+ const char *zClass,
|
|
+ const char *zKeyIn,
|
|
+ char *zKeyOut
|
|
+){
|
|
+ sqlite3_snprintf(KVSTORAGE_KEY_SZ, zKeyOut, "kvvfs-%s-%s", zClass, zKeyIn);
|
|
+}
|
|
+
|
|
+/* Write content into a key. zClass is the particular namespace of the
|
|
+** underlying key/value store to use - either "local" or "session".
|
|
+**
|
|
+** Both zKey and zData are zero-terminated pure text strings.
|
|
+**
|
|
+** Return the number of errors.
|
|
+*/
|
|
+static int kvstorageWrite(
|
|
+ const char *zClass,
|
|
+ const char *zKey,
|
|
+ const char *zData
|
|
+){
|
|
+ FILE *fd;
|
|
+ char zXKey[KVSTORAGE_KEY_SZ];
|
|
+ kvstorageMakeKey(zClass, zKey, zXKey);
|
|
+ fd = fopen(zXKey, "wb");
|
|
+ if( fd ){
|
|
+ SQLITE_KV_TRACE(("KVVFS-WRITE %-15s (%d) %.50s%s\n", zXKey,
|
|
+ (int)strlen(zData), zData,
|
|
+ strlen(zData)>50 ? "..." : ""));
|
|
+ fputs(zData, fd);
|
|
+ fclose(fd);
|
|
+ return 0;
|
|
+ }else{
|
|
+ return 1;
|
|
+ }
|
|
+}
|
|
+
|
|
+/* Delete a key (with its corresponding data) from the key/value
|
|
+** namespace given by zClass. If the key does not previously exist,
|
|
+** this routine is a no-op.
|
|
+*/
|
|
+static int kvstorageDelete(const char *zClass, const char *zKey){
|
|
+ char zXKey[KVSTORAGE_KEY_SZ];
|
|
+ kvstorageMakeKey(zClass, zKey, zXKey);
|
|
+ unlink(zXKey);
|
|
+ SQLITE_KV_TRACE(("KVVFS-DELETE %-15s\n", zXKey));
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Read the value associated with a zKey from the key/value namespace given
|
|
+** by zClass and put the text data associated with that key in the first
|
|
+** nBuf bytes of zBuf[]. The value might be truncated if zBuf is not large
|
|
+** enough to hold it all. The value put into zBuf must always be zero
|
|
+** terminated, even if it gets truncated because nBuf is not large enough.
|
|
+**
|
|
+** Return the total number of bytes in the data, without truncation, and
|
|
+** not counting the final zero terminator. Return -1 if the key does
|
|
+** not exist.
|
|
+**
|
|
+** If nBuf<=0 then this routine simply returns the size of the data without
|
|
+** actually reading it.
|
|
+*/
|
|
+static int kvstorageRead(
|
|
+ const char *zClass,
|
|
+ const char *zKey,
|
|
+ char *zBuf,
|
|
+ int nBuf
|
|
+){
|
|
+ FILE *fd;
|
|
+ struct stat buf;
|
|
+ char zXKey[KVSTORAGE_KEY_SZ];
|
|
+ kvstorageMakeKey(zClass, zKey, zXKey);
|
|
+ if( access(zXKey, R_OK)!=0
|
|
+ || stat(zXKey, &buf)!=0
|
|
+ || !S_ISREG(buf.st_mode)
|
|
+ ){
|
|
+ SQLITE_KV_TRACE(("KVVFS-READ %-15s (-1)\n", zXKey));
|
|
+ return -1;
|
|
+ }
|
|
+ if( nBuf<=0 ){
|
|
+ return (int)buf.st_size;
|
|
+ }else if( nBuf==1 ){
|
|
+ zBuf[0] = 0;
|
|
+ SQLITE_KV_TRACE(("KVVFS-READ %-15s (%d)\n", zXKey,
|
|
+ (int)buf.st_size));
|
|
+ return (int)buf.st_size;
|
|
+ }
|
|
+ if( nBuf > buf.st_size + 1 ){
|
|
+ nBuf = buf.st_size + 1;
|
|
+ }
|
|
+ fd = fopen(zXKey, "rb");
|
|
+ if( fd==0 ){
|
|
+ SQLITE_KV_TRACE(("KVVFS-READ %-15s (-1)\n", zXKey));
|
|
+ return -1;
|
|
+ }else{
|
|
+ sqlite3_int64 n = fread(zBuf, 1, nBuf-1, fd);
|
|
+ fclose(fd);
|
|
+ zBuf[n] = 0;
|
|
+ SQLITE_KV_TRACE(("KVVFS-READ %-15s (%lld) %.50s%s\n", zXKey,
|
|
+ n, zBuf, n>50 ? "..." : ""));
|
|
+ return (int)n;
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+** An internal level of indirection which enables us to replace the
|
|
+** kvvfs i/o methods with JavaScript implementations in WASM builds.
|
|
+** Maintenance reminder: if this struct changes in any way, the JSON
|
|
+** rendering of its structure must be updated in
|
|
+** sqlite3_wasm_enum_json(). There are no binary compatibility
|
|
+** concerns, so it does not need an iVersion member. This file is
|
|
+** necessarily always compiled together with sqlite3_wasm_enum_json(),
|
|
+** and JS code dynamically creates the mapping of members based on
|
|
+** that JSON description.
|
|
+*/
|
|
+typedef struct sqlite3_kvvfs_methods sqlite3_kvvfs_methods;
|
|
+struct sqlite3_kvvfs_methods {
|
|
+ int (*xRead)(const char *zClass, const char *zKey, char *zBuf, int nBuf);
|
|
+ int (*xWrite)(const char *zClass, const char *zKey, const char *zData);
|
|
+ int (*xDelete)(const char *zClass, const char *zKey);
|
|
+ const int nKeySize;
|
|
+};
|
|
+
|
|
+/*
|
|
+** This object holds the kvvfs I/O methods which may be swapped out
|
|
+** for JavaScript-side implementations in WASM builds. In such builds
|
|
+** it cannot be const, but in native builds it should be so that
|
|
+** the compiler can hopefully optimize this level of indirection out.
|
|
+** That said, kvvfs is intended primarily for use in WASM builds.
|
|
+**
|
|
+** Note that this is not explicitly flagged as static because the
|
|
+** amalgamation build will tag it with SQLITE_PRIVATE.
|
|
+*/
|
|
+#ifndef SQLITE_WASM
|
|
+const
|
|
+#endif
|
|
+SQLITE_PRIVATE sqlite3_kvvfs_methods sqlite3KvvfsMethods = {
|
|
+kvstorageRead,
|
|
+kvstorageWrite,
|
|
+kvstorageDelete,
|
|
+KVSTORAGE_KEY_SZ
|
|
+};
|
|
+
|
|
+/****** Utility subroutines ************************************************/
|
|
+
|
|
+/*
|
|
+** Encode binary into the text encoded used to persist on disk.
|
|
+** The output text is stored in aOut[], which must be at least
|
|
+** nData+1 bytes in length.
|
|
+**
|
|
+** Return the actual length of the encoded text, not counting the
|
|
+** zero terminator at the end.
|
|
+**
|
|
+** Encoding format
|
|
+** ---------------
|
|
+**
|
|
+** * Non-zero bytes are encoded as upper-case hexadecimal
|
|
+**
|
|
+** * A sequence of one or more zero-bytes that are not at the
|
|
+** beginning of the buffer are encoded as a little-endian
|
|
+** base-26 number using a..z. "a" means 0. "b" means 1,
|
|
+** "z" means 25. "ab" means 26. "ac" means 52. And so forth.
|
|
+**
|
|
+** * Because there is no overlap between the encoding characters
|
|
+** of hexadecimal and base-26 numbers, it is always clear where
|
|
+** one stops and the next begins.
|
|
+*/
|
|
+static int kvvfsEncode(const char *aData, int nData, char *aOut){
|
|
+ int i, j;
|
|
+ const unsigned char *a = (const unsigned char*)aData;
|
|
+ for(i=j=0; i<nData; i++){
|
|
+ unsigned char c = a[i];
|
|
+ if( c!=0 ){
|
|
+ aOut[j++] = "0123456789ABCDEF"[c>>4];
|
|
+ aOut[j++] = "0123456789ABCDEF"[c&0xf];
|
|
+ }else{
|
|
+ /* A sequence of 1 or more zeros is stored as a little-endian
|
|
+ ** base-26 number using a..z as the digits. So one zero is "b".
|
|
+ ** Two zeros is "c". 25 zeros is "z", 26 zeros is "ab", 27 is "bb",
|
|
+ ** and so forth.
|
|
+ */
|
|
+ int k;
|
|
+ for(k=1; i+k<nData && a[i+k]==0; k++){}
|
|
+ i += k-1;
|
|
+ while( k>0 ){
|
|
+ aOut[j++] = 'a'+(k%26);
|
|
+ k /= 26;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ aOut[j] = 0;
|
|
+ return j;
|
|
+}
|
|
+
|
|
+static const signed char kvvfsHexValue[256] = {
|
|
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
+ -1, -1, -1, -1, -1, -1, -1, -1, -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, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
|
|
+ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
+
|
|
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
|
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
|
|
+};
|
|
+
|
|
+/*
|
|
+** Decode the text encoding back to binary. The binary content is
|
|
+** written into pOut, which must be at least nOut bytes in length.
|
|
+**
|
|
+** The return value is the number of bytes actually written into aOut[].
|
|
+*/
|
|
+static int kvvfsDecode(const char *a, char *aOut, int nOut){
|
|
+ int i, j;
|
|
+ int c;
|
|
+ const unsigned char *aIn = (const unsigned char*)a;
|
|
+ i = 0;
|
|
+ j = 0;
|
|
+ while( 1 ){
|
|
+ c = kvvfsHexValue[aIn[i]];
|
|
+ if( c<0 ){
|
|
+ int n = 0;
|
|
+ int mult = 1;
|
|
+ c = aIn[i];
|
|
+ if( c==0 ) break;
|
|
+ while( c>='a' && c<='z' ){
|
|
+ n += (c - 'a')*mult;
|
|
+ mult *= 26;
|
|
+ c = aIn[++i];
|
|
+ }
|
|
+ if( j+n>nOut ) return -1;
|
|
+ memset(&aOut[j], 0, n);
|
|
+ j += n;
|
|
+ if( c==0 || mult==1 ) break; /* progress stalled if mult==1 */
|
|
+ }else{
|
|
+ aOut[j] = c<<4;
|
|
+ c = kvvfsHexValue[aIn[++i]];
|
|
+ if( c<0 ) break;
|
|
+ aOut[j++] += c;
|
|
+ i++;
|
|
+ }
|
|
+ }
|
|
+ return j;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Decode a complete journal file. Allocate space in pFile->aJrnl
|
|
+** and store the decoding there. Or leave pFile->aJrnl set to NULL
|
|
+** if an error is encountered.
|
|
+**
|
|
+** The first few characters of the text encoding will be a little-endian
|
|
+** base-26 number (digits a..z) that is the total number of bytes
|
|
+** in the decoded journal file image. This base-26 number is followed
|
|
+** by a single space, then the encoding of the journal. The space
|
|
+** separator is required to act as a terminator for the base-26 number.
|
|
+*/
|
|
+static void kvvfsDecodeJournal(
|
|
+ KVVfsFile *pFile, /* Store decoding in pFile->aJrnl */
|
|
+ const char *zTxt, /* Text encoding. Zero-terminated */
|
|
+ int nTxt /* Bytes in zTxt, excluding zero terminator */
|
|
+){
|
|
+ unsigned int n = 0;
|
|
+ int c, i, mult;
|
|
+ i = 0;
|
|
+ mult = 1;
|
|
+ while( (c = zTxt[i++])>='a' && c<='z' ){
|
|
+ n += (zTxt[i] - 'a')*mult;
|
|
+ mult *= 26;
|
|
+ }
|
|
+ sqlite3_free(pFile->aJrnl);
|
|
+ pFile->aJrnl = sqlite3_malloc64( n );
|
|
+ if( pFile->aJrnl==0 ){
|
|
+ pFile->nJrnl = 0;
|
|
+ return;
|
|
+ }
|
|
+ pFile->nJrnl = n;
|
|
+ n = kvvfsDecode(zTxt+i, pFile->aJrnl, pFile->nJrnl);
|
|
+ if( n<pFile->nJrnl ){
|
|
+ sqlite3_free(pFile->aJrnl);
|
|
+ pFile->aJrnl = 0;
|
|
+ pFile->nJrnl = 0;
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+** Read or write the "sz" element, containing the database file size.
|
|
+*/
|
|
+static sqlite3_int64 kvvfsReadFileSize(KVVfsFile *pFile){
|
|
+ char zData[50];
|
|
+ zData[0] = 0;
|
|
+ sqlite3KvvfsMethods.xRead(pFile->zClass, "sz", zData, sizeof(zData)-1);
|
|
+ return strtoll(zData, 0, 0);
|
|
+}
|
|
+static int kvvfsWriteFileSize(KVVfsFile *pFile, sqlite3_int64 sz){
|
|
+ char zData[50];
|
|
+ sqlite3_snprintf(sizeof(zData), zData, "%lld", sz);
|
|
+ return sqlite3KvvfsMethods.xWrite(pFile->zClass, "sz", zData);
|
|
+}
|
|
+
|
|
+/****** sqlite3_io_methods methods ******************************************/
|
|
+
|
|
+/*
|
|
+** Close an kvvfs-file.
|
|
+*/
|
|
+static int kvvfsClose(sqlite3_file *pProtoFile){
|
|
+ KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
|
|
+
|
|
+ SQLITE_KV_LOG(("xClose %s %s\n", pFile->zClass,
|
|
+ pFile->isJournal ? "journal" : "db"));
|
|
+ sqlite3_free(pFile->aJrnl);
|
|
+ sqlite3_free(pFile->aData);
|
|
+ return SQLITE_OK;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Read from the -journal file.
|
|
+*/
|
|
+static int kvvfsReadJrnl(
|
|
+ sqlite3_file *pProtoFile,
|
|
+ void *zBuf,
|
|
+ int iAmt,
|
|
+ sqlite_int64 iOfst
|
|
+){
|
|
+ KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
|
|
+ assert( pFile->isJournal );
|
|
+ SQLITE_KV_LOG(("xRead('%s-journal',%d,%lld)\n", pFile->zClass, iAmt, iOfst));
|
|
+ if( pFile->aJrnl==0 ){
|
|
+ int szTxt = kvstorageRead(pFile->zClass, "jrnl", 0, 0);
|
|
+ char *aTxt;
|
|
+ if( szTxt<=4 ){
|
|
+ return SQLITE_IOERR;
|
|
+ }
|
|
+ aTxt = sqlite3_malloc64( szTxt+1 );
|
|
+ if( aTxt==0 ) return SQLITE_NOMEM;
|
|
+ kvstorageRead(pFile->zClass, "jrnl", aTxt, szTxt+1);
|
|
+ kvvfsDecodeJournal(pFile, aTxt, szTxt);
|
|
+ sqlite3_free(aTxt);
|
|
+ if( pFile->aJrnl==0 ) return SQLITE_IOERR;
|
|
+ }
|
|
+ if( iOfst+iAmt>pFile->nJrnl ){
|
|
+ return SQLITE_IOERR_SHORT_READ;
|
|
+ }
|
|
+ memcpy(zBuf, pFile->aJrnl+iOfst, iAmt);
|
|
+ return SQLITE_OK;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Read from the database file.
|
|
+*/
|
|
+static int kvvfsReadDb(
|
|
+ sqlite3_file *pProtoFile,
|
|
+ void *zBuf,
|
|
+ int iAmt,
|
|
+ sqlite_int64 iOfst
|
|
+){
|
|
+ KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
|
|
+ unsigned int pgno;
|
|
+ int got, n;
|
|
+ char zKey[30];
|
|
+ char *aData = pFile->aData;
|
|
+ assert( iOfst>=0 );
|
|
+ assert( iAmt>=0 );
|
|
+ SQLITE_KV_LOG(("xRead('%s-db',%d,%lld)\n", pFile->zClass, iAmt, iOfst));
|
|
+ if( iOfst+iAmt>=512 ){
|
|
+ if( (iOfst % iAmt)!=0 ){
|
|
+ return SQLITE_IOERR_READ;
|
|
+ }
|
|
+ if( (iAmt & (iAmt-1))!=0 || iAmt<512 || iAmt>65536 ){
|
|
+ return SQLITE_IOERR_READ;
|
|
+ }
|
|
+ pFile->szPage = iAmt;
|
|
+ pgno = 1 + iOfst/iAmt;
|
|
+ }else{
|
|
+ pgno = 1;
|
|
+ }
|
|
+ sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno);
|
|
+ got = sqlite3KvvfsMethods.xRead(pFile->zClass, zKey,
|
|
+ aData, SQLITE_KVOS_SZ-1);
|
|
+ if( got<0 ){
|
|
+ n = 0;
|
|
+ }else{
|
|
+ aData[got] = 0;
|
|
+ if( iOfst+iAmt<512 ){
|
|
+ int k = iOfst+iAmt;
|
|
+ aData[k*2] = 0;
|
|
+ n = kvvfsDecode(aData, &aData[2000], SQLITE_KVOS_SZ-2000);
|
|
+ if( n>=iOfst+iAmt ){
|
|
+ memcpy(zBuf, &aData[2000+iOfst], iAmt);
|
|
+ n = iAmt;
|
|
+ }else{
|
|
+ n = 0;
|
|
+ }
|
|
+ }else{
|
|
+ n = kvvfsDecode(aData, zBuf, iAmt);
|
|
+ }
|
|
+ }
|
|
+ if( n<iAmt ){
|
|
+ memset(zBuf+n, 0, iAmt-n);
|
|
+ return SQLITE_IOERR_SHORT_READ;
|
|
+ }
|
|
+ return SQLITE_OK;
|
|
+}
|
|
+
|
|
+
|
|
+/*
|
|
+** Write into the -journal file.
|
|
+*/
|
|
+static int kvvfsWriteJrnl(
|
|
+ sqlite3_file *pProtoFile,
|
|
+ const void *zBuf,
|
|
+ int iAmt,
|
|
+ sqlite_int64 iOfst
|
|
+){
|
|
+ KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
|
|
+ sqlite3_int64 iEnd = iOfst+iAmt;
|
|
+ SQLITE_KV_LOG(("xWrite('%s-journal',%d,%lld)\n", pFile->zClass, iAmt, iOfst));
|
|
+ if( iEnd>=0x10000000 ) return SQLITE_FULL;
|
|
+ if( pFile->aJrnl==0 || pFile->nJrnl<iEnd ){
|
|
+ char *aNew = sqlite3_realloc(pFile->aJrnl, iEnd);
|
|
+ if( aNew==0 ){
|
|
+ return SQLITE_IOERR_NOMEM;
|
|
+ }
|
|
+ pFile->aJrnl = aNew;
|
|
+ if( pFile->nJrnl<iOfst ){
|
|
+ memset(pFile->aJrnl+pFile->nJrnl, 0, iOfst-pFile->nJrnl);
|
|
+ }
|
|
+ pFile->nJrnl = iEnd;
|
|
+ }
|
|
+ memcpy(pFile->aJrnl+iOfst, zBuf, iAmt);
|
|
+ return SQLITE_OK;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Write into the database file.
|
|
+*/
|
|
+static int kvvfsWriteDb(
|
|
+ sqlite3_file *pProtoFile,
|
|
+ const void *zBuf,
|
|
+ int iAmt,
|
|
+ sqlite_int64 iOfst
|
|
+){
|
|
+ KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
|
|
+ unsigned int pgno;
|
|
+ char zKey[30];
|
|
+ char *aData = pFile->aData;
|
|
+ SQLITE_KV_LOG(("xWrite('%s-db',%d,%lld)\n", pFile->zClass, iAmt, iOfst));
|
|
+ assert( iAmt>=512 && iAmt<=65536 );
|
|
+ assert( (iAmt & (iAmt-1))==0 );
|
|
+ assert( pFile->szPage<0 || pFile->szPage==iAmt );
|
|
+ pFile->szPage = iAmt;
|
|
+ pgno = 1 + iOfst/iAmt;
|
|
+ sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno);
|
|
+ kvvfsEncode(zBuf, iAmt, aData);
|
|
+ if( sqlite3KvvfsMethods.xWrite(pFile->zClass, zKey, aData) ){
|
|
+ return SQLITE_IOERR;
|
|
+ }
|
|
+ if( iOfst+iAmt > pFile->szDb ){
|
|
+ pFile->szDb = iOfst + iAmt;
|
|
+ }
|
|
+ return SQLITE_OK;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Truncate an kvvfs-file.
|
|
+*/
|
|
+static int kvvfsTruncateJrnl(sqlite3_file *pProtoFile, sqlite_int64 size){
|
|
+ KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
|
|
+ SQLITE_KV_LOG(("xTruncate('%s-journal',%lld)\n", pFile->zClass, size));
|
|
+ assert( size==0 );
|
|
+ sqlite3KvvfsMethods.xDelete(pFile->zClass, "jrnl");
|
|
+ sqlite3_free(pFile->aJrnl);
|
|
+ pFile->aJrnl = 0;
|
|
+ pFile->nJrnl = 0;
|
|
+ return SQLITE_OK;
|
|
+}
|
|
+static int kvvfsTruncateDb(sqlite3_file *pProtoFile, sqlite_int64 size){
|
|
+ KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
|
|
+ if( pFile->szDb>size
|
|
+ && pFile->szPage>0
|
|
+ && (size % pFile->szPage)==0
|
|
+ ){
|
|
+ char zKey[50];
|
|
+ unsigned int pgno, pgnoMax;
|
|
+ SQLITE_KV_LOG(("xTruncate('%s-db',%lld)\n", pFile->zClass, size));
|
|
+ pgno = 1 + size/pFile->szPage;
|
|
+ pgnoMax = 2 + pFile->szDb/pFile->szPage;
|
|
+ while( pgno<=pgnoMax ){
|
|
+ sqlite3_snprintf(sizeof(zKey), zKey, "%u", pgno);
|
|
+ sqlite3KvvfsMethods.xDelete(pFile->zClass, zKey);
|
|
+ pgno++;
|
|
+ }
|
|
+ pFile->szDb = size;
|
|
+ return kvvfsWriteFileSize(pFile, size) ? SQLITE_IOERR : SQLITE_OK;
|
|
+ }
|
|
+ return SQLITE_IOERR;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Sync an kvvfs-file.
|
|
+*/
|
|
+static int kvvfsSyncJrnl(sqlite3_file *pProtoFile, int flags){
|
|
+ int i, n;
|
|
+ KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
|
|
+ char *zOut;
|
|
+ SQLITE_KV_LOG(("xSync('%s-journal')\n", pFile->zClass));
|
|
+ if( pFile->nJrnl<=0 ){
|
|
+ return kvvfsTruncateJrnl(pProtoFile, 0);
|
|
+ }
|
|
+ zOut = sqlite3_malloc64( pFile->nJrnl*2 + 50 );
|
|
+ if( zOut==0 ){
|
|
+ return SQLITE_IOERR_NOMEM;
|
|
+ }
|
|
+ n = pFile->nJrnl;
|
|
+ i = 0;
|
|
+ do{
|
|
+ zOut[i++] = 'a' + (n%26);
|
|
+ n /= 26;
|
|
+ }while( n>0 );
|
|
+ zOut[i++] = ' ';
|
|
+ kvvfsEncode(pFile->aJrnl, pFile->nJrnl, &zOut[i]);
|
|
+ i = sqlite3KvvfsMethods.xWrite(pFile->zClass, "jrnl", zOut);
|
|
+ sqlite3_free(zOut);
|
|
+ return i ? SQLITE_IOERR : SQLITE_OK;
|
|
+}
|
|
+static int kvvfsSyncDb(sqlite3_file *pProtoFile, int flags){
|
|
+ return SQLITE_OK;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Return the current file-size of an kvvfs-file.
|
|
+*/
|
|
+static int kvvfsFileSizeJrnl(sqlite3_file *pProtoFile, sqlite_int64 *pSize){
|
|
+ KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
|
|
+ SQLITE_KV_LOG(("xFileSize('%s-journal')\n", pFile->zClass));
|
|
+ *pSize = pFile->nJrnl;
|
|
+ return SQLITE_OK;
|
|
+}
|
|
+static int kvvfsFileSizeDb(sqlite3_file *pProtoFile, sqlite_int64 *pSize){
|
|
+ KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
|
|
+ SQLITE_KV_LOG(("xFileSize('%s-db')\n", pFile->zClass));
|
|
+ if( pFile->szDb>=0 ){
|
|
+ *pSize = pFile->szDb;
|
|
+ }else{
|
|
+ *pSize = kvvfsReadFileSize(pFile);
|
|
+ }
|
|
+ return SQLITE_OK;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Lock an kvvfs-file.
|
|
+*/
|
|
+static int kvvfsLock(sqlite3_file *pProtoFile, int eLock){
|
|
+ KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
|
|
+ assert( !pFile->isJournal );
|
|
+ SQLITE_KV_LOG(("xLock(%s,%d)\n", pFile->zClass, eLock));
|
|
+
|
|
+ if( eLock!=SQLITE_LOCK_NONE ){
|
|
+ pFile->szDb = kvvfsReadFileSize(pFile);
|
|
+ }
|
|
+ return SQLITE_OK;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Unlock an kvvfs-file.
|
|
+*/
|
|
+static int kvvfsUnlock(sqlite3_file *pProtoFile, int eLock){
|
|
+ KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
|
|
+ assert( !pFile->isJournal );
|
|
+ SQLITE_KV_LOG(("xUnlock(%s,%d)\n", pFile->zClass, eLock));
|
|
+ if( eLock==SQLITE_LOCK_NONE ){
|
|
+ pFile->szDb = -1;
|
|
+ }
|
|
+ return SQLITE_OK;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Check if another file-handle holds a RESERVED lock on an kvvfs-file.
|
|
+*/
|
|
+static int kvvfsCheckReservedLock(sqlite3_file *pProtoFile, int *pResOut){
|
|
+ SQLITE_KV_LOG(("xCheckReservedLock\n"));
|
|
+ *pResOut = 0;
|
|
+ return SQLITE_OK;
|
|
+}
|
|
+
|
|
+/*
|
|
+** File control method. For custom operations on an kvvfs-file.
|
|
+*/
|
|
+static int kvvfsFileControlJrnl(sqlite3_file *pProtoFile, int op, void *pArg){
|
|
+ SQLITE_KV_LOG(("xFileControl(%d) on journal\n", op));
|
|
+ return SQLITE_NOTFOUND;
|
|
+}
|
|
+static int kvvfsFileControlDb(sqlite3_file *pProtoFile, int op, void *pArg){
|
|
+ SQLITE_KV_LOG(("xFileControl(%d) on database\n", op));
|
|
+ if( op==SQLITE_FCNTL_SYNC ){
|
|
+ KVVfsFile *pFile = (KVVfsFile *)pProtoFile;
|
|
+ int rc = SQLITE_OK;
|
|
+ SQLITE_KV_LOG(("xSync('%s-db')\n", pFile->zClass));
|
|
+ if( pFile->szDb>0 && 0!=kvvfsWriteFileSize(pFile, pFile->szDb) ){
|
|
+ rc = SQLITE_IOERR;
|
|
+ }
|
|
+ return rc;
|
|
+ }
|
|
+ return SQLITE_NOTFOUND;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Return the sector-size in bytes for an kvvfs-file.
|
|
+*/
|
|
+static int kvvfsSectorSize(sqlite3_file *pFile){
|
|
+ return 512;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Return the device characteristic flags supported by an kvvfs-file.
|
|
+*/
|
|
+static int kvvfsDeviceCharacteristics(sqlite3_file *pProtoFile){
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/****** sqlite3_vfs methods *************************************************/
|
|
+
|
|
+/*
|
|
+** Open an kvvfs file handle.
|
|
+*/
|
|
+static int kvvfsOpen(
|
|
+ sqlite3_vfs *pProtoVfs,
|
|
+ const char *zName,
|
|
+ sqlite3_file *pProtoFile,
|
|
+ int flags,
|
|
+ int *pOutFlags
|
|
+){
|
|
+ KVVfsFile *pFile = (KVVfsFile*)pProtoFile;
|
|
+ if( zName==0 ) zName = "";
|
|
+ SQLITE_KV_LOG(("xOpen(\"%s\")\n", zName));
|
|
+ if( strcmp(zName, "local")==0
|
|
+ || strcmp(zName, "session")==0
|
|
+ ){
|
|
+ pFile->isJournal = 0;
|
|
+ pFile->base.pMethods = &kvvfs_db_io_methods;
|
|
+ }else
|
|
+ if( strcmp(zName, "local-journal")==0
|
|
+ || strcmp(zName, "session-journal")==0
|
|
+ ){
|
|
+ pFile->isJournal = 1;
|
|
+ pFile->base.pMethods = &kvvfs_jrnl_io_methods;
|
|
+ }else{
|
|
+ return SQLITE_CANTOPEN;
|
|
+ }
|
|
+ if( zName[0]=='s' ){
|
|
+ pFile->zClass = "session";
|
|
+ }else{
|
|
+ pFile->zClass = "local";
|
|
+ }
|
|
+ pFile->aData = sqlite3_malloc64(SQLITE_KVOS_SZ);
|
|
+ if( pFile->aData==0 ){
|
|
+ return SQLITE_NOMEM;
|
|
+ }
|
|
+ pFile->aJrnl = 0;
|
|
+ pFile->nJrnl = 0;
|
|
+ pFile->szPage = -1;
|
|
+ pFile->szDb = -1;
|
|
+ return SQLITE_OK;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Delete the file located at zPath. If the dirSync argument is true,
|
|
+** ensure the file-system modifications are synced to disk before
|
|
+** returning.
|
|
+*/
|
|
+static int kvvfsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
|
|
+ if( strcmp(zPath, "local-journal")==0 ){
|
|
+ sqlite3KvvfsMethods.xDelete("local", "jrnl");
|
|
+ }else
|
|
+ if( strcmp(zPath, "session-journal")==0 ){
|
|
+ sqlite3KvvfsMethods.xDelete("session", "jrnl");
|
|
+ }
|
|
+ return SQLITE_OK;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Test for access permissions. Return true if the requested permission
|
|
+** is available, or false otherwise.
|
|
+*/
|
|
+static int kvvfsAccess(
|
|
+ sqlite3_vfs *pProtoVfs,
|
|
+ const char *zPath,
|
|
+ int flags,
|
|
+ int *pResOut
|
|
+){
|
|
+ SQLITE_KV_LOG(("xAccess(\"%s\")\n", zPath));
|
|
+ if( strcmp(zPath, "local-journal")==0 ){
|
|
+ *pResOut = sqlite3KvvfsMethods.xRead("local", "jrnl", 0, 0)>0;
|
|
+ }else
|
|
+ if( strcmp(zPath, "session-journal")==0 ){
|
|
+ *pResOut = sqlite3KvvfsMethods.xRead("session", "jrnl", 0, 0)>0;
|
|
+ }else
|
|
+ if( strcmp(zPath, "local")==0 ){
|
|
+ *pResOut = sqlite3KvvfsMethods.xRead("local", "sz", 0, 0)>0;
|
|
+ }else
|
|
+ if( strcmp(zPath, "session")==0 ){
|
|
+ *pResOut = sqlite3KvvfsMethods.xRead("session", "sz", 0, 0)>0;
|
|
+ }else
|
|
+ {
|
|
+ *pResOut = 0;
|
|
+ }
|
|
+ SQLITE_KV_LOG(("xAccess returns %d\n",*pResOut));
|
|
+ return SQLITE_OK;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Populate buffer zOut with the full canonical pathname corresponding
|
|
+** to the pathname in zPath. zOut is guaranteed to point to a buffer
|
|
+** of at least (INST_MAX_PATHNAME+1) bytes.
|
|
+*/
|
|
+static int kvvfsFullPathname(
|
|
+ sqlite3_vfs *pVfs,
|
|
+ const char *zPath,
|
|
+ int nOut,
|
|
+ char *zOut
|
|
+){
|
|
+ size_t nPath;
|
|
+#ifdef SQLITE_OS_KV_ALWAYS_LOCAL
|
|
+ zPath = "local";
|
|
+#endif
|
|
+ nPath = strlen(zPath);
|
|
+ SQLITE_KV_LOG(("xFullPathname(\"%s\")\n", zPath));
|
|
+ if( nOut<nPath+1 ) nPath = nOut - 1;
|
|
+ memcpy(zOut, zPath, nPath);
|
|
+ zOut[nPath] = 0;
|
|
+ return SQLITE_OK;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Open the dynamic library located at zPath and return a handle.
|
|
+*/
|
|
+static void *kvvfsDlOpen(sqlite3_vfs *pVfs, const char *zPath){
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Populate the buffer pointed to by zBufOut with nByte bytes of
|
|
+** random data.
|
|
+*/
|
|
+static int kvvfsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
|
|
+ memset(zBufOut, 0, nByte);
|
|
+ return nByte;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Sleep for nMicro microseconds. Return the number of microseconds
|
|
+** actually slept.
|
|
+*/
|
|
+static int kvvfsSleep(sqlite3_vfs *pVfs, int nMicro){
|
|
+ return SQLITE_OK;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Return the current time as a Julian Day number in *pTimeOut.
|
|
+*/
|
|
+static int kvvfsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
|
|
+ sqlite3_int64 i = 0;
|
|
+ int rc;
|
|
+ rc = kvvfsCurrentTimeInt64(0, &i);
|
|
+ *pTimeOut = i/86400000.0;
|
|
+ return rc;
|
|
+}
|
|
+#include <sys/time.h>
|
|
+static int kvvfsCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *pTimeOut){
|
|
+ static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000;
|
|
+ struct timeval sNow;
|
|
+ (void)gettimeofday(&sNow, 0); /* Cannot fail given valid arguments */
|
|
+ *pTimeOut = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_usec/1000;
|
|
+ return SQLITE_OK;
|
|
+}
|
|
+#endif /* SQLITE_OS_KV || SQLITE_OS_UNIX */
|
|
+
|
|
+#if SQLITE_OS_KV
|
|
+/*
|
|
+** This routine is called initialize the KV-vfs as the default VFS.
|
|
+*/
|
|
+SQLITE_API int sqlite3_os_init(void){
|
|
+ return sqlite3_vfs_register(&sqlite3OsKvvfsObject, 1);
|
|
+}
|
|
+SQLITE_API int sqlite3_os_end(void){
|
|
+ return SQLITE_OK;
|
|
+}
|
|
+#endif /* SQLITE_OS_KV */
|
|
+
|
|
+#if SQLITE_OS_UNIX && defined(SQLITE_OS_KV_OPTIONAL)
|
|
+SQLITE_PRIVATE int sqlite3KvvfsInit(void){
|
|
+ return sqlite3_vfs_register(&sqlite3OsKvvfsObject, 0);
|
|
+}
|
|
+#endif
|
|
+
|
|
+/************** End of os_kv.c ***********************************************/
|
|
/************** Begin file os_unix.c *****************************************/
|
|
/*
|
|
** 2004 May 22
|
|
@@ -33153,7 +36977,7 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
|
|
** Styles 4, 5, and 7 are only available of SQLITE_ENABLE_LOCKING_STYLE
|
|
** is defined to 1. The SQLITE_ENABLE_LOCKING_STYLE also enables automatic
|
|
** selection of the appropriate locking style based on the filesystem
|
|
-** where the database is located.
|
|
+** where the database is located.
|
|
*/
|
|
#if !defined(SQLITE_ENABLE_LOCKING_STYLE)
|
|
# if defined(__APPLE__)
|
|
@@ -33179,15 +37003,16 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
|
|
/*
|
|
** standard include files.
|
|
*/
|
|
-#include <sys/types.h>
|
|
-#include <sys/stat.h>
|
|
+#include <sys/types.h> /* amalgamator: keep */
|
|
+#include <sys/stat.h> /* amalgamator: keep */
|
|
#include <fcntl.h>
|
|
#include <sys/ioctl.h>
|
|
-#include <unistd.h>
|
|
+#include <unistd.h> /* amalgamator: keep */
|
|
/* #include <time.h> */
|
|
-#include <sys/time.h>
|
|
+#include <sys/time.h> /* amalgamator: keep */
|
|
#include <errno.h>
|
|
-#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
|
|
+#if (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) \
|
|
+ && !defined(SQLITE_WASI)
|
|
# include <sys/mman.h>
|
|
#endif
|
|
|
|
@@ -33214,7 +37039,8 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
|
|
# if defined(__APPLE__) && ((__MAC_OS_X_VERSION_MIN_REQUIRED > 1050) || \
|
|
(__IPHONE_OS_VERSION_MIN_REQUIRED > 2000))
|
|
# if (!defined(TARGET_OS_EMBEDDED) || (TARGET_OS_EMBEDDED==0)) \
|
|
- && (!defined(TARGET_IPHONE_SIMULATOR) || (TARGET_IPHONE_SIMULATOR==0))
|
|
+ && (!defined(TARGET_IPHONE_SIMULATOR) || (TARGET_IPHONE_SIMULATOR==0))\
|
|
+ && (!defined(TARGET_OS_MACCATALYST) || (TARGET_OS_MACCATALYST==0))
|
|
# undef HAVE_GETHOSTUUID
|
|
# define HAVE_GETHOSTUUID 1
|
|
# else
|
|
@@ -33274,12 +37100,49 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
|
|
*/
|
|
#define SQLITE_MAX_SYMLINKS 100
|
|
|
|
+/*
|
|
+** Remove and stub certain info for WASI (WebAssembly System
|
|
+** Interface) builds.
|
|
+*/
|
|
+#ifdef SQLITE_WASI
|
|
+# undef HAVE_FCHMOD
|
|
+# undef HAVE_FCHOWN
|
|
+# undef HAVE_MREMAP
|
|
+# define HAVE_MREMAP 0
|
|
+# ifndef SQLITE_DEFAULT_UNIX_VFS
|
|
+# define SQLITE_DEFAULT_UNIX_VFS "unix-dotfile"
|
|
+ /* ^^^ should SQLITE_DEFAULT_UNIX_VFS be "unix-none"? */
|
|
+# endif
|
|
+# ifndef F_RDLCK
|
|
+# define F_RDLCK 0
|
|
+# define F_WRLCK 1
|
|
+# define F_UNLCK 2
|
|
+# if __LONG_MAX == 0x7fffffffL
|
|
+# define F_GETLK 12
|
|
+# define F_SETLK 13
|
|
+# define F_SETLKW 14
|
|
+# else
|
|
+# define F_GETLK 5
|
|
+# define F_SETLK 6
|
|
+# define F_SETLKW 7
|
|
+# endif
|
|
+# endif
|
|
+#else /* !SQLITE_WASI */
|
|
+# ifndef HAVE_FCHMOD
|
|
+# define HAVE_FCHMOD
|
|
+# endif
|
|
+#endif /* SQLITE_WASI */
|
|
+
|
|
+#ifdef SQLITE_WASI
|
|
+# define osGetpid(X) (pid_t)1
|
|
+#else
|
|
/* Always cast the getpid() return type for compatibility with
|
|
** kernel modules in VxWorks. */
|
|
-#define osGetpid(X) (pid_t)getpid()
|
|
+# define osGetpid(X) (pid_t)getpid()
|
|
+#endif
|
|
|
|
/*
|
|
-** Only set the lastErrno if the error code is a real error and not
|
|
+** Only set the lastErrno if the error code is a real error and not
|
|
** a normal expected return code of SQLITE_BUSY or SQLITE_OK
|
|
*/
|
|
#define IS_LOCK_ERROR(x) ((x != SQLITE_OK) && (x != SQLITE_BUSY))
|
|
@@ -33347,7 +37210,7 @@ struct unixFile {
|
|
** whenever any part of the database changes. An assertion fault will
|
|
** occur if a file is updated without also updating the transaction
|
|
** counter. This test is made to avoid new problems similar to the
|
|
- ** one described by ticket #3584.
|
|
+ ** one described by ticket #3584.
|
|
*/
|
|
unsigned char transCntrChng; /* True if the transaction counter changed */
|
|
unsigned char dbUpdate; /* True if any part of database file changed */
|
|
@@ -33356,7 +37219,7 @@ struct unixFile {
|
|
#endif
|
|
|
|
#ifdef SQLITE_TEST
|
|
- /* In test mode, increase the size of this structure a bit so that
|
|
+ /* In test mode, increase the size of this structure a bit so that
|
|
** it is larger than the struct CrashFile defined in test6.c.
|
|
*/
|
|
char aPadding[32];
|
|
@@ -33388,205 +37251,7 @@ static pid_t randomnessPid = 0;
|
|
/*
|
|
** Include code that is common to all os_*.c files
|
|
*/
|
|
-/************** Include os_common.h in the middle of os_unix.c ***************/
|
|
-/************** Begin file os_common.h ***************************************/
|
|
-/*
|
|
-** 2004 May 22
|
|
-**
|
|
-** The author disclaims copyright to this source code. In place of
|
|
-** a legal notice, here is a blessing:
|
|
-**
|
|
-** May you do good and not evil.
|
|
-** May you find forgiveness for yourself and forgive others.
|
|
-** May you share freely, never taking more than you give.
|
|
-**
|
|
-******************************************************************************
|
|
-**
|
|
-** This file contains macros and a little bit of code that is common to
|
|
-** all of the platform-specific files (os_*.c) and is #included into those
|
|
-** files.
|
|
-**
|
|
-** This file should be #included by the os_*.c files only. It is not a
|
|
-** general purpose header file.
|
|
-*/
|
|
-#ifndef _OS_COMMON_H_
|
|
-#define _OS_COMMON_H_
|
|
-
|
|
-/*
|
|
-** At least two bugs have slipped in because we changed the MEMORY_DEBUG
|
|
-** macro to SQLITE_DEBUG and some older makefiles have not yet made the
|
|
-** switch. The following code should catch this problem at compile-time.
|
|
-*/
|
|
-#ifdef MEMORY_DEBUG
|
|
-# error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead."
|
|
-#endif
|
|
-
|
|
-/*
|
|
-** Macros for performance tracing. Normally turned off. Only works
|
|
-** on i486 hardware.
|
|
-*/
|
|
-#ifdef SQLITE_PERFORMANCE_TRACE
|
|
-
|
|
-/*
|
|
-** hwtime.h contains inline assembler code for implementing
|
|
-** high-performance timing routines.
|
|
-*/
|
|
-/************** Include hwtime.h in the middle of os_common.h ****************/
|
|
-/************** Begin file hwtime.h ******************************************/
|
|
-/*
|
|
-** 2008 May 27
|
|
-**
|
|
-** The author disclaims copyright to this source code. In place of
|
|
-** a legal notice, here is a blessing:
|
|
-**
|
|
-** May you do good and not evil.
|
|
-** May you find forgiveness for yourself and forgive others.
|
|
-** May you share freely, never taking more than you give.
|
|
-**
|
|
-******************************************************************************
|
|
-**
|
|
-** This file contains inline asm code for retrieving "high-performance"
|
|
-** counters for x86 and x86_64 class CPUs.
|
|
-*/
|
|
-#ifndef SQLITE_HWTIME_H
|
|
-#define SQLITE_HWTIME_H
|
|
-
|
|
-/*
|
|
-** The following routine only works on pentium-class (or newer) processors.
|
|
-** It uses the RDTSC opcode to read the cycle count value out of the
|
|
-** processor and returns that value. This can be used for high-res
|
|
-** profiling.
|
|
-*/
|
|
-#if !defined(__STRICT_ANSI__) && \
|
|
- (defined(__GNUC__) || defined(_MSC_VER)) && \
|
|
- (defined(i386) || defined(__i386__) || defined(_M_IX86))
|
|
-
|
|
- #if defined(__GNUC__)
|
|
-
|
|
- __inline__ sqlite_uint64 sqlite3Hwtime(void){
|
|
- unsigned int lo, hi;
|
|
- __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
|
|
- return (sqlite_uint64)hi << 32 | lo;
|
|
- }
|
|
-
|
|
- #elif defined(_MSC_VER)
|
|
-
|
|
- __declspec(naked) __inline sqlite_uint64 __cdecl sqlite3Hwtime(void){
|
|
- __asm {
|
|
- rdtsc
|
|
- ret ; return value at EDX:EAX
|
|
- }
|
|
- }
|
|
-
|
|
- #endif
|
|
-
|
|
-#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__x86_64__))
|
|
-
|
|
- __inline__ sqlite_uint64 sqlite3Hwtime(void){
|
|
- unsigned long val;
|
|
- __asm__ __volatile__ ("rdtsc" : "=A" (val));
|
|
- return val;
|
|
- }
|
|
-
|
|
-#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__ppc__))
|
|
-
|
|
- __inline__ sqlite_uint64 sqlite3Hwtime(void){
|
|
- unsigned long long retval;
|
|
- unsigned long junk;
|
|
- __asm__ __volatile__ ("\n\
|
|
- 1: mftbu %1\n\
|
|
- mftb %L0\n\
|
|
- mftbu %0\n\
|
|
- cmpw %0,%1\n\
|
|
- bne 1b"
|
|
- : "=r" (retval), "=r" (junk));
|
|
- return retval;
|
|
- }
|
|
-
|
|
-#else
|
|
-
|
|
- /*
|
|
- ** asm() is needed for hardware timing support. Without asm(),
|
|
- ** disable the sqlite3Hwtime() routine.
|
|
- **
|
|
- ** sqlite3Hwtime() is only used for some obscure debugging
|
|
- ** and analysis configurations, not in any deliverable, so this
|
|
- ** should not be a great loss.
|
|
- */
|
|
-SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); }
|
|
-
|
|
-#endif
|
|
-
|
|
-#endif /* !defined(SQLITE_HWTIME_H) */
|
|
-
|
|
-/************** End of hwtime.h **********************************************/
|
|
-/************** Continuing where we left off in os_common.h ******************/
|
|
-
|
|
-static sqlite_uint64 g_start;
|
|
-static sqlite_uint64 g_elapsed;
|
|
-#define TIMER_START g_start=sqlite3Hwtime()
|
|
-#define TIMER_END g_elapsed=sqlite3Hwtime()-g_start
|
|
-#define TIMER_ELAPSED g_elapsed
|
|
-#else
|
|
-#define TIMER_START
|
|
-#define TIMER_END
|
|
-#define TIMER_ELAPSED ((sqlite_uint64)0)
|
|
-#endif
|
|
-
|
|
-/*
|
|
-** If we compile with the SQLITE_TEST macro set, then the following block
|
|
-** of code will give us the ability to simulate a disk I/O error. This
|
|
-** is used for testing the I/O recovery logic.
|
|
-*/
|
|
-#if defined(SQLITE_TEST)
|
|
-SQLITE_API extern int sqlite3_io_error_hit;
|
|
-SQLITE_API extern int sqlite3_io_error_hardhit;
|
|
-SQLITE_API extern int sqlite3_io_error_pending;
|
|
-SQLITE_API extern int sqlite3_io_error_persist;
|
|
-SQLITE_API extern int sqlite3_io_error_benign;
|
|
-SQLITE_API extern int sqlite3_diskfull_pending;
|
|
-SQLITE_API extern int sqlite3_diskfull;
|
|
-#define SimulateIOErrorBenign(X) sqlite3_io_error_benign=(X)
|
|
-#define SimulateIOError(CODE) \
|
|
- if( (sqlite3_io_error_persist && sqlite3_io_error_hit) \
|
|
- || sqlite3_io_error_pending-- == 1 ) \
|
|
- { local_ioerr(); CODE; }
|
|
-static void local_ioerr(){
|
|
- IOTRACE(("IOERR\n"));
|
|
- sqlite3_io_error_hit++;
|
|
- if( !sqlite3_io_error_benign ) sqlite3_io_error_hardhit++;
|
|
-}
|
|
-#define SimulateDiskfullError(CODE) \
|
|
- if( sqlite3_diskfull_pending ){ \
|
|
- if( sqlite3_diskfull_pending == 1 ){ \
|
|
- local_ioerr(); \
|
|
- sqlite3_diskfull = 1; \
|
|
- sqlite3_io_error_hit = 1; \
|
|
- CODE; \
|
|
- }else{ \
|
|
- sqlite3_diskfull_pending--; \
|
|
- } \
|
|
- }
|
|
-#else
|
|
-#define SimulateIOErrorBenign(X)
|
|
-#define SimulateIOError(A)
|
|
-#define SimulateDiskfullError(A)
|
|
-#endif /* defined(SQLITE_TEST) */
|
|
-
|
|
-/*
|
|
-** When testing, keep a count of the number of open files.
|
|
-*/
|
|
-#if defined(SQLITE_TEST)
|
|
-SQLITE_API extern int sqlite3_open_file_count;
|
|
-#define OpenCounter(X) sqlite3_open_file_count+=(X)
|
|
-#else
|
|
-#define OpenCounter(X)
|
|
-#endif /* defined(SQLITE_TEST) */
|
|
-
|
|
-#endif /* !defined(_OS_COMMON_H_) */
|
|
-
|
|
-/************** End of os_common.h *******************************************/
|
|
-/************** Continuing where we left off in os_unix.c ********************/
|
|
+/* #include "os_common.h" */
|
|
|
|
/*
|
|
** Define various macros that are missing from some systems.
|
|
@@ -33699,7 +37364,7 @@ static struct unix_syscall {
|
|
#ifdef __DJGPP__
|
|
{ "fstat", 0, 0 },
|
|
#define osFstat(a,b,c) 0
|
|
-#else
|
|
+#else
|
|
{ "fstat", (sqlite3_syscall_ptr)fstat, 0 },
|
|
#define osFstat ((int(*)(int,struct stat*))aSyscall[5].pCurrent)
|
|
#endif
|
|
@@ -33746,7 +37411,11 @@ static struct unix_syscall {
|
|
#define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off64_t))\
|
|
aSyscall[13].pCurrent)
|
|
|
|
+#if defined(HAVE_FCHMOD)
|
|
{ "fchmod", (sqlite3_syscall_ptr)fchmod, 0 },
|
|
+#else
|
|
+ { "fchmod", (sqlite3_syscall_ptr)0, 0 },
|
|
+#endif
|
|
#define osFchmod ((int(*)(int,mode_t))aSyscall[14].pCurrent)
|
|
|
|
#if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
|
|
@@ -33782,14 +37451,16 @@ 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_WAL) || SQLITE_MAX_MMAP_SIZE>0) \
|
|
+ && !defined(SQLITE_WASI)
|
|
{ "mmap", (sqlite3_syscall_ptr)mmap, 0 },
|
|
#else
|
|
{ "mmap", (sqlite3_syscall_ptr)0, 0 },
|
|
#endif
|
|
#define osMmap ((void*(*)(void*,size_t,int,int,int,off_t))aSyscall[22].pCurrent)
|
|
|
|
-#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
|
|
+#if (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0) \
|
|
+ && !defined(SQLITE_WASI)
|
|
{ "munmap", (sqlite3_syscall_ptr)munmap, 0 },
|
|
#else
|
|
{ "munmap", (sqlite3_syscall_ptr)0, 0 },
|
|
@@ -33937,7 +37608,7 @@ static const char *unixNextSystemCall(sqlite3_vfs *p, const char *zName){
|
|
|
|
/*
|
|
** Do not accept any file descriptor less than this value, in order to avoid
|
|
-** opening database file using file descriptors that are commonly used for
|
|
+** opening database file using file descriptors that are commonly used for
|
|
** standard input, output, and error.
|
|
*/
|
|
#ifndef SQLITE_MINIMUM_FILE_DESCRIPTOR
|
|
@@ -33975,18 +37646,21 @@ static int robust_open(const char *z, int f, mode_t m){
|
|
break;
|
|
}
|
|
if( fd>=SQLITE_MINIMUM_FILE_DESCRIPTOR ) break;
|
|
+ if( (f & (O_EXCL|O_CREAT))==(O_EXCL|O_CREAT) ){
|
|
+ (void)osUnlink(z);
|
|
+ }
|
|
osClose(fd);
|
|
- sqlite3_log(SQLITE_WARNING,
|
|
+ sqlite3_log(SQLITE_WARNING,
|
|
"attempt to open \"%s\" as file descriptor %d", z, fd);
|
|
fd = -1;
|
|
- if( osOpen("/dev/null", f, m)<0 ) break;
|
|
+ if( osOpen("/dev/null", O_RDONLY, m)<0 ) break;
|
|
}
|
|
if( fd>=0 ){
|
|
if( m!=0 ){
|
|
struct stat statbuf;
|
|
- if( osFstat(fd, &statbuf)==0
|
|
+ if( osFstat(fd, &statbuf)==0
|
|
&& statbuf.st_size==0
|
|
- && (statbuf.st_mode&0777)!=m
|
|
+ && (statbuf.st_mode&0777)!=m
|
|
){
|
|
osFchmod(fd, m);
|
|
}
|
|
@@ -34001,11 +37675,11 @@ static int robust_open(const char *z, int f, mode_t m){
|
|
/*
|
|
** Helper functions to obtain and relinquish the global mutex. The
|
|
** global mutex is used to protect the unixInodeInfo and
|
|
-** vxworksFileId objects used by this file, all of which may be
|
|
+** vxworksFileId objects used by this file, all of which may be
|
|
** shared by multiple threads.
|
|
**
|
|
-** Function unixMutexHeld() is used to assert() that the global mutex
|
|
-** is held when required. This function is only used as part of assert()
|
|
+** Function unixMutexHeld() is used to assert() that the global mutex
|
|
+** is held when required. This function is only used as part of assert()
|
|
** statements. e.g.
|
|
**
|
|
** unixEnterMutex()
|
|
@@ -34127,7 +37801,7 @@ static int lockTrace(int fd, int op, struct flock *p){
|
|
static int robust_ftruncate(int h, sqlite3_int64 sz){
|
|
int rc;
|
|
#ifdef __ANDROID__
|
|
- /* On Android, ftruncate() always uses 32-bit offsets, even if
|
|
+ /* On Android, ftruncate() always uses 32-bit offsets, even if
|
|
** _FILE_OFFSET_BITS=64 is defined. This means it is unsafe to attempt to
|
|
** truncate a file to any size larger than 2GiB. Silently ignore any
|
|
** such attempts. */
|
|
@@ -34143,32 +37817,32 @@ static int robust_ftruncate(int h, sqlite3_int64 sz){
|
|
** This routine translates a standard POSIX errno code into something
|
|
** useful to the clients of the sqlite3 functions. Specifically, it is
|
|
** intended to translate a variety of "try again" errors into SQLITE_BUSY
|
|
-** and a variety of "please close the file descriptor NOW" errors into
|
|
+** and a variety of "please close the file descriptor NOW" errors into
|
|
** SQLITE_IOERR
|
|
-**
|
|
+**
|
|
** Errors during initialization of locks, or file system support for locks,
|
|
** should handle ENOLCK, ENOTSUP, EOPNOTSUPP separately.
|
|
*/
|
|
static int sqliteErrorFromPosixError(int posixError, int sqliteIOErr) {
|
|
- assert( (sqliteIOErr == SQLITE_IOERR_LOCK) ||
|
|
- (sqliteIOErr == SQLITE_IOERR_UNLOCK) ||
|
|
+ assert( (sqliteIOErr == SQLITE_IOERR_LOCK) ||
|
|
+ (sqliteIOErr == SQLITE_IOERR_UNLOCK) ||
|
|
(sqliteIOErr == SQLITE_IOERR_RDLOCK) ||
|
|
(sqliteIOErr == SQLITE_IOERR_CHECKRESERVEDLOCK) );
|
|
switch (posixError) {
|
|
- case EACCES:
|
|
+ case EACCES:
|
|
case EAGAIN:
|
|
case ETIMEDOUT:
|
|
case EBUSY:
|
|
case EINTR:
|
|
- case ENOLCK:
|
|
- /* random NFS retry error, unless during file system support
|
|
+ case ENOLCK:
|
|
+ /* random NFS retry error, unless during file system support
|
|
* introspection, in which it actually means what it says */
|
|
return SQLITE_BUSY;
|
|
-
|
|
- case EPERM:
|
|
+
|
|
+ case EPERM:
|
|
return SQLITE_PERM;
|
|
-
|
|
- default:
|
|
+
|
|
+ default:
|
|
return sqliteIOErr;
|
|
}
|
|
}
|
|
@@ -34183,7 +37857,7 @@ static int sqliteErrorFromPosixError(int posixError, int sqliteIOErr) {
|
|
**
|
|
** A pointer to an instance of the following structure can be used as a
|
|
** unique file ID in VxWorks. Each instance of this structure contains
|
|
-** a copy of the canonical filename. There is also a reference count.
|
|
+** a copy of the canonical filename. There is also a reference count.
|
|
** The structure is reclaimed when the number of pointers to it drops to
|
|
** zero.
|
|
**
|
|
@@ -34199,7 +37873,7 @@ struct vxworksFileId {
|
|
};
|
|
|
|
#if OS_VXWORKS
|
|
-/*
|
|
+/*
|
|
** All unique filenames are held on a linked list headed by this
|
|
** variable:
|
|
*/
|
|
@@ -34271,7 +37945,7 @@ static struct vxworksFileId *vxworksFindFileId(const char *zAbsoluteName){
|
|
*/
|
|
unixEnterMutex();
|
|
for(pCandidate=vxworksFileList; pCandidate; pCandidate=pCandidate->pNext){
|
|
- if( pCandidate->nName==n
|
|
+ if( pCandidate->nName==n
|
|
&& memcmp(pCandidate->zCanonicalName, pNew->zCanonicalName, n)==0
|
|
){
|
|
sqlite3_free(pNew);
|
|
@@ -34364,7 +38038,7 @@ static void vxworksReleaseFileId(struct vxworksFileId *pId){
|
|
** cnt>0 means there are cnt shared locks on the file.
|
|
**
|
|
** Any attempt to lock or unlock a file first checks the locking
|
|
-** structure. The fcntl() system call is only invoked to set a
|
|
+** structure. The fcntl() system call is only invoked to set a
|
|
** POSIX lock if the internal lock structure transitions between
|
|
** a locked and an unlocked state.
|
|
**
|
|
@@ -34397,7 +38071,7 @@ static void vxworksReleaseFileId(struct vxworksFileId *pId){
|
|
**
|
|
** SQLite used to support LinuxThreads. But support for LinuxThreads
|
|
** was dropped beginning with version 3.7.0. SQLite will still work with
|
|
-** LinuxThreads provided that (1) there is no more than one connection
|
|
+** LinuxThreads provided that (1) there is no more than one connection
|
|
** per database file in the same process and (2) database connections
|
|
** do not move across threads.
|
|
*/
|
|
@@ -34414,7 +38088,7 @@ struct unixFileId {
|
|
/* We are told that some versions of Android contain a bug that
|
|
** sizes ino_t at only 32-bits instead of 64-bits. (See
|
|
** https://android-review.googlesource.com/#/c/115351/3/dist/sqlite3.c)
|
|
- ** To work around this, always allocate 64-bits for the inode number.
|
|
+ ** To work around this, always allocate 64-bits for the inode number.
|
|
** On small machines that only have 32-bit inodes, this wastes 4 bytes,
|
|
** but that should not be a big deal. */
|
|
/* WAS: ino_t ino; */
|
|
@@ -34502,7 +38176,7 @@ int unixFileMutexNotheld(unixFile *pFile){
|
|
** strerror_r().
|
|
**
|
|
** The first argument passed to the macro should be the error code that
|
|
-** will be returned to SQLite (e.g. SQLITE_IOERR_DELETE, SQLITE_CANTOPEN).
|
|
+** will be returned to SQLite (e.g. SQLITE_IOERR_DELETE, SQLITE_CANTOPEN).
|
|
** The two subsequent arguments should be the name of the OS function that
|
|
** failed (e.g. "unlink", "open") and the associated file-system path,
|
|
** if any.
|
|
@@ -34520,7 +38194,7 @@ static int unixLogErrorAtLine(
|
|
/* If this is not a threadsafe build (SQLITE_THREADSAFE==0), then use
|
|
** the strerror() function to obtain the human-readable error message
|
|
** equivalent to errno. Otherwise, use strerror_r().
|
|
- */
|
|
+ */
|
|
#if SQLITE_THREADSAFE && defined(HAVE_STRERROR_R)
|
|
char aErr[80];
|
|
memset(aErr, 0, sizeof(aErr));
|
|
@@ -34528,18 +38202,18 @@ static int unixLogErrorAtLine(
|
|
|
|
/* If STRERROR_R_CHAR_P (set by autoconf scripts) or __USE_GNU is defined,
|
|
** assume that the system provides the GNU version of strerror_r() that
|
|
- ** returns a pointer to a buffer containing the error message. That pointer
|
|
- ** may point to aErr[], or it may point to some static storage somewhere.
|
|
- ** Otherwise, assume that the system provides the POSIX version of
|
|
+ ** returns a pointer to a buffer containing the error message. That pointer
|
|
+ ** may point to aErr[], or it may point to some static storage somewhere.
|
|
+ ** Otherwise, assume that the system provides the POSIX version of
|
|
** strerror_r(), which always writes an error message into aErr[].
|
|
**
|
|
** If the code incorrectly assumes that it is the POSIX version that is
|
|
** available, the error message will often be an empty string. Not a
|
|
- ** huge problem. Incorrectly concluding that the GNU version is available
|
|
+ ** huge problem. Incorrectly concluding that the GNU version is available
|
|
** could lead to a segfault though.
|
|
*/
|
|
#if defined(STRERROR_R_CHAR_P) || defined(__USE_GNU)
|
|
- zErr =
|
|
+ zErr =
|
|
# endif
|
|
strerror_r(iErrno, aErr, sizeof(aErr)-1);
|
|
|
|
@@ -34590,7 +38264,7 @@ static void storeLastErrno(unixFile *pFile, int error){
|
|
|
|
/*
|
|
** Close all file descriptors accumuated in the unixInodeInfo->pUnused list.
|
|
-*/
|
|
+*/
|
|
static void closePendingFds(unixFile *pFile){
|
|
unixInodeInfo *pInode = pFile->pInode;
|
|
UnixUnusedFd *p;
|
|
@@ -34745,7 +38419,7 @@ static int fileHasMoved(unixFile *pFile){
|
|
#else
|
|
struct stat buf;
|
|
return pFile->pInode!=0 &&
|
|
- (osStat(pFile->zPath, &buf)!=0
|
|
+ (osStat(pFile->zPath, &buf)!=0
|
|
|| (u64)buf.st_ino!=pFile->pInode->fileId.ino);
|
|
#endif
|
|
}
|
|
@@ -34826,7 +38500,7 @@ static int unixCheckReservedLock(sqlite3_file *id, int *pResOut){
|
|
}
|
|
}
|
|
#endif
|
|
-
|
|
+
|
|
sqlite3_mutex_leave(pFile->pInode->pLockMutex);
|
|
OSTRACE(("TEST WR-LOCK %d %d %d (unix)\n", pFile->h, rc, reserved));
|
|
|
|
@@ -34834,6 +38508,9 @@ static int unixCheckReservedLock(sqlite3_file *id, int *pResOut){
|
|
return rc;
|
|
}
|
|
|
|
+/* Forward declaration*/
|
|
+static int unixSleep(sqlite3_vfs*,int);
|
|
+
|
|
/*
|
|
** Set a posix-advisory-lock.
|
|
**
|
|
@@ -34855,16 +38532,17 @@ static int osSetPosixAdvisoryLock(
|
|
struct flock *pLock, /* The description of the lock */
|
|
unixFile *pFile /* Structure holding timeout value */
|
|
){
|
|
+ int tm = pFile->iBusyTimeout;
|
|
int rc = osFcntl(h,F_SETLK,pLock);
|
|
- while( rc<0 && pFile->iBusyTimeout>0 ){
|
|
+ while( rc<0 && tm>0 ){
|
|
/* On systems that support some kind of blocking file lock with a timeout,
|
|
** make appropriate changes here to invoke that blocking file lock. On
|
|
** generic posix, however, there is no such API. So we simply try the
|
|
** lock once every millisecond until either the timeout expires, or until
|
|
** the lock is obtained. */
|
|
- usleep(1000);
|
|
+ unixSleep(0,1000);
|
|
rc = osFcntl(h,F_SETLK,pLock);
|
|
- pFile->iBusyTimeout--;
|
|
+ tm--;
|
|
}
|
|
return rc;
|
|
}
|
|
@@ -34872,7 +38550,7 @@ static int osSetPosixAdvisoryLock(
|
|
|
|
|
|
/*
|
|
-** Attempt to set a system-lock on the file pFile. The lock is
|
|
+** Attempt to set a system-lock on the file pFile. The lock is
|
|
** described by pLock.
|
|
**
|
|
** If the pFile was opened read/write from unix-excl, then the only lock
|
|
@@ -34933,7 +38611,7 @@ static int unixFileLock(unixFile *pFile, struct flock *pLock){
|
|
**
|
|
** UNLOCKED -> SHARED
|
|
** SHARED -> RESERVED
|
|
-** SHARED -> (PENDING) -> EXCLUSIVE
|
|
+** SHARED -> EXCLUSIVE
|
|
** RESERVED -> (PENDING) -> EXCLUSIVE
|
|
** PENDING -> EXCLUSIVE
|
|
**
|
|
@@ -34964,21 +38642,22 @@ static int unixLock(sqlite3_file *id, int eFileLock){
|
|
**
|
|
** A process may only obtain a RESERVED lock after it has a SHARED lock.
|
|
** A RESERVED lock is implemented by grabbing a write-lock on the
|
|
- ** 'reserved byte'.
|
|
+ ** 'reserved byte'.
|
|
**
|
|
- ** A process may only obtain a PENDING lock after it has obtained a
|
|
- ** SHARED lock. A PENDING lock is implemented by obtaining a write-lock
|
|
- ** on the 'pending byte'. This ensures that no new SHARED locks can be
|
|
- ** obtained, but existing SHARED locks are allowed to persist. A process
|
|
- ** does not have to obtain a RESERVED lock on the way to a PENDING lock.
|
|
- ** This property is used by the algorithm for rolling back a journal file
|
|
- ** after a crash.
|
|
+ ** An EXCLUSIVE lock may only be requested after either a SHARED or
|
|
+ ** RESERVED lock is held. An EXCLUSIVE lock is implemented by obtaining
|
|
+ ** a write-lock on the entire 'shared byte range'. Since all other locks
|
|
+ ** require a read-lock on one of the bytes within this range, this ensures
|
|
+ ** that no other locks are held on the database.
|
|
**
|
|
- ** An EXCLUSIVE lock, obtained after a PENDING lock is held, is
|
|
- ** implemented by obtaining a write-lock on the entire 'shared byte
|
|
- ** range'. Since all other locks require a read-lock on one of the bytes
|
|
- ** within this range, this ensures that no other locks are held on the
|
|
- ** database.
|
|
+ ** If a process that holds a RESERVED lock requests an EXCLUSIVE, then
|
|
+ ** a PENDING lock is obtained first. A PENDING lock is implemented by
|
|
+ ** obtaining a write-lock on the 'pending byte'. This ensures that no new
|
|
+ ** SHARED locks can be obtained, but existing SHARED locks are allowed to
|
|
+ ** persist. If the call to this function fails to obtain the EXCLUSIVE
|
|
+ ** lock in this case, it holds the PENDING lock intead. The client may
|
|
+ ** then re-attempt the EXCLUSIVE lock later on, after existing SHARED
|
|
+ ** locks have cleared.
|
|
*/
|
|
int rc = SQLITE_OK;
|
|
unixFile *pFile = (unixFile*)id;
|
|
@@ -35019,7 +38698,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){
|
|
/* If some thread using this PID has a lock via a different unixFile*
|
|
** handle that precludes the requested lock, return BUSY.
|
|
*/
|
|
- if( (pFile->eFileLock!=pInode->eFileLock &&
|
|
+ if( (pFile->eFileLock!=pInode->eFileLock &&
|
|
(pInode->eFileLock>=PENDING_LOCK || eFileLock>SHARED_LOCK))
|
|
){
|
|
rc = SQLITE_BUSY;
|
|
@@ -35030,7 +38709,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){
|
|
** has a SHARED or RESERVED lock, then increment reference counts and
|
|
** return SQLITE_OK.
|
|
*/
|
|
- if( eFileLock==SHARED_LOCK &&
|
|
+ if( eFileLock==SHARED_LOCK &&
|
|
(pInode->eFileLock==SHARED_LOCK || pInode->eFileLock==RESERVED_LOCK) ){
|
|
assert( eFileLock==SHARED_LOCK );
|
|
assert( pFile->eFileLock==0 );
|
|
@@ -35048,8 +38727,8 @@ static int unixLock(sqlite3_file *id, int eFileLock){
|
|
*/
|
|
lock.l_len = 1L;
|
|
lock.l_whence = SEEK_SET;
|
|
- if( eFileLock==SHARED_LOCK
|
|
- || (eFileLock==EXCLUSIVE_LOCK && pFile->eFileLock<PENDING_LOCK)
|
|
+ if( eFileLock==SHARED_LOCK
|
|
+ || (eFileLock==EXCLUSIVE_LOCK && pFile->eFileLock==RESERVED_LOCK)
|
|
){
|
|
lock.l_type = (eFileLock==SHARED_LOCK?F_RDLCK:F_WRLCK);
|
|
lock.l_start = PENDING_BYTE;
|
|
@@ -35060,6 +38739,9 @@ static int unixLock(sqlite3_file *id, int eFileLock){
|
|
storeLastErrno(pFile, tErrno);
|
|
}
|
|
goto end_lock;
|
|
+ }else if( eFileLock==EXCLUSIVE_LOCK ){
|
|
+ pFile->eFileLock = PENDING_LOCK;
|
|
+ pInode->eFileLock = PENDING_LOCK;
|
|
}
|
|
}
|
|
|
|
@@ -35087,7 +38769,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){
|
|
if( unixFileLock(pFile, &lock) && rc==SQLITE_OK ){
|
|
/* This could happen with a network mount */
|
|
tErrno = errno;
|
|
- rc = SQLITE_IOERR_UNLOCK;
|
|
+ rc = SQLITE_IOERR_UNLOCK;
|
|
}
|
|
|
|
if( rc ){
|
|
@@ -35129,7 +38811,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){
|
|
}
|
|
}
|
|
}
|
|
-
|
|
+
|
|
|
|
#ifdef SQLITE_DEBUG
|
|
/* Set up the transaction-counter change checking flags when
|
|
@@ -35147,18 +38829,14 @@ static int unixLock(sqlite3_file *id, int eFileLock){
|
|
}
|
|
#endif
|
|
|
|
-
|
|
if( rc==SQLITE_OK ){
|
|
pFile->eFileLock = eFileLock;
|
|
pInode->eFileLock = eFileLock;
|
|
- }else if( eFileLock==EXCLUSIVE_LOCK ){
|
|
- pFile->eFileLock = PENDING_LOCK;
|
|
- pInode->eFileLock = PENDING_LOCK;
|
|
}
|
|
|
|
end_lock:
|
|
sqlite3_mutex_leave(pInode->pLockMutex);
|
|
- OSTRACE(("LOCK %d %s %s (unix)\n", pFile->h, azFileLock(eFileLock),
|
|
+ OSTRACE(("LOCK %d %s %s (unix)\n", pFile->h, azFileLock(eFileLock),
|
|
rc==SQLITE_OK ? "ok" : "failed"));
|
|
return rc;
|
|
}
|
|
@@ -35183,11 +38861,11 @@ static void setPendingFd(unixFile *pFile){
|
|
**
|
|
** If the locking level of the file descriptor is already at or below
|
|
** the requested locking level, this routine is a no-op.
|
|
-**
|
|
+**
|
|
** If handleNFSUnlock is true, then on downgrading an EXCLUSIVE_LOCK to SHARED
|
|
** the byte range is divided into 2 parts and the first part is unlocked then
|
|
-** set to a read lock, then the other part is simply unlocked. This works
|
|
-** around a bug in BSD NFS lockd (also seen on MacOSX 10.3+) that fails to
|
|
+** set to a read lock, then the other part is simply unlocked. This works
|
|
+** around a bug in BSD NFS lockd (also seen on MacOSX 10.3+) that fails to
|
|
** remove the write lock on a region when a read lock is set.
|
|
*/
|
|
static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
|
|
@@ -35225,7 +38903,7 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
|
|
|
|
/* downgrading to a shared lock on NFS involves clearing the write lock
|
|
** before establishing the readlock - to avoid a race condition we downgrade
|
|
- ** the lock in 2 blocks, so that part of the range will be covered by a
|
|
+ ** the lock in 2 blocks, so that part of the range will be covered by a
|
|
** write lock until the rest is covered by a read lock:
|
|
** 1: [WWWWW]
|
|
** 2: [....W]
|
|
@@ -35241,7 +38919,7 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
|
|
if( handleNFSUnlock ){
|
|
int tErrno; /* Error code from system call errors */
|
|
off_t divSize = SHARED_SIZE - 1;
|
|
-
|
|
+
|
|
lock.l_type = F_UNLCK;
|
|
lock.l_whence = SEEK_SET;
|
|
lock.l_start = SHARED_FIRST;
|
|
@@ -35283,11 +38961,11 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
|
|
lock.l_len = SHARED_SIZE;
|
|
if( unixFileLock(pFile, &lock) ){
|
|
/* In theory, the call to unixFileLock() cannot fail because another
|
|
- ** process is holding an incompatible lock. If it does, this
|
|
+ ** process is holding an incompatible lock. If it does, this
|
|
** indicates that the other process is not following the locking
|
|
** protocol. If this happens, return SQLITE_IOERR_RDLOCK. Returning
|
|
- ** SQLITE_BUSY would confuse the upper layer (in practice it causes
|
|
- ** an assert to fail). */
|
|
+ ** SQLITE_BUSY would confuse the upper layer (in practice it causes
|
|
+ ** an assert to fail). */
|
|
rc = SQLITE_IOERR_RDLOCK;
|
|
storeLastErrno(pFile, errno);
|
|
goto end_unlock;
|
|
@@ -35363,7 +39041,7 @@ static void unixUnmapfile(unixFile *pFd);
|
|
#endif
|
|
|
|
/*
|
|
-** This function performs the parts of the "close file" operation
|
|
+** This function performs the parts of the "close file" operation
|
|
** common to all locking schemes. It closes the directory and file
|
|
** handles, if they are valid, and sets all fields of the unixFile
|
|
** structure to 0.
|
|
@@ -35426,13 +39104,14 @@ static int unixClose(sqlite3_file *id){
|
|
if( pInode->nLock ){
|
|
/* If there are outstanding locks, do not actually close the file just
|
|
** yet because that would clear those locks. Instead, add the file
|
|
- ** descriptor to pInode->pUnused list. It will be automatically closed
|
|
+ ** descriptor to pInode->pUnused list. It will be automatically closed
|
|
** when the last lock is cleared.
|
|
*/
|
|
setPendingFd(pFile);
|
|
}
|
|
sqlite3_mutex_leave(pInode->pLockMutex);
|
|
releaseInodeInfo(pFile);
|
|
+ assert( pFile->pShm==0 );
|
|
rc = closeUnixFile(id);
|
|
unixLeaveMutex();
|
|
return rc;
|
|
@@ -35526,7 +39205,7 @@ static int dotlockCheckReservedLock(sqlite3_file *id, int *pResOut) {
|
|
unixFile *pFile = (unixFile*)id;
|
|
|
|
SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
|
|
-
|
|
+
|
|
assert( pFile );
|
|
reserved = osAccess((const char*)pFile->lockingContext, 0)==0;
|
|
OSTRACE(("TEST WR-LOCK %d %d %d (dotlock)\n", pFile->h, rc, reserved));
|
|
@@ -35580,7 +39259,7 @@ static int dotlockLock(sqlite3_file *id, int eFileLock) {
|
|
#endif
|
|
return SQLITE_OK;
|
|
}
|
|
-
|
|
+
|
|
/* grab an exclusive lock */
|
|
rc = osMkdir(zLockFile, 0777);
|
|
if( rc<0 ){
|
|
@@ -35595,8 +39274,8 @@ static int dotlockLock(sqlite3_file *id, int eFileLock) {
|
|
}
|
|
}
|
|
return rc;
|
|
- }
|
|
-
|
|
+ }
|
|
+
|
|
/* got it, set the type and return ok */
|
|
pFile->eFileLock = eFileLock;
|
|
return rc;
|
|
@@ -35620,7 +39299,7 @@ static int dotlockUnlock(sqlite3_file *id, int eFileLock) {
|
|
OSTRACE(("UNLOCK %d %d was %d pid=%d (dotlock)\n", pFile->h, eFileLock,
|
|
pFile->eFileLock, osGetpid(0)));
|
|
assert( eFileLock<=SHARED_LOCK );
|
|
-
|
|
+
|
|
/* no-op if possible */
|
|
if( pFile->eFileLock==eFileLock ){
|
|
return SQLITE_OK;
|
|
@@ -35633,7 +39312,7 @@ static int dotlockUnlock(sqlite3_file *id, int eFileLock) {
|
|
pFile->eFileLock = SHARED_LOCK;
|
|
return SQLITE_OK;
|
|
}
|
|
-
|
|
+
|
|
/* To fully unlock the database, delete the lock file */
|
|
assert( eFileLock==NO_LOCK );
|
|
rc = osRmdir(zLockFile);
|
|
@@ -35645,7 +39324,7 @@ static int dotlockUnlock(sqlite3_file *id, int eFileLock) {
|
|
rc = SQLITE_IOERR_UNLOCK;
|
|
storeLastErrno(pFile, tErrno);
|
|
}
|
|
- return rc;
|
|
+ return rc;
|
|
}
|
|
pFile->eFileLock = NO_LOCK;
|
|
return SQLITE_OK;
|
|
@@ -35692,7 +39371,7 @@ static int robust_flock(int fd, int op){
|
|
#else
|
|
# define robust_flock(a,b) flock(a,b)
|
|
#endif
|
|
-
|
|
+
|
|
|
|
/*
|
|
** This routine checks if there is a RESERVED lock held on the specified
|
|
@@ -35704,16 +39383,16 @@ static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){
|
|
int rc = SQLITE_OK;
|
|
int reserved = 0;
|
|
unixFile *pFile = (unixFile*)id;
|
|
-
|
|
+
|
|
SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
|
|
-
|
|
+
|
|
assert( pFile );
|
|
-
|
|
+
|
|
/* Check if a thread in this process holds such a lock */
|
|
if( pFile->eFileLock>SHARED_LOCK ){
|
|
reserved = 1;
|
|
}
|
|
-
|
|
+
|
|
/* Otherwise see if some other process holds it. */
|
|
if( !reserved ){
|
|
/* attempt to get the lock */
|
|
@@ -35724,7 +39403,7 @@ static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){
|
|
if ( lrc ) {
|
|
int tErrno = errno;
|
|
/* unlock failed with an error */
|
|
- lrc = SQLITE_IOERR_UNLOCK;
|
|
+ lrc = SQLITE_IOERR_UNLOCK;
|
|
storeLastErrno(pFile, tErrno);
|
|
rc = lrc;
|
|
}
|
|
@@ -35732,7 +39411,7 @@ static int flockCheckReservedLock(sqlite3_file *id, int *pResOut){
|
|
int tErrno = errno;
|
|
reserved = 1;
|
|
/* someone else might have it reserved */
|
|
- lrc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
|
|
+ lrc = sqliteErrorFromPosixError(tErrno, SQLITE_IOERR_LOCK);
|
|
if( IS_LOCK_ERROR(lrc) ){
|
|
storeLastErrno(pFile, tErrno);
|
|
rc = lrc;
|
|
@@ -35786,15 +39465,15 @@ static int flockLock(sqlite3_file *id, int eFileLock) {
|
|
|
|
assert( pFile );
|
|
|
|
- /* if we already have a lock, it is exclusive.
|
|
+ /* if we already have a lock, it is exclusive.
|
|
** Just adjust level and punt on outta here. */
|
|
if (pFile->eFileLock > NO_LOCK) {
|
|
pFile->eFileLock = eFileLock;
|
|
return SQLITE_OK;
|
|
}
|
|
-
|
|
+
|
|
/* grab an exclusive lock */
|
|
-
|
|
+
|
|
if (robust_flock(pFile->h, LOCK_EX | LOCK_NB)) {
|
|
int tErrno = errno;
|
|
/* didn't get, must be busy */
|
|
@@ -35806,7 +39485,7 @@ static int flockLock(sqlite3_file *id, int eFileLock) {
|
|
/* got it, set the type and return ok */
|
|
pFile->eFileLock = eFileLock;
|
|
}
|
|
- OSTRACE(("LOCK %d %s %s (flock)\n", pFile->h, azFileLock(eFileLock),
|
|
+ OSTRACE(("LOCK %d %s %s (flock)\n", pFile->h, azFileLock(eFileLock),
|
|
rc==SQLITE_OK ? "ok" : "failed"));
|
|
#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
|
|
if( (rc & 0xff) == SQLITE_IOERR ){
|
|
@@ -35826,23 +39505,23 @@ static int flockLock(sqlite3_file *id, int eFileLock) {
|
|
*/
|
|
static int flockUnlock(sqlite3_file *id, int eFileLock) {
|
|
unixFile *pFile = (unixFile*)id;
|
|
-
|
|
+
|
|
assert( pFile );
|
|
OSTRACE(("UNLOCK %d %d was %d pid=%d (flock)\n", pFile->h, eFileLock,
|
|
pFile->eFileLock, osGetpid(0)));
|
|
assert( eFileLock<=SHARED_LOCK );
|
|
-
|
|
+
|
|
/* no-op if possible */
|
|
if( pFile->eFileLock==eFileLock ){
|
|
return SQLITE_OK;
|
|
}
|
|
-
|
|
+
|
|
/* shared can just be set because we always have an exclusive */
|
|
if (eFileLock==SHARED_LOCK) {
|
|
pFile->eFileLock = eFileLock;
|
|
return SQLITE_OK;
|
|
}
|
|
-
|
|
+
|
|
/* no, really, unlock. */
|
|
if( robust_flock(pFile->h, LOCK_UN) ){
|
|
#ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS
|
|
@@ -35893,14 +39572,14 @@ static int semXCheckReservedLock(sqlite3_file *id, int *pResOut) {
|
|
unixFile *pFile = (unixFile*)id;
|
|
|
|
SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
|
|
-
|
|
+
|
|
assert( pFile );
|
|
|
|
/* Check if a thread in this process holds such a lock */
|
|
if( pFile->eFileLock>SHARED_LOCK ){
|
|
reserved = 1;
|
|
}
|
|
-
|
|
+
|
|
/* Otherwise see if some other process holds it. */
|
|
if( !reserved ){
|
|
sem_t *pSem = pFile->pInode->pSem;
|
|
@@ -35959,14 +39638,14 @@ static int semXLock(sqlite3_file *id, int eFileLock) {
|
|
sem_t *pSem = pFile->pInode->pSem;
|
|
int rc = SQLITE_OK;
|
|
|
|
- /* if we already have a lock, it is exclusive.
|
|
+ /* if we already have a lock, it is exclusive.
|
|
** Just adjust level and punt on outta here. */
|
|
if (pFile->eFileLock > NO_LOCK) {
|
|
pFile->eFileLock = eFileLock;
|
|
rc = SQLITE_OK;
|
|
goto sem_end_lock;
|
|
}
|
|
-
|
|
+
|
|
/* lock semaphore now but bail out when already locked. */
|
|
if( sem_trywait(pSem)==-1 ){
|
|
rc = SQLITE_BUSY;
|
|
@@ -35996,18 +39675,18 @@ static int semXUnlock(sqlite3_file *id, int eFileLock) {
|
|
OSTRACE(("UNLOCK %d %d was %d pid=%d (sem)\n", pFile->h, eFileLock,
|
|
pFile->eFileLock, osGetpid(0)));
|
|
assert( eFileLock<=SHARED_LOCK );
|
|
-
|
|
+
|
|
/* no-op if possible */
|
|
if( pFile->eFileLock==eFileLock ){
|
|
return SQLITE_OK;
|
|
}
|
|
-
|
|
+
|
|
/* shared can just be set because we always have an exclusive */
|
|
if (eFileLock==SHARED_LOCK) {
|
|
pFile->eFileLock = eFileLock;
|
|
return SQLITE_OK;
|
|
}
|
|
-
|
|
+
|
|
/* no, really unlock. */
|
|
if ( sem_post(pSem)==-1 ) {
|
|
int rc, tErrno = errno;
|
|
@@ -36015,7 +39694,7 @@ static int semXUnlock(sqlite3_file *id, int eFileLock) {
|
|
if( IS_LOCK_ERROR(rc) ){
|
|
storeLastErrno(pFile, tErrno);
|
|
}
|
|
- return rc;
|
|
+ return rc;
|
|
}
|
|
pFile->eFileLock = NO_LOCK;
|
|
return SQLITE_OK;
|
|
@@ -36081,7 +39760,7 @@ struct ByteRangeLockPB2
|
|
/*
|
|
** This is a utility for setting or clearing a bit-range lock on an
|
|
** AFP filesystem.
|
|
-**
|
|
+**
|
|
** Return SQLITE_OK on success, SQLITE_BUSY on failure.
|
|
*/
|
|
static int afpSetLock(
|
|
@@ -36093,14 +39772,14 @@ static int afpSetLock(
|
|
){
|
|
struct ByteRangeLockPB2 pb;
|
|
int err;
|
|
-
|
|
+
|
|
pb.unLockFlag = setLockFlag ? 0 : 1;
|
|
pb.startEndFlag = 0;
|
|
pb.offset = offset;
|
|
- pb.length = length;
|
|
+ pb.length = length;
|
|
pb.fd = pFile->h;
|
|
-
|
|
- OSTRACE(("AFPSETLOCK [%s] for %d%s in range %llx:%llx\n",
|
|
+
|
|
+ OSTRACE(("AFPSETLOCK [%s] for %d%s in range %llx:%llx\n",
|
|
(setLockFlag?"ON":"OFF"), pFile->h, (pb.fd==-1?"[testval-1]":""),
|
|
offset, length));
|
|
err = fsctl(path, afpfsByteRangeLock2FSCTL, &pb, 0);
|
|
@@ -36135,9 +39814,9 @@ static int afpCheckReservedLock(sqlite3_file *id, int *pResOut){
|
|
int reserved = 0;
|
|
unixFile *pFile = (unixFile*)id;
|
|
afpLockingContext *context;
|
|
-
|
|
+
|
|
SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
|
|
-
|
|
+
|
|
assert( pFile );
|
|
context = (afpLockingContext *) pFile->lockingContext;
|
|
if( context->reserved ){
|
|
@@ -36149,12 +39828,12 @@ static int afpCheckReservedLock(sqlite3_file *id, int *pResOut){
|
|
if( pFile->pInode->eFileLock>SHARED_LOCK ){
|
|
reserved = 1;
|
|
}
|
|
-
|
|
+
|
|
/* Otherwise see if some other process holds it.
|
|
*/
|
|
if( !reserved ){
|
|
/* lock the RESERVED byte */
|
|
- int lrc = afpSetLock(context->dbPath, pFile, RESERVED_BYTE, 1,1);
|
|
+ int lrc = afpSetLock(context->dbPath, pFile, RESERVED_BYTE, 1,1);
|
|
if( SQLITE_OK==lrc ){
|
|
/* if we succeeded in taking the reserved lock, unlock it to restore
|
|
** the original state */
|
|
@@ -36167,10 +39846,10 @@ static int afpCheckReservedLock(sqlite3_file *id, int *pResOut){
|
|
rc=lrc;
|
|
}
|
|
}
|
|
-
|
|
+
|
|
sqlite3_mutex_leave(pFile->pInode->pLockMutex);
|
|
OSTRACE(("TEST WR-LOCK %d %d %d (afp)\n", pFile->h, rc, reserved));
|
|
-
|
|
+
|
|
*pResOut = reserved;
|
|
return rc;
|
|
}
|
|
@@ -36204,7 +39883,7 @@ static int afpLock(sqlite3_file *id, int eFileLock){
|
|
unixFile *pFile = (unixFile*)id;
|
|
unixInodeInfo *pInode = pFile->pInode;
|
|
afpLockingContext *context = (afpLockingContext *) pFile->lockingContext;
|
|
-
|
|
+
|
|
assert( pFile );
|
|
OSTRACE(("LOCK %d %s was %s(%s,%d) pid=%d (afp)\n", pFile->h,
|
|
azFileLock(eFileLock), azFileLock(pFile->eFileLock),
|
|
@@ -36228,7 +39907,7 @@ static int afpLock(sqlite3_file *id, int eFileLock){
|
|
assert( pFile->eFileLock!=NO_LOCK || eFileLock==SHARED_LOCK );
|
|
assert( eFileLock!=PENDING_LOCK );
|
|
assert( eFileLock!=RESERVED_LOCK || pFile->eFileLock==SHARED_LOCK );
|
|
-
|
|
+
|
|
/* This mutex is needed because pFile->pInode is shared across threads
|
|
*/
|
|
pInode = pFile->pInode;
|
|
@@ -36237,18 +39916,18 @@ static int afpLock(sqlite3_file *id, int eFileLock){
|
|
/* If some thread using this PID has a lock via a different unixFile*
|
|
** handle that precludes the requested lock, return BUSY.
|
|
*/
|
|
- if( (pFile->eFileLock!=pInode->eFileLock &&
|
|
+ if( (pFile->eFileLock!=pInode->eFileLock &&
|
|
(pInode->eFileLock>=PENDING_LOCK || eFileLock>SHARED_LOCK))
|
|
){
|
|
rc = SQLITE_BUSY;
|
|
goto afp_end_lock;
|
|
}
|
|
-
|
|
+
|
|
/* If a SHARED lock is requested, and some thread using this PID already
|
|
** has a SHARED or RESERVED lock, then increment reference counts and
|
|
** return SQLITE_OK.
|
|
*/
|
|
- if( eFileLock==SHARED_LOCK &&
|
|
+ if( eFileLock==SHARED_LOCK &&
|
|
(pInode->eFileLock==SHARED_LOCK || pInode->eFileLock==RESERVED_LOCK) ){
|
|
assert( eFileLock==SHARED_LOCK );
|
|
assert( pFile->eFileLock==0 );
|
|
@@ -36258,12 +39937,12 @@ static int afpLock(sqlite3_file *id, int eFileLock){
|
|
pInode->nLock++;
|
|
goto afp_end_lock;
|
|
}
|
|
-
|
|
+
|
|
/* A PENDING lock is needed before acquiring a SHARED lock and before
|
|
** acquiring an EXCLUSIVE lock. For the SHARED lock, the PENDING will
|
|
** be released.
|
|
*/
|
|
- if( eFileLock==SHARED_LOCK
|
|
+ if( eFileLock==SHARED_LOCK
|
|
|| (eFileLock==EXCLUSIVE_LOCK && pFile->eFileLock<PENDING_LOCK)
|
|
){
|
|
int failed;
|
|
@@ -36273,30 +39952,30 @@ static int afpLock(sqlite3_file *id, int eFileLock){
|
|
goto afp_end_lock;
|
|
}
|
|
}
|
|
-
|
|
+
|
|
/* If control gets to this point, then actually go ahead and make
|
|
** operating system calls for the specified lock.
|
|
*/
|
|
if( eFileLock==SHARED_LOCK ){
|
|
int lrc1, lrc2, lrc1Errno = 0;
|
|
long lk, mask;
|
|
-
|
|
+
|
|
assert( pInode->nShared==0 );
|
|
assert( pInode->eFileLock==0 );
|
|
-
|
|
+
|
|
mask = (sizeof(long)==8) ? LARGEST_INT64 : 0x7fffffff;
|
|
/* Now get the read-lock SHARED_LOCK */
|
|
/* note that the quality of the randomness doesn't matter that much */
|
|
- lk = random();
|
|
+ lk = random();
|
|
pInode->sharedByte = (lk & mask)%(SHARED_SIZE - 1);
|
|
- lrc1 = afpSetLock(context->dbPath, pFile,
|
|
+ lrc1 = afpSetLock(context->dbPath, pFile,
|
|
SHARED_FIRST+pInode->sharedByte, 1, 1);
|
|
if( IS_LOCK_ERROR(lrc1) ){
|
|
lrc1Errno = pFile->lastErrno;
|
|
}
|
|
/* Drop the temporary PENDING lock */
|
|
lrc2 = afpSetLock(context->dbPath, pFile, PENDING_BYTE, 1, 0);
|
|
-
|
|
+
|
|
if( IS_LOCK_ERROR(lrc1) ) {
|
|
storeLastErrno(pFile, lrc1Errno);
|
|
rc = lrc1;
|
|
@@ -36331,34 +40010,34 @@ static int afpLock(sqlite3_file *id, int eFileLock){
|
|
}
|
|
if (!failed && eFileLock == EXCLUSIVE_LOCK) {
|
|
/* Acquire an EXCLUSIVE lock */
|
|
-
|
|
- /* Remove the shared lock before trying the range. we'll need to
|
|
+
|
|
+ /* Remove the shared lock before trying the range. we'll need to
|
|
** reestablish the shared lock if we can't get the afpUnlock
|
|
*/
|
|
if( !(failed = afpSetLock(context->dbPath, pFile, SHARED_FIRST +
|
|
pInode->sharedByte, 1, 0)) ){
|
|
int failed2 = SQLITE_OK;
|
|
/* now attemmpt to get the exclusive lock range */
|
|
- failed = afpSetLock(context->dbPath, pFile, SHARED_FIRST,
|
|
+ failed = afpSetLock(context->dbPath, pFile, SHARED_FIRST,
|
|
SHARED_SIZE, 1);
|
|
- if( failed && (failed2 = afpSetLock(context->dbPath, pFile,
|
|
+ if( failed && (failed2 = afpSetLock(context->dbPath, pFile,
|
|
SHARED_FIRST + pInode->sharedByte, 1, 1)) ){
|
|
/* Can't reestablish the shared lock. Sqlite can't deal, this is
|
|
** a critical I/O error
|
|
*/
|
|
- rc = ((failed & 0xff) == SQLITE_IOERR) ? failed2 :
|
|
+ rc = ((failed & 0xff) == SQLITE_IOERR) ? failed2 :
|
|
SQLITE_IOERR_LOCK;
|
|
goto afp_end_lock;
|
|
- }
|
|
+ }
|
|
}else{
|
|
- rc = failed;
|
|
+ rc = failed;
|
|
}
|
|
}
|
|
if( failed ){
|
|
rc = failed;
|
|
}
|
|
}
|
|
-
|
|
+
|
|
if( rc==SQLITE_OK ){
|
|
pFile->eFileLock = eFileLock;
|
|
pInode->eFileLock = eFileLock;
|
|
@@ -36366,10 +40045,10 @@ static int afpLock(sqlite3_file *id, int eFileLock){
|
|
pFile->eFileLock = PENDING_LOCK;
|
|
pInode->eFileLock = PENDING_LOCK;
|
|
}
|
|
-
|
|
+
|
|
afp_end_lock:
|
|
sqlite3_mutex_leave(pInode->pLockMutex);
|
|
- OSTRACE(("LOCK %d %s %s (afp)\n", pFile->h, azFileLock(eFileLock),
|
|
+ OSTRACE(("LOCK %d %s %s (afp)\n", pFile->h, azFileLock(eFileLock),
|
|
rc==SQLITE_OK ? "ok" : "failed"));
|
|
return rc;
|
|
}
|
|
@@ -36408,7 +40087,7 @@ static int afpUnlock(sqlite3_file *id, int eFileLock) {
|
|
SimulateIOErrorBenign(1);
|
|
SimulateIOError( h=(-1) )
|
|
SimulateIOErrorBenign(0);
|
|
-
|
|
+
|
|
#ifdef SQLITE_DEBUG
|
|
/* When reducing a lock such that other processes can start
|
|
** reading the database file again, make sure that the
|
|
@@ -36423,7 +40102,7 @@ static int afpUnlock(sqlite3_file *id, int eFileLock) {
|
|
|| pFile->transCntrChng==1 );
|
|
pFile->inNormalWrite = 0;
|
|
#endif
|
|
-
|
|
+
|
|
if( pFile->eFileLock==EXCLUSIVE_LOCK ){
|
|
rc = afpSetLock(context->dbPath, pFile, SHARED_FIRST, SHARED_SIZE, 0);
|
|
if( rc==SQLITE_OK && (eFileLock==SHARED_LOCK || pInode->nShared>1) ){
|
|
@@ -36436,11 +40115,11 @@ static int afpUnlock(sqlite3_file *id, int eFileLock) {
|
|
}
|
|
if( rc==SQLITE_OK && pFile->eFileLock>=PENDING_LOCK ){
|
|
rc = afpSetLock(context->dbPath, pFile, PENDING_BYTE, 1, 0);
|
|
- }
|
|
+ }
|
|
if( rc==SQLITE_OK && pFile->eFileLock>=RESERVED_LOCK && context->reserved ){
|
|
rc = afpSetLock(context->dbPath, pFile, RESERVED_BYTE, 1, 0);
|
|
- if( !rc ){
|
|
- context->reserved = 0;
|
|
+ if( !rc ){
|
|
+ context->reserved = 0;
|
|
}
|
|
}
|
|
if( rc==SQLITE_OK && (eFileLock==SHARED_LOCK || pInode->nShared>1)){
|
|
@@ -36473,7 +40152,7 @@ static int afpUnlock(sqlite3_file *id, int eFileLock) {
|
|
if( pInode->nLock==0 ) closePendingFds(pFile);
|
|
}
|
|
}
|
|
-
|
|
+
|
|
sqlite3_mutex_leave(pInode->pLockMutex);
|
|
if( rc==SQLITE_OK ){
|
|
pFile->eFileLock = eFileLock;
|
|
@@ -36482,7 +40161,7 @@ static int afpUnlock(sqlite3_file *id, int eFileLock) {
|
|
}
|
|
|
|
/*
|
|
-** Close a file & cleanup AFP specific locking context
|
|
+** Close a file & cleanup AFP specific locking context
|
|
*/
|
|
static int afpClose(sqlite3_file *id) {
|
|
int rc = SQLITE_OK;
|
|
@@ -36540,7 +40219,7 @@ static int nfsUnlock(sqlite3_file *id, int eFileLock){
|
|
/*
|
|
** The code above is the NFS lock implementation. The code is specific
|
|
** to MacOSX and does not work on other unix platforms. No alternative
|
|
-** is available.
|
|
+** is available.
|
|
**
|
|
********************* End of the NFS lock implementation **********************
|
|
******************************************************************************/
|
|
@@ -36548,7 +40227,7 @@ static int nfsUnlock(sqlite3_file *id, int eFileLock){
|
|
/******************************************************************************
|
|
**************** Non-locking sqlite3_file methods *****************************
|
|
**
|
|
-** The next division contains implementations for all methods of the
|
|
+** The next division contains implementations for all methods of the
|
|
** sqlite3_file object other than the locking methods. The locking
|
|
** methods were defined in divisions above (one locking method per
|
|
** division). Those methods that are common to all locking modes
|
|
@@ -36556,7 +40235,7 @@ static int nfsUnlock(sqlite3_file *id, int eFileLock){
|
|
*/
|
|
|
|
/*
|
|
-** Seek to the offset passed as the second argument, then read cnt
|
|
+** 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
|
|
@@ -36618,8 +40297,8 @@ static int seekAndRead(unixFile *id, sqlite3_int64 offset, void *pBuf, int cnt){
|
|
** wrong.
|
|
*/
|
|
static int unixRead(
|
|
- sqlite3_file *id,
|
|
- void *pBuf,
|
|
+ sqlite3_file *id,
|
|
+ void *pBuf,
|
|
int amt,
|
|
sqlite3_int64 offset
|
|
){
|
|
@@ -36629,12 +40308,12 @@ static int unixRead(
|
|
assert( offset>=0 );
|
|
assert( amt>0 );
|
|
|
|
- /* If this is a database file (not a journal, master-journal or temp
|
|
+ /* If this is a database file (not a journal, super-journal or temp
|
|
** file), the bytes in the locking range should never be read or written. */
|
|
#if 0
|
|
assert( pFile->pPreallocatedUnused==0
|
|
|| offset>=PENDING_BYTE+512
|
|
- || offset+amt<=PENDING_BYTE
|
|
+ || offset+amt<=PENDING_BYTE
|
|
);
|
|
#endif
|
|
|
|
@@ -36659,7 +40338,24 @@ static int unixRead(
|
|
if( got==amt ){
|
|
return SQLITE_OK;
|
|
}else if( got<0 ){
|
|
- /* lastErrno set by seekAndRead */
|
|
+ /* pFile->lastErrno has been set by seekAndRead().
|
|
+ ** Usually we return SQLITE_IOERR_READ here, though for some
|
|
+ ** kinds of errors we return SQLITE_IOERR_CORRUPTFS. The
|
|
+ ** SQLITE_IOERR_CORRUPTFS will be converted into SQLITE_CORRUPT
|
|
+ ** prior to returning to the application by the sqlite3ApiExit()
|
|
+ ** routine.
|
|
+ */
|
|
+ switch( pFile->lastErrno ){
|
|
+ case ERANGE:
|
|
+ case EIO:
|
|
+#ifdef ENXIO
|
|
+ case ENXIO:
|
|
+#endif
|
|
+#ifdef EDEVERR
|
|
+ case EDEVERR:
|
|
+#endif
|
|
+ return SQLITE_IOERR_CORRUPTFS;
|
|
+ }
|
|
return SQLITE_IOERR_READ;
|
|
}else{
|
|
storeLastErrno(pFile, 0); /* not a system error */
|
|
@@ -36672,7 +40368,7 @@ static int unixRead(
|
|
/*
|
|
** Attempt to seek the file-descriptor passed as the first argument to
|
|
** absolute offset iOff, then attempt to write nBuf bytes of data from
|
|
-** pBuf to it. If an error occurs, return -1 and set *piErrno. Otherwise,
|
|
+** pBuf to it. If an error occurs, return -1 and set *piErrno. Otherwise,
|
|
** return the actual number of bytes written (which may be less than
|
|
** nBuf).
|
|
*/
|
|
@@ -36732,22 +40428,22 @@ static int seekAndWrite(unixFile *id, i64 offset, const void *pBuf, int cnt){
|
|
** or some other error code on failure.
|
|
*/
|
|
static int unixWrite(
|
|
- sqlite3_file *id,
|
|
- const void *pBuf,
|
|
+ sqlite3_file *id,
|
|
+ const void *pBuf,
|
|
int amt,
|
|
- sqlite3_int64 offset
|
|
+ sqlite3_int64 offset
|
|
){
|
|
unixFile *pFile = (unixFile*)id;
|
|
int wrote = 0;
|
|
assert( id );
|
|
assert( amt>0 );
|
|
|
|
- /* If this is a database file (not a journal, master-journal or temp
|
|
+ /* If this is a database file (not a journal, super-journal or temp
|
|
** file), the bytes in the locking range should never be read or written. */
|
|
#if 0
|
|
assert( pFile->pPreallocatedUnused==0
|
|
|| offset>=PENDING_BYTE+512
|
|
- || offset+amt<=PENDING_BYTE
|
|
+ || offset+amt<=PENDING_BYTE
|
|
);
|
|
#endif
|
|
|
|
@@ -36789,7 +40485,7 @@ static int unixWrite(
|
|
}
|
|
}
|
|
#endif
|
|
-
|
|
+
|
|
while( (wrote = seekAndWrite(pFile, offset, pBuf, amt))<amt && wrote>0 ){
|
|
amt -= wrote;
|
|
offset += wrote;
|
|
@@ -36855,8 +40551,8 @@ SQLITE_API int sqlite3_fullsync_count = 0;
|
|
**
|
|
** SQLite sets the dataOnly flag if the size of the file is unchanged.
|
|
** The idea behind dataOnly is that it should only write the file content
|
|
-** to disk, not the inode. We only set dataOnly if the file size is
|
|
-** unchanged since the file size is part of the inode. However,
|
|
+** to disk, not the inode. We only set dataOnly if the file size is
|
|
+** unchanged since the file size is part of the inode. However,
|
|
** Ted Ts'o tells us that fdatasync() will also write the inode if the
|
|
** file size has changed. The only real difference between fdatasync()
|
|
** and fsync(), Ted tells us, is that fdatasync() will not flush the
|
|
@@ -36870,7 +40566,7 @@ static int full_fsync(int fd, int fullSync, int dataOnly){
|
|
int rc;
|
|
|
|
/* The following "ifdef/elif/else/" block has the same structure as
|
|
- ** the one below. It is replicated here solely to avoid cluttering
|
|
+ ** the one below. It is replicated here solely to avoid cluttering
|
|
** up the real code with the UNUSED_PARAMETER() macros.
|
|
*/
|
|
#ifdef SQLITE_NO_SYNC
|
|
@@ -36884,7 +40580,7 @@ static int full_fsync(int fd, int fullSync, int dataOnly){
|
|
UNUSED_PARAMETER(dataOnly);
|
|
#endif
|
|
|
|
- /* Record the number of times that we do a normal fsync() and
|
|
+ /* Record the number of times that we do a normal fsync() and
|
|
** FULLSYNC. This is used during testing to verify that this procedure
|
|
** gets called with the correct arguments.
|
|
*/
|
|
@@ -36910,11 +40606,11 @@ static int full_fsync(int fd, int fullSync, int dataOnly){
|
|
rc = 1;
|
|
}
|
|
/* If the FULLFSYNC failed, fall back to attempting an fsync().
|
|
- ** It shouldn't be possible for fullfsync to fail on the local
|
|
+ ** It shouldn't be possible for fullfsync to fail on the local
|
|
** file system (on OSX), so failure indicates that FULLFSYNC
|
|
- ** isn't supported for this file system. So, attempt an fsync
|
|
- ** and (for now) ignore the overhead of a superfluous fcntl call.
|
|
- ** It'd be better to detect fullfsync support once and avoid
|
|
+ ** isn't supported for this file system. So, attempt an fsync
|
|
+ ** and (for now) ignore the overhead of a superfluous fcntl call.
|
|
+ ** It'd be better to detect fullfsync support once and avoid
|
|
** the fcntl call every time sync is called.
|
|
*/
|
|
if( rc ) rc = fsync(fd);
|
|
@@ -36924,7 +40620,7 @@ static int full_fsync(int fd, int fullSync, int dataOnly){
|
|
** so currently we default to the macro that redefines fdatasync to fsync
|
|
*/
|
|
rc = fsync(fd);
|
|
-#else
|
|
+#else
|
|
rc = fdatasync(fd);
|
|
#if OS_VXWORKS
|
|
if( rc==-1 && errno==ENOTSUP ){
|
|
@@ -36975,7 +40671,7 @@ static int openDirectory(const char *zFilename, int *pFd){
|
|
if( zDirname[0]!='/' ) zDirname[0] = '.';
|
|
zDirname[1] = 0;
|
|
}
|
|
- fd = robust_open(zDirname, O_RDONLY|O_BINARY|O_NOFOLLOW, 0);
|
|
+ fd = robust_open(zDirname, O_RDONLY|O_BINARY, 0);
|
|
if( fd>=0 ){
|
|
OSTRACE(("OPENDIR %-3d %s\n", fd, zDirname));
|
|
}
|
|
@@ -37085,7 +40781,7 @@ static int unixTruncate(sqlite3_file *id, i64 nByte){
|
|
#if SQLITE_MAX_MMAP_SIZE>0
|
|
/* If the file was just truncated to a size smaller than the currently
|
|
** mapped region, reduce the effective mapping size as well. SQLite will
|
|
- ** use read() and write() to access data beyond this point from now on.
|
|
+ ** use read() and write() to access data beyond this point from now on.
|
|
*/
|
|
if( nByte<pFile->mmapSize ){
|
|
pFile->mmapSize = nByte;
|
|
@@ -37131,8 +40827,8 @@ static int unixFileSize(sqlite3_file *id, i64 *pSize){
|
|
static int proxyFileControl(sqlite3_file*,int,void*);
|
|
#endif
|
|
|
|
-/*
|
|
-** This function is called to handle the SQLITE_FCNTL_SIZE_HINT
|
|
+/*
|
|
+** This function is called to handle the SQLITE_FCNTL_SIZE_HINT
|
|
** file-control operation. Enlarge the database to nBytes in size
|
|
** (rounded up to the next chunk-size). If the database is already
|
|
** nBytes or larger, this routine is a no-op.
|
|
@@ -37141,7 +40837,7 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){
|
|
if( pFile->szChunk>0 ){
|
|
i64 nSize; /* Required file size */
|
|
struct stat buf; /* Used to hold return values of fstat() */
|
|
-
|
|
+
|
|
if( osFstat(pFile->h, &buf) ){
|
|
return SQLITE_IOERR_FSTAT;
|
|
}
|
|
@@ -37150,8 +40846,8 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){
|
|
if( nSize>(i64)buf.st_size ){
|
|
|
|
#if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
|
|
- /* The code below is handling the return value of osFallocate()
|
|
- ** correctly. posix_fallocate() is defined to "returns zero on success,
|
|
+ /* The code below is handling the return value of osFallocate()
|
|
+ ** correctly. posix_fallocate() is defined to "returns zero on success,
|
|
** or an error number on failure". See the manpage for details. */
|
|
int err;
|
|
do{
|
|
@@ -37159,7 +40855,7 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){
|
|
}while( err==EINTR );
|
|
if( err && err!=EINVAL ) return SQLITE_IOERR_WRITE;
|
|
#else
|
|
- /* If the OS does not have posix_fallocate(), fake it. Write a
|
|
+ /* If the OS does not have posix_fallocate(), fake it. Write a
|
|
** single byte to the last byte in each block that falls entirely
|
|
** within the extended region. Then, if required, a single byte
|
|
** at offset (nSize-1), to set the size of the file correctly.
|
|
@@ -37218,6 +40914,9 @@ static void unixModeBit(unixFile *pFile, unsigned char mask, int *pArg){
|
|
|
|
/* Forward declaration */
|
|
static int unixGetTempname(int nBuf, char *zBuf);
|
|
+#ifndef SQLITE_OMIT_WAL
|
|
+ static int unixFcntlExternalReader(unixFile*, int*);
|
|
+#endif
|
|
|
|
/*
|
|
** Information and control of an open file handle.
|
|
@@ -37285,7 +40984,9 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
|
|
}
|
|
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
|
case SQLITE_FCNTL_LOCK_TIMEOUT: {
|
|
+ int iOld = pFile->iBusyTimeout;
|
|
pFile->iBusyTimeout = *(int*)pArg;
|
|
+ *(int*)pArg = iOld;
|
|
return SQLITE_OK;
|
|
}
|
|
#endif
|
|
@@ -37332,15 +41033,24 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
|
|
return proxyFileControl(id,op,pArg);
|
|
}
|
|
#endif /* SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__) */
|
|
+
|
|
+ case SQLITE_FCNTL_EXTERNAL_READER: {
|
|
+#ifndef SQLITE_OMIT_WAL
|
|
+ return unixFcntlExternalReader((unixFile*)id, (int*)pArg);
|
|
+#else
|
|
+ *(int*)pArg = 0;
|
|
+ return SQLITE_OK;
|
|
+#endif
|
|
+ }
|
|
}
|
|
return SQLITE_NOTFOUND;
|
|
}
|
|
|
|
/*
|
|
** If pFd->sectorSize is non-zero when this function is called, it is a
|
|
-** no-op. Otherwise, the values of pFd->sectorSize and
|
|
-** pFd->deviceCharacteristics are set according to the file-system
|
|
-** characteristics.
|
|
+** no-op. Otherwise, the values of pFd->sectorSize and
|
|
+** pFd->deviceCharacteristics are set according to the file-system
|
|
+** characteristics.
|
|
**
|
|
** There are two versions of this function. One for QNX and one for all
|
|
** other systems.
|
|
@@ -37374,7 +41084,7 @@ static void setDeviceCharacteristics(unixFile *pFd){
|
|
static void setDeviceCharacteristics(unixFile *pFile){
|
|
if( pFile->sectorSize == 0 ){
|
|
struct statvfs fsInfo;
|
|
-
|
|
+
|
|
/* Set defaults for non-supported filesystems */
|
|
pFile->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE;
|
|
pFile->deviceCharacteristics = 0;
|
|
@@ -37483,7 +41193,7 @@ static int unixDeviceCharacteristics(sqlite3_file *id){
|
|
/*
|
|
** Return the system page size.
|
|
**
|
|
-** This function should not be called directly by other code in this file.
|
|
+** This function should not be called directly by other code in this file.
|
|
** Instead, it should be called via macro osGetpagesize().
|
|
*/
|
|
static int unixGetpagesize(void){
|
|
@@ -37501,7 +41211,7 @@ static int unixGetpagesize(void){
|
|
#ifndef SQLITE_OMIT_WAL
|
|
|
|
/*
|
|
-** Object used to represent an shared memory buffer.
|
|
+** Object used to represent an shared memory buffer.
|
|
**
|
|
** When multiple threads all reference the same wal-index, each thread
|
|
** has its own unixShm object, but they all point to a single instance
|
|
@@ -37521,7 +41231,7 @@ static int unixGetpagesize(void){
|
|
** nRef
|
|
**
|
|
** The following fields are read-only after the object is created:
|
|
-**
|
|
+**
|
|
** hShm
|
|
** zFilename
|
|
**
|
|
@@ -37541,6 +41251,7 @@ struct unixShmNode {
|
|
char **apRegion; /* Array of mapped shared-memory regions */
|
|
int nRef; /* Number of unixShm objects pointing to this */
|
|
unixShm *pFirst; /* All unixShm objects pointing to this */
|
|
+ int aLock[SQLITE_SHM_NLOCK]; /* # shared locks on slot, -1==excl lock */
|
|
#ifdef SQLITE_DEBUG
|
|
u8 exclMask; /* Mask of exclusive locks held */
|
|
u8 sharedMask; /* Mask of shared locks held */
|
|
@@ -37576,6 +41287,40 @@ struct unixShm {
|
|
#define UNIX_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */
|
|
#define UNIX_SHM_DMS (UNIX_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */
|
|
|
|
+/*
|
|
+** Use F_GETLK to check whether or not there are any readers with open
|
|
+** wal-mode transactions in other processes on database file pFile. If
|
|
+** no error occurs, return SQLITE_OK and set (*piOut) to 1 if there are
|
|
+** such transactions, or 0 otherwise. If an error occurs, return an
|
|
+** SQLite error code. The final value of *piOut is undefined in this
|
|
+** case.
|
|
+*/
|
|
+static int unixFcntlExternalReader(unixFile *pFile, int *piOut){
|
|
+ int rc = SQLITE_OK;
|
|
+ *piOut = 0;
|
|
+ if( pFile->pShm){
|
|
+ unixShmNode *pShmNode = pFile->pShm->pShmNode;
|
|
+ struct flock f;
|
|
+
|
|
+ memset(&f, 0, sizeof(f));
|
|
+ f.l_type = F_WRLCK;
|
|
+ f.l_whence = SEEK_SET;
|
|
+ f.l_start = UNIX_SHM_BASE + 3;
|
|
+ f.l_len = SQLITE_SHM_NLOCK - 3;
|
|
+
|
|
+ sqlite3_mutex_enter(pShmNode->pShmMutex);
|
|
+ if( osFcntl(pShmNode->hShm, F_GETLK, &f)<0 ){
|
|
+ rc = SQLITE_IOERR_LOCK;
|
|
+ }else{
|
|
+ *piOut = (f.l_type!=F_UNLCK);
|
|
+ }
|
|
+ sqlite3_mutex_leave(pShmNode->pShmMutex);
|
|
+ }
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+
|
|
/*
|
|
** Apply posix advisory locks for all bytes from ofst through ofst+n-1.
|
|
**
|
|
@@ -37604,13 +41349,20 @@ static int unixShmSystemLock(
|
|
assert( n>=1 && n<=SQLITE_SHM_NLOCK );
|
|
|
|
if( pShmNode->hShm>=0 ){
|
|
+ int res;
|
|
/* Initialize the locking parameters */
|
|
f.l_type = lockType;
|
|
f.l_whence = SEEK_SET;
|
|
f.l_start = ofst;
|
|
f.l_len = n;
|
|
- rc = osSetPosixAdvisoryLock(pShmNode->hShm, &f, pFile);
|
|
- rc = (rc!=(-1)) ? SQLITE_OK : SQLITE_BUSY;
|
|
+ res = osSetPosixAdvisoryLock(pShmNode->hShm, &f, pFile);
|
|
+ if( res==-1 ){
|
|
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
|
+ rc = (pFile->iBusyTimeout ? SQLITE_BUSY_TIMEOUT : SQLITE_BUSY);
|
|
+#else
|
|
+ rc = SQLITE_BUSY;
|
|
+#endif
|
|
+ }
|
|
}
|
|
|
|
/* Update the global lock state and do debug tracing */
|
|
@@ -37648,7 +41400,7 @@ static int unixShmSystemLock(
|
|
}
|
|
#endif
|
|
|
|
- return rc;
|
|
+ return rc;
|
|
}
|
|
|
|
/*
|
|
@@ -37704,7 +41456,7 @@ static void unixShmPurge(unixFile *pFd){
|
|
** take it now. Return SQLITE_OK if successful, or an SQLite error
|
|
** code otherwise.
|
|
**
|
|
-** If the DMS cannot be locked because this is a readonly_shm=1
|
|
+** If the DMS cannot be locked because this is a readonly_shm=1
|
|
** connection and no other process already holds a lock, return
|
|
** SQLITE_READONLY_CANTINIT and set pShmNode->isUnlocked=1.
|
|
*/
|
|
@@ -37715,7 +41467,7 @@ static int unixLockSharedMemory(unixFile *pDbFd, unixShmNode *pShmNode){
|
|
/* Use F_GETLK to determine the locks other processes are holding
|
|
** on the DMS byte. If it indicates that another process is holding
|
|
** a SHARED lock, then this process may also take a SHARED lock
|
|
- ** and proceed with opening the *-shm file.
|
|
+ ** and proceed with opening the *-shm file.
|
|
**
|
|
** Or, if no other process is holding any lock, then this process
|
|
** is the first to open it. In this case take an EXCLUSIVE lock on the
|
|
@@ -37763,20 +41515,20 @@ static int unixLockSharedMemory(unixFile *pDbFd, unixShmNode *pShmNode){
|
|
}
|
|
|
|
/*
|
|
-** Open a shared-memory area associated with open database file pDbFd.
|
|
+** Open a shared-memory area associated with open database file pDbFd.
|
|
** This particular implementation uses mmapped files.
|
|
**
|
|
** The file used to implement shared-memory is in the same directory
|
|
** as the open database file and has the same name as the open database
|
|
** file with the "-shm" suffix added. For example, if the database file
|
|
** is "/home/user1/config.db" then the file that is created and mmapped
|
|
-** for shared memory will be called "/home/user1/config.db-shm".
|
|
+** for shared memory will be called "/home/user1/config.db-shm".
|
|
**
|
|
** Another approach to is to use files in /dev/shm or /dev/tmp or an
|
|
** some other tmpfs mount. But if a file in a different directory
|
|
** from the database file is used, then differing access permissions
|
|
** or a chroot() might cause two different processes on the same
|
|
-** database to end up using different files for shared memory -
|
|
+** database to end up using different files for shared memory -
|
|
** meaning that their memory would not really be shared - resulting
|
|
** in database corruption. Nevertheless, this tmpfs file usage
|
|
** can be enabled at compile-time using -DSQLITE_SHM_DIRECTORY="/dev/shm"
|
|
@@ -37846,7 +41598,7 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
|
|
memset(pShmNode, 0, sizeof(*pShmNode)+nShmFilename);
|
|
zShm = pShmNode->zFilename = (char*)&pShmNode[1];
|
|
#ifdef SQLITE_SHM_DIRECTORY
|
|
- sqlite3_snprintf(nShmFilename, zShm,
|
|
+ sqlite3_snprintf(nShmFilename, zShm,
|
|
SQLITE_SHM_DIRECTORY "/sqlite-shm-%x-%x",
|
|
(u32)sStat.st_ino, (u32)sStat.st_dev);
|
|
#else
|
|
@@ -37921,22 +41673,22 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
|
|
}
|
|
|
|
/*
|
|
-** This function is called to obtain a pointer to region iRegion of the
|
|
-** shared-memory associated with the database file fd. Shared-memory regions
|
|
-** are numbered starting from zero. Each shared-memory region is szRegion
|
|
+** This function is called to obtain a pointer to region iRegion of the
|
|
+** shared-memory associated with the database file fd. Shared-memory regions
|
|
+** are numbered starting from zero. Each shared-memory region is szRegion
|
|
** bytes in size.
|
|
**
|
|
** If an error occurs, an error code is returned and *pp is set to NULL.
|
|
**
|
|
** Otherwise, if the bExtend parameter is 0 and the requested shared-memory
|
|
** region has not been allocated (by any client, including one running in a
|
|
-** separate process), then *pp is set to NULL and SQLITE_OK returned. If
|
|
-** bExtend is non-zero and the requested shared-memory region has not yet
|
|
+** separate process), then *pp is set to NULL and SQLITE_OK returned. If
|
|
+** bExtend is non-zero and the requested shared-memory region has not yet
|
|
** been allocated, it is allocated by this function.
|
|
**
|
|
** If the shared-memory region has already been allocated or is allocated by
|
|
-** this call as described above, then it is mapped into this processes
|
|
-** address space (if it is not already), *pp is set to point to the mapped
|
|
+** this call as described above, then it is mapped into this processes
|
|
+** address space (if it is not already), *pp is set to point to the mapped
|
|
** memory and SQLITE_OK returned.
|
|
*/
|
|
static int unixShmMap(
|
|
@@ -37991,7 +41743,7 @@ static int unixShmMap(
|
|
rc = SQLITE_IOERR_SHMSIZE;
|
|
goto shmpage_out;
|
|
}
|
|
-
|
|
+
|
|
if( sStat.st_size<nByte ){
|
|
/* The requested memory region does not exist. If bExtend is set to
|
|
** false, exit early. *pp will be set to NULL and SQLITE_OK returned.
|
|
@@ -38040,7 +41792,7 @@ static int unixShmMap(
|
|
void *pMem;
|
|
if( pShmNode->hShm>=0 ){
|
|
pMem = osMmap(0, nMap,
|
|
- pShmNode->isReadonly ? PROT_READ : PROT_READ|PROT_WRITE,
|
|
+ pShmNode->isReadonly ? PROT_READ : PROT_READ|PROT_WRITE,
|
|
MAP_SHARED, pShmNode->hShm, szRegion*(i64)pShmNode->nRegion
|
|
);
|
|
if( pMem==MAP_FAILED ){
|
|
@@ -38074,6 +41826,38 @@ static int unixShmMap(
|
|
return rc;
|
|
}
|
|
|
|
+/*
|
|
+** Check that the pShmNode->aLock[] array comports with the locking bitmasks
|
|
+** held by each client. Return true if it does, or false otherwise. This
|
|
+** is to be used in an assert(). e.g.
|
|
+**
|
|
+** assert( assertLockingArrayOk(pShmNode) );
|
|
+*/
|
|
+#ifdef SQLITE_DEBUG
|
|
+static int assertLockingArrayOk(unixShmNode *pShmNode){
|
|
+ unixShm *pX;
|
|
+ int aLock[SQLITE_SHM_NLOCK];
|
|
+ assert( sqlite3_mutex_held(pShmNode->pShmMutex) );
|
|
+
|
|
+ memset(aLock, 0, sizeof(aLock));
|
|
+ for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
|
|
+ int i;
|
|
+ for(i=0; i<SQLITE_SHM_NLOCK; i++){
|
|
+ if( pX->exclMask & (1<<i) ){
|
|
+ assert( aLock[i]==0 );
|
|
+ aLock[i] = -1;
|
|
+ }else if( pX->sharedMask & (1<<i) ){
|
|
+ assert( aLock[i]>=0 );
|
|
+ aLock[i]++;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ assert( 0==memcmp(pShmNode->aLock, aLock, sizeof(aLock)) );
|
|
+ return (memcmp(pShmNode->aLock, aLock, sizeof(aLock))==0);
|
|
+}
|
|
+#endif
|
|
+
|
|
/*
|
|
** Change the lock state for a shared-memory segment.
|
|
**
|
|
@@ -38089,11 +41873,17 @@ static int unixShmLock(
|
|
int flags /* What to do with the lock */
|
|
){
|
|
unixFile *pDbFd = (unixFile*)fd; /* Connection holding shared memory */
|
|
- unixShm *p = pDbFd->pShm; /* The shared memory being locked */
|
|
- unixShm *pX; /* For looping over all siblings */
|
|
- unixShmNode *pShmNode = p->pShmNode; /* The underlying file iNode */
|
|
+ unixShm *p; /* The shared memory being locked */
|
|
+ unixShmNode *pShmNode; /* The underlying file iNode */
|
|
int rc = SQLITE_OK; /* Result code */
|
|
u16 mask; /* Mask of locks to take or release */
|
|
+ int *aLock;
|
|
+
|
|
+ p = pDbFd->pShm;
|
|
+ if( p==0 ) return SQLITE_IOERR_SHMLOCK;
|
|
+ pShmNode = p->pShmNode;
|
|
+ if( NEVER(pShmNode==0) ) return SQLITE_IOERR_SHMLOCK;
|
|
+ aLock = pShmNode->aLock;
|
|
|
|
assert( pShmNode==pDbFd->pInode->pShmNode );
|
|
assert( pShmNode->pInode==pDbFd->pInode );
|
|
@@ -38107,81 +41897,101 @@ static int unixShmLock(
|
|
assert( pShmNode->hShm>=0 || pDbFd->pInode->bProcessLock==1 );
|
|
assert( pShmNode->hShm<0 || pDbFd->pInode->bProcessLock==0 );
|
|
|
|
+ /* Check that, if this to be a blocking lock, no locks that occur later
|
|
+ ** in the following list than the lock being obtained are already held:
|
|
+ **
|
|
+ ** 1. Checkpointer lock (ofst==1).
|
|
+ ** 2. Write lock (ofst==0).
|
|
+ ** 3. Read locks (ofst>=3 && ofst<SQLITE_SHM_NLOCK).
|
|
+ **
|
|
+ ** In other words, if this is a blocking lock, none of the locks that
|
|
+ ** occur later in the above list than the lock being obtained may be
|
|
+ ** held.
|
|
+ **
|
|
+ ** It is not permitted to block on the RECOVER lock.
|
|
+ */
|
|
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
|
+ assert( (flags & SQLITE_SHM_UNLOCK) || pDbFd->iBusyTimeout==0 || (
|
|
+ (ofst!=2) /* not RECOVER */
|
|
+ && (ofst!=1 || (p->exclMask|p->sharedMask)==0)
|
|
+ && (ofst!=0 || (p->exclMask|p->sharedMask)<3)
|
|
+ && (ofst<3 || (p->exclMask|p->sharedMask)<(1<<ofst))
|
|
+ ));
|
|
+#endif
|
|
+
|
|
mask = (1<<(ofst+n)) - (1<<ofst);
|
|
assert( n>1 || mask==(1<<ofst) );
|
|
sqlite3_mutex_enter(pShmNode->pShmMutex);
|
|
+ assert( assertLockingArrayOk(pShmNode) );
|
|
if( flags & SQLITE_SHM_UNLOCK ){
|
|
- u16 allMask = 0; /* Mask of locks held by siblings */
|
|
-
|
|
- /* See if any siblings hold this same lock */
|
|
- for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
|
|
- if( pX==p ) continue;
|
|
- assert( (pX->exclMask & (p->exclMask|p->sharedMask))==0 );
|
|
- allMask |= pX->sharedMask;
|
|
- }
|
|
+ if( (p->exclMask|p->sharedMask) & mask ){
|
|
+ int ii;
|
|
+ int bUnlock = 1;
|
|
|
|
- /* Unlock the system-level locks */
|
|
- if( (mask & allMask)==0 ){
|
|
- rc = unixShmSystemLock(pDbFd, F_UNLCK, ofst+UNIX_SHM_BASE, n);
|
|
- }else{
|
|
- rc = SQLITE_OK;
|
|
- }
|
|
+ for(ii=ofst; ii<ofst+n; ii++){
|
|
+ if( aLock[ii]>((p->sharedMask & (1<<ii)) ? 1 : 0) ){
|
|
+ bUnlock = 0;
|
|
+ }
|
|
+ }
|
|
|
|
- /* Undo the local locks */
|
|
- if( rc==SQLITE_OK ){
|
|
- p->exclMask &= ~mask;
|
|
- p->sharedMask &= ~mask;
|
|
- }
|
|
- }else if( flags & SQLITE_SHM_SHARED ){
|
|
- u16 allShared = 0; /* Union of locks held by connections other than "p" */
|
|
+ if( bUnlock ){
|
|
+ rc = unixShmSystemLock(pDbFd, F_UNLCK, ofst+UNIX_SHM_BASE, n);
|
|
+ if( rc==SQLITE_OK ){
|
|
+ memset(&aLock[ofst], 0, sizeof(int)*n);
|
|
+ }
|
|
+ }else if( ALWAYS(p->sharedMask & (1<<ofst)) ){
|
|
+ assert( n==1 && aLock[ofst]>1 );
|
|
+ aLock[ofst]--;
|
|
+ }
|
|
|
|
- /* Find out which shared locks are already held by sibling connections.
|
|
- ** If any sibling already holds an exclusive lock, go ahead and return
|
|
- ** SQLITE_BUSY.
|
|
- */
|
|
- for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
|
|
- if( (pX->exclMask & mask)!=0 ){
|
|
- rc = SQLITE_BUSY;
|
|
- break;
|
|
+ /* Undo the local locks */
|
|
+ if( rc==SQLITE_OK ){
|
|
+ p->exclMask &= ~mask;
|
|
+ p->sharedMask &= ~mask;
|
|
}
|
|
- allShared |= pX->sharedMask;
|
|
}
|
|
-
|
|
- /* Get shared locks at the system level, if necessary */
|
|
- if( rc==SQLITE_OK ){
|
|
- if( (allShared & mask)==0 ){
|
|
+ }else if( flags & SQLITE_SHM_SHARED ){
|
|
+ assert( n==1 );
|
|
+ assert( (p->exclMask & (1<<ofst))==0 );
|
|
+ if( (p->sharedMask & mask)==0 ){
|
|
+ if( aLock[ofst]<0 ){
|
|
+ rc = SQLITE_BUSY;
|
|
+ }else if( aLock[ofst]==0 ){
|
|
rc = unixShmSystemLock(pDbFd, F_RDLCK, ofst+UNIX_SHM_BASE, n);
|
|
- }else{
|
|
- rc = SQLITE_OK;
|
|
}
|
|
- }
|
|
|
|
- /* Get the local shared locks */
|
|
- if( rc==SQLITE_OK ){
|
|
- p->sharedMask |= mask;
|
|
+ /* Get the local shared locks */
|
|
+ if( rc==SQLITE_OK ){
|
|
+ p->sharedMask |= mask;
|
|
+ aLock[ofst]++;
|
|
+ }
|
|
}
|
|
}else{
|
|
/* Make sure no sibling connections hold locks that will block this
|
|
- ** lock. If any do, return SQLITE_BUSY right away.
|
|
- */
|
|
- for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
|
|
- if( (pX->exclMask & mask)!=0 || (pX->sharedMask & mask)!=0 ){
|
|
+ ** lock. If any do, return SQLITE_BUSY right away. */
|
|
+ int ii;
|
|
+ for(ii=ofst; ii<ofst+n; ii++){
|
|
+ assert( (p->sharedMask & mask)==0 );
|
|
+ if( ALWAYS((p->exclMask & (1<<ii))==0) && aLock[ii] ){
|
|
rc = SQLITE_BUSY;
|
|
break;
|
|
}
|
|
}
|
|
-
|
|
- /* Get the exclusive locks at the system level. Then if successful
|
|
- ** also mark the local connection as being locked.
|
|
- */
|
|
+
|
|
+ /* Get the exclusive locks at the system level. Then if successful
|
|
+ ** also update the in-memory values. */
|
|
if( rc==SQLITE_OK ){
|
|
rc = unixShmSystemLock(pDbFd, F_WRLCK, ofst+UNIX_SHM_BASE, n);
|
|
if( rc==SQLITE_OK ){
|
|
assert( (p->sharedMask & mask)==0 );
|
|
p->exclMask |= mask;
|
|
+ for(ii=ofst; ii<ofst+n; ii++){
|
|
+ aLock[ii] = -1;
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
+ assert( assertLockingArrayOk(pShmNode) );
|
|
sqlite3_mutex_leave(pShmNode->pShmMutex);
|
|
OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %03x,%03x\n",
|
|
p->id, osGetpid(0), p->sharedMask, p->exclMask));
|
|
@@ -38189,7 +41999,7 @@ static int unixShmLock(
|
|
}
|
|
|
|
/*
|
|
-** Implement a memory barrier or memory fence on shared memory.
|
|
+** Implement a memory barrier or memory fence on shared memory.
|
|
**
|
|
** All loads and stores begun before the barrier must complete before
|
|
** any load or store begun after the barrier.
|
|
@@ -38199,15 +42009,15 @@ static void unixShmBarrier(
|
|
){
|
|
UNUSED_PARAMETER(fd);
|
|
sqlite3MemoryBarrier(); /* compiler-defined memory barrier */
|
|
- assert( fd->pMethods->xLock==nolockLock
|
|
- || unixFileMutexNotheld((unixFile*)fd)
|
|
+ assert( fd->pMethods->xLock==nolockLock
|
|
+ || unixFileMutexNotheld((unixFile*)fd)
|
|
);
|
|
unixEnterMutex(); /* Also mutex, for redundancy */
|
|
unixLeaveMutex();
|
|
}
|
|
|
|
/*
|
|
-** Close a connection to shared-memory. Delete the underlying
|
|
+** Close a connection to shared-memory. Delete the underlying
|
|
** storage if deleteFlag is true.
|
|
**
|
|
** If there is no shared memory associated with the connection then this
|
|
@@ -38281,7 +42091,7 @@ static void unixUnmapfile(unixFile *pFd){
|
|
}
|
|
|
|
/*
|
|
-** Attempt to set the size of the memory mapping maintained by file
|
|
+** Attempt to set the size of the memory mapping maintained by file
|
|
** descriptor pFd to nNew bytes. Any existing mapping is discarded.
|
|
**
|
|
** If successful, this function sets the following variables:
|
|
@@ -38373,14 +42183,14 @@ static void unixRemapfile(
|
|
|
|
/*
|
|
** Memory map or remap the file opened by file-descriptor pFd (if the file
|
|
-** is already mapped, the existing mapping is replaced by the new). Or, if
|
|
-** there already exists a mapping for this file, and there are still
|
|
+** is already mapped, the existing mapping is replaced by the new). Or, if
|
|
+** there already exists a mapping for this file, and there are still
|
|
** outstanding xFetch() references to it, this function is a no-op.
|
|
**
|
|
-** If parameter nByte is non-negative, then it is the requested size of
|
|
-** the mapping to create. Otherwise, if nByte is less than zero, then the
|
|
+** If parameter nByte is non-negative, then it is the requested size of
|
|
+** the mapping to create. Otherwise, if nByte is less than zero, then the
|
|
** requested size is the size of the file on disk. The actual size of the
|
|
-** created mapping is either the requested size or the value configured
|
|
+** created mapping is either the requested size or the value configured
|
|
** using SQLITE_FCNTL_MMAP_LIMIT, whichever is smaller.
|
|
**
|
|
** SQLITE_OK is returned if no error occurs (even if the mapping is not
|
|
@@ -38421,7 +42231,7 @@ static int unixMapfile(unixFile *pFd, i64 nMap){
|
|
** Finally, if an error does occur, return an SQLite error code. The final
|
|
** value of *pp is undefined in this case.
|
|
**
|
|
-** If this function does return a pointer, the caller must eventually
|
|
+** If this function does return a pointer, the caller must eventually
|
|
** release the reference by calling unixUnfetch().
|
|
*/
|
|
static int unixFetch(sqlite3_file *fd, i64 iOff, int nAmt, void **pp){
|
|
@@ -38446,13 +42256,13 @@ static int unixFetch(sqlite3_file *fd, i64 iOff, int nAmt, void **pp){
|
|
}
|
|
|
|
/*
|
|
-** If the third argument is non-NULL, then this function releases a
|
|
+** If the third argument is non-NULL, then this function releases a
|
|
** reference obtained by an earlier call to unixFetch(). The second
|
|
** argument passed to this function must be the same as the corresponding
|
|
-** argument that was passed to the unixFetch() invocation.
|
|
+** argument that was passed to the unixFetch() invocation.
|
|
**
|
|
-** Or, if the third argument is NULL, then this function is being called
|
|
-** to inform the VFS layer that, according to POSIX, any existing mapping
|
|
+** Or, if the third argument is NULL, then this function is being called
|
|
+** to inform the VFS layer that, according to POSIX, any existing mapping
|
|
** may now be invalid and should be unmapped.
|
|
*/
|
|
static int unixUnfetch(sqlite3_file *fd, i64 iOff, void *p){
|
|
@@ -38460,7 +42270,7 @@ static int unixUnfetch(sqlite3_file *fd, i64 iOff, void *p){
|
|
unixFile *pFd = (unixFile *)fd; /* The underlying database file */
|
|
UNUSED_PARAMETER(iOff);
|
|
|
|
- /* If p==0 (unmap the entire file) then there must be no outstanding
|
|
+ /* If p==0 (unmap the entire file) then there must be no outstanding
|
|
** xFetch references. Or, if p!=0 (meaning it is an xFetch reference),
|
|
** then there must be at least one outstanding. */
|
|
assert( (p==0)==(pFd->nFetchOut==0) );
|
|
@@ -38668,8 +42478,8 @@ IOMETHODS(
|
|
#endif
|
|
|
|
#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
|
|
-/*
|
|
-** This "finder" function attempts to determine the best locking strategy
|
|
+/*
|
|
+** This "finder" function attempts to determine the best locking strategy
|
|
** for the database file "filePath". It then returns the sqlite3_io_methods
|
|
** object that implements that strategy.
|
|
**
|
|
@@ -38711,8 +42521,8 @@ static const sqlite3_io_methods *autolockIoFinderImpl(
|
|
}
|
|
|
|
/* Default case. Handles, amongst others, "nfs".
|
|
- ** Test byte-range lock using fcntl(). If the call succeeds,
|
|
- ** assume that the file-system supports POSIX style locks.
|
|
+ ** Test byte-range lock using fcntl(). If the call succeeds,
|
|
+ ** assume that the file-system supports POSIX style locks.
|
|
*/
|
|
lockInfo.l_len = 1;
|
|
lockInfo.l_start = 0;
|
|
@@ -38728,7 +42538,7 @@ static const sqlite3_io_methods *autolockIoFinderImpl(
|
|
return &dotlockIoMethods;
|
|
}
|
|
}
|
|
-static const sqlite3_io_methods
|
|
+static const sqlite3_io_methods
|
|
*(*const autolockIoFinder)(const char*,unixFile*) = autolockIoFinderImpl;
|
|
|
|
#endif /* defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE */
|
|
@@ -38764,7 +42574,7 @@ static const sqlite3_io_methods *vxworksIoFinderImpl(
|
|
return &semIoMethods;
|
|
}
|
|
}
|
|
-static const sqlite3_io_methods
|
|
+static const sqlite3_io_methods
|
|
*(*const vxworksIoFinder)(const char*,unixFile*) = vxworksIoFinderImpl;
|
|
|
|
#endif /* OS_VXWORKS */
|
|
@@ -38892,14 +42702,14 @@ static int fillInUnixFile(
|
|
robust_close(pNew, h, __LINE__);
|
|
h = -1;
|
|
}
|
|
- unixLeaveMutex();
|
|
+ unixLeaveMutex();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
else if( pLockingStyle == &dotlockIoMethods ){
|
|
/* Dotfile locking uses the file path so it needs to be included in
|
|
- ** the dotlockLockingContext
|
|
+ ** the dotlockLockingContext
|
|
*/
|
|
char *zLockFile;
|
|
int nFilename;
|
|
@@ -38937,7 +42747,7 @@ static int fillInUnixFile(
|
|
unixLeaveMutex();
|
|
}
|
|
#endif
|
|
-
|
|
+
|
|
storeLastErrno(pNew, 0);
|
|
#if OS_VXWORKS
|
|
if( rc!=SQLITE_OK ){
|
|
@@ -38950,32 +42760,42 @@ static int fillInUnixFile(
|
|
if( rc!=SQLITE_OK ){
|
|
if( h>=0 ) robust_close(pNew, h, __LINE__);
|
|
}else{
|
|
- pNew->pMethod = pLockingStyle;
|
|
+ pId->pMethods = pLockingStyle;
|
|
OpenCounter(+1);
|
|
verifyDbFile(pNew);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
+/*
|
|
+** Directories to consider for temp files.
|
|
+*/
|
|
+static const char *azTempDirs[] = {
|
|
+ 0,
|
|
+ 0,
|
|
+ "/var/tmp",
|
|
+ "/usr/tmp",
|
|
+ "/tmp",
|
|
+ "."
|
|
+};
|
|
+
|
|
+/*
|
|
+** Initialize first two members of azTempDirs[] array.
|
|
+*/
|
|
+static void unixTempFileInit(void){
|
|
+ azTempDirs[0] = getenv("SQLITE_TMPDIR");
|
|
+ azTempDirs[1] = getenv("TMPDIR");
|
|
+}
|
|
+
|
|
/*
|
|
** Return the name of a directory in which to put temporary files.
|
|
** If no suitable temporary file directory can be found, return NULL.
|
|
*/
|
|
static const char *unixTempFileDir(void){
|
|
- static const char *azDirs[] = {
|
|
- 0,
|
|
- 0,
|
|
- "/var/tmp",
|
|
- "/usr/tmp",
|
|
- "/tmp",
|
|
- "."
|
|
- };
|
|
unsigned int i = 0;
|
|
struct stat buf;
|
|
const char *zDir = sqlite3_temp_directory;
|
|
|
|
- if( !azDirs[0] ) azDirs[0] = getenv("SQLITE_TMPDIR");
|
|
- if( !azDirs[1] ) azDirs[1] = getenv("TMPDIR");
|
|
while(1){
|
|
if( zDir!=0
|
|
&& osStat(zDir, &buf)==0
|
|
@@ -38984,8 +42804,8 @@ static const char *unixTempFileDir(void){
|
|
){
|
|
return zDir;
|
|
}
|
|
- if( i>=sizeof(azDirs)/sizeof(azDirs[0]) ) break;
|
|
- zDir = azDirs[i++];
|
|
+ if( i>=sizeof(azTempDirs)/sizeof(azTempDirs[0]) ) break;
|
|
+ zDir = azTempDirs[i++];
|
|
}
|
|
return 0;
|
|
}
|
|
@@ -38998,26 +42818,35 @@ static const char *unixTempFileDir(void){
|
|
static int unixGetTempname(int nBuf, char *zBuf){
|
|
const char *zDir;
|
|
int iLimit = 0;
|
|
+ int rc = SQLITE_OK;
|
|
|
|
/* It's odd to simulate an io-error here, but really this is just
|
|
** using the io-error infrastructure to test that SQLite handles this
|
|
- ** function failing.
|
|
+ ** function failing.
|
|
*/
|
|
zBuf[0] = 0;
|
|
SimulateIOError( return SQLITE_IOERR );
|
|
|
|
+ sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
|
|
zDir = unixTempFileDir();
|
|
- if( zDir==0 ) return SQLITE_IOERR_GETTEMPPATH;
|
|
- do{
|
|
- u64 r;
|
|
- sqlite3_randomness(sizeof(r), &r);
|
|
- assert( nBuf>2 );
|
|
- zBuf[nBuf-2] = 0;
|
|
- sqlite3_snprintf(nBuf, zBuf, "%s/"SQLITE_TEMP_FILE_PREFIX"%llx%c",
|
|
- zDir, r, 0);
|
|
- if( zBuf[nBuf-2]!=0 || (iLimit++)>10 ) return SQLITE_ERROR;
|
|
- }while( osAccess(zBuf,0)==0 );
|
|
- return SQLITE_OK;
|
|
+ if( zDir==0 ){
|
|
+ rc = SQLITE_IOERR_GETTEMPPATH;
|
|
+ }else{
|
|
+ do{
|
|
+ u64 r;
|
|
+ sqlite3_randomness(sizeof(r), &r);
|
|
+ assert( nBuf>2 );
|
|
+ zBuf[nBuf-2] = 0;
|
|
+ sqlite3_snprintf(nBuf, zBuf, "%s/"SQLITE_TEMP_FILE_PREFIX"%llx%c",
|
|
+ zDir, r, 0);
|
|
+ if( zBuf[nBuf-2]!=0 || (iLimit++)>10 ){
|
|
+ rc = SQLITE_ERROR;
|
|
+ break;
|
|
+ }
|
|
+ }while( osAccess(zBuf,0)==0 );
|
|
+ }
|
|
+ sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
|
|
+ return rc;
|
|
}
|
|
|
|
#if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
|
|
@@ -39030,8 +42859,8 @@ static int proxyTransformUnixFile(unixFile*, const char*);
|
|
#endif
|
|
|
|
/*
|
|
-** Search for an unused file descriptor that was opened on the database
|
|
-** file (not a journal or master-journal file) identified by pathname
|
|
+** Search for an unused file descriptor that was opened on the database
|
|
+** file (not a journal or super-journal file) identified by pathname
|
|
** zPath with SQLITE_OPEN_XXX flags matching those passed as the second
|
|
** argument to this function.
|
|
**
|
|
@@ -39039,7 +42868,7 @@ static int proxyTransformUnixFile(unixFile*, const char*);
|
|
** but the associated file descriptor could not be closed because some
|
|
** other file descriptor open on the same file is holding a file-lock.
|
|
** Refer to comments in the unixClose() function and the lengthy comment
|
|
-** describing "Posix Advisory Locking" at the start of this file for
|
|
+** describing "Posix Advisory Locking" at the start of this file for
|
|
** further details. Also, ticket #4018.
|
|
**
|
|
** If a suitable file descriptor is found, then it is returned. If no
|
|
@@ -39050,8 +42879,8 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){
|
|
|
|
/* Do not search for an unused file descriptor on vxworks. Not because
|
|
** vxworks would not benefit from the change (it might, we're not sure),
|
|
- ** but because no way to test it is currently available. It is better
|
|
- ** not to risk breaking vxworks support for the sake of such an obscure
|
|
+ ** but because no way to test it is currently available. It is better
|
|
+ ** not to risk breaking vxworks support for the sake of such an obscure
|
|
** feature. */
|
|
#if !OS_VXWORKS
|
|
struct stat sStat; /* Results of stat() call */
|
|
@@ -39093,7 +42922,7 @@ static UnixUnusedFd *findReusableFd(const char *zPath, int flags){
|
|
}
|
|
|
|
/*
|
|
-** Find the mode, uid and gid of file zFile.
|
|
+** Find the mode, uid and gid of file zFile.
|
|
*/
|
|
static int getFileMode(
|
|
const char *zFile, /* File name */
|
|
@@ -39117,16 +42946,16 @@ static int getFileMode(
|
|
** This function is called by unixOpen() to determine the unix permissions
|
|
** to create new files with. If no error occurs, then SQLITE_OK is returned
|
|
** and a value suitable for passing as the third argument to open(2) is
|
|
-** written to *pMode. If an IO error occurs, an SQLite error code is
|
|
+** written to *pMode. If an IO error occurs, an SQLite error code is
|
|
** returned and the value of *pMode is not modified.
|
|
**
|
|
** In most cases, this routine sets *pMode to 0, which will become
|
|
** an indication to robust_open() to create the file using
|
|
** SQLITE_DEFAULT_FILE_PERMISSIONS adjusted by the umask.
|
|
-** But if the file being opened is a WAL or regular journal file, then
|
|
-** this function queries the file-system for the permissions on the
|
|
-** corresponding database file and sets *pMode to this value. Whenever
|
|
-** possible, WAL and journal files are created using the same permissions
|
|
+** But if the file being opened is a WAL or regular journal file, then
|
|
+** this function queries the file-system for the permissions on the
|
|
+** corresponding database file and sets *pMode to this value. Whenever
|
|
+** possible, WAL and journal files are created using the same permissions
|
|
** as the associated database file.
|
|
**
|
|
** If the SQLITE_ENABLE_8_3_NAMES option is enabled, then the
|
|
@@ -39158,22 +42987,25 @@ static int findCreateFileMode(
|
|
** "<path to db>-journalNN"
|
|
** "<path to db>-walNN"
|
|
**
|
|
- ** where NN is a decimal number. The NN naming schemes are
|
|
+ ** where NN is a decimal number. The NN naming schemes are
|
|
** used by the test_multiplex.c module.
|
|
+ **
|
|
+ ** In normal operation, the journal file name will always contain
|
|
+ ** a '-' character. However in 8+3 filename mode, or if a corrupt
|
|
+ ** rollback journal specifies a super-journal with a goofy name, then
|
|
+ ** the '-' might be missing or the '-' might be the first character in
|
|
+ ** the filename. In that case, just return SQLITE_OK with *pMode==0.
|
|
*/
|
|
- nDb = sqlite3Strlen30(zPath) - 1;
|
|
- while( zPath[nDb]!='-' ){
|
|
- /* In normal operation, the journal file name will always contain
|
|
- ** a '-' character. However in 8+3 filename mode, or if a corrupt
|
|
- ** rollback journal specifies a master journal with a goofy name, then
|
|
- ** the '-' might be missing. */
|
|
- if( nDb==0 || zPath[nDb]=='.' ) return SQLITE_OK;
|
|
+ nDb = sqlite3Strlen30(zPath) - 1;
|
|
+ while( nDb>0 && zPath[nDb]!='.' ){
|
|
+ if( zPath[nDb]=='-' ){
|
|
+ memcpy(zDb, zPath, nDb);
|
|
+ zDb[nDb] = '\0';
|
|
+ rc = getFileMode(zDb, pMode, pUid, pGid);
|
|
+ break;
|
|
+ }
|
|
nDb--;
|
|
}
|
|
- memcpy(zDb, zPath, nDb);
|
|
- zDb[nDb] = '\0';
|
|
-
|
|
- rc = getFileMode(zDb, pMode, pUid, pGid);
|
|
}else if( flags & SQLITE_OPEN_DELETEONCLOSE ){
|
|
*pMode = 0600;
|
|
}else if( flags & SQLITE_OPEN_URI ){
|
|
@@ -39191,7 +43023,7 @@ static int findCreateFileMode(
|
|
|
|
/*
|
|
** Open the file zPath.
|
|
-**
|
|
+**
|
|
** Previously, the SQLite OS layer used three functions in place of this
|
|
** one:
|
|
**
|
|
@@ -39202,13 +43034,13 @@ static int findCreateFileMode(
|
|
** These calls correspond to the following combinations of flags:
|
|
**
|
|
** ReadWrite() -> (READWRITE | CREATE)
|
|
-** ReadOnly() -> (READONLY)
|
|
+** ReadOnly() -> (READONLY)
|
|
** OpenExclusive() -> (READWRITE | CREATE | EXCLUSIVE)
|
|
**
|
|
** The old OpenExclusive() accepted a boolean argument - "delFlag". If
|
|
** true, the file was configured to be automatically deleted when the
|
|
-** file handle closed. To achieve the same effect using this new
|
|
-** interface, add the DELETEONCLOSE flag to those specified above for
|
|
+** file handle closed. To achieve the same effect using this new
|
|
+** interface, add the DELETEONCLOSE flag to those specified above for
|
|
** OpenExclusive().
|
|
*/
|
|
static int unixOpen(
|
|
@@ -39238,13 +43070,13 @@ static int unixOpen(
|
|
struct statfs fsInfo;
|
|
#endif
|
|
|
|
- /* If creating a master or main-file journal, this function will open
|
|
+ /* If creating a super- or main-file journal, this function will open
|
|
** a file-descriptor on the directory too. The first time unixSync()
|
|
** is called the directory file descriptor will be fsync()ed and close()d.
|
|
*/
|
|
int isNewJrnl = (isCreate && (
|
|
- eType==SQLITE_OPEN_MASTER_JOURNAL
|
|
- || eType==SQLITE_OPEN_MAIN_JOURNAL
|
|
+ eType==SQLITE_OPEN_SUPER_JOURNAL
|
|
+ || eType==SQLITE_OPEN_MAIN_JOURNAL
|
|
|| eType==SQLITE_OPEN_WAL
|
|
));
|
|
|
|
@@ -39254,9 +43086,9 @@ static int unixOpen(
|
|
char zTmpname[MAX_PATHNAME+2];
|
|
const char *zName = zPath;
|
|
|
|
- /* Check the following statements are true:
|
|
+ /* Check the following statements are true:
|
|
**
|
|
- ** (a) Exactly one of the READWRITE and READONLY flags must be set, and
|
|
+ ** (a) Exactly one of the READWRITE and READONLY flags must be set, and
|
|
** (b) if CREATE is set, then READWRITE must also be set, and
|
|
** (c) if EXCLUSIVE is set, then CREATE must also be set.
|
|
** (d) if DELETEONCLOSE is set, then CREATE must also be set.
|
|
@@ -39266,17 +43098,17 @@ static int unixOpen(
|
|
assert(isExclusive==0 || isCreate);
|
|
assert(isDelete==0 || isCreate);
|
|
|
|
- /* The main DB, main journal, WAL file and master journal are never
|
|
+ /* The main DB, main journal, WAL file and super-journal are never
|
|
** automatically deleted. Nor are they ever temporary files. */
|
|
assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_DB );
|
|
assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_JOURNAL );
|
|
- assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MASTER_JOURNAL );
|
|
+ assert( (!isDelete && zName) || eType!=SQLITE_OPEN_SUPER_JOURNAL );
|
|
assert( (!isDelete && zName) || eType!=SQLITE_OPEN_WAL );
|
|
|
|
/* Assert that the upper layer has set one of the "file-type" flags. */
|
|
- assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB
|
|
- || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL
|
|
- || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL
|
|
+ assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB
|
|
+ || eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL
|
|
+ || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_SUPER_JOURNAL
|
|
|| eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL
|
|
);
|
|
|
|
@@ -39291,6 +43123,11 @@ static int unixOpen(
|
|
}
|
|
memset(p, 0, sizeof(unixFile));
|
|
|
|
+#ifdef SQLITE_ASSERT_NO_FILES
|
|
+ /* Applications that never read or write a persistent disk files */
|
|
+ assert( zName==0 );
|
|
+#endif
|
|
+
|
|
if( eType==SQLITE_OPEN_MAIN_DB ){
|
|
UnixUnusedFd *pUnused;
|
|
pUnused = findReusableFd(zName, flags);
|
|
@@ -39325,7 +43162,7 @@ static int unixOpen(
|
|
|
|
/* Determine the value of the flags parameter passed to POSIX function
|
|
** open(). These must be calculated even if open() is not called, as
|
|
- ** they may be stored as part of the file handle and used by the
|
|
+ ** they may be stored as part of the file handle and used by the
|
|
** 'conch file' locking functions later on. */
|
|
if( isReadonly ) openFlags |= O_RDONLY;
|
|
if( isReadWrite ) openFlags |= O_RDWR;
|
|
@@ -39390,7 +43227,7 @@ static int unixOpen(
|
|
|
|
if( p->pPreallocatedUnused ){
|
|
p->pPreallocatedUnused->fd = fd;
|
|
- p->pPreallocatedUnused->flags =
|
|
+ p->pPreallocatedUnused->flags =
|
|
flags & (SQLITE_OPEN_READONLY|SQLITE_OPEN_READWRITE);
|
|
}
|
|
|
|
@@ -39412,7 +43249,7 @@ static int unixOpen(
|
|
p->openFlags = openFlags;
|
|
}
|
|
#endif
|
|
-
|
|
+
|
|
#if defined(__APPLE__) || SQLITE_ENABLE_LOCKING_STYLE
|
|
if( fstatfs(fd, &fsInfo) == -1 ){
|
|
storeLastErrno(p, errno);
|
|
@@ -39443,7 +43280,7 @@ static int unixOpen(
|
|
char *envforce = getenv("SQLITE_FORCE_PROXY_LOCKING");
|
|
int useProxy = 0;
|
|
|
|
- /* SQLITE_FORCE_PROXY_LOCKING==1 means force always use proxy, 0 means
|
|
+ /* SQLITE_FORCE_PROXY_LOCKING==1 means force always use proxy, 0 means
|
|
** never use proxy, NULL means use proxy for non-local files only. */
|
|
if( envforce!=NULL ){
|
|
useProxy = atoi(envforce)>0;
|
|
@@ -39455,9 +43292,9 @@ static int unixOpen(
|
|
if( rc==SQLITE_OK ){
|
|
rc = proxyTransformUnixFile((unixFile*)pFile, ":auto:");
|
|
if( rc!=SQLITE_OK ){
|
|
- /* Use unixClose to clean up the resources added in fillInUnixFile
|
|
- ** and clear all the structure's references. Specifically,
|
|
- ** pFile->pMethods will be NULL so sqlite3OsClose will be a no-op
|
|
+ /* Use unixClose to clean up the resources added in fillInUnixFile
|
|
+ ** and clear all the structure's references. Specifically,
|
|
+ ** pFile->pMethods will be NULL so sqlite3OsClose will be a no-op
|
|
*/
|
|
unixClose(pFile);
|
|
return rc;
|
|
@@ -39467,9 +43304,9 @@ static int unixOpen(
|
|
}
|
|
}
|
|
#endif
|
|
-
|
|
- assert( zPath==0 || zPath[0]=='/'
|
|
- || eType==SQLITE_OPEN_MASTER_JOURNAL || eType==SQLITE_OPEN_MAIN_JOURNAL
|
|
+
|
|
+ assert( zPath==0 || zPath[0]=='/'
|
|
+ || eType==SQLITE_OPEN_SUPER_JOURNAL || eType==SQLITE_OPEN_MAIN_JOURNAL
|
|
);
|
|
rc = fillInUnixFile(pVfs, fd, pFile, zPath, ctrlFlags);
|
|
|
|
@@ -39558,38 +43395,105 @@ static int unixAccess(
|
|
}
|
|
|
|
/*
|
|
-**
|
|
+** A pathname under construction
|
|
+*/
|
|
+typedef struct DbPath DbPath;
|
|
+struct DbPath {
|
|
+ int rc; /* Non-zero following any error */
|
|
+ int nSymlink; /* Number of symlinks resolved */
|
|
+ char *zOut; /* Write the pathname here */
|
|
+ int nOut; /* Bytes of space available to zOut[] */
|
|
+ int nUsed; /* Bytes of zOut[] currently being used */
|
|
+};
|
|
+
|
|
+/* Forward reference */
|
|
+static void appendAllPathElements(DbPath*,const char*);
|
|
+
|
|
+/*
|
|
+** Append a single path element to the DbPath under construction
|
|
*/
|
|
-static int mkFullPathname(
|
|
- const char *zPath, /* Input path */
|
|
- char *zOut, /* Output buffer */
|
|
- int nOut /* Allocated size of buffer zOut */
|
|
+static void appendOnePathElement(
|
|
+ DbPath *pPath, /* Path under construction, to which to append zName */
|
|
+ const char *zName, /* Name to append to pPath. Not zero-terminated */
|
|
+ int nName /* Number of significant bytes in zName */
|
|
){
|
|
- int nPath = sqlite3Strlen30(zPath);
|
|
- int iOff = 0;
|
|
- if( zPath[0]!='/' ){
|
|
- if( osGetcwd(zOut, nOut-2)==0 ){
|
|
- return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd", zPath);
|
|
+ assert( nName>0 );
|
|
+ assert( zName!=0 );
|
|
+ if( zName[0]=='.' ){
|
|
+ if( nName==1 ) return;
|
|
+ if( zName[1]=='.' && nName==2 ){
|
|
+ if( pPath->nUsed>1 ){
|
|
+ assert( pPath->zOut[0]=='/' );
|
|
+ while( pPath->zOut[--pPath->nUsed]!='/' ){}
|
|
+ }
|
|
+ return;
|
|
}
|
|
- iOff = sqlite3Strlen30(zOut);
|
|
- zOut[iOff++] = '/';
|
|
}
|
|
- if( (iOff+nPath+1)>nOut ){
|
|
- /* SQLite assumes that xFullPathname() nul-terminates the output buffer
|
|
- ** even if it returns an error. */
|
|
- zOut[iOff] = '\0';
|
|
- return SQLITE_CANTOPEN_BKPT;
|
|
+ if( pPath->nUsed + nName + 2 >= pPath->nOut ){
|
|
+ pPath->rc = SQLITE_ERROR;
|
|
+ return;
|
|
}
|
|
- sqlite3_snprintf(nOut-iOff, &zOut[iOff], "%s", zPath);
|
|
- return SQLITE_OK;
|
|
+ pPath->zOut[pPath->nUsed++] = '/';
|
|
+ memcpy(&pPath->zOut[pPath->nUsed], zName, nName);
|
|
+ pPath->nUsed += nName;
|
|
+#if defined(HAVE_READLINK) && defined(HAVE_LSTAT)
|
|
+ if( pPath->rc==SQLITE_OK ){
|
|
+ const char *zIn;
|
|
+ struct stat buf;
|
|
+ pPath->zOut[pPath->nUsed] = 0;
|
|
+ zIn = pPath->zOut;
|
|
+ if( osLstat(zIn, &buf)!=0 ){
|
|
+ if( errno!=ENOENT ){
|
|
+ pPath->rc = unixLogError(SQLITE_CANTOPEN_BKPT, "lstat", zIn);
|
|
+ }
|
|
+ }else if( S_ISLNK(buf.st_mode) ){
|
|
+ ssize_t got;
|
|
+ char zLnk[SQLITE_MAX_PATHLEN+2];
|
|
+ if( pPath->nSymlink++ > SQLITE_MAX_SYMLINK ){
|
|
+ pPath->rc = SQLITE_CANTOPEN_BKPT;
|
|
+ return;
|
|
+ }
|
|
+ got = osReadlink(zIn, zLnk, sizeof(zLnk)-2);
|
|
+ if( got<=0 || got>=(ssize_t)sizeof(zLnk)-2 ){
|
|
+ pPath->rc = unixLogError(SQLITE_CANTOPEN_BKPT, "readlink", zIn);
|
|
+ return;
|
|
+ }
|
|
+ zLnk[got] = 0;
|
|
+ if( zLnk[0]=='/' ){
|
|
+ pPath->nUsed = 0;
|
|
+ }else{
|
|
+ pPath->nUsed -= nName + 1;
|
|
+ }
|
|
+ appendAllPathElements(pPath, zLnk);
|
|
+ }
|
|
+ }
|
|
+#endif
|
|
+}
|
|
+
|
|
+/*
|
|
+** Append all path elements in zPath to the DbPath under construction.
|
|
+*/
|
|
+static void appendAllPathElements(
|
|
+ DbPath *pPath, /* Path under construction, to which to append zName */
|
|
+ const char *zPath /* Path to append to pPath. Is zero-terminated */
|
|
+){
|
|
+ int i = 0;
|
|
+ int j = 0;
|
|
+ do{
|
|
+ while( zPath[i] && zPath[i]!='/' ){ i++; }
|
|
+ if( i>j ){
|
|
+ appendOnePathElement(pPath, &zPath[j], i-j);
|
|
+ }
|
|
+ j = i+1;
|
|
+ }while( zPath[i++] );
|
|
}
|
|
|
|
/*
|
|
** Turn a relative pathname into a full pathname. The relative path
|
|
** is stored as a nul-terminated string in the buffer pointed to by
|
|
-** zPath.
|
|
+** zPath.
|
|
**
|
|
-** zOut points to a buffer of at least sqlite3_vfs.mxPathname bytes
|
|
+** zOut points to a buffer of at least sqlite3_vfs.mxPathname bytes
|
|
** (in this case, MAX_PATHNAME bytes). The full-path is written to
|
|
** this buffer before returning.
|
|
*/
|
|
@@ -39599,86 +43503,27 @@ static int unixFullPathname(
|
|
int nOut, /* Size of output buffer in bytes */
|
|
char *zOut /* Output buffer */
|
|
){
|
|
-#if !defined(HAVE_READLINK) || !defined(HAVE_LSTAT)
|
|
- return mkFullPathname(zPath, zOut, nOut);
|
|
-#else
|
|
- int rc = SQLITE_OK;
|
|
- int nByte;
|
|
- int nLink = 0; /* Number of symbolic links followed so far */
|
|
- const char *zIn = zPath; /* Input path for each iteration of loop */
|
|
- char *zDel = 0;
|
|
-
|
|
- assert( pVfs->mxPathname==MAX_PATHNAME );
|
|
+ DbPath path;
|
|
UNUSED_PARAMETER(pVfs);
|
|
-
|
|
- /* It's odd to simulate an io-error here, but really this is just
|
|
- ** using the io-error infrastructure to test that SQLite handles this
|
|
- ** function failing. This function could fail if, for example, the
|
|
- ** current working directory has been unlinked.
|
|
- */
|
|
- SimulateIOError( return SQLITE_ERROR );
|
|
-
|
|
- do {
|
|
-
|
|
- /* Call stat() on path zIn. Set bLink to true if the path is a symbolic
|
|
- ** link, or false otherwise. */
|
|
- int bLink = 0;
|
|
- struct stat buf;
|
|
- if( osLstat(zIn, &buf)!=0 ){
|
|
- if( errno!=ENOENT ){
|
|
- rc = unixLogError(SQLITE_CANTOPEN_BKPT, "lstat", zIn);
|
|
- }
|
|
- }else{
|
|
- bLink = S_ISLNK(buf.st_mode);
|
|
- }
|
|
-
|
|
- if( bLink ){
|
|
- nLink++;
|
|
- if( zDel==0 ){
|
|
- zDel = sqlite3_malloc(nOut);
|
|
- if( zDel==0 ) rc = SQLITE_NOMEM_BKPT;
|
|
- }else if( nLink>=SQLITE_MAX_SYMLINKS ){
|
|
- rc = SQLITE_CANTOPEN_BKPT;
|
|
- }
|
|
-
|
|
- if( rc==SQLITE_OK ){
|
|
- nByte = osReadlink(zIn, zDel, nOut-1);
|
|
- if( nByte<0 ){
|
|
- rc = unixLogError(SQLITE_CANTOPEN_BKPT, "readlink", zIn);
|
|
- }else{
|
|
- if( zDel[0]!='/' ){
|
|
- int n;
|
|
- for(n = sqlite3Strlen30(zIn); n>0 && zIn[n-1]!='/'; n--);
|
|
- if( nByte+n+1>nOut ){
|
|
- rc = SQLITE_CANTOPEN_BKPT;
|
|
- }else{
|
|
- memmove(&zDel[n], zDel, nByte+1);
|
|
- memcpy(zDel, zIn, n);
|
|
- nByte += n;
|
|
- }
|
|
- }
|
|
- zDel[nByte] = '\0';
|
|
- }
|
|
- }
|
|
-
|
|
- zIn = zDel;
|
|
- }
|
|
-
|
|
- assert( rc!=SQLITE_OK || zIn!=zOut || zIn[0]=='/' );
|
|
- if( rc==SQLITE_OK && zIn!=zOut ){
|
|
- rc = mkFullPathname(zIn, zOut, nOut);
|
|
+ path.rc = 0;
|
|
+ path.nUsed = 0;
|
|
+ path.nSymlink = 0;
|
|
+ path.nOut = nOut;
|
|
+ path.zOut = zOut;
|
|
+ if( zPath[0]!='/' ){
|
|
+ char zPwd[SQLITE_MAX_PATHLEN+2];
|
|
+ if( osGetcwd(zPwd, sizeof(zPwd)-2)==0 ){
|
|
+ return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd", zPath);
|
|
}
|
|
- if( bLink==0 ) break;
|
|
- zIn = zOut;
|
|
- }while( rc==SQLITE_OK );
|
|
-
|
|
- sqlite3_free(zDel);
|
|
- if( rc==SQLITE_OK && nLink ) rc = SQLITE_OK_SYMLINK;
|
|
- return rc;
|
|
-#endif /* HAVE_READLINK && HAVE_LSTAT */
|
|
+ appendAllPathElements(&path, zPwd);
|
|
+ }
|
|
+ appendAllPathElements(&path, zPath);
|
|
+ zOut[path.nUsed] = 0;
|
|
+ if( path.rc || path.nUsed<2 ) return SQLITE_CANTOPEN_BKPT;
|
|
+ if( path.nSymlink ) return SQLITE_OK_SYMLINK;
|
|
+ return SQLITE_OK;
|
|
}
|
|
|
|
-
|
|
#ifndef SQLITE_OMIT_LOAD_EXTENSION
|
|
/*
|
|
** Interfaces for opening a shared library, finding entry points
|
|
@@ -39708,7 +43553,7 @@ static void unixDlError(sqlite3_vfs *NotUsed, int nBuf, char *zBufOut){
|
|
unixLeaveMutex();
|
|
}
|
|
static void (*unixDlSym(sqlite3_vfs *NotUsed, void *p, const char*zSym))(void){
|
|
- /*
|
|
+ /*
|
|
** GCC with -pedantic-errors says that C90 does not allow a void* to be
|
|
** cast into a pointer to a function. And yet the library dlsym() routine
|
|
** returns a void* which is really a pointer to a function. So how do we
|
|
@@ -39718,7 +43563,7 @@ static void (*unixDlSym(sqlite3_vfs *NotUsed, void *p, const char*zSym))(void){
|
|
** parameters void* and const char* and returning a pointer to a function.
|
|
** We initialize x by assigning it a pointer to the dlsym() function.
|
|
** (That assignment requires a cast.) Then we call the function that
|
|
- ** x points to.
|
|
+ ** x points to.
|
|
**
|
|
** This work-around is unlikely to work correctly on any system where
|
|
** you really cannot cast a function pointer into void*. But then, on the
|
|
@@ -39761,7 +43606,7 @@ static int unixRandomness(sqlite3_vfs *NotUsed, int nBuf, char *zBuf){
|
|
** tests repeatable.
|
|
*/
|
|
memset(zBuf, 0, nBuf);
|
|
- randomnessPid = osGetpid(0);
|
|
+ randomnessPid = osGetpid(0);
|
|
#if !defined(SQLITE_TEST) && !defined(SQLITE_OMIT_RANDOMNESS)
|
|
{
|
|
int fd, got;
|
|
@@ -39792,7 +43637,7 @@ static int unixRandomness(sqlite3_vfs *NotUsed, int nBuf, char *zBuf){
|
|
** than the argument.
|
|
*/
|
|
static int unixSleep(sqlite3_vfs *NotUsed, int microseconds){
|
|
-#if OS_VXWORKS
|
|
+#if OS_VXWORKS || _POSIX_C_SOURCE >= 199309L
|
|
struct timespec sp;
|
|
|
|
sp.tv_sec = microseconds / 1000000;
|
|
@@ -39801,7 +43646,8 @@ static int unixSleep(sqlite3_vfs *NotUsed, int microseconds){
|
|
UNUSED_PARAMETER(NotUsed);
|
|
return microseconds;
|
|
#elif defined(HAVE_USLEEP) && HAVE_USLEEP
|
|
- usleep(microseconds);
|
|
+ if( microseconds>=1000000 ) sleep(microseconds/1000000);
|
|
+ if( microseconds%1000000 ) usleep(microseconds%1000000);
|
|
UNUSED_PARAMETER(NotUsed);
|
|
return microseconds;
|
|
#else
|
|
@@ -39828,7 +43674,7 @@ SQLITE_API int sqlite3_current_time = 0; /* Fake system time in seconds since 1
|
|
** epoch of noon in Greenwich on November 24, 4714 B.C according to the
|
|
** proleptic Gregorian calendar.
|
|
**
|
|
-** On success, return SQLITE_OK. Return SQLITE_ERROR if the time and date
|
|
+** On success, return SQLITE_OK. Return SQLITE_ERROR if the time and date
|
|
** cannot be found.
|
|
*/
|
|
static int unixCurrentTimeInt64(sqlite3_vfs *NotUsed, sqlite3_int64 *piNow){
|
|
@@ -39935,7 +43781,7 @@ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){
|
|
** To address the performance and cache coherency issues, proxy file locking
|
|
** changes the way database access is controlled by limiting access to a
|
|
** single host at a time and moving file locks off of the database file
|
|
-** and onto a proxy file on the local file system.
|
|
+** and onto a proxy file on the local file system.
|
|
**
|
|
**
|
|
** Using proxy locks
|
|
@@ -39961,19 +43807,19 @@ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){
|
|
** actual proxy file name is generated from the name and path of the
|
|
** database file. For example:
|
|
**
|
|
-** For database path "/Users/me/foo.db"
|
|
+** For database path "/Users/me/foo.db"
|
|
** The lock path will be "<tmpdir>/sqliteplocks/_Users_me_foo.db:auto:")
|
|
**
|
|
** Once a lock proxy is configured for a database connection, it can not
|
|
** be removed, however it may be switched to a different proxy path via
|
|
** the above APIs (assuming the conch file is not being held by another
|
|
-** connection or process).
|
|
+** connection or process).
|
|
**
|
|
**
|
|
** How proxy locking works
|
|
** -----------------------
|
|
**
|
|
-** Proxy file locking relies primarily on two new supporting files:
|
|
+** Proxy file locking relies primarily on two new supporting files:
|
|
**
|
|
** * conch file to limit access to the database file to a single host
|
|
** at a time
|
|
@@ -40000,11 +43846,11 @@ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){
|
|
** host (the conch ensures that they all use the same local lock file).
|
|
**
|
|
** Requesting the lock proxy does not immediately take the conch, it is
|
|
-** only taken when the first request to lock database file is made.
|
|
+** only taken when the first request to lock database file is made.
|
|
** This matches the semantics of the traditional locking behavior, where
|
|
** opening a connection to a database file does not take a lock on it.
|
|
-** The shared lock and an open file descriptor are maintained until
|
|
-** the connection to the database is closed.
|
|
+** The shared lock and an open file descriptor are maintained until
|
|
+** the connection to the database is closed.
|
|
**
|
|
** The proxy file and the lock file are never deleted so they only need
|
|
** to be created the first time they are used.
|
|
@@ -40018,7 +43864,7 @@ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){
|
|
** automatically configured for proxy locking, lock files are
|
|
** named automatically using the same logic as
|
|
** PRAGMA lock_proxy_file=":auto:"
|
|
-**
|
|
+**
|
|
** SQLITE_PROXY_DEBUG
|
|
**
|
|
** Enables the logging of error messages during host id file
|
|
@@ -40033,8 +43879,8 @@ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){
|
|
**
|
|
** Permissions to use when creating a directory for storing the
|
|
** lock proxy files, only used when LOCKPROXYDIR is not set.
|
|
-**
|
|
-**
|
|
+**
|
|
+**
|
|
** As mentioned above, when compiled with SQLITE_PREFER_PROXY_LOCKING,
|
|
** setting the environment variable SQLITE_FORCE_PROXY_LOCKING to 1 will
|
|
** force proxy locking to be used for every database file opened, and 0
|
|
@@ -40044,12 +43890,12 @@ static int unixGetLastError(sqlite3_vfs *NotUsed, int NotUsed2, char *NotUsed3){
|
|
*/
|
|
|
|
/*
|
|
-** Proxy locking is only available on MacOSX
|
|
+** Proxy locking is only available on MacOSX
|
|
*/
|
|
#if defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
|
|
|
|
/*
|
|
-** The proxyLockingContext has the path and file structures for the remote
|
|
+** The proxyLockingContext has the path and file structures for the remote
|
|
** and local proxy files in it
|
|
*/
|
|
typedef struct proxyLockingContext proxyLockingContext;
|
|
@@ -40065,10 +43911,10 @@ struct proxyLockingContext {
|
|
sqlite3_io_methods const *pOldMethod; /* Original I/O methods for close */
|
|
};
|
|
|
|
-/*
|
|
-** The proxy lock file path for the database at dbPath is written into lPath,
|
|
+/*
|
|
+** The proxy lock file path for the database at dbPath is written into lPath,
|
|
** which must point to valid, writable memory large enough for a maxLen length
|
|
-** file path.
|
|
+** file path.
|
|
*/
|
|
static int proxyGetLockPath(const char *dbPath, char *lPath, size_t maxLen){
|
|
int len;
|
|
@@ -40085,7 +43931,7 @@ static int proxyGetLockPath(const char *dbPath, char *lPath, size_t maxLen){
|
|
lPath, errno, osGetpid(0)));
|
|
return SQLITE_IOERR_LOCK;
|
|
}
|
|
- len = strlcat(lPath, "sqliteplocks", maxLen);
|
|
+ len = strlcat(lPath, "sqliteplocks", maxLen);
|
|
}
|
|
# else
|
|
len = strlcpy(lPath, "/tmp/", maxLen);
|
|
@@ -40095,7 +43941,7 @@ static int proxyGetLockPath(const char *dbPath, char *lPath, size_t maxLen){
|
|
if( lPath[len-1]!='/' ){
|
|
len = strlcat(lPath, "/", maxLen);
|
|
}
|
|
-
|
|
+
|
|
/* transform the db path to a unique cache name */
|
|
dbLen = (int)strlen(dbPath);
|
|
for( i=0; i<dbLen && (i+len+7)<(int)maxLen; i++){
|
|
@@ -40108,14 +43954,14 @@ static int proxyGetLockPath(const char *dbPath, char *lPath, size_t maxLen){
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** Creates the lock file and any missing directories in lockPath
|
|
*/
|
|
static int proxyCreateLockPath(const char *lockPath){
|
|
int i, len;
|
|
char buf[MAXPATHLEN];
|
|
int start = 0;
|
|
-
|
|
+
|
|
assert(lockPath!=NULL);
|
|
/* try to create all the intermediate directories */
|
|
len = (int)strlen(lockPath);
|
|
@@ -40123,7 +43969,7 @@ static int proxyCreateLockPath(const char *lockPath){
|
|
for( i=1; i<len; i++ ){
|
|
if( lockPath[i] == '/' && (i - start > 0) ){
|
|
/* only mkdir if leaf dir != "." or "/" or ".." */
|
|
- if( i-start>2 || (i-start==1 && buf[start] != '.' && buf[start] != '/')
|
|
+ if( i-start>2 || (i-start==1 && buf[start] != '.' && buf[start] != '/')
|
|
|| (i-start==2 && buf[start] != '.' && buf[start+1] != '.') ){
|
|
buf[i]='\0';
|
|
if( osMkdir(buf, SQLITE_DEFAULT_PROXYDIR_PERMISSIONS) ){
|
|
@@ -40200,13 +44046,13 @@ static int proxyCreateUnixFile(
|
|
switch (terrno) {
|
|
case EACCES:
|
|
return SQLITE_PERM;
|
|
- case EIO:
|
|
+ case EIO:
|
|
return SQLITE_IOERR_LOCK; /* even though it is the conch */
|
|
default:
|
|
return SQLITE_CANTOPEN_BKPT;
|
|
}
|
|
}
|
|
-
|
|
+
|
|
pNew = (unixFile *)sqlite3_malloc64(sizeof(*pNew));
|
|
if( pNew==NULL ){
|
|
rc = SQLITE_NOMEM_BKPT;
|
|
@@ -40220,13 +44066,13 @@ static int proxyCreateUnixFile(
|
|
pUnused->fd = fd;
|
|
pUnused->flags = openFlags;
|
|
pNew->pPreallocatedUnused = pUnused;
|
|
-
|
|
+
|
|
rc = fillInUnixFile(&dummyVfs, fd, (sqlite3_file*)pNew, path, 0);
|
|
if( rc==SQLITE_OK ){
|
|
*ppFile = pNew;
|
|
return SQLITE_OK;
|
|
}
|
|
-end_create_proxy:
|
|
+end_create_proxy:
|
|
robust_close(pNew, fd, __LINE__);
|
|
sqlite3_free(pNew);
|
|
sqlite3_free(pUnused);
|
|
@@ -40245,7 +44091,7 @@ SQLITE_API int sqlite3_hostid_num = 0;
|
|
extern int gethostuuid(uuid_t id, const struct timespec *wait);
|
|
#endif
|
|
|
|
-/* get the host ID via gethostuuid(), pHostID must point to PROXY_HOSTIDLEN
|
|
+/* get the host ID via gethostuuid(), pHostID must point to PROXY_HOSTIDLEN
|
|
** bytes of writable memory.
|
|
*/
|
|
static int proxyGetHostID(unsigned char *pHostID, int *pError){
|
|
@@ -40271,7 +44117,7 @@ static int proxyGetHostID(unsigned char *pHostID, int *pError){
|
|
pHostID[0] = (char)(pHostID[0] + (char)(sqlite3_hostid_num & 0xFF));
|
|
}
|
|
#endif
|
|
-
|
|
+
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
@@ -40282,14 +44128,14 @@ static int proxyGetHostID(unsigned char *pHostID, int *pError){
|
|
#define PROXY_PATHINDEX (PROXY_HEADERLEN+PROXY_HOSTIDLEN)
|
|
#define PROXY_MAXCONCHLEN (PROXY_HEADERLEN+PROXY_HOSTIDLEN+MAXPATHLEN)
|
|
|
|
-/*
|
|
-** Takes an open conch file, copies the contents to a new path and then moves
|
|
+/*
|
|
+** Takes an open conch file, copies the contents to a new path and then moves
|
|
** it back. The newly created file's file descriptor is assigned to the
|
|
-** conch file structure and finally the original conch file descriptor is
|
|
+** conch file structure and finally the original conch file descriptor is
|
|
** closed. Returns zero if successful.
|
|
*/
|
|
static int proxyBreakConchLock(unixFile *pFile, uuid_t myHostID){
|
|
- proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext;
|
|
+ proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext;
|
|
unixFile *conchFile = pCtx->conchFile;
|
|
char tPath[MAXPATHLEN];
|
|
char buf[PROXY_MAXCONCHLEN];
|
|
@@ -40303,7 +44149,7 @@ static int proxyBreakConchLock(unixFile *pFile, uuid_t myHostID){
|
|
|
|
/* create a new path by replace the trailing '-conch' with '-break' */
|
|
pathLen = strlcpy(tPath, cPath, MAXPATHLEN);
|
|
- if( pathLen>MAXPATHLEN || pathLen<6 ||
|
|
+ if( pathLen>MAXPATHLEN || pathLen<6 ||
|
|
(strlcpy(&tPath[pathLen-5], "break", 6) != 5) ){
|
|
sqlite3_snprintf(sizeof(errmsg),errmsg,"path error (len %d)",(int)pathLen);
|
|
goto end_breaklock;
|
|
@@ -40345,24 +44191,24 @@ static int proxyBreakConchLock(unixFile *pFile, uuid_t myHostID){
|
|
return rc;
|
|
}
|
|
|
|
-/* Take the requested lock on the conch file and break a stale lock if the
|
|
+/* Take the requested lock on the conch file and break a stale lock if the
|
|
** host id matches.
|
|
*/
|
|
static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){
|
|
- proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext;
|
|
+ proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext;
|
|
unixFile *conchFile = pCtx->conchFile;
|
|
int rc = SQLITE_OK;
|
|
int nTries = 0;
|
|
struct timespec conchModTime;
|
|
-
|
|
+
|
|
memset(&conchModTime, 0, sizeof(conchModTime));
|
|
do {
|
|
rc = conchFile->pMethod->xLock((sqlite3_file*)conchFile, lockType);
|
|
nTries ++;
|
|
if( rc==SQLITE_BUSY ){
|
|
/* If the lock failed (busy):
|
|
- * 1st try: get the mod time of the conch, wait 0.5s and try again.
|
|
- * 2nd try: fail if the mod time changed or host id is different, wait
|
|
+ * 1st try: get the mod time of the conch, wait 0.5s and try again.
|
|
+ * 2nd try: fail if the mod time changed or host id is different, wait
|
|
* 10 sec and try again
|
|
* 3rd try: break the lock unless the mod time has changed.
|
|
*/
|
|
@@ -40371,20 +44217,20 @@ static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){
|
|
storeLastErrno(pFile, errno);
|
|
return SQLITE_IOERR_LOCK;
|
|
}
|
|
-
|
|
+
|
|
if( nTries==1 ){
|
|
conchModTime = buf.st_mtimespec;
|
|
- usleep(500000); /* wait 0.5 sec and try the lock again*/
|
|
- continue;
|
|
+ unixSleep(0,500000); /* wait 0.5 sec and try the lock again*/
|
|
+ continue;
|
|
}
|
|
|
|
assert( nTries>1 );
|
|
- if( conchModTime.tv_sec != buf.st_mtimespec.tv_sec ||
|
|
+ if( conchModTime.tv_sec != buf.st_mtimespec.tv_sec ||
|
|
conchModTime.tv_nsec != buf.st_mtimespec.tv_nsec ){
|
|
return SQLITE_BUSY;
|
|
}
|
|
-
|
|
- if( nTries==2 ){
|
|
+
|
|
+ if( nTries==2 ){
|
|
char tBuf[PROXY_MAXCONCHLEN];
|
|
int len = osPread(conchFile->h, tBuf, PROXY_MAXCONCHLEN, 0);
|
|
if( len<0 ){
|
|
@@ -40400,10 +44246,10 @@ static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){
|
|
/* don't break the lock on short read or a version mismatch */
|
|
return SQLITE_BUSY;
|
|
}
|
|
- usleep(10000000); /* wait 10 sec and try the lock again */
|
|
- continue;
|
|
+ unixSleep(0,10000000); /* wait 10 sec and try the lock again */
|
|
+ continue;
|
|
}
|
|
-
|
|
+
|
|
assert( nTries==3 );
|
|
if( 0==proxyBreakConchLock(pFile, myHostID) ){
|
|
rc = SQLITE_OK;
|
|
@@ -40416,19 +44262,19 @@ static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){
|
|
}
|
|
}
|
|
} while( rc==SQLITE_BUSY && nTries<3 );
|
|
-
|
|
+
|
|
return rc;
|
|
}
|
|
|
|
-/* Takes the conch by taking a shared lock and read the contents conch, if
|
|
-** lockPath is non-NULL, the host ID and lock file path must match. A NULL
|
|
-** lockPath means that the lockPath in the conch file will be used if the
|
|
-** host IDs match, or a new lock path will be generated automatically
|
|
+/* Takes the conch by taking a shared lock and read the contents conch, if
|
|
+** lockPath is non-NULL, the host ID and lock file path must match. A NULL
|
|
+** lockPath means that the lockPath in the conch file will be used if the
|
|
+** host IDs match, or a new lock path will be generated automatically
|
|
** and written to the conch file.
|
|
*/
|
|
static int proxyTakeConch(unixFile *pFile){
|
|
- proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext;
|
|
-
|
|
+ proxyLockingContext *pCtx = (proxyLockingContext *)pFile->lockingContext;
|
|
+
|
|
if( pCtx->conchHeld!=0 ){
|
|
return SQLITE_OK;
|
|
}else{
|
|
@@ -40444,7 +44290,7 @@ static int proxyTakeConch(unixFile *pFile){
|
|
int readLen = 0;
|
|
int tryOldLockPath = 0;
|
|
int forceNewLockPath = 0;
|
|
-
|
|
+
|
|
OSTRACE(("TAKECONCH %d for %s pid=%d\n", conchFile->h,
|
|
(pCtx->lockProxyPath ? pCtx->lockProxyPath : ":auto:"),
|
|
osGetpid(0)));
|
|
@@ -40465,21 +44311,21 @@ static int proxyTakeConch(unixFile *pFile){
|
|
storeLastErrno(pFile, conchFile->lastErrno);
|
|
rc = SQLITE_IOERR_READ;
|
|
goto end_takeconch;
|
|
- }else if( readLen<=(PROXY_HEADERLEN+PROXY_HOSTIDLEN) ||
|
|
+ }else if( readLen<=(PROXY_HEADERLEN+PROXY_HOSTIDLEN) ||
|
|
readBuf[0]!=(char)PROXY_CONCHVERSION ){
|
|
- /* a short read or version format mismatch means we need to create a new
|
|
- ** conch file.
|
|
+ /* a short read or version format mismatch means we need to create a new
|
|
+ ** conch file.
|
|
*/
|
|
createConch = 1;
|
|
}
|
|
/* if the host id matches and the lock path already exists in the conch
|
|
- ** we'll try to use the path there, if we can't open that path, we'll
|
|
- ** retry with a new auto-generated path
|
|
+ ** we'll try to use the path there, if we can't open that path, we'll
|
|
+ ** retry with a new auto-generated path
|
|
*/
|
|
do { /* in case we need to try again for an :auto: named lock file */
|
|
|
|
if( !createConch && !forceNewLockPath ){
|
|
- hostIdMatch = !memcmp(&readBuf[PROXY_HEADERLEN], myHostID,
|
|
+ hostIdMatch = !memcmp(&readBuf[PROXY_HEADERLEN], myHostID,
|
|
PROXY_HOSTIDLEN);
|
|
/* if the conch has data compare the contents */
|
|
if( !pCtx->lockProxyPath ){
|
|
@@ -40488,7 +44334,7 @@ static int proxyTakeConch(unixFile *pFile){
|
|
*/
|
|
if( hostIdMatch ){
|
|
size_t pathLen = (readLen - PROXY_PATHINDEX);
|
|
-
|
|
+
|
|
if( pathLen>=MAXPATHLEN ){
|
|
pathLen=MAXPATHLEN-1;
|
|
}
|
|
@@ -40504,23 +44350,23 @@ static int proxyTakeConch(unixFile *pFile){
|
|
readLen-PROXY_PATHINDEX)
|
|
){
|
|
/* conch host and lock path match */
|
|
- goto end_takeconch;
|
|
+ goto end_takeconch;
|
|
}
|
|
}
|
|
-
|
|
+
|
|
/* if the conch isn't writable and doesn't match, we can't take it */
|
|
if( (conchFile->openFlags&O_RDWR) == 0 ){
|
|
rc = SQLITE_BUSY;
|
|
goto end_takeconch;
|
|
}
|
|
-
|
|
+
|
|
/* either the conch didn't match or we need to create a new one */
|
|
if( !pCtx->lockProxyPath ){
|
|
proxyGetLockPath(pCtx->dbPath, lockPath, MAXPATHLEN);
|
|
tempLockPath = lockPath;
|
|
/* create a copy of the lock path _only_ if the conch is taken */
|
|
}
|
|
-
|
|
+
|
|
/* update conch with host and path (this will fail if other process
|
|
** has a shared lock already), if the host id matches, use the big
|
|
** stick.
|
|
@@ -40531,7 +44377,7 @@ static int proxyTakeConch(unixFile *pFile){
|
|
/* We are trying for an exclusive lock but another thread in this
|
|
** same process is still holding a shared lock. */
|
|
rc = SQLITE_BUSY;
|
|
- } else {
|
|
+ } else {
|
|
rc = proxyConchLock(pFile, myHostID, EXCLUSIVE_LOCK);
|
|
}
|
|
}else{
|
|
@@ -40540,7 +44386,7 @@ static int proxyTakeConch(unixFile *pFile){
|
|
if( rc==SQLITE_OK ){
|
|
char writeBuffer[PROXY_MAXCONCHLEN];
|
|
int writeSize = 0;
|
|
-
|
|
+
|
|
writeBuffer[0] = (char)PROXY_CONCHVERSION;
|
|
memcpy(&writeBuffer[PROXY_HEADERLEN], myHostID, PROXY_HOSTIDLEN);
|
|
if( pCtx->lockProxyPath!=NULL ){
|
|
@@ -40553,8 +44399,8 @@ static int proxyTakeConch(unixFile *pFile){
|
|
robust_ftruncate(conchFile->h, writeSize);
|
|
rc = unixWrite((sqlite3_file *)conchFile, writeBuffer, writeSize, 0);
|
|
full_fsync(conchFile->h,0,0);
|
|
- /* If we created a new conch file (not just updated the contents of a
|
|
- ** valid conch file), try to match the permissions of the database
|
|
+ /* If we created a new conch file (not just updated the contents of a
|
|
+ ** valid conch file), try to match the permissions of the database
|
|
*/
|
|
if( rc==SQLITE_OK && createConch ){
|
|
struct stat buf;
|
|
@@ -40578,14 +44424,14 @@ static int proxyTakeConch(unixFile *pFile){
|
|
}
|
|
}else{
|
|
int code = errno;
|
|
- fprintf(stderr, "STAT FAILED[%d] with %d %s\n",
|
|
+ fprintf(stderr, "STAT FAILED[%d] with %d %s\n",
|
|
err, code, strerror(code));
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, SHARED_LOCK);
|
|
-
|
|
+
|
|
end_takeconch:
|
|
OSTRACE(("TRANSPROXY: CLOSE %d\n", pFile->h));
|
|
if( rc==SQLITE_OK && pFile->openFlags ){
|
|
@@ -40608,7 +44454,7 @@ static int proxyTakeConch(unixFile *pFile){
|
|
rc = proxyCreateUnixFile(path, &pCtx->lockProxy, 1);
|
|
if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM && tryOldLockPath ){
|
|
/* we couldn't create the proxy lock file with the old lock file path
|
|
- ** so try again via auto-naming
|
|
+ ** so try again via auto-naming
|
|
*/
|
|
forceNewLockPath = 1;
|
|
tryOldLockPath = 0;
|
|
@@ -40628,7 +44474,7 @@ static int proxyTakeConch(unixFile *pFile){
|
|
}
|
|
if( rc==SQLITE_OK ){
|
|
pCtx->conchHeld = 1;
|
|
-
|
|
+
|
|
if( pCtx->lockProxy->pMethod == &afpIoMethods ){
|
|
afpLockingContext *afpCtx;
|
|
afpCtx = (afpLockingContext *)pCtx->lockProxy->lockingContext;
|
|
@@ -40640,7 +44486,7 @@ static int proxyTakeConch(unixFile *pFile){
|
|
OSTRACE(("TAKECONCH %d %s\n", conchFile->h,
|
|
rc==SQLITE_OK?"ok":"failed"));
|
|
return rc;
|
|
- } while (1); /* in case we need to retry the :auto: lock file -
|
|
+ } while (1); /* in case we need to retry the :auto: lock file -
|
|
** we should never get here except via the 'continue' call. */
|
|
}
|
|
}
|
|
@@ -40656,7 +44502,7 @@ static int proxyReleaseConch(unixFile *pFile){
|
|
pCtx = (proxyLockingContext *)pFile->lockingContext;
|
|
conchFile = pCtx->conchFile;
|
|
OSTRACE(("RELEASECONCH %d for %s pid=%d\n", conchFile->h,
|
|
- (pCtx->lockProxyPath ? pCtx->lockProxyPath : ":auto:"),
|
|
+ (pCtx->lockProxyPath ? pCtx->lockProxyPath : ":auto:"),
|
|
osGetpid(0)));
|
|
if( pCtx->conchHeld>0 ){
|
|
rc = conchFile->pMethod->xUnlock((sqlite3_file*)conchFile, NO_LOCK);
|
|
@@ -40684,13 +44530,13 @@ static int proxyCreateConchPathname(char *dbPath, char **pConchPath){
|
|
char *conchPath; /* buffer in which to construct conch name */
|
|
|
|
/* Allocate space for the conch filename and initialize the name to
|
|
- ** the name of the original database file. */
|
|
+ ** the name of the original database file. */
|
|
*pConchPath = conchPath = (char *)sqlite3_malloc64(len + 8);
|
|
if( conchPath==0 ){
|
|
return SQLITE_NOMEM_BKPT;
|
|
}
|
|
memcpy(conchPath, dbPath, len+1);
|
|
-
|
|
+
|
|
/* now insert a "." before the last / character */
|
|
for( i=(len-1); i>=0; i-- ){
|
|
if( conchPath[i]=='/' ){
|
|
@@ -40713,7 +44559,7 @@ static int proxyCreateConchPathname(char *dbPath, char **pConchPath){
|
|
|
|
|
|
/* Takes a fully configured proxy locking-style unix file and switches
|
|
-** the local lock file path
|
|
+** the local lock file path
|
|
*/
|
|
static int switchLockProxyPath(unixFile *pFile, const char *path) {
|
|
proxyLockingContext *pCtx = (proxyLockingContext*)pFile->lockingContext;
|
|
@@ -40722,7 +44568,7 @@ static int switchLockProxyPath(unixFile *pFile, const char *path) {
|
|
|
|
if( pFile->eFileLock!=NO_LOCK ){
|
|
return SQLITE_BUSY;
|
|
- }
|
|
+ }
|
|
|
|
/* nothing to do if the path is NULL, :auto: or matches the existing path */
|
|
if( !path || path[0]=='\0' || !strcmp(path, ":auto:") ||
|
|
@@ -40740,7 +44586,7 @@ static int switchLockProxyPath(unixFile *pFile, const char *path) {
|
|
sqlite3_free(oldPath);
|
|
pCtx->lockProxyPath = sqlite3DbStrDup(0, path);
|
|
}
|
|
-
|
|
+
|
|
return rc;
|
|
}
|
|
|
|
@@ -40754,7 +44600,7 @@ static int switchLockProxyPath(unixFile *pFile, const char *path) {
|
|
static int proxyGetDbPathForUnixFile(unixFile *pFile, char *dbPath){
|
|
#if defined(__APPLE__)
|
|
if( pFile->pMethod == &afpIoMethods ){
|
|
- /* afp style keeps a reference to the db path in the filePath field
|
|
+ /* afp style keeps a reference to the db path in the filePath field
|
|
** of the struct */
|
|
assert( (int)strlen((char*)pFile->lockingContext)<=MAXPATHLEN );
|
|
strlcpy(dbPath, ((afpLockingContext *)pFile->lockingContext)->dbPath,
|
|
@@ -40775,9 +44621,9 @@ static int proxyGetDbPathForUnixFile(unixFile *pFile, char *dbPath){
|
|
}
|
|
|
|
/*
|
|
-** Takes an already filled in unix file and alters it so all file locking
|
|
+** Takes an already filled in unix file and alters it so all file locking
|
|
** will be performed on the local proxy lock file. The following fields
|
|
-** are preserved in the locking context so that they can be restored and
|
|
+** are preserved in the locking context so that they can be restored and
|
|
** the unix structure properly cleaned up at close time:
|
|
** ->lockingContext
|
|
** ->pMethod
|
|
@@ -40787,7 +44633,7 @@ static int proxyTransformUnixFile(unixFile *pFile, const char *path) {
|
|
char dbPath[MAXPATHLEN+1]; /* Name of the database file */
|
|
char *lockPath=NULL;
|
|
int rc = SQLITE_OK;
|
|
-
|
|
+
|
|
if( pFile->eFileLock!=NO_LOCK ){
|
|
return SQLITE_BUSY;
|
|
}
|
|
@@ -40797,7 +44643,7 @@ static int proxyTransformUnixFile(unixFile *pFile, const char *path) {
|
|
}else{
|
|
lockPath=(char *)path;
|
|
}
|
|
-
|
|
+
|
|
OSTRACE(("TRANSPROXY %d for %s pid=%d\n", pFile->h,
|
|
(lockPath ? lockPath : ":auto:"), osGetpid(0)));
|
|
|
|
@@ -40831,7 +44677,7 @@ static int proxyTransformUnixFile(unixFile *pFile, const char *path) {
|
|
rc = SQLITE_OK;
|
|
}
|
|
}
|
|
- }
|
|
+ }
|
|
if( rc==SQLITE_OK && lockPath ){
|
|
pCtx->lockProxyPath = sqlite3DbStrDup(0, lockPath);
|
|
}
|
|
@@ -40843,7 +44689,7 @@ static int proxyTransformUnixFile(unixFile *pFile, const char *path) {
|
|
}
|
|
}
|
|
if( rc==SQLITE_OK ){
|
|
- /* all memory is allocated, proxys are created and assigned,
|
|
+ /* all memory is allocated, proxys are created and assigned,
|
|
** switch the locking context and pMethod then return.
|
|
*/
|
|
pCtx->oldLockingContext = pFile->lockingContext;
|
|
@@ -40851,12 +44697,12 @@ static int proxyTransformUnixFile(unixFile *pFile, const char *path) {
|
|
pCtx->pOldMethod = pFile->pMethod;
|
|
pFile->pMethod = &proxyIoMethods;
|
|
}else{
|
|
- if( pCtx->conchFile ){
|
|
+ if( pCtx->conchFile ){
|
|
pCtx->conchFile->pMethod->xClose((sqlite3_file *)pCtx->conchFile);
|
|
sqlite3_free(pCtx->conchFile);
|
|
}
|
|
sqlite3DbFree(0, pCtx->lockProxyPath);
|
|
- sqlite3_free(pCtx->conchFilePath);
|
|
+ sqlite3_free(pCtx->conchFilePath);
|
|
sqlite3_free(pCtx);
|
|
}
|
|
OSTRACE(("TRANSPROXY %d %s\n", pFile->h,
|
|
@@ -40894,7 +44740,7 @@ static int proxyFileControl(sqlite3_file *id, int op, void *pArg){
|
|
if( isProxyStyle ){
|
|
/* turn off proxy locking - not supported. If support is added for
|
|
** switching proxy locking mode off then it will need to fail if
|
|
- ** the journal mode is WAL mode.
|
|
+ ** the journal mode is WAL mode.
|
|
*/
|
|
rc = SQLITE_ERROR /*SQLITE_PROTOCOL? SQLITE_MISUSE?*/;
|
|
}else{
|
|
@@ -40904,9 +44750,9 @@ static int proxyFileControl(sqlite3_file *id, int op, void *pArg){
|
|
}else{
|
|
const char *proxyPath = (const char *)pArg;
|
|
if( isProxyStyle ){
|
|
- proxyLockingContext *pCtx =
|
|
+ proxyLockingContext *pCtx =
|
|
(proxyLockingContext*)pFile->lockingContext;
|
|
- if( !strcmp(pArg, ":auto:")
|
|
+ if( !strcmp(pArg, ":auto:")
|
|
|| (pCtx->lockProxyPath &&
|
|
!strncmp(pCtx->lockProxyPath, proxyPath, MAXPATHLEN))
|
|
){
|
|
@@ -41031,7 +44877,7 @@ static int proxyClose(sqlite3_file *id) {
|
|
unixFile *lockProxy = pCtx->lockProxy;
|
|
unixFile *conchFile = pCtx->conchFile;
|
|
int rc = SQLITE_OK;
|
|
-
|
|
+
|
|
if( lockProxy ){
|
|
rc = lockProxy->pMethod->xUnlock((sqlite3_file*)lockProxy, NO_LOCK);
|
|
if( rc ) return rc;
|
|
@@ -41068,7 +44914,7 @@ static int proxyClose(sqlite3_file *id) {
|
|
** The proxy locking style is intended for use with AFP filesystems.
|
|
** And since AFP is only supported on MacOSX, the proxy locking is also
|
|
** restricted to MacOSX.
|
|
-**
|
|
+**
|
|
**
|
|
******************* End of the proxy lock implementation **********************
|
|
******************************************************************************/
|
|
@@ -41086,8 +44932,8 @@ static int proxyClose(sqlite3_file *id) {
|
|
** necessarily been initialized when this routine is called, and so they
|
|
** should not be used.
|
|
*/
|
|
-SQLITE_API int sqlite3_os_init(void){
|
|
- /*
|
|
+SQLITE_API int sqlite3_os_init(void){
|
|
+ /*
|
|
** The following macro defines an initializer for an sqlite3_vfs object.
|
|
** The name of the VFS is NAME. The pAppData is a pointer to a pointer
|
|
** to the "finder" function. (pAppData is a pointer to a pointer because
|
|
@@ -41103,7 +44949,7 @@ SQLITE_API int sqlite3_os_init(void){
|
|
**
|
|
** Most finders simply return a pointer to a fixed sqlite3_io_methods
|
|
** object. But the "autolockIoFinder" available on MacOSX does a little
|
|
- ** more than that; it looks at the filesystem type that hosts the
|
|
+ ** more than that; it looks at the filesystem type that hosts the
|
|
** database file and tries to choose an locking method appropriate for
|
|
** that filesystem time.
|
|
*/
|
|
@@ -41173,10 +45019,40 @@ SQLITE_API int sqlite3_os_init(void){
|
|
|
|
/* Register all VFSes defined in the aVfs[] array */
|
|
for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){
|
|
+#ifdef SQLITE_DEFAULT_UNIX_VFS
|
|
+ sqlite3_vfs_register(&aVfs[i],
|
|
+ 0==strcmp(aVfs[i].zName,SQLITE_DEFAULT_UNIX_VFS));
|
|
+#else
|
|
sqlite3_vfs_register(&aVfs[i], i==0);
|
|
+#endif
|
|
}
|
|
+#ifdef SQLITE_OS_KV_OPTIONAL
|
|
+ sqlite3KvvfsInit();
|
|
+#endif
|
|
unixBigLock = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1);
|
|
- return SQLITE_OK;
|
|
+
|
|
+#ifndef SQLITE_OMIT_WAL
|
|
+ /* Validate lock assumptions */
|
|
+ assert( SQLITE_SHM_NLOCK==8 ); /* Number of available locks */
|
|
+ assert( UNIX_SHM_BASE==120 ); /* Start of locking area */
|
|
+ /* Locks:
|
|
+ ** WRITE UNIX_SHM_BASE 120
|
|
+ ** CKPT UNIX_SHM_BASE+1 121
|
|
+ ** RECOVER UNIX_SHM_BASE+2 122
|
|
+ ** READ-0 UNIX_SHM_BASE+3 123
|
|
+ ** READ-1 UNIX_SHM_BASE+4 124
|
|
+ ** READ-2 UNIX_SHM_BASE+5 125
|
|
+ ** READ-3 UNIX_SHM_BASE+6 126
|
|
+ ** READ-4 UNIX_SHM_BASE+7 127
|
|
+ ** DMS UNIX_SHM_BASE+8 128
|
|
+ */
|
|
+ assert( UNIX_SHM_DMS==128 ); /* Byte offset of the deadman-switch */
|
|
+#endif
|
|
+
|
|
+ /* Initialize temp file dir array. */
|
|
+ unixTempFileInit();
|
|
+
|
|
+ return SQLITE_OK;
|
|
}
|
|
|
|
/*
|
|
@@ -41186,11 +45062,11 @@ SQLITE_API int sqlite3_os_init(void){
|
|
** to release dynamically allocated objects. But not on unix.
|
|
** This routine is a no-op for unix.
|
|
*/
|
|
-SQLITE_API int sqlite3_os_end(void){
|
|
+SQLITE_API int sqlite3_os_end(void){
|
|
unixBigLock = 0;
|
|
- return SQLITE_OK;
|
|
+ return SQLITE_OK;
|
|
}
|
|
-
|
|
+
|
|
#endif /* SQLITE_OS_UNIX */
|
|
|
|
/************** End of os_unix.c *********************************************/
|
|
@@ -41215,205 +45091,7 @@ SQLITE_API int sqlite3_os_end(void){
|
|
/*
|
|
** Include code that is common to all os_*.c files
|
|
*/
|
|
-/************** Include os_common.h in the middle of os_win.c ****************/
|
|
-/************** Begin file os_common.h ***************************************/
|
|
-/*
|
|
-** 2004 May 22
|
|
-**
|
|
-** The author disclaims copyright to this source code. In place of
|
|
-** a legal notice, here is a blessing:
|
|
-**
|
|
-** May you do good and not evil.
|
|
-** May you find forgiveness for yourself and forgive others.
|
|
-** May you share freely, never taking more than you give.
|
|
-**
|
|
-******************************************************************************
|
|
-**
|
|
-** This file contains macros and a little bit of code that is common to
|
|
-** all of the platform-specific files (os_*.c) and is #included into those
|
|
-** files.
|
|
-**
|
|
-** This file should be #included by the os_*.c files only. It is not a
|
|
-** general purpose header file.
|
|
-*/
|
|
-#ifndef _OS_COMMON_H_
|
|
-#define _OS_COMMON_H_
|
|
-
|
|
-/*
|
|
-** At least two bugs have slipped in because we changed the MEMORY_DEBUG
|
|
-** macro to SQLITE_DEBUG and some older makefiles have not yet made the
|
|
-** switch. The following code should catch this problem at compile-time.
|
|
-*/
|
|
-#ifdef MEMORY_DEBUG
|
|
-# error "The MEMORY_DEBUG macro is obsolete. Use SQLITE_DEBUG instead."
|
|
-#endif
|
|
-
|
|
-/*
|
|
-** Macros for performance tracing. Normally turned off. Only works
|
|
-** on i486 hardware.
|
|
-*/
|
|
-#ifdef SQLITE_PERFORMANCE_TRACE
|
|
-
|
|
-/*
|
|
-** hwtime.h contains inline assembler code for implementing
|
|
-** high-performance timing routines.
|
|
-*/
|
|
-/************** Include hwtime.h in the middle of os_common.h ****************/
|
|
-/************** Begin file hwtime.h ******************************************/
|
|
-/*
|
|
-** 2008 May 27
|
|
-**
|
|
-** The author disclaims copyright to this source code. In place of
|
|
-** a legal notice, here is a blessing:
|
|
-**
|
|
-** May you do good and not evil.
|
|
-** May you find forgiveness for yourself and forgive others.
|
|
-** May you share freely, never taking more than you give.
|
|
-**
|
|
-******************************************************************************
|
|
-**
|
|
-** This file contains inline asm code for retrieving "high-performance"
|
|
-** counters for x86 and x86_64 class CPUs.
|
|
-*/
|
|
-#ifndef SQLITE_HWTIME_H
|
|
-#define SQLITE_HWTIME_H
|
|
-
|
|
-/*
|
|
-** The following routine only works on pentium-class (or newer) processors.
|
|
-** It uses the RDTSC opcode to read the cycle count value out of the
|
|
-** processor and returns that value. This can be used for high-res
|
|
-** profiling.
|
|
-*/
|
|
-#if !defined(__STRICT_ANSI__) && \
|
|
- (defined(__GNUC__) || defined(_MSC_VER)) && \
|
|
- (defined(i386) || defined(__i386__) || defined(_M_IX86))
|
|
-
|
|
- #if defined(__GNUC__)
|
|
-
|
|
- __inline__ sqlite_uint64 sqlite3Hwtime(void){
|
|
- unsigned int lo, hi;
|
|
- __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
|
|
- return (sqlite_uint64)hi << 32 | lo;
|
|
- }
|
|
-
|
|
- #elif defined(_MSC_VER)
|
|
-
|
|
- __declspec(naked) __inline sqlite_uint64 __cdecl sqlite3Hwtime(void){
|
|
- __asm {
|
|
- rdtsc
|
|
- ret ; return value at EDX:EAX
|
|
- }
|
|
- }
|
|
-
|
|
- #endif
|
|
-
|
|
-#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__x86_64__))
|
|
-
|
|
- __inline__ sqlite_uint64 sqlite3Hwtime(void){
|
|
- unsigned long val;
|
|
- __asm__ __volatile__ ("rdtsc" : "=A" (val));
|
|
- return val;
|
|
- }
|
|
-
|
|
-#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__ppc__))
|
|
-
|
|
- __inline__ sqlite_uint64 sqlite3Hwtime(void){
|
|
- unsigned long long retval;
|
|
- unsigned long junk;
|
|
- __asm__ __volatile__ ("\n\
|
|
- 1: mftbu %1\n\
|
|
- mftb %L0\n\
|
|
- mftbu %0\n\
|
|
- cmpw %0,%1\n\
|
|
- bne 1b"
|
|
- : "=r" (retval), "=r" (junk));
|
|
- return retval;
|
|
- }
|
|
-
|
|
-#else
|
|
-
|
|
- /*
|
|
- ** asm() is needed for hardware timing support. Without asm(),
|
|
- ** disable the sqlite3Hwtime() routine.
|
|
- **
|
|
- ** sqlite3Hwtime() is only used for some obscure debugging
|
|
- ** and analysis configurations, not in any deliverable, so this
|
|
- ** should not be a great loss.
|
|
- */
|
|
-SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); }
|
|
-
|
|
-#endif
|
|
-
|
|
-#endif /* !defined(SQLITE_HWTIME_H) */
|
|
-
|
|
-/************** End of hwtime.h **********************************************/
|
|
-/************** Continuing where we left off in os_common.h ******************/
|
|
-
|
|
-static sqlite_uint64 g_start;
|
|
-static sqlite_uint64 g_elapsed;
|
|
-#define TIMER_START g_start=sqlite3Hwtime()
|
|
-#define TIMER_END g_elapsed=sqlite3Hwtime()-g_start
|
|
-#define TIMER_ELAPSED g_elapsed
|
|
-#else
|
|
-#define TIMER_START
|
|
-#define TIMER_END
|
|
-#define TIMER_ELAPSED ((sqlite_uint64)0)
|
|
-#endif
|
|
-
|
|
-/*
|
|
-** If we compile with the SQLITE_TEST macro set, then the following block
|
|
-** of code will give us the ability to simulate a disk I/O error. This
|
|
-** is used for testing the I/O recovery logic.
|
|
-*/
|
|
-#if defined(SQLITE_TEST)
|
|
-SQLITE_API extern int sqlite3_io_error_hit;
|
|
-SQLITE_API extern int sqlite3_io_error_hardhit;
|
|
-SQLITE_API extern int sqlite3_io_error_pending;
|
|
-SQLITE_API extern int sqlite3_io_error_persist;
|
|
-SQLITE_API extern int sqlite3_io_error_benign;
|
|
-SQLITE_API extern int sqlite3_diskfull_pending;
|
|
-SQLITE_API extern int sqlite3_diskfull;
|
|
-#define SimulateIOErrorBenign(X) sqlite3_io_error_benign=(X)
|
|
-#define SimulateIOError(CODE) \
|
|
- if( (sqlite3_io_error_persist && sqlite3_io_error_hit) \
|
|
- || sqlite3_io_error_pending-- == 1 ) \
|
|
- { local_ioerr(); CODE; }
|
|
-static void local_ioerr(){
|
|
- IOTRACE(("IOERR\n"));
|
|
- sqlite3_io_error_hit++;
|
|
- if( !sqlite3_io_error_benign ) sqlite3_io_error_hardhit++;
|
|
-}
|
|
-#define SimulateDiskfullError(CODE) \
|
|
- if( sqlite3_diskfull_pending ){ \
|
|
- if( sqlite3_diskfull_pending == 1 ){ \
|
|
- local_ioerr(); \
|
|
- sqlite3_diskfull = 1; \
|
|
- sqlite3_io_error_hit = 1; \
|
|
- CODE; \
|
|
- }else{ \
|
|
- sqlite3_diskfull_pending--; \
|
|
- } \
|
|
- }
|
|
-#else
|
|
-#define SimulateIOErrorBenign(X)
|
|
-#define SimulateIOError(A)
|
|
-#define SimulateDiskfullError(A)
|
|
-#endif /* defined(SQLITE_TEST) */
|
|
-
|
|
-/*
|
|
-** When testing, keep a count of the number of open files.
|
|
-*/
|
|
-#if defined(SQLITE_TEST)
|
|
-SQLITE_API extern int sqlite3_open_file_count;
|
|
-#define OpenCounter(X) sqlite3_open_file_count+=(X)
|
|
-#else
|
|
-#define OpenCounter(X)
|
|
-#endif /* defined(SQLITE_TEST) */
|
|
-
|
|
-#endif /* !defined(_OS_COMMON_H_) */
|
|
-
|
|
-/************** End of os_common.h *******************************************/
|
|
-/************** Continuing where we left off in os_win.c *********************/
|
|
+/* #include "os_common.h" */
|
|
|
|
/*
|
|
** Include the header file for the Windows VFS.
|
|
@@ -42685,17 +46363,17 @@ SQLITE_API int sqlite3_win32_compact_heap(LPUINT pnLargest){
|
|
*/
|
|
SQLITE_API int sqlite3_win32_reset_heap(){
|
|
int rc;
|
|
- MUTEX_LOGIC( sqlite3_mutex *pMaster; ) /* The main static mutex */
|
|
+ MUTEX_LOGIC( sqlite3_mutex *pMainMtx; ) /* The main static mutex */
|
|
MUTEX_LOGIC( sqlite3_mutex *pMem; ) /* The memsys static mutex */
|
|
- MUTEX_LOGIC( pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); )
|
|
+ MUTEX_LOGIC( pMainMtx = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); )
|
|
MUTEX_LOGIC( pMem = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MEM); )
|
|
- sqlite3_mutex_enter(pMaster);
|
|
+ sqlite3_mutex_enter(pMainMtx);
|
|
sqlite3_mutex_enter(pMem);
|
|
winMemAssertMagic();
|
|
if( winMemGetHeap()!=NULL && winMemGetOwned() && sqlite3_memory_used()==0 ){
|
|
/*
|
|
** At this point, there should be no outstanding memory allocations on
|
|
- ** the heap. Also, since both the master and memsys locks are currently
|
|
+ ** the heap. Also, since both the main and memsys locks are currently
|
|
** being held by us, no other function (i.e. from another thread) should
|
|
** be able to even access the heap. Attempt to destroy and recreate our
|
|
** isolated Win32 native heap now.
|
|
@@ -42718,7 +46396,7 @@ SQLITE_API int sqlite3_win32_reset_heap(){
|
|
rc = SQLITE_BUSY;
|
|
}
|
|
sqlite3_mutex_leave(pMem);
|
|
- sqlite3_mutex_leave(pMaster);
|
|
+ sqlite3_mutex_leave(pMainMtx);
|
|
return rc;
|
|
}
|
|
#endif /* SQLITE_WIN32_MALLOC */
|
|
@@ -43313,10 +46991,12 @@ SQLITE_API int sqlite3_win32_set_directory8(
|
|
const char *zValue /* New value for directory being set or reset */
|
|
){
|
|
char **ppDirectory = 0;
|
|
+ int rc;
|
|
#ifndef SQLITE_OMIT_AUTOINIT
|
|
- int rc = sqlite3_initialize();
|
|
+ rc = sqlite3_initialize();
|
|
if( rc ) return rc;
|
|
#endif
|
|
+ sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
|
|
if( type==SQLITE_WIN32_DATA_DIRECTORY_TYPE ){
|
|
ppDirectory = &sqlite3_data_directory;
|
|
}else if( type==SQLITE_WIN32_TEMP_DIRECTORY_TYPE ){
|
|
@@ -43331,14 +47011,19 @@ SQLITE_API int sqlite3_win32_set_directory8(
|
|
if( zValue && zValue[0] ){
|
|
zCopy = sqlite3_mprintf("%s", zValue);
|
|
if ( zCopy==0 ){
|
|
- return SQLITE_NOMEM_BKPT;
|
|
+ rc = SQLITE_NOMEM_BKPT;
|
|
+ goto set_directory8_done;
|
|
}
|
|
}
|
|
sqlite3_free(*ppDirectory);
|
|
*ppDirectory = zCopy;
|
|
- return SQLITE_OK;
|
|
+ rc = SQLITE_OK;
|
|
+ }else{
|
|
+ rc = SQLITE_ERROR;
|
|
}
|
|
- return SQLITE_ERROR;
|
|
+set_directory8_done:
|
|
+ sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
|
|
+ return rc;
|
|
}
|
|
|
|
/*
|
|
@@ -44897,6 +48582,7 @@ static void winModeBit(winFile *pFile, unsigned char mask, int *pArg){
|
|
/* Forward references to VFS helper methods used for temporary files */
|
|
static int winGetTempname(sqlite3_vfs *, char **);
|
|
static int winIsDir(const void *);
|
|
+static BOOL winIsLongPathPrefix(const char *);
|
|
static BOOL winIsDriveLetterAndColon(const char *);
|
|
|
|
/*
|
|
@@ -45464,10 +49150,14 @@ static int winShmLock(
|
|
winFile *pDbFd = (winFile*)fd; /* Connection holding shared memory */
|
|
winShm *p = pDbFd->pShm; /* The shared memory being locked */
|
|
winShm *pX; /* For looping over all siblings */
|
|
- winShmNode *pShmNode = p->pShmNode;
|
|
+ winShmNode *pShmNode;
|
|
int rc = SQLITE_OK; /* Result code */
|
|
u16 mask; /* Mask of locks to take or release */
|
|
|
|
+ if( p==0 ) return SQLITE_IOERR_SHMLOCK;
|
|
+ pShmNode = p->pShmNode;
|
|
+ if( NEVER(pShmNode==0) ) return SQLITE_IOERR_SHMLOCK;
|
|
+
|
|
assert( ofst>=0 && ofst+n<=SQLITE_SHM_NLOCK );
|
|
assert( n>=1 );
|
|
assert( flags==(SQLITE_SHM_LOCK | SQLITE_SHM_SHARED)
|
|
@@ -46107,6 +49797,19 @@ static int winMakeEndInDirSep(int nBuf, char *zBuf){
|
|
return 0;
|
|
}
|
|
|
|
+/*
|
|
+** If sqlite3_temp_directory is defined, take the mutex and return true.
|
|
+**
|
|
+** If sqlite3_temp_directory is NULL (undefined), omit the mutex and
|
|
+** return false.
|
|
+*/
|
|
+static int winTempDirDefined(void){
|
|
+ sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
|
|
+ if( sqlite3_temp_directory!=0 ) return 1;
|
|
+ sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
|
|
+ return 0;
|
|
+}
|
|
+
|
|
/*
|
|
** Create a temporary file name and store the resulting pointer into pzBuf.
|
|
** The pointer returned in pzBuf must be freed via sqlite3_free().
|
|
@@ -46143,20 +49846,23 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
|
|
*/
|
|
nDir = nMax - (nPre + 15);
|
|
assert( nDir>0 );
|
|
- if( sqlite3_temp_directory ){
|
|
+ if( winTempDirDefined() ){
|
|
int nDirLen = sqlite3Strlen30(sqlite3_temp_directory);
|
|
if( nDirLen>0 ){
|
|
if( !winIsDirSep(sqlite3_temp_directory[nDirLen-1]) ){
|
|
nDirLen++;
|
|
}
|
|
if( nDirLen>nDir ){
|
|
+ sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
|
|
sqlite3_free(zBuf);
|
|
OSTRACE(("TEMP-FILENAME rc=SQLITE_ERROR\n"));
|
|
return winLogError(SQLITE_ERROR, 0, "winGetTempname1", 0);
|
|
}
|
|
sqlite3_snprintf(nMax, zBuf, "%s", sqlite3_temp_directory);
|
|
}
|
|
+ sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
|
|
}
|
|
+
|
|
#if defined(__CYGWIN__)
|
|
else{
|
|
static const char *azDirs[] = {
|
|
@@ -46417,7 +50123,7 @@ static int winOpen(
|
|
|
|
#ifndef NDEBUG
|
|
int isOpenJournal = (isCreate && (
|
|
- eType==SQLITE_OPEN_MASTER_JOURNAL
|
|
+ eType==SQLITE_OPEN_SUPER_JOURNAL
|
|
|| eType==SQLITE_OPEN_MAIN_JOURNAL
|
|
|| eType==SQLITE_OPEN_WAL
|
|
));
|
|
@@ -46438,17 +50144,17 @@ static int winOpen(
|
|
assert(isExclusive==0 || isCreate);
|
|
assert(isDelete==0 || isCreate);
|
|
|
|
- /* The main DB, main journal, WAL file and master journal are never
|
|
+ /* The main DB, main journal, WAL file and super-journal are never
|
|
** automatically deleted. Nor are they ever temporary files. */
|
|
assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_DB );
|
|
assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_JOURNAL );
|
|
- assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MASTER_JOURNAL );
|
|
+ assert( (!isDelete && zName) || eType!=SQLITE_OPEN_SUPER_JOURNAL );
|
|
assert( (!isDelete && zName) || eType!=SQLITE_OPEN_WAL );
|
|
|
|
/* Assert that the upper layer has set one of the "file-type" flags. */
|
|
assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB
|
|
|| eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL
|
|
- || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL
|
|
+ || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_SUPER_JOURNAL
|
|
|| eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL
|
|
);
|
|
|
|
@@ -46520,7 +50226,11 @@ static int winOpen(
|
|
dwCreationDisposition = OPEN_EXISTING;
|
|
}
|
|
|
|
- dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
|
|
+ if( 0==sqlite3_uri_boolean(zName, "exclusive", 0) ){
|
|
+ dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
|
|
+ }else{
|
|
+ dwShareMode = 0;
|
|
+ }
|
|
|
|
if( isDelete ){
|
|
#if SQLITE_OS_WINCE
|
|
@@ -46660,13 +50370,15 @@ static int winOpen(
|
|
}
|
|
|
|
sqlite3_free(zTmpname);
|
|
- pFile->pMethod = pAppData ? pAppData->pMethod : &winIoMethod;
|
|
+ id->pMethods = pAppData ? pAppData->pMethod : &winIoMethod;
|
|
pFile->pVfs = pVfs;
|
|
pFile->h = h;
|
|
if( isReadonly ){
|
|
pFile->ctrlFlags |= WINFILE_RDONLY;
|
|
}
|
|
- if( sqlite3_uri_boolean(zName, "psow", SQLITE_POWERSAFE_OVERWRITE) ){
|
|
+ if( (flags & SQLITE_OPEN_MAIN_DB)
|
|
+ && sqlite3_uri_boolean(zName, "psow", SQLITE_POWERSAFE_OVERWRITE)
|
|
+ ){
|
|
pFile->ctrlFlags |= WINFILE_PSOW;
|
|
}
|
|
pFile->lastErrno = NO_ERROR;
|
|
@@ -46876,6 +50588,17 @@ static int winAccess(
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
+/*
|
|
+** Returns non-zero if the specified path name starts with the "long path"
|
|
+** prefix.
|
|
+*/
|
|
+static BOOL winIsLongPathPrefix(
|
|
+ const char *zPathname
|
|
+){
|
|
+ return ( zPathname[0]=='\\' && zPathname[1]=='\\'
|
|
+ && zPathname[2]=='?' && zPathname[3]=='\\' );
|
|
+}
|
|
+
|
|
/*
|
|
** Returns non-zero if the specified path name starts with a drive letter
|
|
** followed by a colon character.
|
|
@@ -46928,7 +50651,7 @@ static BOOL winIsVerbatimPathname(
|
|
** pathname into zOut[]. zOut[] will be at least pVfs->mxPathname
|
|
** bytes in size.
|
|
*/
|
|
-static int winFullPathname(
|
|
+static int winFullPathnameNoMutex(
|
|
sqlite3_vfs *pVfs, /* Pointer to vfs object */
|
|
const char *zRelative, /* Possibly relative input path */
|
|
int nFull, /* Size of output buffer in bytes */
|
|
@@ -46940,10 +50663,11 @@ static int winFullPathname(
|
|
char *zOut;
|
|
#endif
|
|
|
|
- /* If this path name begins with "/X:", where "X" is any alphabetic
|
|
- ** character, discard the initial "/" from the pathname.
|
|
+ /* If this path name begins with "/X:" or "\\?\", where "X" is any
|
|
+ ** alphabetic character, discard the initial "/" from the pathname.
|
|
*/
|
|
- if( zRelative[0]=='/' && winIsDriveLetterAndColon(zRelative+1) ){
|
|
+ if( zRelative[0]=='/' && (winIsDriveLetterAndColon(zRelative+1)
|
|
+ || winIsLongPathPrefix(zRelative+1)) ){
|
|
zRelative++;
|
|
}
|
|
|
|
@@ -47106,6 +50830,20 @@ static int winFullPathname(
|
|
}
|
|
#endif
|
|
}
|
|
+static int winFullPathname(
|
|
+ sqlite3_vfs *pVfs, /* Pointer to vfs object */
|
|
+ const char *zRelative, /* Possibly relative input path */
|
|
+ int nFull, /* Size of output buffer in bytes */
|
|
+ char *zFull /* Output buffer */
|
|
+){
|
|
+ int rc;
|
|
+ MUTEX_LOGIC( sqlite3_mutex *pMutex; )
|
|
+ MUTEX_LOGIC( pMutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR); )
|
|
+ sqlite3_mutex_enter(pMutex);
|
|
+ rc = winFullPathnameNoMutex(pVfs, zRelative, nFull, zFull);
|
|
+ sqlite3_mutex_leave(pMutex);
|
|
+ return rc;
|
|
+}
|
|
|
|
#ifndef SQLITE_OMIT_LOAD_EXTENSION
|
|
/*
|
|
@@ -47550,31 +51288,88 @@ SQLITE_API int sqlite3_os_end(void){
|
|
** sqlite3_deserialize().
|
|
*/
|
|
/* #include "sqliteInt.h" */
|
|
-#ifdef SQLITE_ENABLE_DESERIALIZE
|
|
+#ifndef SQLITE_OMIT_DESERIALIZE
|
|
|
|
/*
|
|
** Forward declaration of objects used by this utility
|
|
*/
|
|
typedef struct sqlite3_vfs MemVfs;
|
|
typedef struct MemFile MemFile;
|
|
+typedef struct MemStore MemStore;
|
|
|
|
/* Access to a lower-level VFS that (might) implement dynamic loading,
|
|
** access to randomness, etc.
|
|
*/
|
|
#define ORIGVFS(p) ((sqlite3_vfs*)((p)->pAppData))
|
|
|
|
-/* An open file */
|
|
-struct MemFile {
|
|
- sqlite3_file base; /* IO methods */
|
|
+/* Storage for a memdb file.
|
|
+**
|
|
+** An memdb object can be shared or separate. Shared memdb objects can be
|
|
+** used by more than one database connection. Mutexes are used by shared
|
|
+** memdb objects to coordinate access. Separate memdb objects are only
|
|
+** connected to a single database connection and do not require additional
|
|
+** mutexes.
|
|
+**
|
|
+** Shared memdb objects have .zFName!=0 and .pMutex!=0. They are created
|
|
+** using "file:/name?vfs=memdb". The first character of the name must be
|
|
+** "/" or else the object will be a separate memdb object. All shared
|
|
+** memdb objects are stored in memdb_g.apMemStore[] in an arbitrary order.
|
|
+**
|
|
+** Separate memdb objects are created using a name that does not begin
|
|
+** with "/" or using sqlite3_deserialize().
|
|
+**
|
|
+** Access rules for shared MemStore objects:
|
|
+**
|
|
+** * .zFName is initialized when the object is created and afterwards
|
|
+** is unchanged until the object is destroyed. So it can be accessed
|
|
+** at any time as long as we know the object is not being destroyed,
|
|
+** which means while either the SQLITE_MUTEX_STATIC_VFS1 or
|
|
+** .pMutex is held or the object is not part of memdb_g.apMemStore[].
|
|
+**
|
|
+** * Can .pMutex can only be changed while holding the
|
|
+** SQLITE_MUTEX_STATIC_VFS1 mutex or while the object is not part
|
|
+** of memdb_g.apMemStore[].
|
|
+**
|
|
+** * Other fields can only be changed while holding the .pMutex mutex
|
|
+** or when the .nRef is less than zero and the object is not part of
|
|
+** memdb_g.apMemStore[].
|
|
+**
|
|
+** * The .aData pointer has the added requirement that it can can only
|
|
+** be changed (for resizing) when nMmap is zero.
|
|
+**
|
|
+*/
|
|
+struct MemStore {
|
|
sqlite3_int64 sz; /* Size of the file */
|
|
sqlite3_int64 szAlloc; /* Space allocated to aData */
|
|
sqlite3_int64 szMax; /* Maximum allowed size of the file */
|
|
unsigned char *aData; /* content of the file */
|
|
+ sqlite3_mutex *pMutex; /* Used by shared stores only */
|
|
int nMmap; /* Number of memory mapped pages */
|
|
unsigned mFlags; /* Flags */
|
|
+ int nRdLock; /* Number of readers */
|
|
+ int nWrLock; /* Number of writers. (Always 0 or 1) */
|
|
+ int nRef; /* Number of users of this MemStore */
|
|
+ char *zFName; /* The filename for shared stores */
|
|
+};
|
|
+
|
|
+/* An open file */
|
|
+struct MemFile {
|
|
+ sqlite3_file base; /* IO methods */
|
|
+ MemStore *pStore; /* The storage */
|
|
int eLock; /* Most recent lock against this file */
|
|
};
|
|
|
|
+/*
|
|
+** File-scope variables for holding the memdb files that are accessible
|
|
+** to multiple database connections in separate threads.
|
|
+**
|
|
+** Must hold SQLITE_MUTEX_STATIC_VFS1 to access any part of this object.
|
|
+*/
|
|
+static struct MemFS {
|
|
+ int nMemStore; /* Number of shared MemStore objects */
|
|
+ MemStore **apMemStore; /* Array of all shared MemStore objects */
|
|
+} memdb_g;
|
|
+
|
|
/*
|
|
** Methods for MemFile
|
|
*/
|
|
@@ -47585,6 +51380,7 @@ static int memdbTruncate(sqlite3_file*, sqlite3_int64 size);
|
|
static int memdbSync(sqlite3_file*, int flags);
|
|
static int memdbFileSize(sqlite3_file*, sqlite3_int64 *pSize);
|
|
static int memdbLock(sqlite3_file*, int);
|
|
+static int memdbUnlock(sqlite3_file*, int);
|
|
/* static int memdbCheckReservedLock(sqlite3_file*, int *pResOut);// not used */
|
|
static int memdbFileControl(sqlite3_file*, int op, void *pArg);
|
|
/* static int memdbSectorSize(sqlite3_file*); // not used */
|
|
@@ -47615,7 +51411,7 @@ static sqlite3_vfs memdb_vfs = {
|
|
1024, /* mxPathname */
|
|
0, /* pNext */
|
|
"memdb", /* zName */
|
|
- 0, /* pAppData (set when registered) */
|
|
+ 0, /* pAppData (set when registered) */
|
|
memdbOpen, /* xOpen */
|
|
0, /* memdbDelete, */ /* xDelete */
|
|
memdbAccess, /* xAccess */
|
|
@@ -47628,7 +51424,10 @@ static sqlite3_vfs memdb_vfs = {
|
|
memdbSleep, /* xSleep */
|
|
0, /* memdbCurrentTime, */ /* xCurrentTime */
|
|
memdbGetLastError, /* xGetLastError */
|
|
- memdbCurrentTimeInt64 /* xCurrentTimeInt64 */
|
|
+ memdbCurrentTimeInt64, /* xCurrentTimeInt64 */
|
|
+ 0, /* xSetSystemCall */
|
|
+ 0, /* xGetSystemCall */
|
|
+ 0, /* xNextSystemCall */
|
|
};
|
|
|
|
static const sqlite3_io_methods memdb_io_methods = {
|
|
@@ -47640,7 +51439,7 @@ static const sqlite3_io_methods memdb_io_methods = {
|
|
memdbSync, /* xSync */
|
|
memdbFileSize, /* xFileSize */
|
|
memdbLock, /* xLock */
|
|
- memdbLock, /* xUnlock - same as xLock in this case */
|
|
+ memdbUnlock, /* xUnlock */
|
|
0, /* memdbCheckReservedLock, */ /* xCheckReservedLock */
|
|
memdbFileControl, /* xFileControl */
|
|
0, /* memdbSectorSize,*/ /* xSectorSize */
|
|
@@ -47653,17 +51452,68 @@ static const sqlite3_io_methods memdb_io_methods = {
|
|
memdbUnfetch /* xUnfetch */
|
|
};
|
|
|
|
+/*
|
|
+** Enter/leave the mutex on a MemStore
|
|
+*/
|
|
+#if defined(SQLITE_THREADSAFE) && SQLITE_THREADSAFE==0
|
|
+static void memdbEnter(MemStore *p){
|
|
+ UNUSED_PARAMETER(p);
|
|
+}
|
|
+static void memdbLeave(MemStore *p){
|
|
+ UNUSED_PARAMETER(p);
|
|
+}
|
|
+#else
|
|
+static void memdbEnter(MemStore *p){
|
|
+ sqlite3_mutex_enter(p->pMutex);
|
|
+}
|
|
+static void memdbLeave(MemStore *p){
|
|
+ sqlite3_mutex_leave(p->pMutex);
|
|
+}
|
|
+#endif
|
|
+
|
|
|
|
|
|
/*
|
|
** Close an memdb-file.
|
|
-**
|
|
-** The pData pointer is owned by the application, so there is nothing
|
|
-** to free.
|
|
+** Free the underlying MemStore object when its refcount drops to zero
|
|
+** or less.
|
|
*/
|
|
static int memdbClose(sqlite3_file *pFile){
|
|
- MemFile *p = (MemFile *)pFile;
|
|
- if( p->mFlags & SQLITE_DESERIALIZE_FREEONCLOSE ) sqlite3_free(p->aData);
|
|
+ MemStore *p = ((MemFile*)pFile)->pStore;
|
|
+ if( p->zFName ){
|
|
+ int i;
|
|
+#ifndef SQLITE_MUTEX_OMIT
|
|
+ sqlite3_mutex *pVfsMutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1);
|
|
+#endif
|
|
+ sqlite3_mutex_enter(pVfsMutex);
|
|
+ for(i=0; ALWAYS(i<memdb_g.nMemStore); i++){
|
|
+ if( memdb_g.apMemStore[i]==p ){
|
|
+ memdbEnter(p);
|
|
+ if( p->nRef==1 ){
|
|
+ memdb_g.apMemStore[i] = memdb_g.apMemStore[--memdb_g.nMemStore];
|
|
+ if( memdb_g.nMemStore==0 ){
|
|
+ sqlite3_free(memdb_g.apMemStore);
|
|
+ memdb_g.apMemStore = 0;
|
|
+ }
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ sqlite3_mutex_leave(pVfsMutex);
|
|
+ }else{
|
|
+ memdbEnter(p);
|
|
+ }
|
|
+ p->nRef--;
|
|
+ if( p->nRef<=0 ){
|
|
+ if( p->mFlags & SQLITE_DESERIALIZE_FREEONCLOSE ){
|
|
+ sqlite3_free(p->aData);
|
|
+ }
|
|
+ memdbLeave(p);
|
|
+ sqlite3_mutex_free(p->pMutex);
|
|
+ sqlite3_free(p);
|
|
+ }else{
|
|
+ memdbLeave(p);
|
|
+ }
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
@@ -47671,27 +51521,30 @@ static int memdbClose(sqlite3_file *pFile){
|
|
** Read data from an memdb-file.
|
|
*/
|
|
static int memdbRead(
|
|
- sqlite3_file *pFile,
|
|
- void *zBuf,
|
|
- int iAmt,
|
|
+ sqlite3_file *pFile,
|
|
+ void *zBuf,
|
|
+ int iAmt,
|
|
sqlite_int64 iOfst
|
|
){
|
|
- MemFile *p = (MemFile *)pFile;
|
|
+ MemStore *p = ((MemFile*)pFile)->pStore;
|
|
+ memdbEnter(p);
|
|
if( iOfst+iAmt>p->sz ){
|
|
memset(zBuf, 0, iAmt);
|
|
if( iOfst<p->sz ) memcpy(zBuf, p->aData+iOfst, p->sz - iOfst);
|
|
+ memdbLeave(p);
|
|
return SQLITE_IOERR_SHORT_READ;
|
|
}
|
|
memcpy(zBuf, p->aData+iOfst, iAmt);
|
|
+ memdbLeave(p);
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
/*
|
|
** Try to enlarge the memory allocation to hold at least sz bytes
|
|
*/
|
|
-static int memdbEnlarge(MemFile *p, sqlite3_int64 newSz){
|
|
+static int memdbEnlarge(MemStore *p, sqlite3_int64 newSz){
|
|
unsigned char *pNew;
|
|
- if( (p->mFlags & SQLITE_DESERIALIZE_RESIZEABLE)==0 || p->nMmap>0 ){
|
|
+ if( (p->mFlags & SQLITE_DESERIALIZE_RESIZEABLE)==0 || NEVER(p->nMmap>0) ){
|
|
return SQLITE_FULL;
|
|
}
|
|
if( newSz>p->szMax ){
|
|
@@ -47699,8 +51552,8 @@ static int memdbEnlarge(MemFile *p, sqlite3_int64 newSz){
|
|
}
|
|
newSz *= 2;
|
|
if( newSz>p->szMax ) newSz = p->szMax;
|
|
- pNew = sqlite3_realloc64(p->aData, newSz);
|
|
- if( pNew==0 ) return SQLITE_NOMEM;
|
|
+ pNew = sqlite3Realloc(p->aData, newSz);
|
|
+ if( pNew==0 ) return SQLITE_IOERR_NOMEM;
|
|
p->aData = pNew;
|
|
p->szAlloc = newSz;
|
|
return SQLITE_OK;
|
|
@@ -47715,19 +51568,27 @@ static int memdbWrite(
|
|
int iAmt,
|
|
sqlite_int64 iOfst
|
|
){
|
|
- MemFile *p = (MemFile *)pFile;
|
|
- if( NEVER(p->mFlags & SQLITE_DESERIALIZE_READONLY) ) return SQLITE_READONLY;
|
|
+ MemStore *p = ((MemFile*)pFile)->pStore;
|
|
+ memdbEnter(p);
|
|
+ if( NEVER(p->mFlags & SQLITE_DESERIALIZE_READONLY) ){
|
|
+ /* Can't happen: memdbLock() will return SQLITE_READONLY before
|
|
+ ** reaching this point */
|
|
+ memdbLeave(p);
|
|
+ return SQLITE_IOERR_WRITE;
|
|
+ }
|
|
if( iOfst+iAmt>p->sz ){
|
|
int rc;
|
|
if( iOfst+iAmt>p->szAlloc
|
|
&& (rc = memdbEnlarge(p, iOfst+iAmt))!=SQLITE_OK
|
|
){
|
|
+ memdbLeave(p);
|
|
return rc;
|
|
}
|
|
if( iOfst>p->sz ) memset(p->aData+p->sz, 0, iOfst-p->sz);
|
|
p->sz = iOfst+iAmt;
|
|
}
|
|
memcpy(p->aData+iOfst, z, iAmt);
|
|
+ memdbLeave(p);
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
@@ -47739,16 +51600,25 @@ static int memdbWrite(
|
|
** the size of a file, never to increase the size.
|
|
*/
|
|
static int memdbTruncate(sqlite3_file *pFile, sqlite_int64 size){
|
|
- MemFile *p = (MemFile *)pFile;
|
|
- if( NEVER(size>p->sz) ) return SQLITE_FULL;
|
|
- p->sz = size;
|
|
- return SQLITE_OK;
|
|
+ MemStore *p = ((MemFile*)pFile)->pStore;
|
|
+ int rc = SQLITE_OK;
|
|
+ memdbEnter(p);
|
|
+ if( size>p->sz ){
|
|
+ /* This can only happen with a corrupt wal mode db */
|
|
+ rc = SQLITE_CORRUPT;
|
|
+ }else{
|
|
+ p->sz = size;
|
|
+ }
|
|
+ memdbLeave(p);
|
|
+ return rc;
|
|
}
|
|
|
|
/*
|
|
** Sync an memdb-file.
|
|
*/
|
|
static int memdbSync(sqlite3_file *pFile, int flags){
|
|
+ UNUSED_PARAMETER(pFile);
|
|
+ UNUSED_PARAMETER(flags);
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
@@ -47756,8 +51626,10 @@ static int memdbSync(sqlite3_file *pFile, int flags){
|
|
** Return the current file-size of an memdb-file.
|
|
*/
|
|
static int memdbFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
|
|
- MemFile *p = (MemFile *)pFile;
|
|
+ MemStore *p = ((MemFile*)pFile)->pStore;
|
|
+ memdbEnter(p);
|
|
*pSize = p->sz;
|
|
+ memdbLeave(p);
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
@@ -47765,19 +51637,90 @@ static int memdbFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
|
|
** Lock an memdb-file.
|
|
*/
|
|
static int memdbLock(sqlite3_file *pFile, int eLock){
|
|
- MemFile *p = (MemFile *)pFile;
|
|
- if( eLock>SQLITE_LOCK_SHARED
|
|
- && (p->mFlags & SQLITE_DESERIALIZE_READONLY)!=0
|
|
- ){
|
|
- return SQLITE_READONLY;
|
|
+ MemFile *pThis = (MemFile*)pFile;
|
|
+ MemStore *p = pThis->pStore;
|
|
+ int rc = SQLITE_OK;
|
|
+ if( eLock<=pThis->eLock ) return SQLITE_OK;
|
|
+ memdbEnter(p);
|
|
+
|
|
+ assert( p->nWrLock==0 || p->nWrLock==1 );
|
|
+ assert( pThis->eLock<=SQLITE_LOCK_SHARED || p->nWrLock==1 );
|
|
+ assert( pThis->eLock==SQLITE_LOCK_NONE || p->nRdLock>=1 );
|
|
+
|
|
+ if( eLock>SQLITE_LOCK_SHARED && (p->mFlags & SQLITE_DESERIALIZE_READONLY) ){
|
|
+ rc = SQLITE_READONLY;
|
|
+ }else{
|
|
+ switch( eLock ){
|
|
+ case SQLITE_LOCK_SHARED: {
|
|
+ assert( pThis->eLock==SQLITE_LOCK_NONE );
|
|
+ if( p->nWrLock>0 ){
|
|
+ rc = SQLITE_BUSY;
|
|
+ }else{
|
|
+ p->nRdLock++;
|
|
+ }
|
|
+ break;
|
|
+ };
|
|
+
|
|
+ case SQLITE_LOCK_RESERVED:
|
|
+ case SQLITE_LOCK_PENDING: {
|
|
+ assert( pThis->eLock>=SQLITE_LOCK_SHARED );
|
|
+ if( ALWAYS(pThis->eLock==SQLITE_LOCK_SHARED) ){
|
|
+ if( p->nWrLock>0 ){
|
|
+ rc = SQLITE_BUSY;
|
|
+ }else{
|
|
+ p->nWrLock = 1;
|
|
+ }
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ default: {
|
|
+ assert( eLock==SQLITE_LOCK_EXCLUSIVE );
|
|
+ assert( pThis->eLock>=SQLITE_LOCK_SHARED );
|
|
+ if( p->nRdLock>1 ){
|
|
+ rc = SQLITE_BUSY;
|
|
+ }else if( pThis->eLock==SQLITE_LOCK_SHARED ){
|
|
+ p->nWrLock = 1;
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ if( rc==SQLITE_OK ) pThis->eLock = eLock;
|
|
+ memdbLeave(p);
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Unlock an memdb-file.
|
|
+*/
|
|
+static int memdbUnlock(sqlite3_file *pFile, int eLock){
|
|
+ MemFile *pThis = (MemFile*)pFile;
|
|
+ MemStore *p = pThis->pStore;
|
|
+ if( eLock>=pThis->eLock ) return SQLITE_OK;
|
|
+ memdbEnter(p);
|
|
+
|
|
+ assert( eLock==SQLITE_LOCK_SHARED || eLock==SQLITE_LOCK_NONE );
|
|
+ if( eLock==SQLITE_LOCK_SHARED ){
|
|
+ if( ALWAYS(pThis->eLock>SQLITE_LOCK_SHARED) ){
|
|
+ p->nWrLock--;
|
|
+ }
|
|
+ }else{
|
|
+ if( pThis->eLock>SQLITE_LOCK_SHARED ){
|
|
+ p->nWrLock--;
|
|
+ }
|
|
+ p->nRdLock--;
|
|
}
|
|
- p->eLock = eLock;
|
|
+
|
|
+ pThis->eLock = eLock;
|
|
+ memdbLeave(p);
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
-#if 0 /* Never used because memdbAccess() always returns false */
|
|
+#if 0
|
|
/*
|
|
-** Check if another file-handle holds a RESERVED lock on an memdb-file.
|
|
+** This interface is only used for crash recovery, which does not
|
|
+** occur on an in-memory database.
|
|
*/
|
|
static int memdbCheckReservedLock(sqlite3_file *pFile, int *pResOut){
|
|
*pResOut = 0;
|
|
@@ -47785,12 +51728,14 @@ static int memdbCheckReservedLock(sqlite3_file *pFile, int *pResOut){
|
|
}
|
|
#endif
|
|
|
|
+
|
|
/*
|
|
** File control method. For custom operations on an memdb-file.
|
|
*/
|
|
static int memdbFileControl(sqlite3_file *pFile, int op, void *pArg){
|
|
- MemFile *p = (MemFile *)pFile;
|
|
+ MemStore *p = ((MemFile*)pFile)->pStore;
|
|
int rc = SQLITE_NOTFOUND;
|
|
+ memdbEnter(p);
|
|
if( op==SQLITE_FCNTL_VFSNAME ){
|
|
*(char**)pArg = sqlite3_mprintf("memdb(%p,%lld)", p->aData, p->sz);
|
|
rc = SQLITE_OK;
|
|
@@ -47808,6 +51753,7 @@ static int memdbFileControl(sqlite3_file *pFile, int op, void *pArg){
|
|
*(sqlite3_int64*)pArg = iLimit;
|
|
rc = SQLITE_OK;
|
|
}
|
|
+ memdbLeave(p);
|
|
return rc;
|
|
}
|
|
|
|
@@ -47824,7 +51770,8 @@ static int memdbSectorSize(sqlite3_file *pFile){
|
|
** Return the device characteristic flags supported by an memdb-file.
|
|
*/
|
|
static int memdbDeviceCharacteristics(sqlite3_file *pFile){
|
|
- return SQLITE_IOCAP_ATOMIC |
|
|
+ UNUSED_PARAMETER(pFile);
|
|
+ return SQLITE_IOCAP_ATOMIC |
|
|
SQLITE_IOCAP_POWERSAFE_OVERWRITE |
|
|
SQLITE_IOCAP_SAFE_APPEND |
|
|
SQLITE_IOCAP_SEQUENTIAL;
|
|
@@ -47837,20 +51784,26 @@ static int memdbFetch(
|
|
int iAmt,
|
|
void **pp
|
|
){
|
|
- MemFile *p = (MemFile *)pFile;
|
|
- if( iOfst+iAmt>p->sz ){
|
|
+ MemStore *p = ((MemFile*)pFile)->pStore;
|
|
+ memdbEnter(p);
|
|
+ if( iOfst+iAmt>p->sz || (p->mFlags & SQLITE_DESERIALIZE_RESIZEABLE)!=0 ){
|
|
*pp = 0;
|
|
}else{
|
|
p->nMmap++;
|
|
*pp = (void*)(p->aData + iOfst);
|
|
}
|
|
+ memdbLeave(p);
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
/* Release a memory-mapped page */
|
|
static int memdbUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){
|
|
- MemFile *p = (MemFile *)pFile;
|
|
+ MemStore *p = ((MemFile*)pFile)->pStore;
|
|
+ UNUSED_PARAMETER(iOfst);
|
|
+ UNUSED_PARAMETER(pPage);
|
|
+ memdbEnter(p);
|
|
p->nMmap--;
|
|
+ memdbLeave(p);
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
@@ -47860,24 +51813,83 @@ static int memdbUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){
|
|
static int memdbOpen(
|
|
sqlite3_vfs *pVfs,
|
|
const char *zName,
|
|
- sqlite3_file *pFile,
|
|
+ sqlite3_file *pFd,
|
|
int flags,
|
|
int *pOutFlags
|
|
){
|
|
- MemFile *p = (MemFile*)pFile;
|
|
- if( (flags & SQLITE_OPEN_MAIN_DB)==0 ){
|
|
- return ORIGVFS(pVfs)->xOpen(ORIGVFS(pVfs), zName, pFile, flags, pOutFlags);
|
|
+ MemFile *pFile = (MemFile*)pFd;
|
|
+ MemStore *p = 0;
|
|
+ int szName;
|
|
+ UNUSED_PARAMETER(pVfs);
|
|
+
|
|
+ memset(pFile, 0, sizeof(*pFile));
|
|
+ szName = sqlite3Strlen30(zName);
|
|
+ if( szName>1 && (zName[0]=='/' || zName[0]=='\\') ){
|
|
+ int i;
|
|
+#ifndef SQLITE_MUTEX_OMIT
|
|
+ sqlite3_mutex *pVfsMutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_VFS1);
|
|
+#endif
|
|
+ sqlite3_mutex_enter(pVfsMutex);
|
|
+ for(i=0; i<memdb_g.nMemStore; i++){
|
|
+ if( strcmp(memdb_g.apMemStore[i]->zFName,zName)==0 ){
|
|
+ p = memdb_g.apMemStore[i];
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ if( p==0 ){
|
|
+ MemStore **apNew;
|
|
+ p = sqlite3Malloc( sizeof(*p) + szName + 3 );
|
|
+ if( p==0 ){
|
|
+ sqlite3_mutex_leave(pVfsMutex);
|
|
+ return SQLITE_NOMEM;
|
|
+ }
|
|
+ apNew = sqlite3Realloc(memdb_g.apMemStore,
|
|
+ sizeof(apNew[0])*(memdb_g.nMemStore+1) );
|
|
+ if( apNew==0 ){
|
|
+ sqlite3_free(p);
|
|
+ sqlite3_mutex_leave(pVfsMutex);
|
|
+ return SQLITE_NOMEM;
|
|
+ }
|
|
+ apNew[memdb_g.nMemStore++] = p;
|
|
+ memdb_g.apMemStore = apNew;
|
|
+ memset(p, 0, sizeof(*p));
|
|
+ p->mFlags = SQLITE_DESERIALIZE_RESIZEABLE|SQLITE_DESERIALIZE_FREEONCLOSE;
|
|
+ p->szMax = sqlite3GlobalConfig.mxMemdbSize;
|
|
+ p->zFName = (char*)&p[1];
|
|
+ memcpy(p->zFName, zName, szName+1);
|
|
+ p->pMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
|
|
+ if( p->pMutex==0 ){
|
|
+ memdb_g.nMemStore--;
|
|
+ sqlite3_free(p);
|
|
+ sqlite3_mutex_leave(pVfsMutex);
|
|
+ return SQLITE_NOMEM;
|
|
+ }
|
|
+ p->nRef = 1;
|
|
+ memdbEnter(p);
|
|
+ }else{
|
|
+ memdbEnter(p);
|
|
+ p->nRef++;
|
|
+ }
|
|
+ sqlite3_mutex_leave(pVfsMutex);
|
|
+ }else{
|
|
+ p = sqlite3Malloc( sizeof(*p) );
|
|
+ if( p==0 ){
|
|
+ return SQLITE_NOMEM;
|
|
+ }
|
|
+ memset(p, 0, sizeof(*p));
|
|
+ p->mFlags = SQLITE_DESERIALIZE_RESIZEABLE | SQLITE_DESERIALIZE_FREEONCLOSE;
|
|
+ p->szMax = sqlite3GlobalConfig.mxMemdbSize;
|
|
}
|
|
- memset(p, 0, sizeof(*p));
|
|
- p->mFlags = SQLITE_DESERIALIZE_RESIZEABLE | SQLITE_DESERIALIZE_FREEONCLOSE;
|
|
- assert( pOutFlags!=0 ); /* True because flags==SQLITE_OPEN_MAIN_DB */
|
|
- *pOutFlags = flags | SQLITE_OPEN_MEMORY;
|
|
- p->base.pMethods = &memdb_io_methods;
|
|
- p->szMax = sqlite3GlobalConfig.mxMemdbSize;
|
|
+ pFile->pStore = p;
|
|
+ if( pOutFlags!=0 ){
|
|
+ *pOutFlags = flags | SQLITE_OPEN_MEMORY;
|
|
+ }
|
|
+ pFd->pMethods = &memdb_io_methods;
|
|
+ memdbLeave(p);
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
-#if 0 /* Only used to delete rollback journals, master journals, and WAL
|
|
+#if 0 /* Only used to delete rollback journals, super-journals, and WAL
|
|
** files, none of which exist in memdb. So this routine is never used */
|
|
/*
|
|
** Delete the file located at zPath. If the dirSync argument is true,
|
|
@@ -47896,11 +51908,14 @@ static int memdbDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
|
|
** With memdb, no files ever exist on disk. So always return false.
|
|
*/
|
|
static int memdbAccess(
|
|
- sqlite3_vfs *pVfs,
|
|
- const char *zPath,
|
|
- int flags,
|
|
+ sqlite3_vfs *pVfs,
|
|
+ const char *zPath,
|
|
+ int flags,
|
|
int *pResOut
|
|
){
|
|
+ UNUSED_PARAMETER(pVfs);
|
|
+ UNUSED_PARAMETER(zPath);
|
|
+ UNUSED_PARAMETER(flags);
|
|
*pResOut = 0;
|
|
return SQLITE_OK;
|
|
}
|
|
@@ -47911,11 +51926,12 @@ static int memdbAccess(
|
|
** of at least (INST_MAX_PATHNAME+1) bytes.
|
|
*/
|
|
static int memdbFullPathname(
|
|
- sqlite3_vfs *pVfs,
|
|
- const char *zPath,
|
|
- int nOut,
|
|
+ sqlite3_vfs *pVfs,
|
|
+ const char *zPath,
|
|
+ int nOut,
|
|
char *zOut
|
|
){
|
|
+ UNUSED_PARAMETER(pVfs);
|
|
sqlite3_snprintf(nOut, zOut, "%s", zPath);
|
|
return SQLITE_OK;
|
|
}
|
|
@@ -47929,7 +51945,7 @@ static void *memdbDlOpen(sqlite3_vfs *pVfs, const char *zPath){
|
|
|
|
/*
|
|
** Populate the buffer zErrMsg (size nByte bytes) with a human readable
|
|
-** utf-8 string describing the most recent error encountered associated
|
|
+** utf-8 string describing the most recent error encountered associated
|
|
** with dynamic libraries.
|
|
*/
|
|
static void memdbDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
|
|
@@ -47951,7 +51967,7 @@ static void memdbDlClose(sqlite3_vfs *pVfs, void *pHandle){
|
|
}
|
|
|
|
/*
|
|
-** Populate the buffer pointed to by zBufOut with nByte bytes of
|
|
+** Populate the buffer pointed to by zBufOut with nByte bytes of
|
|
** random data.
|
|
*/
|
|
static int memdbRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
|
|
@@ -47959,7 +51975,7 @@ static int memdbRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
|
|
}
|
|
|
|
/*
|
|
-** Sleep for nMicro microseconds. Return the number of microseconds
|
|
+** Sleep for nMicro microseconds. Return the number of microseconds
|
|
** actually slept.
|
|
*/
|
|
static int memdbSleep(sqlite3_vfs *pVfs, int nMicro){
|
|
@@ -47988,9 +52004,14 @@ static int memdbCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){
|
|
*/
|
|
static MemFile *memdbFromDbSchema(sqlite3 *db, const char *zSchema){
|
|
MemFile *p = 0;
|
|
+ MemStore *pStore;
|
|
int rc = sqlite3_file_control(db, zSchema, SQLITE_FCNTL_FILE_POINTER, &p);
|
|
if( rc ) return 0;
|
|
if( p->base.pMethods!=&memdb_io_methods ) return 0;
|
|
+ pStore = p->pStore;
|
|
+ memdbEnter(pStore);
|
|
+ if( pStore->zFName!=0 ) p = 0;
|
|
+ memdbLeave(pStore);
|
|
return p;
|
|
}
|
|
|
|
@@ -48026,12 +52047,14 @@ SQLITE_API unsigned char *sqlite3_serialize(
|
|
if( piSize ) *piSize = -1;
|
|
if( iDb<0 ) return 0;
|
|
if( p ){
|
|
- if( piSize ) *piSize = p->sz;
|
|
+ MemStore *pStore = p->pStore;
|
|
+ assert( pStore->pMutex==0 );
|
|
+ if( piSize ) *piSize = pStore->sz;
|
|
if( mFlags & SQLITE_SERIALIZE_NOCOPY ){
|
|
- pOut = p->aData;
|
|
+ pOut = pStore->aData;
|
|
}else{
|
|
- pOut = sqlite3_malloc64( p->sz );
|
|
- if( pOut ) memcpy(pOut, p->aData, p->sz);
|
|
+ pOut = sqlite3_malloc64( pStore->sz );
|
|
+ if( pOut ) memcpy(pOut, pStore->aData, pStore->sz);
|
|
}
|
|
return pOut;
|
|
}
|
|
@@ -48065,7 +52088,7 @@ SQLITE_API unsigned char *sqlite3_serialize(
|
|
}else{
|
|
memset(pTo, 0, szPage);
|
|
}
|
|
- sqlite3PagerUnref(pPage);
|
|
+ sqlite3PagerUnref(pPage);
|
|
}
|
|
}
|
|
}
|
|
@@ -48101,13 +52124,18 @@ SQLITE_API int sqlite3_deserialize(
|
|
sqlite3_mutex_enter(db->mutex);
|
|
if( zSchema==0 ) zSchema = db->aDb[0].zDbSName;
|
|
iDb = sqlite3FindDbName(db, zSchema);
|
|
- if( iDb<0 ){
|
|
+ testcase( iDb==1 );
|
|
+ if( iDb<2 && iDb!=0 ){
|
|
rc = SQLITE_ERROR;
|
|
goto end_deserialize;
|
|
- }
|
|
+ }
|
|
zSql = sqlite3_mprintf("ATTACH x AS %Q", zSchema);
|
|
- rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
|
|
- sqlite3_free(zSql);
|
|
+ if( zSql==0 ){
|
|
+ rc = SQLITE_NOMEM;
|
|
+ }else{
|
|
+ rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
|
|
+ sqlite3_free(zSql);
|
|
+ }
|
|
if( rc ) goto end_deserialize;
|
|
db->init.iDb = (u8)iDb;
|
|
db->init.reopenMemdb = 1;
|
|
@@ -48121,39 +52149,54 @@ SQLITE_API int sqlite3_deserialize(
|
|
if( p==0 ){
|
|
rc = SQLITE_ERROR;
|
|
}else{
|
|
- p->aData = pData;
|
|
- p->sz = szDb;
|
|
- p->szAlloc = szBuf;
|
|
- p->szMax = szBuf;
|
|
- if( p->szMax<sqlite3GlobalConfig.mxMemdbSize ){
|
|
- p->szMax = sqlite3GlobalConfig.mxMemdbSize;
|
|
+ MemStore *pStore = p->pStore;
|
|
+ pStore->aData = pData;
|
|
+ pData = 0;
|
|
+ pStore->sz = szDb;
|
|
+ pStore->szAlloc = szBuf;
|
|
+ pStore->szMax = szBuf;
|
|
+ if( pStore->szMax<sqlite3GlobalConfig.mxMemdbSize ){
|
|
+ pStore->szMax = sqlite3GlobalConfig.mxMemdbSize;
|
|
}
|
|
- p->mFlags = mFlags;
|
|
+ pStore->mFlags = mFlags;
|
|
rc = SQLITE_OK;
|
|
}
|
|
|
|
end_deserialize:
|
|
sqlite3_finalize(pStmt);
|
|
+ if( pData && (mFlags & SQLITE_DESERIALIZE_FREEONCLOSE)!=0 ){
|
|
+ sqlite3_free(pData);
|
|
+ }
|
|
sqlite3_mutex_leave(db->mutex);
|
|
return rc;
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
+** Return true if the VFS is the memvfs.
|
|
+*/
|
|
+SQLITE_PRIVATE int sqlite3IsMemdb(const sqlite3_vfs *pVfs){
|
|
+ return pVfs==&memdb_vfs;
|
|
+}
|
|
+
|
|
+/*
|
|
** This routine is called when the extension is loaded.
|
|
** Register the new VFS.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3MemdbInit(void){
|
|
sqlite3_vfs *pLower = sqlite3_vfs_find(0);
|
|
- int sz = pLower->szOsFile;
|
|
+ unsigned int sz;
|
|
+ if( NEVER(pLower==0) ) return SQLITE_ERROR;
|
|
+ sz = pLower->szOsFile;
|
|
memdb_vfs.pAppData = pLower;
|
|
- /* In all known configurations of SQLite, the size of a default
|
|
- ** sqlite3_file is greater than the size of a memdb sqlite3_file.
|
|
- ** Should that ever change, remove the following NEVER() */
|
|
- if( NEVER(sz<sizeof(MemFile)) ) sz = sizeof(MemFile);
|
|
+ /* The following conditional can only be true when compiled for
|
|
+ ** Windows x86 and SQLITE_MAX_MMAP_SIZE=0. We always leave
|
|
+ ** it in, to be safe, but it is marked as NO_TEST since there
|
|
+ ** is no way to reach it under most builds. */
|
|
+ if( sz<sizeof(MemFile) ) sz = sizeof(MemFile); /*NO_TEST*/
|
|
memdb_vfs.szOsFile = sz;
|
|
return sqlite3_vfs_register(&memdb_vfs, 0);
|
|
}
|
|
-#endif /* SQLITE_ENABLE_DESERIALIZE */
|
|
+#endif /* SQLITE_OMIT_DESERIALIZE */
|
|
|
|
/************** End of memdb.c ***********************************************/
|
|
/************** Begin file bitvec.c ******************************************/
|
|
@@ -48176,8 +52219,8 @@ SQLITE_PRIVATE int sqlite3MemdbInit(void){
|
|
** property. Usually only a few pages are meet either condition.
|
|
** So the bitmap is usually sparse and has low cardinality.
|
|
** But sometimes (for example when during a DROP of a large table) most
|
|
-** or all of the pages in a database can get journalled. In those cases,
|
|
-** the bitmap becomes dense with high cardinality. The algorithm needs
|
|
+** or all of the pages in a database can get journalled. In those cases,
|
|
+** the bitmap becomes dense with high cardinality. The algorithm needs
|
|
** to handle both cases well.
|
|
**
|
|
** The size of the bitmap is fixed when the object is created.
|
|
@@ -48198,13 +52241,13 @@ SQLITE_PRIVATE int sqlite3MemdbInit(void){
|
|
/* Size of the Bitvec structure in bytes. */
|
|
#define BITVEC_SZ 512
|
|
|
|
-/* Round the union size down to the nearest pointer boundary, since that's how
|
|
+/* Round the union size down to the nearest pointer boundary, since that's how
|
|
** it will be aligned within the Bitvec struct. */
|
|
#define BITVEC_USIZE \
|
|
(((BITVEC_SZ-(3*sizeof(u32)))/sizeof(Bitvec*))*sizeof(Bitvec*))
|
|
|
|
-/* Type of the array "element" for the bitmap representation.
|
|
-** Should be a power of 2, and ideally, evenly divide into BITVEC_USIZE.
|
|
+/* Type of the array "element" for the bitmap representation.
|
|
+** Should be a power of 2, and ideally, evenly divide into BITVEC_USIZE.
|
|
** Setting this to the "natural word" size of your CPU may improve
|
|
** performance. */
|
|
#define BITVEC_TELEM u8
|
|
@@ -48217,12 +52260,12 @@ SQLITE_PRIVATE int sqlite3MemdbInit(void){
|
|
|
|
/* Number of u32 values in hash table. */
|
|
#define BITVEC_NINT (BITVEC_USIZE/sizeof(u32))
|
|
-/* Maximum number of entries in hash table before
|
|
+/* Maximum number of entries in hash table before
|
|
** sub-dividing and re-hashing. */
|
|
#define BITVEC_MXHASH (BITVEC_NINT/2)
|
|
/* Hashing function for the aHash representation.
|
|
-** Empirical testing showed that the *37 multiplier
|
|
-** (an arbitrary prime)in the hash function provided
|
|
+** Empirical testing showed that the *37 multiplier
|
|
+** (an arbitrary prime)in the hash function provided
|
|
** no fewer collisions than the no-op *1. */
|
|
#define BITVEC_HASH(X) (((X)*1)%BITVEC_NINT)
|
|
|
|
@@ -48268,7 +52311,7 @@ struct Bitvec {
|
|
|
|
/*
|
|
** Create a new bitmap object able to handle bits between 0 and iSize,
|
|
-** inclusive. Return a pointer to the new object. Return NULL if
|
|
+** inclusive. Return a pointer to the new object. Return NULL if
|
|
** malloc fails.
|
|
*/
|
|
SQLITE_PRIVATE Bitvec *sqlite3BitvecCreate(u32 iSize){
|
|
@@ -48512,7 +52555,7 @@ SQLITE_PRIVATE int sqlite3BitvecBuiltinTest(int sz, int *aOp){
|
|
sqlite3BitvecClear(0, 1, pTmpSpace);
|
|
|
|
/* Run the program */
|
|
- pc = 0;
|
|
+ pc = i = 0;
|
|
while( (op = aOp[pc])!=0 ){
|
|
switch( op ){
|
|
case 1:
|
|
@@ -48524,7 +52567,7 @@ SQLITE_PRIVATE int sqlite3BitvecBuiltinTest(int sz, int *aOp){
|
|
break;
|
|
}
|
|
case 3:
|
|
- case 4:
|
|
+ case 4:
|
|
default: {
|
|
nx = 2;
|
|
sqlite3_randomness(sizeof(i), &i);
|
|
@@ -48604,7 +52647,7 @@ SQLITE_PRIVATE int sqlite3BitvecBuiltinTest(int sz, int *aOp){
|
|
**
|
|
** The PCache.pSynced variable is used to optimize searching for a dirty
|
|
** page to eject from the cache mid-transaction. It is better to eject
|
|
-** a page that does not require a journal sync than one that does.
|
|
+** a page that does not require a journal sync than one that does.
|
|
** Therefore, pSynced is maintained so that it *almost* always points
|
|
** to either the oldest page in the pDirty/pDirtyTail list that has a
|
|
** clear PGHDR_NEED_SYNC flag or to a page that is older than this one
|
|
@@ -48614,7 +52657,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 */
|
|
@@ -48639,13 +52682,21 @@ struct PCache {
|
|
int sqlite3PcacheTrace = 2; /* 0: off 1: simple 2: cache dumps */
|
|
int sqlite3PcacheMxDump = 9999; /* Max cache entries for pcacheDump() */
|
|
# define pcacheTrace(X) if(sqlite3PcacheTrace){sqlite3DebugPrintf X;}
|
|
- void pcacheDump(PCache *pCache){
|
|
- int N;
|
|
- int i, j;
|
|
- sqlite3_pcache_page *pLower;
|
|
+ static void pcachePageTrace(int i, sqlite3_pcache_page *pLower){
|
|
PgHdr *pPg;
|
|
unsigned char *a;
|
|
-
|
|
+ int j;
|
|
+ pPg = (PgHdr*)pLower->pExtra;
|
|
+ printf("%3lld: nRef %2d flgs %02x data ", i, pPg->nRef, pPg->flags);
|
|
+ a = (unsigned char *)pLower->pBuf;
|
|
+ for(j=0; j<12; j++) printf("%02x", a[j]);
|
|
+ printf(" ptr %p\n", pPg);
|
|
+ }
|
|
+ static void pcacheDump(PCache *pCache){
|
|
+ int N;
|
|
+ int i;
|
|
+ sqlite3_pcache_page *pLower;
|
|
+
|
|
if( sqlite3PcacheTrace<2 ) return;
|
|
if( pCache->pCache==0 ) return;
|
|
N = sqlite3PcachePagecount(pCache);
|
|
@@ -48653,21 +52704,32 @@ struct PCache {
|
|
for(i=1; i<=N; i++){
|
|
pLower = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, i, 0);
|
|
if( pLower==0 ) continue;
|
|
- 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("\n");
|
|
- if( pPg->pPage==0 ){
|
|
+ pcachePageTrace(i, pLower);
|
|
+ if( ((PgHdr*)pLower)->pPage==0 ){
|
|
sqlite3GlobalConfig.pcache2.xUnpin(pCache->pCache, pLower, 0);
|
|
}
|
|
}
|
|
}
|
|
- #else
|
|
+#else
|
|
# define pcacheTrace(X)
|
|
+# define pcachePageTrace(PGNO, X)
|
|
# define pcacheDump(X)
|
|
#endif
|
|
|
|
+/*
|
|
+** 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
|
|
+static int pageOnDirtyList(PCache *pCache, PgHdr *pPg){
|
|
+ PgHdr *p;
|
|
+ for(p=pCache->pDirty; p; p=p->pDirtyNext){
|
|
+ if( p==pPg ) return 1;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+#endif
|
|
+
|
|
/*
|
|
** Check invariants on a PgHdr entry. Return true if everything is OK.
|
|
** Return false if any invariant is violated.
|
|
@@ -48686,8 +52748,13 @@ 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( pCache->pDirty!=pPg ); /* CLEAN pages not on dirty list */
|
|
- assert( pCache->pDirtyTail!=pPg );
|
|
+ assert( !pageOnDirtyList(pCache, pPg) );/* CLEAN pages not on dirty list */
|
|
+ }else{
|
|
+ assert( (pPg->flags & PGHDR_DIRTY)!=0 );/* If not CLEAN must be DIRTY */
|
|
+ assert( pPg->pDirtyNext==0 || pPg->pDirtyNext->pDirtyPrev==pPg );
|
|
+ assert( pPg->pDirtyPrev==0 || pPg->pDirtyPrev->pDirtyNext==pPg );
|
|
+ assert( pPg->pDirtyPrev!=0 || pCache->pDirty==pPg );
|
|
+ assert( pageOnDirtyList(pCache, pPg) );
|
|
}
|
|
/* WRITEABLE pages must also be DIRTY */
|
|
if( pPg->flags & PGHDR_WRITEABLE ){
|
|
@@ -48737,12 +52804,12 @@ static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){
|
|
if( addRemove & PCACHE_DIRTYLIST_REMOVE ){
|
|
assert( pPage->pDirtyNext || pPage==p->pDirtyTail );
|
|
assert( pPage->pDirtyPrev || pPage==p->pDirty );
|
|
-
|
|
+
|
|
/* Update the PCache1.pSynced variable if necessary. */
|
|
if( p->pSynced==pPage ){
|
|
p->pSynced = pPage->pDirtyPrev;
|
|
}
|
|
-
|
|
+
|
|
if( pPage->pDirtyNext ){
|
|
pPage->pDirtyNext->pDirtyPrev = pPage->pDirtyPrev;
|
|
}else{
|
|
@@ -48752,7 +52819,7 @@ static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){
|
|
if( pPage->pDirtyPrev ){
|
|
pPage->pDirtyPrev->pDirtyNext = pPage->pDirtyNext;
|
|
}else{
|
|
- /* If there are now no dirty pages in the cache, set eCreate to 2.
|
|
+ /* If there are now no dirty pages in the cache, set eCreate to 2.
|
|
** This is an optimization that allows sqlite3PcacheFetch() to skip
|
|
** searching for a dirty page to eject from the cache when it might
|
|
** otherwise have to. */
|
|
@@ -48781,11 +52848,11 @@ static void pcacheManageDirtyList(PgHdr *pPage, u8 addRemove){
|
|
p->pDirty = pPage;
|
|
|
|
/* If pSynced is NULL and this page has a clear NEED_SYNC flag, set
|
|
- ** pSynced to point to it. Checking the NEED_SYNC flag is an
|
|
+ ** pSynced to point to it. Checking the NEED_SYNC flag is an
|
|
** optimization, as if pSynced points to a page with the NEED_SYNC
|
|
- ** flag set sqlite3PcacheFetchStress() searches through all newer
|
|
+ ** flag set sqlite3PcacheFetchStress() searches through all newer
|
|
** entries of the dirty-list for a page with NEED_SYNC clear anyway. */
|
|
- if( !p->pSynced
|
|
+ if( !p->pSynced
|
|
&& 0==(pPage->flags&PGHDR_NEED_SYNC) /*OPTIMIZATION-IF-FALSE*/
|
|
){
|
|
p->pSynced = pPage;
|
|
@@ -48816,17 +52883,20 @@ static int numberOfCachePages(PCache *p){
|
|
** suggested cache size is set to N. */
|
|
return p->szCache;
|
|
}else{
|
|
+ i64 n;
|
|
/* IMPLEMANTATION-OF: R-59858-46238 If the argument N is negative, then the
|
|
** number of cache pages is adjusted to be a number of pages that would
|
|
** use approximately abs(N*1024) bytes of memory based on the current
|
|
** page size. */
|
|
- return (int)((-1024*(i64)p->szCache)/(p->szPage+p->szExtra));
|
|
+ n = ((-1024*(i64)p->szCache)/(p->szPage+p->szExtra));
|
|
+ if( n>1000000000 ) n = 1000000000;
|
|
+ return (int)n;
|
|
}
|
|
}
|
|
|
|
/*************************************************** General Interfaces ******
|
|
**
|
|
-** Initialize and shutdown the page cache subsystem. Neither of these
|
|
+** Initialize and shutdown the page cache subsystem. Neither of these
|
|
** functions are threadsafe.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3PcacheInitialize(void){
|
|
@@ -48853,8 +52923,8 @@ SQLITE_PRIVATE int sqlite3PcacheSize(void){ return sizeof(PCache); }
|
|
|
|
/*
|
|
** Create a new PCache object. Storage space to hold the object
|
|
-** has already been allocated and is passed in as the p pointer.
|
|
-** The caller discovers how much space needs to be allocated by
|
|
+** has already been allocated and is passed in as the p pointer.
|
|
+** The caller discovers how much space needs to be allocated by
|
|
** calling sqlite3PcacheSize().
|
|
**
|
|
** szExtra is some extra space allocated for each page. The first
|
|
@@ -48958,15 +53028,16 @@ SQLITE_PRIVATE sqlite3_pcache_page *sqlite3PcacheFetch(
|
|
assert( createFlag==0 || pCache->eCreate==eCreate );
|
|
assert( createFlag==0 || eCreate==1+(!pCache->bPurgeable||!pCache->pDirty) );
|
|
pRes = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate);
|
|
- pcacheTrace(("%p.FETCH %d%s (result: %p)\n",pCache,pgno,
|
|
+ pcacheTrace(("%p.FETCH %d%s (result: %p) ",pCache,pgno,
|
|
createFlag?" create":"",pRes));
|
|
+ pcachePageTrace(pgno, pRes);
|
|
return pRes;
|
|
}
|
|
|
|
/*
|
|
** If the sqlite3PcacheFetch() routine is unable to allocate a new
|
|
** page because no clean pages are available for reuse and the cache
|
|
-** size limit has been reached, then this routine can be invoked to
|
|
+** size limit has been reached, then this routine can be invoked to
|
|
** try harder to allocate a page. This routine might invoke the stress
|
|
** callback to spill dirty pages to the journal. It will then try to
|
|
** allocate the new page and will only fail to allocate a new page on
|
|
@@ -48983,17 +53054,17 @@ SQLITE_PRIVATE int sqlite3PcacheFetchStress(
|
|
if( pCache->eCreate==2 ) return 0;
|
|
|
|
if( sqlite3PcachePagecount(pCache)>pCache->szSpill ){
|
|
- /* Find a dirty page to write-out and recycle. First try to find a
|
|
+ /* Find a dirty page to write-out and recycle. First try to find a
|
|
** page that does not require a journal-sync (one with PGHDR_NEED_SYNC
|
|
- ** cleared), but if that is not possible settle for any other
|
|
+ ** cleared), but if that is not possible settle for any other
|
|
** unreferenced dirty page.
|
|
**
|
|
** If the LRU page in the dirty list that has a clear PGHDR_NEED_SYNC
|
|
** flag is currently referenced, then the following may leave pSynced
|
|
** set incorrectly (pointing to other than the LRU page with NEED_SYNC
|
|
** cleared). This is Ok, as pSynced is just an optimization. */
|
|
- for(pPg=pCache->pSynced;
|
|
- pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC));
|
|
+ for(pPg=pCache->pSynced;
|
|
+ pPg && (pPg->nRef || (pPg->flags&PGHDR_NEED_SYNC));
|
|
pPg=pPg->pDirtyPrev
|
|
);
|
|
pCache->pSynced = pPg;
|
|
@@ -49003,7 +53074,7 @@ SQLITE_PRIVATE int sqlite3PcacheFetchStress(
|
|
if( pPg ){
|
|
int rc;
|
|
#ifdef SQLITE_LOG_CACHE_SPILL
|
|
- sqlite3_log(SQLITE_FULL,
|
|
+ sqlite3_log(SQLITE_FULL,
|
|
"spill page %d making room for %d - cache used: %d/%d",
|
|
pPg->pgno, pgno,
|
|
sqlite3GlobalConfig.pcache2.xPagecount(pCache->pCache),
|
|
@@ -49087,6 +53158,7 @@ SQLITE_PRIVATE void SQLITE_NOINLINE sqlite3PcacheRelease(PgHdr *p){
|
|
pcacheUnpin(p);
|
|
}else{
|
|
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT);
|
|
+ assert( sqlite3PcachePageSanity(p) );
|
|
}
|
|
}
|
|
}
|
|
@@ -49130,6 +53202,7 @@ SQLITE_PRIVATE void sqlite3PcacheMakeDirty(PgHdr *p){
|
|
pcacheTrace(("%p.DIRTY %d\n",p->pCache,p->pgno));
|
|
assert( (p->flags & (PGHDR_DIRTY|PGHDR_CLEAN))==PGHDR_DIRTY );
|
|
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_ADD);
|
|
+ assert( sqlite3PcachePageSanity(p) );
|
|
}
|
|
assert( sqlite3PcachePageSanity(p) );
|
|
}
|
|
@@ -49188,18 +53261,28 @@ SQLITE_PRIVATE void sqlite3PcacheClearSyncFlags(PCache *pCache){
|
|
}
|
|
|
|
/*
|
|
-** Change the page number of page p to newPgno.
|
|
+** Change the page number of page p to newPgno.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){
|
|
PCache *pCache = p->pCache;
|
|
+ sqlite3_pcache_page *pOther;
|
|
assert( p->nRef>0 );
|
|
assert( newPgno>0 );
|
|
assert( sqlite3PcachePageSanity(p) );
|
|
pcacheTrace(("%p.MOVE %d -> %d\n",pCache,p->pgno,newPgno));
|
|
+ pOther = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, newPgno, 0);
|
|
+ if( pOther ){
|
|
+ PgHdr *pXPage = (PgHdr*)pOther->pExtra;
|
|
+ assert( pXPage->nRef==0 );
|
|
+ pXPage->nRef++;
|
|
+ pCache->nRefSum++;
|
|
+ sqlite3PcacheDrop(pXPage);
|
|
+ }
|
|
sqlite3GlobalConfig.pcache2.xRekey(pCache->pCache, p->pPage, p->pgno,newPgno);
|
|
p->pgno = newPgno;
|
|
if( (p->flags&PGHDR_DIRTY) && (p->flags&PGHDR_NEED_SYNC) ){
|
|
pcacheManageDirtyList(p, PCACHE_DIRTYLIST_FRONT);
|
|
+ assert( sqlite3PcachePageSanity(p) );
|
|
}
|
|
}
|
|
|
|
@@ -49251,7 +53334,7 @@ SQLITE_PRIVATE void sqlite3PcacheClose(PCache *pCache){
|
|
sqlite3GlobalConfig.pcache2.xDestroy(pCache->pCache);
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** Discard the contents of the cache.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3PcacheClear(PCache *pCache){
|
|
@@ -49342,24 +53425,24 @@ SQLITE_PRIVATE PgHdr *sqlite3PcacheDirtyList(PCache *pCache){
|
|
return pcacheSortDirtyList(pCache->pDirty);
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** Return the total number of references to all pages held by the cache.
|
|
**
|
|
** 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;
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** Return the total number of pages in the cache.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3PcachePagecount(PCache *pCache){
|
|
@@ -49401,7 +53484,7 @@ SQLITE_PRIVATE int sqlite3PcacheSetSpillsize(PCache *p, int mxPage){
|
|
p->szSpill = mxPage;
|
|
}
|
|
res = numberOfCachePages(p);
|
|
- if( res<p->szSpill ) res = p->szSpill;
|
|
+ if( res<p->szSpill ) res = p->szSpill;
|
|
return res;
|
|
}
|
|
|
|
@@ -49432,7 +53515,7 @@ SQLITE_PRIVATE int sqlite3PCachePercentDirty(PCache *pCache){
|
|
}
|
|
|
|
#ifdef SQLITE_DIRECT_OVERFLOW_READ
|
|
-/*
|
|
+/*
|
|
** Return true if there are one or more dirty pages in the cache. Else false.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3PCacheIsDirty(PCache *pCache){
|
|
@@ -49497,12 +53580,13 @@ SQLITE_PRIVATE void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHd
|
|
** size can vary according to architecture, compile-time options, and
|
|
** SQLite library version number.
|
|
**
|
|
-** If SQLITE_PCACHE_SEPARATE_HEADER is defined, then the extension is obtained
|
|
-** using a separate memory allocation from the database page content. This
|
|
-** seeks to overcome the "clownshoe" problem (also called "internal
|
|
-** fragmentation" in academic literature) of allocating a few bytes more
|
|
-** than a power of two with the memory allocator rounding up to the next
|
|
-** power of two, and leaving the rounded-up space unused.
|
|
+** Historical note: It used to be that if the SQLITE_PCACHE_SEPARATE_HEADER
|
|
+** was defined, then the page content would be held in a separate memory
|
|
+** allocation from the PgHdr1. This was intended to avoid clownshoe memory
|
|
+** allocations. However, the btree layer needs a small (16-byte) overrun
|
|
+** area after the page content buffer. The header serves as that overrun
|
|
+** area. Therefore SQLITE_PCACHE_SEPARATE_HEADER was discontinued to avoid
|
|
+** any possibility of a memory error.
|
|
**
|
|
** This module tracks pointers to PgHdr1 objects. Only pcache.c communicates
|
|
** with this module. Information is passed back and forth as PgHdr1 pointers.
|
|
@@ -49521,7 +53605,7 @@ SQLITE_PRIVATE void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHd
|
|
**
|
|
** The third case is a chunk of heap memory (defaulting to 100 pages worth)
|
|
** that is allocated when the page cache is created. The size of the local
|
|
-** bulk allocation can be adjusted using
|
|
+** bulk allocation can be adjusted using
|
|
**
|
|
** sqlite3_config(SQLITE_CONFIG_PAGECACHE, (void*)0, 0, N).
|
|
**
|
|
@@ -49546,31 +53630,41 @@ typedef struct PgFreeslot PgFreeslot;
|
|
typedef struct PGroup PGroup;
|
|
|
|
/*
|
|
-** Each cache entry is represented by an instance of the following
|
|
-** structure. Unless SQLITE_PCACHE_SEPARATE_HEADER is defined, a buffer of
|
|
-** PgHdr1.pCache->szPage bytes is allocated directly before this structure
|
|
-** in memory.
|
|
+** Each cache entry is represented by an instance of the following
|
|
+** structure. A buffer of PgHdr1.pCache->szPage bytes is allocated
|
|
+** directly before this structure and is used to cache the page content.
|
|
+**
|
|
+** When reading a corrupt database file, it is possible that SQLite might
|
|
+** read a few bytes (no more than 16 bytes) past the end of the page buffer.
|
|
+** It will only read past the end of the page buffer, never write. This
|
|
+** object is positioned immediately after the page buffer to serve as an
|
|
+** overrun area, so that overreads are harmless.
|
|
**
|
|
-** Note: Variables isBulkLocal and isAnchor were once type "u8". That works,
|
|
-** but causes a 2-byte gap in the structure for most architectures (since
|
|
+** Variables isBulkLocal and isAnchor were once type "u8". That works,
|
|
+** but causes a 2-byte gap in the structure for most architectures (since
|
|
** pointers must be either 4 or 8-byte aligned). As this structure is located
|
|
** 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
|
|
+** 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
|
|
-** ensures there is no such gap, and therefore no bytes of unitialized memory
|
|
-** in the structure.
|
|
+** ensures there is no such gap, and therefore no bytes of uninitialized
|
|
+** memory in the structure.
|
|
+**
|
|
+** The pLruNext and pLruPrev pointers form a double-linked circular list
|
|
+** of all pages that are unpinned. The PGroup.lru element (which should be
|
|
+** the only element on the list with PgHdr1.isAnchor set to 1) forms the
|
|
+** beginning and the end of the list.
|
|
*/
|
|
struct PgHdr1 {
|
|
- sqlite3_pcache_page page; /* Base class. Must be first. pBuf & pExtra */
|
|
- unsigned int iKey; /* Key value (page number) */
|
|
- u16 isBulkLocal; /* This page from bulk local storage */
|
|
- u16 isAnchor; /* This is the PGroup.lru element */
|
|
- PgHdr1 *pNext; /* Next in hash table chain */
|
|
- PCache1 *pCache; /* Cache that currently owns this page */
|
|
- PgHdr1 *pLruNext; /* Next in LRU list of unpinned pages */
|
|
- PgHdr1 *pLruPrev; /* Previous in LRU list of unpinned pages */
|
|
- /* NB: pLruPrev is only valid if pLruNext!=0 */
|
|
+ sqlite3_pcache_page page; /* Base class. Must be first. pBuf & pExtra */
|
|
+ unsigned int iKey; /* Key value (page number) */
|
|
+ u16 isBulkLocal; /* This page from bulk local storage */
|
|
+ u16 isAnchor; /* This is the PGroup.lru element */
|
|
+ PgHdr1 *pNext; /* Next in hash table chain */
|
|
+ PCache1 *pCache; /* Cache that currently owns this page */
|
|
+ PgHdr1 *pLruNext; /* Next in circular LRU list of unpinned pages */
|
|
+ PgHdr1 *pLruPrev; /* Previous in LRU list of unpinned pages */
|
|
+ /* NB: pLruPrev is only valid if pLruNext!=0 */
|
|
};
|
|
|
|
/*
|
|
@@ -49580,7 +53674,7 @@ struct PgHdr1 {
|
|
#define PAGE_IS_PINNED(p) ((p)->pLruNext==0)
|
|
#define PAGE_IS_UNPINNED(p) ((p)->pLruNext!=0)
|
|
|
|
-/* Each page cache (or PCache) belongs to a PGroup. A PGroup is a set
|
|
+/* Each page cache (or PCache) belongs to a PGroup. A PGroup is a set
|
|
** of one or more PCaches that are able to recycle each other's unpinned
|
|
** pages when they are under memory pressure. A PGroup is an instance of
|
|
** the following object.
|
|
@@ -49616,13 +53710,13 @@ struct PGroup {
|
|
** temporary or transient database) has a single page cache which
|
|
** is an instance of this object.
|
|
**
|
|
-** Pointers to structures of this type are cast and returned as
|
|
+** Pointers to structures of this type are cast and returned as
|
|
** opaque sqlite3_pcache* handles.
|
|
*/
|
|
struct PCache1 {
|
|
/* Cache configuration parameters. Page size (szPage) and the purgeable
|
|
** flag (bPurgeable) and the pnPurgeable pointer are all set when the
|
|
- ** cache is created and are never changed thereafter. nMax may be
|
|
+ ** cache is created and are never changed thereafter. nMax may be
|
|
** modified at any time by a call to the pcache1Cachesize() method.
|
|
** The PGroup mutex must be held when accessing nMax.
|
|
*/
|
|
@@ -49670,7 +53764,7 @@ static SQLITE_WSD struct PCacheGlobal {
|
|
*/
|
|
int isInit; /* True if initialized */
|
|
int separateCache; /* Use a new PGroup for each PCache */
|
|
- int nInitPage; /* Initial bulk allocation size */
|
|
+ int nInitPage; /* Initial bulk allocation size */
|
|
int szSlot; /* Size of each free slot */
|
|
int nSlot; /* The number of pcache slots */
|
|
int nReserve; /* Try to keep nFreeSlot above this */
|
|
@@ -49711,7 +53805,7 @@ static SQLITE_WSD struct PCacheGlobal {
|
|
|
|
|
|
/*
|
|
-** This function is called during initialization if a static buffer is
|
|
+** This function is called during initialization if a static buffer is
|
|
** supplied to use for the page-cache by passing the SQLITE_CONFIG_PAGECACHE
|
|
** verb to sqlite3_config(). Parameter pBuf points to an allocation large
|
|
** enough to contain 'n' buffers of 'sz' bytes each.
|
|
@@ -49781,8 +53875,8 @@ static int pcache1InitBulk(PCache1 *pCache){
|
|
|
|
/*
|
|
** Malloc function used within this file to allocate space from the buffer
|
|
-** configured using sqlite3_config(SQLITE_CONFIG_PAGECACHE) option. If no
|
|
-** such buffer exists or there is no space left in it, this function falls
|
|
+** configured using sqlite3_config(SQLITE_CONFIG_PAGECACHE) option. If no
|
|
+** such buffer exists or there is no space left in it, this function falls
|
|
** back to sqlite3Malloc().
|
|
**
|
|
** Multiple threads can run this routine at the same time. Global variables
|
|
@@ -49889,36 +53983,25 @@ static PgHdr1 *pcache1AllocPage(PCache1 *pCache, int benignMalloc){
|
|
}else{
|
|
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
|
|
/* The group mutex must be released before pcache1Alloc() is called. This
|
|
- ** is because it might call sqlite3_release_memory(), which assumes that
|
|
+ ** is because it might call sqlite3_release_memory(), which assumes that
|
|
** this mutex is not held. */
|
|
assert( pcache1.separateCache==0 );
|
|
assert( pCache->pGroup==&pcache1.grp );
|
|
pcache1LeaveMutex(pCache->pGroup);
|
|
#endif
|
|
if( benignMalloc ){ sqlite3BeginBenignMalloc(); }
|
|
-#ifdef SQLITE_PCACHE_SEPARATE_HEADER
|
|
- pPg = pcache1Alloc(pCache->szPage);
|
|
- p = sqlite3Malloc(sizeof(PgHdr1) + pCache->szExtra);
|
|
- if( !pPg || !p ){
|
|
- pcache1Free(pPg);
|
|
- sqlite3_free(p);
|
|
- pPg = 0;
|
|
- }
|
|
-#else
|
|
pPg = pcache1Alloc(pCache->szAlloc);
|
|
-#endif
|
|
if( benignMalloc ){ sqlite3EndBenignMalloc(); }
|
|
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
|
|
pcache1EnterMutex(pCache->pGroup);
|
|
#endif
|
|
if( pPg==0 ) return 0;
|
|
-#ifndef SQLITE_PCACHE_SEPARATE_HEADER
|
|
p = (PgHdr1 *)&((u8 *)pPg)[pCache->szPage];
|
|
-#endif
|
|
p->page.pBuf = pPg;
|
|
p->page.pExtra = &p[1];
|
|
p->isBulkLocal = 0;
|
|
p->isAnchor = 0;
|
|
+ p->pLruPrev = 0; /* Initializing this saves a valgrind error */
|
|
}
|
|
(*pCache->pnPurgeable)++;
|
|
return p;
|
|
@@ -49937,9 +54020,6 @@ static void pcache1FreePage(PgHdr1 *p){
|
|
pCache->pFree = p;
|
|
}else{
|
|
pcache1Free(p->page.pBuf);
|
|
-#ifdef SQLITE_PCACHE_SEPARATE_HEADER
|
|
- sqlite3_free(p);
|
|
-#endif
|
|
}
|
|
(*pCache->pnPurgeable)--;
|
|
}
|
|
@@ -50030,7 +54110,7 @@ static void pcache1ResizeHash(PCache1 *p){
|
|
}
|
|
|
|
/*
|
|
-** This function is used internally to remove the page pPage from the
|
|
+** This function is used internally to remove the page pPage from the
|
|
** PGroup LRU list, if is part of it. If pPage is not part of the PGroup
|
|
** LRU list, then this function is a no-op.
|
|
**
|
|
@@ -50055,7 +54135,7 @@ static PgHdr1 *pcache1PinPage(PgHdr1 *pPage){
|
|
|
|
|
|
/*
|
|
-** Remove the page supplied as an argument from the hash table
|
|
+** Remove the page supplied as an argument from the hash table
|
|
** (PCache1.apHash structure) that it is currently stored in.
|
|
** Also free the page if freePage is true.
|
|
**
|
|
@@ -50098,8 +54178,8 @@ static void pcache1EnforceMaxPage(PCache1 *pCache){
|
|
}
|
|
|
|
/*
|
|
-** Discard all pages from cache pCache with a page number (key value)
|
|
-** greater than or equal to iLimit. Any pinned pages that meet this
|
|
+** Discard all pages from cache pCache with a page number (key value)
|
|
+** greater than or equal to iLimit. Any pinned pages that meet this
|
|
** criteria are unpinned before they are discarded.
|
|
**
|
|
** The PCache mutex must be held when this function is called.
|
|
@@ -50131,7 +54211,7 @@ static void pcache1TruncateUnsafe(
|
|
PgHdr1 **pp;
|
|
PgHdr1 *pPage;
|
|
assert( h<pCache->nHash );
|
|
- pp = &pCache->apHash[h];
|
|
+ pp = &pCache->apHash[h];
|
|
while( (pPage = *pp)!=0 ){
|
|
if( pPage->iKey>=iLimit ){
|
|
pCache->nPage--;
|
|
@@ -50170,7 +54250,7 @@ static int pcache1Init(void *NotUsed){
|
|
**
|
|
** * Use a unified cache in single-threaded applications that have
|
|
** configured a start-time buffer for use as page-cache memory using
|
|
- ** sqlite3_config(SQLITE_CONFIG_PAGECACHE, pBuf, sz, N) with non-NULL
|
|
+ ** sqlite3_config(SQLITE_CONFIG_PAGECACHE, pBuf, sz, N) with non-NULL
|
|
** pBuf argument.
|
|
**
|
|
** * Otherwise use separate caches (mode-1)
|
|
@@ -50205,7 +54285,7 @@ static int pcache1Init(void *NotUsed){
|
|
|
|
/*
|
|
** Implementation of the sqlite3_pcache.xShutdown method.
|
|
-** Note that the static mutex allocated in xInit does
|
|
+** Note that the static mutex allocated in xInit does
|
|
** not need to be freed.
|
|
*/
|
|
static void pcache1Shutdown(void *NotUsed){
|
|
@@ -50268,18 +54348,24 @@ static sqlite3_pcache *pcache1Create(int szPage, int szExtra, int bPurgeable){
|
|
}
|
|
|
|
/*
|
|
-** Implementation of the sqlite3_pcache.xCachesize method.
|
|
+** Implementation of the sqlite3_pcache.xCachesize method.
|
|
**
|
|
** Configure the cache_size limit for a cache.
|
|
*/
|
|
static void pcache1Cachesize(sqlite3_pcache *p, int nMax){
|
|
PCache1 *pCache = (PCache1 *)p;
|
|
+ u32 n;
|
|
+ assert( nMax>=0 );
|
|
if( pCache->bPurgeable ){
|
|
PGroup *pGroup = pCache->pGroup;
|
|
pcache1EnterMutex(pGroup);
|
|
- pGroup->nMaxPage += (nMax - pCache->nMax);
|
|
+ n = (u32)nMax;
|
|
+ if( n > 0x7fff0000 - pGroup->nMaxPage + pCache->nMax ){
|
|
+ n = 0x7fff0000 - pGroup->nMaxPage + pCache->nMax;
|
|
+ }
|
|
+ pGroup->nMaxPage += (n - pCache->nMax);
|
|
pGroup->mxPinned = pGroup->nMaxPage + 10 - pGroup->nMinPage;
|
|
- pCache->nMax = nMax;
|
|
+ pCache->nMax = n;
|
|
pCache->n90pct = pCache->nMax*9/10;
|
|
pcache1EnforceMaxPage(pCache);
|
|
pcache1LeaveMutex(pGroup);
|
|
@@ -50287,7 +54373,7 @@ static void pcache1Cachesize(sqlite3_pcache *p, int nMax){
|
|
}
|
|
|
|
/*
|
|
-** Implementation of the sqlite3_pcache.xShrink method.
|
|
+** Implementation of the sqlite3_pcache.xShrink method.
|
|
**
|
|
** Free up as much memory as possible.
|
|
*/
|
|
@@ -50295,7 +54381,7 @@ static void pcache1Shrink(sqlite3_pcache *p){
|
|
PCache1 *pCache = (PCache1*)p;
|
|
if( pCache->bPurgeable ){
|
|
PGroup *pGroup = pCache->pGroup;
|
|
- int savedMaxPage;
|
|
+ unsigned int savedMaxPage;
|
|
pcache1EnterMutex(pGroup);
|
|
savedMaxPage = pGroup->nMaxPage;
|
|
pGroup->nMaxPage = 0;
|
|
@@ -50306,7 +54392,7 @@ static void pcache1Shrink(sqlite3_pcache *p){
|
|
}
|
|
|
|
/*
|
|
-** Implementation of the sqlite3_pcache.xPagecount method.
|
|
+** Implementation of the sqlite3_pcache.xPagecount method.
|
|
*/
|
|
static int pcache1Pagecount(sqlite3_pcache *p){
|
|
int n;
|
|
@@ -50327,8 +54413,8 @@ static int pcache1Pagecount(sqlite3_pcache *p){
|
|
** for these steps, the main pcache1Fetch() procedure can run faster.
|
|
*/
|
|
static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
|
|
- PCache1 *pCache,
|
|
- unsigned int iKey,
|
|
+ PCache1 *pCache,
|
|
+ unsigned int iKey,
|
|
int createFlag
|
|
){
|
|
unsigned int nPinned;
|
|
@@ -50370,8 +54456,8 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
|
|
}
|
|
}
|
|
|
|
- /* Step 5. If a usable page buffer has still not been found,
|
|
- ** attempt to allocate a new one.
|
|
+ /* Step 5. If a usable page buffer has still not been found,
|
|
+ ** attempt to allocate a new one.
|
|
*/
|
|
if( !pPage ){
|
|
pPage = pcache1AllocPage(pCache, createFlag==1);
|
|
@@ -50396,13 +54482,13 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
|
|
}
|
|
|
|
/*
|
|
-** Implementation of the sqlite3_pcache.xFetch method.
|
|
+** Implementation of the sqlite3_pcache.xFetch method.
|
|
**
|
|
** Fetch a page by key value.
|
|
**
|
|
** Whether or not a new page may be allocated by this function depends on
|
|
** the value of the createFlag argument. 0 means do not allocate a new
|
|
-** page. 1 means allocate a new page if space is easily available. 2
|
|
+** page. 1 means allocate a new page if space is easily available. 2
|
|
** means to try really hard to allocate a new page.
|
|
**
|
|
** For a non-purgeable cache (a cache used as the storage for an in-memory
|
|
@@ -50413,7 +54499,7 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
|
|
** There are three different approaches to obtaining space for a page,
|
|
** depending on the value of parameter createFlag (which may be 0, 1 or 2).
|
|
**
|
|
-** 1. Regardless of the value of createFlag, the cache is searched for a
|
|
+** 1. Regardless of the value of createFlag, the cache is searched for a
|
|
** copy of the requested page. If one is found, it is returned.
|
|
**
|
|
** 2. If createFlag==0 and the page is not already in the cache, NULL is
|
|
@@ -50427,13 +54513,13 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
|
|
** PCache1.nMax, or
|
|
**
|
|
** (b) the number of pages pinned by the cache is greater than
|
|
-** the sum of nMax for all purgeable caches, less the sum of
|
|
+** the sum of nMax for all purgeable caches, less the sum of
|
|
** nMin for all other purgeable caches, or
|
|
**
|
|
** 4. If none of the first three conditions apply and the cache is marked
|
|
** as purgeable, and if one of the following is true:
|
|
**
|
|
-** (a) The number of pages allocated for the cache is already
|
|
+** (a) The number of pages allocated for the cache is already
|
|
** PCache1.nMax, or
|
|
**
|
|
** (b) The number of pages allocated for all purgeable caches is
|
|
@@ -50445,7 +54531,7 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
|
|
**
|
|
** then attempt to recycle a page from the LRU list. If it is the right
|
|
** size, return the recycled buffer. Otherwise, free the buffer and
|
|
-** proceed to step 5.
|
|
+** proceed to step 5.
|
|
**
|
|
** 5. Otherwise, allocate and return a new page buffer.
|
|
**
|
|
@@ -50455,8 +54541,8 @@ static SQLITE_NOINLINE PgHdr1 *pcache1FetchStage2(
|
|
** invokes the appropriate routine.
|
|
*/
|
|
static PgHdr1 *pcache1FetchNoMutex(
|
|
- sqlite3_pcache *p,
|
|
- unsigned int iKey,
|
|
+ sqlite3_pcache *p,
|
|
+ unsigned int iKey,
|
|
int createFlag
|
|
){
|
|
PCache1 *pCache = (PCache1 *)p;
|
|
@@ -50485,8 +54571,8 @@ static PgHdr1 *pcache1FetchNoMutex(
|
|
}
|
|
#if PCACHE1_MIGHT_USE_GROUP_MUTEX
|
|
static PgHdr1 *pcache1FetchWithMutex(
|
|
- sqlite3_pcache *p,
|
|
- unsigned int iKey,
|
|
+ sqlite3_pcache *p,
|
|
+ unsigned int iKey,
|
|
int createFlag
|
|
){
|
|
PCache1 *pCache = (PCache1 *)p;
|
|
@@ -50500,8 +54586,8 @@ static PgHdr1 *pcache1FetchWithMutex(
|
|
}
|
|
#endif
|
|
static sqlite3_pcache_page *pcache1Fetch(
|
|
- sqlite3_pcache *p,
|
|
- unsigned int iKey,
|
|
+ sqlite3_pcache *p,
|
|
+ unsigned int iKey,
|
|
int createFlag
|
|
){
|
|
#if PCACHE1_MIGHT_USE_GROUP_MUTEX || defined(SQLITE_DEBUG)
|
|
@@ -50531,18 +54617,18 @@ static sqlite3_pcache_page *pcache1Fetch(
|
|
** Mark a page as unpinned (eligible for asynchronous recycling).
|
|
*/
|
|
static void pcache1Unpin(
|
|
- sqlite3_pcache *p,
|
|
- sqlite3_pcache_page *pPg,
|
|
+ sqlite3_pcache *p,
|
|
+ sqlite3_pcache_page *pPg,
|
|
int reuseUnlikely
|
|
){
|
|
PCache1 *pCache = (PCache1 *)p;
|
|
PgHdr1 *pPage = (PgHdr1 *)pPg;
|
|
PGroup *pGroup = pCache->pGroup;
|
|
-
|
|
+
|
|
assert( pPage->pCache==pCache );
|
|
pcache1EnterMutex(pGroup);
|
|
|
|
- /* It is an error to call this function if the page is already
|
|
+ /* It is an error to call this function if the page is already
|
|
** part of the PGroup LRU list.
|
|
*/
|
|
assert( pPage->pLruNext==0 );
|
|
@@ -50563,7 +54649,7 @@ static void pcache1Unpin(
|
|
}
|
|
|
|
/*
|
|
-** Implementation of the sqlite3_pcache.xRekey method.
|
|
+** Implementation of the sqlite3_pcache.xRekey method.
|
|
*/
|
|
static void pcache1Rekey(
|
|
sqlite3_pcache *p,
|
|
@@ -50574,23 +54660,26 @@ static void pcache1Rekey(
|
|
PCache1 *pCache = (PCache1 *)p;
|
|
PgHdr1 *pPage = (PgHdr1 *)pPg;
|
|
PgHdr1 **pp;
|
|
- unsigned int h;
|
|
+ unsigned int hOld, hNew;
|
|
assert( pPage->iKey==iOld );
|
|
assert( pPage->pCache==pCache );
|
|
+ assert( iOld!=iNew ); /* The page number really is changing */
|
|
|
|
pcache1EnterMutex(pCache->pGroup);
|
|
|
|
- h = iOld%pCache->nHash;
|
|
- pp = &pCache->apHash[h];
|
|
+ assert( pcache1FetchNoMutex(p, iOld, 0)==pPage ); /* pPg really is iOld */
|
|
+ hOld = iOld%pCache->nHash;
|
|
+ pp = &pCache->apHash[hOld];
|
|
while( (*pp)!=pPage ){
|
|
pp = &(*pp)->pNext;
|
|
}
|
|
*pp = pPage->pNext;
|
|
|
|
- h = iNew%pCache->nHash;
|
|
+ assert( pcache1FetchNoMutex(p, iNew, 0)==0 ); /* iNew not in cache */
|
|
+ hNew = iNew%pCache->nHash;
|
|
pPage->iKey = iNew;
|
|
- pPage->pNext = pCache->apHash[h];
|
|
- pCache->apHash[h] = pPage;
|
|
+ pPage->pNext = pCache->apHash[hNew];
|
|
+ pCache->apHash[hNew] = pPage;
|
|
if( iNew>pCache->iMaxKey ){
|
|
pCache->iMaxKey = iNew;
|
|
}
|
|
@@ -50599,7 +54688,7 @@ static void pcache1Rekey(
|
|
}
|
|
|
|
/*
|
|
-** Implementation of the sqlite3_pcache.xTruncate method.
|
|
+** Implementation of the sqlite3_pcache.xTruncate method.
|
|
**
|
|
** Discard all unpinned pages in the cache with a page number equal to
|
|
** or greater than parameter iLimit. Any pinned pages with a page number
|
|
@@ -50616,7 +54705,7 @@ static void pcache1Truncate(sqlite3_pcache *p, unsigned int iLimit){
|
|
}
|
|
|
|
/*
|
|
-** Implementation of the sqlite3_pcache.xDestroy method.
|
|
+** Implementation of the sqlite3_pcache.xDestroy method.
|
|
**
|
|
** Destroy a cache allocated using pcache1Create().
|
|
*/
|
|
@@ -50682,7 +54771,7 @@ SQLITE_PRIVATE sqlite3_mutex *sqlite3Pcache1Mutex(void){
|
|
** by the current thread may be sqlite3_free()ed.
|
|
**
|
|
** nReq is the number of bytes of memory required. Once this much has
|
|
-** been released, the function returns. The return value is the total number
|
|
+** been released, the function returns. The return value is the total number
|
|
** of bytes of memory released.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3PcacheReleaseMemory(int nReq){
|
|
@@ -50697,9 +54786,6 @@ SQLITE_PRIVATE int sqlite3PcacheReleaseMemory(int nReq){
|
|
&& p->isAnchor==0
|
|
){
|
|
nFree += pcache1MemSize(p->page.pBuf);
|
|
-#ifdef SQLITE_PCACHE_SEPARATE_HEADER
|
|
- nFree += sqlite3MemSize(p);
|
|
-#endif
|
|
assert( PAGE_IS_UNPINNED(p) );
|
|
pcache1PinPage(p);
|
|
pcache1RemoveFromHash(p, 1);
|
|
@@ -50773,7 +54859,7 @@ SQLITE_PRIVATE void sqlite3PcacheStats(
|
|
** extracts the least value from the RowSet.
|
|
**
|
|
** The INSERT primitive might allocate additional memory. Memory is
|
|
-** allocated in chunks so most INSERTs do no allocation. There is an
|
|
+** allocated in chunks so most INSERTs do no allocation. There is an
|
|
** upper bound on the size of allocated memory. No memory is freed
|
|
** until DESTROY.
|
|
**
|
|
@@ -50821,7 +54907,7 @@ SQLITE_PRIVATE void sqlite3PcacheStats(
|
|
** in the list, pLeft points to the tree, and v is unused. The
|
|
** RowSet.pForest value points to the head of this forest list.
|
|
*/
|
|
-struct RowSetEntry {
|
|
+struct RowSetEntry {
|
|
i64 v; /* ROWID value for this entry */
|
|
struct RowSetEntry *pRight; /* Right subtree (larger entries) or list */
|
|
struct RowSetEntry *pLeft; /* Left subtree (smaller entries) */
|
|
@@ -50915,7 +55001,7 @@ SQLITE_PRIVATE void sqlite3RowSetDelete(void *pArg){
|
|
/*
|
|
** Allocate a new RowSetEntry object that is associated with the
|
|
** given RowSet. Return a pointer to the new and completely uninitialized
|
|
-** objected.
|
|
+** object.
|
|
**
|
|
** In an OOM situation, the RowSet.db->mallocFailed flag is set and this
|
|
** routine returns NULL.
|
|
@@ -50973,7 +55059,7 @@ SQLITE_PRIVATE void sqlite3RowSetInsert(RowSet *p, i64 rowid){
|
|
/*
|
|
** Merge two lists of RowSetEntry objects. Remove duplicates.
|
|
**
|
|
-** The input lists are connected via pRight pointers and are
|
|
+** The input lists are connected via pRight pointers and are
|
|
** assumed to each already be in sorted order.
|
|
*/
|
|
static struct RowSetEntry *rowSetEntryMerge(
|
|
@@ -51010,7 +55096,7 @@ static struct RowSetEntry *rowSetEntryMerge(
|
|
/*
|
|
** Sort all elements on the list of RowSetEntry objects into order of
|
|
** increasing v.
|
|
-*/
|
|
+*/
|
|
static struct RowSetEntry *rowSetEntrySort(struct RowSetEntry *pIn){
|
|
unsigned int i;
|
|
struct RowSetEntry *pNext, *aBucket[40];
|
|
@@ -51083,7 +55169,7 @@ static struct RowSetEntry *rowSetNDeepTree(
|
|
struct RowSetEntry *pLeft; /* Left subtree */
|
|
if( *ppList==0 ){ /*OPTIMIZATION-IF-TRUE*/
|
|
/* Prevent unnecessary deep recursion when we run out of entries */
|
|
- return 0;
|
|
+ return 0;
|
|
}
|
|
if( iDepth>1 ){ /*OPTIMIZATION-IF-TRUE*/
|
|
/* This branch causes a *balanced* tree to be generated. A valid tree
|
|
@@ -51191,7 +55277,7 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64
|
|
if( p ){
|
|
struct RowSetEntry **ppPrevTree = &pRowSet->pForest;
|
|
if( (pRowSet->rsFlags & ROWSET_SORTED)==0 ){ /*OPTIMIZATION-IF-FALSE*/
|
|
- /* Only sort the current set of entiries if they need it */
|
|
+ /* Only sort the current set of entries if they need it */
|
|
p = rowSetEntrySort(p);
|
|
}
|
|
for(pTree = pRowSet->pForest; pTree; pTree=pTree->pRight){
|
|
@@ -51253,7 +55339,7 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64
|
|
**
|
|
*************************************************************************
|
|
** This is the implementation of the page cache subsystem or "pager".
|
|
-**
|
|
+**
|
|
** The pager is used to access a database disk file. It implements
|
|
** atomic commit and rollback through the use of a journal file that
|
|
** is separate from the database file. The pager also implements file
|
|
@@ -51276,8 +55362,8 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64
|
|
** May you share freely, never taking more than you give.
|
|
**
|
|
*************************************************************************
|
|
-** This header file defines the interface to the write-ahead logging
|
|
-** system. Refer to the comments below and the header comment attached to
|
|
+** This header file defines the interface to the write-ahead logging
|
|
+** system. Refer to the comments below and the header comment attached to
|
|
** the implementation of each function in log.c for further details.
|
|
*/
|
|
|
|
@@ -51316,8 +55402,8 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64
|
|
|
|
#define WAL_SAVEPOINT_NDATA 4
|
|
|
|
-/* Connection to a write-ahead log (WAL) file.
|
|
-** There is one object of this type for each pager.
|
|
+/* Connection to a write-ahead log (WAL) file.
|
|
+** There is one object of this type for each pager.
|
|
*/
|
|
typedef struct Wal Wal;
|
|
|
|
@@ -51328,7 +55414,7 @@ SQLITE_PRIVATE int sqlite3WalClose(Wal *pWal, sqlite3*, int sync_flags, int, u8
|
|
/* Set the limiting size of a WAL file. */
|
|
SQLITE_PRIVATE void sqlite3WalLimit(Wal*, i64);
|
|
|
|
-/* Used by readers to open (lock) and close (unlock) a snapshot. A
|
|
+/* 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
|
|
** at an instant in time. sqlite3WalOpenSnapshot gets a read lock and
|
|
** preserves the current state even if the other threads or processes
|
|
@@ -51363,7 +55449,7 @@ SQLITE_PRIVATE int sqlite3WalSavepointUndo(Wal *pWal, u32 *aWalData);
|
|
/* Write a frame or frames to the log. */
|
|
SQLITE_PRIVATE int sqlite3WalFrames(Wal *pWal, int, PgHdr *, Pgno, int, int);
|
|
|
|
-/* Copy pages from the log to the database file */
|
|
+/* Copy pages from the log to the database file */
|
|
SQLITE_PRIVATE int sqlite3WalCheckpoint(
|
|
Wal *pWal, /* Write-ahead log connection */
|
|
sqlite3 *db, /* Check this handle's interrupt flag */
|
|
@@ -51391,7 +55477,7 @@ SQLITE_PRIVATE int sqlite3WalExclusiveMode(Wal *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.
|
|
+** WAL module is using shared-memory, return false.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal);
|
|
|
|
@@ -51413,6 +55499,11 @@ SQLITE_PRIVATE int sqlite3WalFramesize(Wal *pWal);
|
|
/* Return the sqlite3_file object for the WAL file */
|
|
SQLITE_PRIVATE sqlite3_file *sqlite3WalFile(Wal *pWal);
|
|
|
|
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
|
+SQLITE_PRIVATE int sqlite3WalWriteLock(Wal *pWal, int bLock);
|
|
+SQLITE_PRIVATE void sqlite3WalDb(Wal *pWal, sqlite3 *db);
|
|
+#endif
|
|
+
|
|
#endif /* ifndef SQLITE_OMIT_WAL */
|
|
#endif /* SQLITE_WAL_H */
|
|
|
|
@@ -51433,60 +55524,60 @@ SQLITE_PRIVATE sqlite3_file *sqlite3WalFile(Wal *pWal);
|
|
**
|
|
** Definition: A page of the database file is said to be "overwriteable" if
|
|
** one or more of the following are true about the page:
|
|
-**
|
|
+**
|
|
** (a) The original content of the page as it was at the beginning of
|
|
** the transaction has been written into the rollback journal and
|
|
** synced.
|
|
-**
|
|
+**
|
|
** (b) The page was a freelist leaf page at the start of the transaction.
|
|
-**
|
|
+**
|
|
** (c) The page number is greater than the largest page that existed in
|
|
** the database file at the start of the transaction.
|
|
-**
|
|
+**
|
|
** (1) A page of the database file is never overwritten unless one of the
|
|
** following are true:
|
|
-**
|
|
+**
|
|
** (a) The page and all other pages on the same sector are overwriteable.
|
|
-**
|
|
+**
|
|
** (b) The atomic page write optimization is enabled, and the entire
|
|
** transaction other than the update of the transaction sequence
|
|
** number consists of a single page change.
|
|
-**
|
|
+**
|
|
** (2) The content of a page written into the rollback journal exactly matches
|
|
** both the content in the database when the rollback journal was written
|
|
** and the content in the database at the beginning of the current
|
|
** transaction.
|
|
-**
|
|
+**
|
|
** (3) Writes to the database file are an integer multiple of the page size
|
|
** in length and are aligned on a page boundary.
|
|
-**
|
|
+**
|
|
** (4) Reads from the database file are either aligned on a page boundary and
|
|
** an integer multiple of the page size in length or are taken from the
|
|
** first 100 bytes of the database file.
|
|
-**
|
|
+**
|
|
** (5) All writes to the database file are synced prior to the rollback journal
|
|
** being deleted, truncated, or zeroed.
|
|
-**
|
|
-** (6) If a master journal file is used, then all writes to the database file
|
|
-** are synced prior to the master journal being deleted.
|
|
-**
|
|
+**
|
|
+** (6) If a super-journal file is used, then all writes to the database file
|
|
+** are synced prior to the super-journal being deleted.
|
|
+**
|
|
** Definition: Two databases (or the same database at two points it time)
|
|
** are said to be "logically equivalent" if they give the same answer to
|
|
** all queries. Note in particular the content of freelist leaf
|
|
** pages can be changed arbitrarily without affecting the logical equivalence
|
|
** of the database.
|
|
-**
|
|
+**
|
|
** (7) At any time, if any subset, including the empty set and the total set,
|
|
-** of the unsynced changes to a rollback journal are removed and the
|
|
+** of the unsynced changes to a rollback journal are removed and the
|
|
** journal is rolled back, the resulting database file will be logically
|
|
** equivalent to the database file at the beginning of the transaction.
|
|
-**
|
|
+**
|
|
** (8) When a transaction is rolled back, the xTruncate method of the VFS
|
|
** is called to restore the database file to the same size it was at
|
|
** the beginning of the transaction. (In some VFSes, the xTruncate
|
|
** method is a no-op, but that does not change the fact the SQLite will
|
|
** invoke it.)
|
|
-**
|
|
+**
|
|
** (9) Whenever the database file is modified, at least one bit in the range
|
|
** of bytes from 24 through 39 inclusive will be changed prior to releasing
|
|
** the EXCLUSIVE lock, thus signaling other connections on the same
|
|
@@ -51519,7 +55610,7 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
|
|
|
|
/*
|
|
** The following two macros are used within the PAGERTRACE() macros above
|
|
-** to print out file-descriptors.
|
|
+** to print out file-descriptors.
|
|
**
|
|
** PAGERID() takes a pointer to a Pager struct as its argument. The
|
|
** associated file-descriptor is returned. FILEHANDLEID() takes an sqlite3_file
|
|
@@ -51540,7 +55631,7 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
|
|
** | | |
|
|
** | V |
|
|
** |<-------WRITER_LOCKED------> ERROR
|
|
-** | | ^
|
|
+** | | ^
|
|
** | V |
|
|
** |<------WRITER_CACHEMOD-------->|
|
|
** | | |
|
|
@@ -51552,7 +55643,7 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
|
|
**
|
|
**
|
|
** List of state transitions and the C [function] that performs each:
|
|
-**
|
|
+**
|
|
** OPEN -> READER [sqlite3PagerSharedLock]
|
|
** READER -> OPEN [pager_unlock]
|
|
**
|
|
@@ -51564,7 +55655,7 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
|
|
**
|
|
** WRITER_*** -> ERROR [pager_error]
|
|
** ERROR -> OPEN [pager_unlock]
|
|
-**
|
|
+**
|
|
**
|
|
** OPEN:
|
|
**
|
|
@@ -51578,9 +55669,9 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
|
|
**
|
|
** READER:
|
|
**
|
|
-** In this state all the requirements for reading the database in
|
|
+** In this state all the requirements for reading the database in
|
|
** rollback (non-WAL) mode are met. Unless the pager is (or recently
|
|
-** was) in exclusive-locking mode, a user-level read transaction is
|
|
+** was) in exclusive-locking mode, a user-level read transaction is
|
|
** open. The database size is known in this state.
|
|
**
|
|
** A connection running with locking_mode=normal enters this state when
|
|
@@ -51590,28 +55681,28 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
|
|
** this state even after the read-transaction is closed. The only way
|
|
** a locking_mode=exclusive connection can transition from READER to OPEN
|
|
** is via the ERROR state (see below).
|
|
-**
|
|
+**
|
|
** * A read transaction may be active (but a write-transaction cannot).
|
|
** * A SHARED or greater lock is held on the database file.
|
|
-** * The dbSize variable may be trusted (even if a user-level read
|
|
+** * The dbSize variable may be trusted (even if a user-level read
|
|
** transaction is not active). The dbOrigSize and dbFileSize variables
|
|
** may not be trusted at this point.
|
|
** * If the database is a WAL database, then the WAL connection is open.
|
|
-** * Even if a read-transaction is not open, it is guaranteed that
|
|
+** * Even if a read-transaction is not open, it is guaranteed that
|
|
** there is no hot-journal in the file-system.
|
|
**
|
|
** WRITER_LOCKED:
|
|
**
|
|
** The pager moves to this state from READER when a write-transaction
|
|
-** is first opened on the database. In WRITER_LOCKED state, all locks
|
|
-** required to start a write-transaction are held, but no actual
|
|
+** is first opened on the database. In WRITER_LOCKED state, all locks
|
|
+** required to start a write-transaction are held, but no actual
|
|
** modifications to the cache or database have taken place.
|
|
**
|
|
-** In rollback mode, a RESERVED or (if the transaction was opened with
|
|
+** In rollback mode, a RESERVED or (if the transaction was opened with
|
|
** BEGIN EXCLUSIVE) EXCLUSIVE lock is obtained on the database file when
|
|
-** moving to this state, but the journal file is not written to or opened
|
|
-** to in this state. If the transaction is committed or rolled back while
|
|
-** in WRITER_LOCKED state, all that is required is to unlock the database
|
|
+** moving to this state, but the journal file is not written to or opened
|
|
+** to in this state. If the transaction is committed or rolled back while
|
|
+** in WRITER_LOCKED state, all that is required is to unlock the database
|
|
** file.
|
|
**
|
|
** IN WAL mode, WalBeginWriteTransaction() is called to lock the log file.
|
|
@@ -51619,7 +55710,7 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
|
|
** is made to obtain an EXCLUSIVE lock on the database file.
|
|
**
|
|
** * A write transaction is active.
|
|
-** * If the connection is open in rollback-mode, a RESERVED or greater
|
|
+** * If the connection is open in rollback-mode, a RESERVED or greater
|
|
** lock is held on the database file.
|
|
** * If the connection is open in WAL-mode, a WAL write transaction
|
|
** is open (i.e. sqlite3WalBeginWriteTransaction() has been successfully
|
|
@@ -51638,7 +55729,7 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
|
|
**
|
|
** * A write transaction is active.
|
|
** * A RESERVED or greater lock is held on the database file.
|
|
-** * The journal file is open and the first header has been written
|
|
+** * The journal file is open and the first header has been written
|
|
** to it, but the header has not been synced to disk.
|
|
** * The contents of the page cache have been modified.
|
|
**
|
|
@@ -51651,7 +55742,7 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
|
|
**
|
|
** * A write transaction is active.
|
|
** * An EXCLUSIVE or greater lock is held on the database file.
|
|
-** * The journal file is open and the first header has been written
|
|
+** * The journal file is open and the first header has been written
|
|
** and synced to disk.
|
|
** * The contents of the page cache have been modified (and possibly
|
|
** written to disk).
|
|
@@ -51663,8 +55754,8 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
|
|
** A rollback-mode pager changes to WRITER_FINISHED state from WRITER_DBMOD
|
|
** state after the entire transaction has been successfully written into the
|
|
** database file. In this state the transaction may be committed simply
|
|
-** by finalizing the journal file. Once in WRITER_FINISHED state, it is
|
|
-** not possible to modify the database further. At this point, the upper
|
|
+** by finalizing the journal file. Once in WRITER_FINISHED state, it is
|
|
+** not possible to modify the database further. At this point, the upper
|
|
** layer must either commit or rollback the transaction.
|
|
**
|
|
** * A write transaction is active.
|
|
@@ -51672,19 +55763,19 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
|
|
** * All writing and syncing of journal and database data has finished.
|
|
** If no error occurred, all that remains is to finalize the journal to
|
|
** commit the transaction. If an error did occur, the caller will need
|
|
-** to rollback the transaction.
|
|
+** to rollback the transaction.
|
|
**
|
|
** ERROR:
|
|
**
|
|
** The ERROR state is entered when an IO or disk-full error (including
|
|
-** SQLITE_IOERR_NOMEM) occurs at a point in the code that makes it
|
|
-** difficult to be sure that the in-memory pager state (cache contents,
|
|
+** SQLITE_IOERR_NOMEM) occurs at a point in the code that makes it
|
|
+** difficult to be sure that the in-memory pager state (cache contents,
|
|
** db size etc.) are consistent with the contents of the file-system.
|
|
**
|
|
** Temporary pager files may enter the ERROR state, but in-memory pagers
|
|
** cannot.
|
|
**
|
|
-** For example, if an IO error occurs while performing a rollback,
|
|
+** For example, if an IO error occurs while performing a rollback,
|
|
** the contents of the page-cache may be left in an inconsistent state.
|
|
** At this point it would be dangerous to change back to READER state
|
|
** (as usually happens after a rollback). Any subsequent readers might
|
|
@@ -51694,13 +55785,13 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
|
|
** instead of READER following such an error.
|
|
**
|
|
** Once it has entered the ERROR state, any attempt to use the pager
|
|
-** to read or write data returns an error. Eventually, once all
|
|
+** to read or write data returns an error. Eventually, once all
|
|
** outstanding transactions have been abandoned, the pager is able to
|
|
-** transition back to OPEN state, discarding the contents of the
|
|
+** 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)
|
|
** when a read-transaction is next opened on the pager (transitioning
|
|
-** the pager into READER state). At that point the system has recovered
|
|
+** the pager into READER state). At that point the system has recovered
|
|
** from the error.
|
|
**
|
|
** Specifically, the pager jumps into the ERROR state if:
|
|
@@ -51716,21 +55807,21 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
|
|
** memory.
|
|
**
|
|
** In other cases, the error is returned to the b-tree layer. The b-tree
|
|
-** layer then attempts a rollback operation. If the error condition
|
|
+** layer then attempts a rollback operation. If the error condition
|
|
** persists, the pager enters the ERROR state via condition (1) above.
|
|
**
|
|
** Condition (3) is necessary because it can be triggered by a read-only
|
|
** statement executed within a transaction. In this case, if the error
|
|
** code were simply returned to the user, the b-tree layer would not
|
|
** automatically attempt a rollback, as it assumes that an error in a
|
|
-** read-only statement cannot leave the pager in an internally inconsistent
|
|
+** read-only statement cannot leave the pager in an internally inconsistent
|
|
** state.
|
|
**
|
|
** * The Pager.errCode variable is set to something other than SQLITE_OK.
|
|
** * There are one or more outstanding references to pages (after the
|
|
** last reference is dropped the pager should move back to OPEN state).
|
|
** * The pager is not an in-memory pager.
|
|
-**
|
|
+**
|
|
**
|
|
** Notes:
|
|
**
|
|
@@ -51740,7 +55831,7 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
|
|
**
|
|
** * Normally, a connection open in exclusive mode is never in PAGER_OPEN
|
|
** state. There are two exceptions: immediately after exclusive-mode has
|
|
-** been turned on (and before any read or write transactions are
|
|
+** been turned on (and before any read or write transactions are
|
|
** executed), and when the pager is leaving the "error state".
|
|
**
|
|
** * See also: assert_pager_state().
|
|
@@ -51754,7 +55845,7 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
|
|
#define PAGER_ERROR 6
|
|
|
|
/*
|
|
-** The Pager.eLock variable is almost always set to one of the
|
|
+** The Pager.eLock variable is almost always set to one of the
|
|
** following locking-states, according to the lock currently held on
|
|
** the database file: NO_LOCK, SHARED_LOCK, RESERVED_LOCK or EXCLUSIVE_LOCK.
|
|
** This variable is kept up to date as locks are taken and released by
|
|
@@ -51769,20 +55860,20 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
|
|
** to a less exclusive (lower) value than the lock that is actually held
|
|
** at the system level, but it is never set to a more exclusive value.
|
|
**
|
|
-** This is usually safe. If an xUnlock fails or appears to fail, there may
|
|
+** This is usually safe. If an xUnlock fails or appears to fail, there may
|
|
** be a few redundant xLock() calls or a lock may be held for longer than
|
|
** required, but nothing really goes wrong.
|
|
**
|
|
** The exception is when the database file is unlocked as the pager moves
|
|
-** from ERROR to OPEN state. At this point there may be a hot-journal file
|
|
+** from ERROR to OPEN state. At this point there may be a hot-journal file
|
|
** in the file-system that needs to be rolled back (as part of an OPEN->SHARED
|
|
** transition, by the same pager or any other). If the call to xUnlock()
|
|
** fails at this point and the pager is left holding an EXCLUSIVE lock, this
|
|
** can confuse the call to xCheckReservedLock() call made later as part
|
|
** of hot-journal detection.
|
|
**
|
|
-** xCheckReservedLock() is defined as returning true "if there is a RESERVED
|
|
-** lock held by this process or any others". So xCheckReservedLock may
|
|
+** xCheckReservedLock() is defined as returning true "if there is a RESERVED
|
|
+** lock held by this process or any others". So xCheckReservedLock may
|
|
** return true because the caller itself is holding an EXCLUSIVE lock (but
|
|
** doesn't know it because of a previous error in xUnlock). If this happens
|
|
** a hot-journal may be mistaken for a journal being created by an active
|
|
@@ -51793,32 +55884,18 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
|
|
** database in the ERROR state, Pager.eLock is set to UNKNOWN_LOCK. It
|
|
** is only changed back to a real locking state after a successful call
|
|
** to xLock(EXCLUSIVE). Also, the code to do the OPEN->SHARED state transition
|
|
-** omits the check for a hot-journal if Pager.eLock is set to UNKNOWN_LOCK
|
|
+** omits the check for a hot-journal if Pager.eLock is set to UNKNOWN_LOCK
|
|
** lock. Instead, it assumes a hot-journal exists and obtains an EXCLUSIVE
|
|
** lock on the database file before attempting to roll it back. See function
|
|
** PagerSharedLock() for more detail.
|
|
**
|
|
-** Pager.eLock may only be set to UNKNOWN_LOCK when the pager is in
|
|
+** Pager.eLock may only be set to UNKNOWN_LOCK when the pager is in
|
|
** PAGER_OPEN state.
|
|
*/
|
|
#define UNKNOWN_LOCK (EXCLUSIVE_LOCK+1)
|
|
|
|
/*
|
|
-** A macro used for invoking the codec if there is one
|
|
-*/
|
|
-#ifdef SQLITE_HAS_CODEC
|
|
-# define CODEC1(P,D,N,X,E) \
|
|
- if( P->xCodec && P->xCodec(P->pCodec,D,N,X)==0 ){ E; }
|
|
-# define CODEC2(P,D,N,X,E,O) \
|
|
- if( P->xCodec==0 ){ O=(char*)D; }else \
|
|
- if( (O=(char*)(P->xCodec(P->pCodec,D,N,X)))==0 ){ E; }
|
|
-#else
|
|
-# define CODEC1(P,D,N,X,E) /* NO-OP */
|
|
-# define CODEC2(P,D,N,X,E,O) O=(char*)D
|
|
-#endif
|
|
-
|
|
-/*
|
|
-** The maximum allowed sector size. 64KiB. If the xSectorsize() method
|
|
+** The maximum allowed sector size. 64KiB. If the xSectorsize() method
|
|
** returns a value larger than this, then MAX_SECTOR_SIZE is used instead.
|
|
** This could conceivably cause corruption following a power failure on
|
|
** such a system. This is currently an undocumented limit.
|
|
@@ -51834,7 +55911,7 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
|
|
**
|
|
** When a savepoint is created, the PagerSavepoint.iHdrOffset field is
|
|
** set to 0. If a journal-header is written into the main journal while
|
|
-** the savepoint is active, then iHdrOffset is set to the byte offset
|
|
+** the savepoint is active, then iHdrOffset is set to the byte offset
|
|
** immediately following the last journal record written into the main
|
|
** journal before the journal-header. This is required during savepoint
|
|
** rollback (see pagerPlaybackSavepoint()).
|
|
@@ -51846,6 +55923,7 @@ struct PagerSavepoint {
|
|
Bitvec *pInSavepoint; /* Set of pages in this savepoint */
|
|
Pgno nOrig; /* Original number of pages in file */
|
|
Pgno iSubRec; /* Index of first record in sub-journal */
|
|
+ int bTruncateOnRelease; /* If stmt journal may be truncated on RELEASE */
|
|
#ifndef SQLITE_OMIT_WAL
|
|
u32 aWalData[WAL_SAVEPOINT_NDATA]; /* WAL savepoint context */
|
|
#endif
|
|
@@ -51884,44 +55962,44 @@ struct PagerSavepoint {
|
|
**
|
|
** changeCountDone
|
|
**
|
|
-** This boolean variable is used to make sure that the change-counter
|
|
-** (the 4-byte header field at byte offset 24 of the database file) is
|
|
-** not updated more often than necessary.
|
|
+** This boolean variable is used to make sure that the change-counter
|
|
+** (the 4-byte header field at byte offset 24 of the database file) is
|
|
+** not updated more often than necessary.
|
|
**
|
|
-** It is set to true when the change-counter field is updated, which
|
|
+** It is set to true when the change-counter field is updated, which
|
|
** can only happen if an exclusive lock is held on the database file.
|
|
-** It is cleared (set to false) whenever an exclusive lock is
|
|
+** It is cleared (set to false) whenever an exclusive lock is
|
|
** relinquished on the database file. Each time a transaction is committed,
|
|
** The changeCountDone flag is inspected. If it is true, the work of
|
|
** updating the change-counter is omitted for the current transaction.
|
|
**
|
|
-** This mechanism means that when running in exclusive mode, a connection
|
|
+** This mechanism means that when running in exclusive mode, a connection
|
|
** need only update the change-counter once, for the first transaction
|
|
** committed.
|
|
**
|
|
-** setMaster
|
|
+** setSuper
|
|
**
|
|
** When PagerCommitPhaseOne() is called to commit a transaction, it may
|
|
-** (or may not) specify a master-journal name to be written into the
|
|
+** (or may not) specify a super-journal name to be written into the
|
|
** journal file before it is synced to disk.
|
|
**
|
|
-** Whether or not a journal file contains a master-journal pointer affects
|
|
-** the way in which the journal file is finalized after the transaction is
|
|
+** Whether or not a journal file contains a super-journal pointer affects
|
|
+** the way in which the journal file is finalized after the transaction is
|
|
** committed or rolled back when running in "journal_mode=PERSIST" mode.
|
|
-** If a journal file does not contain a master-journal pointer, it is
|
|
+** If a journal file does not contain a super-journal pointer, it is
|
|
** finalized by overwriting the first journal header with zeroes. If
|
|
-** it does contain a master-journal pointer the journal file is finalized
|
|
-** by truncating it to zero bytes, just as if the connection were
|
|
+** it does contain a super-journal pointer the journal file is finalized
|
|
+** by truncating it to zero bytes, just as if the connection were
|
|
** running in "journal_mode=truncate" mode.
|
|
**
|
|
-** Journal files that contain master journal pointers cannot be finalized
|
|
+** Journal files that contain super-journal pointers cannot be finalized
|
|
** simply by overwriting the first journal-header with zeroes, as the
|
|
-** master journal pointer could interfere with hot-journal rollback of any
|
|
+** super-journal pointer could interfere with hot-journal rollback of any
|
|
** subsequently interrupted transaction that reuses the journal file.
|
|
**
|
|
** The flag is cleared as soon as the journal file is finalized (either
|
|
** by PagerCommitPhaseTwo or PagerRollback). If an IO error prevents the
|
|
-** journal file from being successfully finalized, the setMaster flag
|
|
+** journal file from being successfully finalized, the setSuper flag
|
|
** is cleared anyway (and the pager will move to ERROR state).
|
|
**
|
|
** doNotSpill
|
|
@@ -51937,12 +56015,12 @@ struct PagerSavepoint {
|
|
** to allocate a new page to prevent the journal file from being written
|
|
** while it is being traversed by code in pager_playback(). The SPILLFLAG_OFF
|
|
** case is a user preference.
|
|
-**
|
|
+**
|
|
** If the SPILLFLAG_NOSYNC bit is set, writing to the database from
|
|
** pagerStress() is permitted, but syncing the journal file is not.
|
|
** This flag is set by sqlite3PagerWrite() when the file-system sector-size
|
|
** is larger than the database page-size in order to prevent a journal sync
|
|
-** from happening in between the journalling of two pages on the same sector.
|
|
+** from happening in between the journalling of two pages on the same sector.
|
|
**
|
|
** subjInMemory
|
|
**
|
|
@@ -51950,16 +56028,16 @@ struct PagerSavepoint {
|
|
** is opened as an in-memory journal file. If false, then in-memory
|
|
** sub-journals are only used for in-memory pager files.
|
|
**
|
|
-** This variable is updated by the upper layer each time a new
|
|
+** This variable is updated by the upper layer each time a new
|
|
** write-transaction is opened.
|
|
**
|
|
** dbSize, dbOrigSize, dbFileSize
|
|
**
|
|
** Variable dbSize is set to the number of pages in the database file.
|
|
** It is valid in PAGER_READER and higher states (all states except for
|
|
-** OPEN and ERROR).
|
|
+** OPEN and ERROR).
|
|
**
|
|
-** dbSize is set based on the size of the database file, which may be
|
|
+** dbSize is set based on the size of the database file, which may be
|
|
** larger than the size of the database (the value stored at offset
|
|
** 28 of the database header by the btree). If the size of the file
|
|
** is not an integer multiple of the page-size, the value stored in
|
|
@@ -51970,10 +56048,10 @@ struct PagerSavepoint {
|
|
**
|
|
** During a write-transaction, if pages with page-numbers greater than
|
|
** dbSize are modified in the cache, dbSize is updated accordingly.
|
|
-** Similarly, if the database is truncated using PagerTruncateImage(),
|
|
+** Similarly, if the database is truncated using PagerTruncateImage(),
|
|
** dbSize is updated.
|
|
**
|
|
-** Variables dbOrigSize and dbFileSize are valid in states
|
|
+** Variables dbOrigSize and dbFileSize are valid in states
|
|
** PAGER_WRITER_LOCKED and higher. dbOrigSize is a copy of the dbSize
|
|
** variable at the start of the transaction. It is used during rollback,
|
|
** and to determine whether or not pages need to be journalled before
|
|
@@ -51982,12 +56060,12 @@ struct PagerSavepoint {
|
|
** Throughout a write-transaction, dbFileSize contains the size of
|
|
** the file on disk in pages. It is set to a copy of dbSize when the
|
|
** write-transaction is first opened, and updated when VFS calls are made
|
|
-** to write or truncate the database file on disk.
|
|
+** to write or truncate the database file on disk.
|
|
**
|
|
-** The only reason the dbFileSize variable is required is to suppress
|
|
-** unnecessary calls to xTruncate() after committing a transaction. If,
|
|
-** when a transaction is committed, the dbFileSize variable indicates
|
|
-** that the database file is larger than the database image (Pager.dbSize),
|
|
+** The only reason the dbFileSize variable is required is to suppress
|
|
+** unnecessary calls to xTruncate() after committing a transaction. If,
|
|
+** when a transaction is committed, the dbFileSize variable indicates
|
|
+** that the database file is larger than the database image (Pager.dbSize),
|
|
** pager_truncate() is called. The pager_truncate() call uses xFilesize()
|
|
** to measure the database file on disk, and then truncates it if required.
|
|
** dbFileSize is not used when rolling back a transaction. In this case
|
|
@@ -51998,20 +56076,20 @@ struct PagerSavepoint {
|
|
** dbHintSize
|
|
**
|
|
** The dbHintSize variable is used to limit the number of calls made to
|
|
-** the VFS xFileControl(FCNTL_SIZE_HINT) method.
|
|
+** the VFS xFileControl(FCNTL_SIZE_HINT) method.
|
|
**
|
|
** dbHintSize is set to a copy of the dbSize variable when a
|
|
** write-transaction is opened (at the same time as dbFileSize and
|
|
** dbOrigSize). If the xFileControl(FCNTL_SIZE_HINT) method is called,
|
|
** dbHintSize is increased to the number of pages that correspond to the
|
|
-** size-hint passed to the method call. See pager_write_pagelist() for
|
|
+** size-hint passed to the method call. See pager_write_pagelist() for
|
|
** details.
|
|
**
|
|
** errCode
|
|
**
|
|
** The Pager.errCode variable is only ever used in PAGER_ERROR state. It
|
|
-** is set to zero in all other states. In PAGER_ERROR state, Pager.errCode
|
|
-** is always set to SQLITE_FULL, SQLITE_IOERR or one of the SQLITE_IOERR_XXX
|
|
+** is set to zero in all other states. In PAGER_ERROR state, Pager.errCode
|
|
+** is always set to SQLITE_FULL, SQLITE_IOERR or one of the SQLITE_IOERR_XXX
|
|
** sub-codes.
|
|
**
|
|
** syncFlags, walSyncFlags
|
|
@@ -52040,6 +56118,7 @@ struct Pager {
|
|
u8 noLock; /* Do not lock (except in WAL mode) */
|
|
u8 readOnly; /* True for a read-only database */
|
|
u8 memDb; /* True to inhibit all file I/O */
|
|
+ u8 memVfs; /* VFS-implemented memory database */
|
|
|
|
/**************************************************************************
|
|
** The following block contains those class members that change during
|
|
@@ -52053,7 +56132,7 @@ struct Pager {
|
|
u8 eState; /* Pager state (OPEN, READER, WRITER_LOCKED..) */
|
|
u8 eLock; /* Current lock held on database file */
|
|
u8 changeCountDone; /* Set after incrementing the change-counter */
|
|
- u8 setMaster; /* True if a m-j name has been written to jrnl */
|
|
+ u8 setSuper; /* Super-jrnl name is written into jrnl */
|
|
u8 doNotSpill; /* Do not spill the cache when non-zero */
|
|
u8 subjInMemory; /* True to use in-memory sub-journals */
|
|
u8 bUseFetch; /* True to use xFetch() */
|
|
@@ -52089,8 +56168,9 @@ struct Pager {
|
|
i16 nReserve; /* Number of unused bytes at end of each page */
|
|
u32 vfsFlags; /* Flags for sqlite3_vfs.xOpen() */
|
|
u32 sectorSize; /* Assumed sector size during rollback */
|
|
- int pageSize; /* Number of bytes in a page */
|
|
Pgno mxPgno; /* Maximum allowed size of the database */
|
|
+ Pgno lckPgno; /* Page number for the locking page */
|
|
+ i64 pageSize; /* Number of bytes in a page */
|
|
i64 journalSizeLimit; /* Size limit for persistent journal files */
|
|
char *zFilename; /* Name of the database file */
|
|
char *zJournal; /* Name of the journal file */
|
|
@@ -52102,12 +56182,6 @@ struct Pager {
|
|
#endif
|
|
void (*xReiniter)(DbPage*); /* Call this routine when reloading pages */
|
|
int (*xGet)(Pager*,Pgno,DbPage**,int); /* Routine to fetch a patch */
|
|
-#ifdef SQLITE_HAS_CODEC
|
|
- void *(*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */
|
|
- void (*xCodecSizeChng)(void*,int,int); /* Notify of page size changes */
|
|
- void (*xCodecFree)(void*); /* Destructor for the codec */
|
|
- void *pCodec; /* First argument to xCodec... methods */
|
|
-#endif
|
|
char *pTmpSpace; /* Pager.pageSize bytes of space for tmp use */
|
|
PCache *pPCache; /* Pointer to page cache object */
|
|
#ifndef SQLITE_OMIT_WAL
|
|
@@ -52118,7 +56192,7 @@ struct Pager {
|
|
|
|
/*
|
|
** Indexes for use with Pager.aStat[]. The Pager.aStat[] array contains
|
|
-** the values accessed by passing SQLITE_DBSTATUS_CACHE_HIT, CACHE_MISS
|
|
+** the values accessed by passing SQLITE_DBSTATUS_CACHE_HIT, CACHE_MISS
|
|
** or CACHE_WRITE to sqlite3_db_status().
|
|
*/
|
|
#define PAGER_STAT_HIT 0
|
|
@@ -52176,7 +56250,7 @@ static const unsigned char aJournalMagic[] = {
|
|
#define JOURNAL_PG_SZ(pPager) ((pPager->pageSize) + 8)
|
|
|
|
/*
|
|
-** The journal header size for this pager. This is usually the same
|
|
+** The journal header size for this pager. This is usually the same
|
|
** size as a single disk sector. See also setSectorSize().
|
|
*/
|
|
#define JOURNAL_HDR_SZ(pPager) (pPager->sectorSize)
|
|
@@ -52203,11 +56277,6 @@ static const unsigned char aJournalMagic[] = {
|
|
# define USEFETCH(x) 0
|
|
#endif
|
|
|
|
-/*
|
|
-** The maximum legal page number is (2^31 - 1).
|
|
-*/
|
|
-#define PAGER_MAX_PGNO 2147483647
|
|
-
|
|
/*
|
|
** The argument to this macro is a file descriptor (type sqlite3_file*).
|
|
** Return 0 if it is not open, or non-zero (but not 1) if it is.
|
|
@@ -52234,9 +56303,6 @@ static const unsigned char aJournalMagic[] = {
|
|
SQLITE_PRIVATE int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno){
|
|
if( pPager->fd->pMethods==0 ) return 0;
|
|
if( sqlite3PCacheIsDirty(pPager->pPCache) ) return 0;
|
|
-#ifdef SQLITE_HAS_CODEC
|
|
- if( pPager->xCodec!=0 ) return 0;
|
|
-#endif
|
|
#ifndef SQLITE_OMIT_WAL
|
|
if( pPager->pWal ){
|
|
u32 iRead = 0;
|
|
@@ -52259,7 +56325,7 @@ SQLITE_PRIVATE int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno){
|
|
# define pagerBeginReadTransaction(z) SQLITE_OK
|
|
#endif
|
|
|
|
-#ifndef NDEBUG
|
|
+#ifndef NDEBUG
|
|
/*
|
|
** Usage:
|
|
**
|
|
@@ -52288,25 +56354,25 @@ static int assert_pager_state(Pager *p){
|
|
assert( p->tempFile==0 || p->eLock==EXCLUSIVE_LOCK );
|
|
assert( p->tempFile==0 || pPager->changeCountDone );
|
|
|
|
- /* If the useJournal flag is clear, the journal-mode must be "OFF".
|
|
+ /* If the useJournal flag is clear, the journal-mode must be "OFF".
|
|
** And if the journal-mode is "OFF", the journal file must not be open.
|
|
*/
|
|
assert( p->journalMode==PAGER_JOURNALMODE_OFF || p->useJournal );
|
|
assert( p->journalMode!=PAGER_JOURNALMODE_OFF || !isOpen(p->jfd) );
|
|
|
|
- /* Check that MEMDB implies noSync. And an in-memory journal. Since
|
|
- ** this means an in-memory pager performs no IO at all, it cannot encounter
|
|
- ** either SQLITE_IOERR or SQLITE_FULL during rollback or while finalizing
|
|
- ** a journal file. (although the in-memory journal implementation may
|
|
- ** return SQLITE_IOERR_NOMEM while the journal file is being written). It
|
|
- ** is therefore not possible for an in-memory pager to enter the ERROR
|
|
+ /* Check that MEMDB implies noSync. And an in-memory journal. Since
|
|
+ ** this means an in-memory pager performs no IO at all, it cannot encounter
|
|
+ ** either SQLITE_IOERR or SQLITE_FULL during rollback or while finalizing
|
|
+ ** a journal file. (although the in-memory journal implementation may
|
|
+ ** return SQLITE_IOERR_NOMEM while the journal file is being written). It
|
|
+ ** is therefore not possible for an in-memory pager to enter the ERROR
|
|
** state.
|
|
*/
|
|
if( MEMDB ){
|
|
assert( !isOpen(p->fd) );
|
|
assert( p->noSync );
|
|
- assert( p->journalMode==PAGER_JOURNALMODE_OFF
|
|
- || p->journalMode==PAGER_JOURNALMODE_MEMORY
|
|
+ assert( p->journalMode==PAGER_JOURNALMODE_OFF
|
|
+ || p->journalMode==PAGER_JOURNALMODE_MEMORY
|
|
);
|
|
assert( p->eState!=PAGER_ERROR && p->eState!=PAGER_OPEN );
|
|
assert( pagerUseWal(p)==0 );
|
|
@@ -52340,7 +56406,7 @@ static int assert_pager_state(Pager *p){
|
|
assert( pPager->dbSize==pPager->dbOrigSize );
|
|
assert( pPager->dbOrigSize==pPager->dbFileSize );
|
|
assert( pPager->dbOrigSize==pPager->dbHintSize );
|
|
- assert( pPager->setMaster==0 );
|
|
+ assert( pPager->setSuper==0 );
|
|
break;
|
|
|
|
case PAGER_WRITER_CACHEMOD:
|
|
@@ -52353,9 +56419,9 @@ static int assert_pager_state(Pager *p){
|
|
** to journal_mode=wal.
|
|
*/
|
|
assert( p->eLock>=RESERVED_LOCK );
|
|
- assert( isOpen(p->jfd)
|
|
- || p->journalMode==PAGER_JOURNALMODE_OFF
|
|
- || p->journalMode==PAGER_JOURNALMODE_WAL
|
|
+ assert( isOpen(p->jfd)
|
|
+ || p->journalMode==PAGER_JOURNALMODE_OFF
|
|
+ || p->journalMode==PAGER_JOURNALMODE_WAL
|
|
);
|
|
}
|
|
assert( pPager->dbOrigSize==pPager->dbFileSize );
|
|
@@ -52367,9 +56433,9 @@ static int assert_pager_state(Pager *p){
|
|
assert( pPager->errCode==SQLITE_OK );
|
|
assert( !pagerUseWal(pPager) );
|
|
assert( p->eLock>=EXCLUSIVE_LOCK );
|
|
- assert( isOpen(p->jfd)
|
|
- || p->journalMode==PAGER_JOURNALMODE_OFF
|
|
- || p->journalMode==PAGER_JOURNALMODE_WAL
|
|
+ assert( isOpen(p->jfd)
|
|
+ || p->journalMode==PAGER_JOURNALMODE_OFF
|
|
+ || p->journalMode==PAGER_JOURNALMODE_WAL
|
|
|| (sqlite3OsDeviceCharacteristics(p->fd)&SQLITE_IOCAP_BATCH_ATOMIC)
|
|
);
|
|
assert( pPager->dbOrigSize<=pPager->dbHintSize );
|
|
@@ -52379,9 +56445,9 @@ static int assert_pager_state(Pager *p){
|
|
assert( p->eLock==EXCLUSIVE_LOCK );
|
|
assert( pPager->errCode==SQLITE_OK );
|
|
assert( !pagerUseWal(pPager) );
|
|
- assert( isOpen(p->jfd)
|
|
- || p->journalMode==PAGER_JOURNALMODE_OFF
|
|
- || p->journalMode==PAGER_JOURNALMODE_WAL
|
|
+ assert( isOpen(p->jfd)
|
|
+ || p->journalMode==PAGER_JOURNALMODE_OFF
|
|
+ || p->journalMode==PAGER_JOURNALMODE_WAL
|
|
|| (sqlite3OsDeviceCharacteristics(p->fd)&SQLITE_IOCAP_BATCH_ATOMIC)
|
|
);
|
|
break;
|
|
@@ -52400,7 +56466,7 @@ static int assert_pager_state(Pager *p){
|
|
}
|
|
#endif /* ifndef NDEBUG */
|
|
|
|
-#ifdef SQLITE_DEBUG
|
|
+#ifdef SQLITE_DEBUG
|
|
/*
|
|
** Return a pointer to a human readable string in a static buffer
|
|
** containing the state of the Pager object passed as an argument. This
|
|
@@ -52470,11 +56536,7 @@ static void setGetterMethod(Pager *pPager){
|
|
if( pPager->errCode ){
|
|
pPager->xGet = getPageError;
|
|
#if SQLITE_MAX_MMAP_SIZE>0
|
|
- }else if( USEFETCH(pPager)
|
|
-#ifdef SQLITE_HAS_CODEC
|
|
- && pPager->xCodec==0
|
|
-#endif
|
|
- ){
|
|
+ }else if( USEFETCH(pPager) ){
|
|
pPager->xGet = getPageMMap;
|
|
#endif /* SQLITE_MAX_MMAP_SIZE>0 */
|
|
}else{
|
|
@@ -52499,6 +56561,9 @@ static int subjRequiresPage(PgHdr *pPg){
|
|
for(i=0; i<pPager->nSavepoint; i++){
|
|
p = &pPager->aSavepoint[i];
|
|
if( p->nOrig>=pgno && 0==sqlite3BitvecTestNotNull(p->pInSavepoint, pgno) ){
|
|
+ for(i=i+1; i<pPager->nSavepoint; i++){
|
|
+ pPager->aSavepoint[i].bTruncateOnRelease = 0;
|
|
+ }
|
|
return 1;
|
|
}
|
|
}
|
|
@@ -52552,7 +56617,7 @@ static int write32bits(sqlite3_file *fd, i64 offset, u32 val){
|
|
** succeeds, set the Pager.eLock variable to match the (attempted) new lock.
|
|
**
|
|
** Except, if Pager.eLock is set to UNKNOWN_LOCK when this function is
|
|
-** called, do not modify it. See the comment above the #define of
|
|
+** called, do not modify it. See the comment above the #define of
|
|
** UNKNOWN_LOCK for an explanation of this.
|
|
*/
|
|
static int pagerUnlockDb(Pager *pPager, int eLock){
|
|
@@ -52576,11 +56641,11 @@ static int pagerUnlockDb(Pager *pPager, int eLock){
|
|
/*
|
|
** Lock the database file to level eLock, which must be either SHARED_LOCK,
|
|
** RESERVED_LOCK or EXCLUSIVE_LOCK. If the caller is successful, set the
|
|
-** Pager.eLock variable to the new locking state.
|
|
+** Pager.eLock variable to the new locking state.
|
|
**
|
|
-** Except, if Pager.eLock is set to UNKNOWN_LOCK when this function is
|
|
-** called, do not modify it unless the new locking state is EXCLUSIVE_LOCK.
|
|
-** See the comment above the #define of UNKNOWN_LOCK for an explanation
|
|
+** Except, if Pager.eLock is set to UNKNOWN_LOCK when this function is
|
|
+** called, do not modify it unless the new locking state is EXCLUSIVE_LOCK.
|
|
+** See the comment above the #define of UNKNOWN_LOCK for an explanation
|
|
** of this.
|
|
*/
|
|
static int pagerLockDb(Pager *pPager, int eLock){
|
|
@@ -52607,7 +56672,7 @@ static int pagerLockDb(Pager *pPager, int eLock){
|
|
** (b) the value returned by OsSectorSize() is less than or equal
|
|
** to the page size.
|
|
**
|
|
-** If it can be used, then the value returned is the size of the journal
|
|
+** If it can be used, then the value returned is the size of the journal
|
|
** file when it contains rollback data for exactly one page.
|
|
**
|
|
** The atomic-batch-write optimization can be used if OsDeviceCharacteristics()
|
|
@@ -52698,73 +56763,73 @@ static void checkPage(PgHdr *pPg){
|
|
|
|
/*
|
|
** When this is called the journal file for pager pPager must be open.
|
|
-** This function attempts to read a master journal file name from the
|
|
-** end of the file and, if successful, copies it into memory supplied
|
|
-** by the caller. See comments above writeMasterJournal() for the format
|
|
-** used to store a master journal file name at the end of a journal file.
|
|
+** This function attempts to read a super-journal file name from the
|
|
+** end of the file and, if successful, copies it into memory supplied
|
|
+** by the caller. See comments above writeSuperJournal() for the format
|
|
+** used to store a super-journal file name at the end of a journal file.
|
|
**
|
|
-** zMaster must point to a buffer of at least nMaster bytes allocated by
|
|
+** zSuper must point to a buffer of at least nSuper bytes allocated by
|
|
** the caller. This should be sqlite3_vfs.mxPathname+1 (to ensure there is
|
|
-** enough space to write the master journal name). If the master journal
|
|
-** name in the journal is longer than nMaster bytes (including a
|
|
-** nul-terminator), then this is handled as if no master journal name
|
|
+** enough space to write the super-journal name). If the super-journal
|
|
+** name in the journal is longer than nSuper bytes (including a
|
|
+** nul-terminator), then this is handled as if no super-journal name
|
|
** were present in the journal.
|
|
**
|
|
-** If a master journal file name is present at the end of the journal
|
|
-** file, then it is copied into the buffer pointed to by zMaster. A
|
|
-** nul-terminator byte is appended to the buffer following the master
|
|
-** journal file name.
|
|
+** If a super-journal file name is present at the end of the journal
|
|
+** file, then it is copied into the buffer pointed to by zSuper. A
|
|
+** nul-terminator byte is appended to the buffer following the
|
|
+** super-journal file name.
|
|
**
|
|
-** If it is determined that no master journal file name is present
|
|
-** zMaster[0] is set to 0 and SQLITE_OK returned.
|
|
+** If it is determined that no super-journal file name is present
|
|
+** zSuper[0] is set to 0 and SQLITE_OK returned.
|
|
**
|
|
** If an error occurs while reading from the journal file, an SQLite
|
|
** error code is returned.
|
|
*/
|
|
-static int readMasterJournal(sqlite3_file *pJrnl, char *zMaster, u32 nMaster){
|
|
+static int readSuperJournal(sqlite3_file *pJrnl, char *zSuper, u32 nSuper){
|
|
int rc; /* Return code */
|
|
- u32 len; /* Length in bytes of master journal name */
|
|
+ u32 len; /* Length in bytes of super-journal name */
|
|
i64 szJ; /* Total size in bytes of journal file pJrnl */
|
|
u32 cksum; /* MJ checksum value read from journal */
|
|
u32 u; /* Unsigned loop counter */
|
|
unsigned char aMagic[8]; /* A buffer to hold the magic header */
|
|
- zMaster[0] = '\0';
|
|
+ zSuper[0] = '\0';
|
|
|
|
if( SQLITE_OK!=(rc = sqlite3OsFileSize(pJrnl, &szJ))
|
|
|| szJ<16
|
|
|| SQLITE_OK!=(rc = read32bits(pJrnl, szJ-16, &len))
|
|
- || len>=nMaster
|
|
+ || len>=nSuper
|
|
|| len>szJ-16
|
|
- || len==0
|
|
+ || len==0
|
|
|| SQLITE_OK!=(rc = read32bits(pJrnl, szJ-12, &cksum))
|
|
|| SQLITE_OK!=(rc = sqlite3OsRead(pJrnl, aMagic, 8, szJ-8))
|
|
|| memcmp(aMagic, aJournalMagic, 8)
|
|
- || SQLITE_OK!=(rc = sqlite3OsRead(pJrnl, zMaster, len, szJ-16-len))
|
|
+ || SQLITE_OK!=(rc = sqlite3OsRead(pJrnl, zSuper, len, szJ-16-len))
|
|
){
|
|
return rc;
|
|
}
|
|
|
|
- /* See if the checksum matches the master journal name */
|
|
+ /* See if the checksum matches the super-journal name */
|
|
for(u=0; u<len; u++){
|
|
- cksum -= zMaster[u];
|
|
+ cksum -= zSuper[u];
|
|
}
|
|
if( cksum ){
|
|
/* If the checksum doesn't add up, then one or more of the disk sectors
|
|
- ** containing the master journal filename is corrupted. This means
|
|
+ ** containing the super-journal filename is corrupted. This means
|
|
** definitely roll back, so just return SQLITE_OK and report a (nul)
|
|
- ** master-journal filename.
|
|
+ ** super-journal filename.
|
|
*/
|
|
len = 0;
|
|
}
|
|
- zMaster[len] = '\0';
|
|
- zMaster[len+1] = '\0';
|
|
-
|
|
+ zSuper[len] = '\0';
|
|
+ zSuper[len+1] = '\0';
|
|
+
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
/*
|
|
-** Return the offset of the sector boundary at or immediately
|
|
-** following the value in pPager->journalOff, assuming a sector
|
|
+** Return the offset of the sector boundary at or immediately
|
|
+** following the value in pPager->journalOff, assuming a sector
|
|
** size of pPager->sectorSize bytes.
|
|
**
|
|
** i.e for a sector size of 512:
|
|
@@ -52775,7 +56840,7 @@ static int readMasterJournal(sqlite3_file *pJrnl, char *zMaster, u32 nMaster){
|
|
** 512 512
|
|
** 100 512
|
|
** 2000 2048
|
|
-**
|
|
+**
|
|
*/
|
|
static i64 journalHdrOffset(Pager *pPager){
|
|
i64 offset = 0;
|
|
@@ -52797,12 +56862,12 @@ static i64 journalHdrOffset(Pager *pPager){
|
|
**
|
|
** If doTruncate is non-zero or the Pager.journalSizeLimit variable is
|
|
** set to 0, then truncate the journal file to zero bytes in size. Otherwise,
|
|
-** zero the 28-byte header at the start of the journal file. In either case,
|
|
-** if the pager is not in no-sync mode, sync the journal file immediately
|
|
+** zero the 28-byte header at the start of the journal file. In either case,
|
|
+** if the pager is not in no-sync mode, sync the journal file immediately
|
|
** after writing or truncating it.
|
|
**
|
|
** If Pager.journalSizeLimit is set to a positive, non-zero value, and
|
|
-** following the truncation or zeroing described above the size of the
|
|
+** following the truncation or zeroing described above the size of the
|
|
** journal file in bytes is larger than this value, then truncate the
|
|
** journal file to Pager.journalSizeLimit bytes. The journal file does
|
|
** not need to be synced following this operation.
|
|
@@ -52828,8 +56893,8 @@ static int zeroJournalHdr(Pager *pPager, int doTruncate){
|
|
rc = sqlite3OsSync(pPager->jfd, SQLITE_SYNC_DATAONLY|pPager->syncFlags);
|
|
}
|
|
|
|
- /* At this point the transaction is committed but the write lock
|
|
- ** is still held on the file. If there is a size limit configured for
|
|
+ /* At this point the transaction is committed but the write lock
|
|
+ ** is still held on the file. If there is a size limit configured for
|
|
** the persistent journal and the journal file currently consumes more
|
|
** space than that limit allows for, truncate it now. There is no need
|
|
** to sync the file following this operation.
|
|
@@ -52857,7 +56922,7 @@ static int zeroJournalHdr(Pager *pPager, int doTruncate){
|
|
** - 4 bytes: Initial database page count.
|
|
** - 4 bytes: Sector size used by the process that wrote this journal.
|
|
** - 4 bytes: Database page size.
|
|
-**
|
|
+**
|
|
** Followed by (JOURNAL_HDR_SZ - 28) bytes of unused space.
|
|
*/
|
|
static int writeJournalHdr(Pager *pPager){
|
|
@@ -52873,8 +56938,8 @@ static int writeJournalHdr(Pager *pPager){
|
|
nHeader = JOURNAL_HDR_SZ(pPager);
|
|
}
|
|
|
|
- /* If there are active savepoints and any of them were created
|
|
- ** since the most recent journal header was written, update the
|
|
+ /* If there are active savepoints and any of them were created
|
|
+ ** since the most recent journal header was written, update the
|
|
** PagerSavepoint.iHdrOffset fields now.
|
|
*/
|
|
for(ii=0; ii<pPager->nSavepoint; ii++){
|
|
@@ -52885,10 +56950,10 @@ static int writeJournalHdr(Pager *pPager){
|
|
|
|
pPager->journalHdr = pPager->journalOff = journalHdrOffset(pPager);
|
|
|
|
- /*
|
|
+ /*
|
|
** Write the nRec Field - the number of page records that follow this
|
|
** journal header. Normally, zero is written to this value at this time.
|
|
- ** After the records are added to the journal (and the journal synced,
|
|
+ ** After the records are added to the journal (and the journal synced,
|
|
** if in full-sync mode), the zero is overwritten with the true number
|
|
** of records (see syncJournal()).
|
|
**
|
|
@@ -52907,7 +56972,7 @@ static int writeJournalHdr(Pager *pPager){
|
|
*/
|
|
assert( isOpen(pPager->fd) || pPager->noSync );
|
|
if( pPager->noSync || (pPager->journalMode==PAGER_JOURNALMODE_MEMORY)
|
|
- || (sqlite3OsDeviceCharacteristics(pPager->fd)&SQLITE_IOCAP_SAFE_APPEND)
|
|
+ || (sqlite3OsDeviceCharacteristics(pPager->fd)&SQLITE_IOCAP_SAFE_APPEND)
|
|
){
|
|
memcpy(zHeader, aJournalMagic, sizeof(aJournalMagic));
|
|
put32bits(&zHeader[sizeof(aJournalMagic)], 0xffffffff);
|
|
@@ -52915,7 +56980,7 @@ static int writeJournalHdr(Pager *pPager){
|
|
memset(zHeader, 0, sizeof(aJournalMagic)+4);
|
|
}
|
|
|
|
- /* The random check-hash initializer */
|
|
+ /* The random check-hash initializer */
|
|
sqlite3_randomness(sizeof(pPager->cksumInit), &pPager->cksumInit);
|
|
put32bits(&zHeader[sizeof(aJournalMagic)+4], pPager->cksumInit);
|
|
/* The initial database size */
|
|
@@ -52934,23 +56999,23 @@ static int writeJournalHdr(Pager *pPager){
|
|
memset(&zHeader[sizeof(aJournalMagic)+20], 0,
|
|
nHeader-(sizeof(aJournalMagic)+20));
|
|
|
|
- /* In theory, it is only necessary to write the 28 bytes that the
|
|
- ** journal header consumes to the journal file here. Then increment the
|
|
- ** Pager.journalOff variable by JOURNAL_HDR_SZ so that the next
|
|
+ /* In theory, it is only necessary to write the 28 bytes that the
|
|
+ ** journal header consumes to the journal file here. Then increment the
|
|
+ ** Pager.journalOff variable by JOURNAL_HDR_SZ so that the next
|
|
** record is written to the following sector (leaving a gap in the file
|
|
** that will be implicitly filled in by the OS).
|
|
**
|
|
- ** However it has been discovered that on some systems this pattern can
|
|
+ ** However it has been discovered that on some systems this pattern can
|
|
** be significantly slower than contiguously writing data to the file,
|
|
- ** even if that means explicitly writing data to the block of
|
|
+ ** even if that means explicitly writing data to the block of
|
|
** (JOURNAL_HDR_SZ - 28) bytes that will not be used. So that is what
|
|
- ** is done.
|
|
+ ** is done.
|
|
**
|
|
- ** The loop is required here in case the sector-size is larger than the
|
|
+ ** The loop is required here in case the sector-size is larger than the
|
|
** database page size. Since the zHeader buffer is only Pager.pageSize
|
|
** bytes in size, more than one call to sqlite3OsWrite() may be required
|
|
** to populate the entire journal header sector.
|
|
- */
|
|
+ */
|
|
for(nWrite=0; rc==SQLITE_OK&&nWrite<JOURNAL_HDR_SZ(pPager); nWrite+=nHeader){
|
|
IOTRACE(("JHDR %p %lld %d\n", pPager, pPager->journalHdr, nHeader))
|
|
rc = sqlite3OsWrite(pPager->jfd, zHeader, nHeader, pPager->journalOff);
|
|
@@ -53048,29 +57113,29 @@ static int readJournalHdr(
|
|
|
|
/* Check that the values read from the page-size and sector-size fields
|
|
** are within range. To be 'in range', both values need to be a power
|
|
- ** of two greater than or equal to 512 or 32, and not greater than their
|
|
+ ** of two greater than or equal to 512 or 32, and not greater than their
|
|
** respective compile time maximum limits.
|
|
*/
|
|
if( iPageSize<512 || iSectorSize<32
|
|
|| iPageSize>SQLITE_MAX_PAGE_SIZE || iSectorSize>MAX_SECTOR_SIZE
|
|
- || ((iPageSize-1)&iPageSize)!=0 || ((iSectorSize-1)&iSectorSize)!=0
|
|
+ || ((iPageSize-1)&iPageSize)!=0 || ((iSectorSize-1)&iSectorSize)!=0
|
|
){
|
|
- /* If the either the page-size or sector-size in the journal-header is
|
|
- ** invalid, then the process that wrote the journal-header must have
|
|
- ** crashed before the header was synced. In this case stop reading
|
|
+ /* If the either the page-size or sector-size in the journal-header is
|
|
+ ** invalid, then the process that wrote the journal-header must have
|
|
+ ** crashed before the header was synced. In this case stop reading
|
|
** the journal file here.
|
|
*/
|
|
return SQLITE_DONE;
|
|
}
|
|
|
|
- /* Update the page-size to match the value read from the journal.
|
|
- ** Use a testcase() macro to make sure that malloc failure within
|
|
+ /* Update the page-size to match the value read from the journal.
|
|
+ ** Use a testcase() macro to make sure that malloc failure within
|
|
** PagerSetPagesize() is tested.
|
|
*/
|
|
rc = sqlite3PagerSetPagesize(pPager, &iPageSize, -1);
|
|
testcase( rc!=SQLITE_OK );
|
|
|
|
- /* Update the assumed sector-size to match the value used by
|
|
+ /* Update the assumed sector-size to match the value used by
|
|
** the process that created this journal. If this journal was
|
|
** created by a process other than this one, then this routine
|
|
** is being called from within pager_playback(). The local value
|
|
@@ -53085,50 +57150,50 @@ static int readJournalHdr(
|
|
|
|
|
|
/*
|
|
-** Write the supplied master journal name into the journal file for pager
|
|
-** pPager at the current location. The master journal name must be the last
|
|
+** Write the supplied super-journal name into the journal file for pager
|
|
+** pPager at the current location. The super-journal name must be the last
|
|
** thing written to a journal file. If the pager is in full-sync mode, the
|
|
** journal file descriptor is advanced to the next sector boundary before
|
|
** anything is written. The format is:
|
|
**
|
|
-** + 4 bytes: PAGER_MJ_PGNO.
|
|
-** + N bytes: Master journal filename in utf-8.
|
|
-** + 4 bytes: N (length of master journal name in bytes, no nul-terminator).
|
|
-** + 4 bytes: Master journal name checksum.
|
|
+** + 4 bytes: PAGER_SJ_PGNO.
|
|
+** + N bytes: super-journal filename in utf-8.
|
|
+** + 4 bytes: N (length of super-journal name in bytes, no nul-terminator).
|
|
+** + 4 bytes: super-journal name checksum.
|
|
** + 8 bytes: aJournalMagic[].
|
|
**
|
|
-** The master journal page checksum is the sum of the bytes in the master
|
|
-** journal name, where each byte is interpreted as a signed 8-bit integer.
|
|
+** The super-journal page checksum is the sum of the bytes in thesuper-journal
|
|
+** name, where each byte is interpreted as a signed 8-bit integer.
|
|
**
|
|
-** If zMaster is a NULL pointer (occurs for a single database transaction),
|
|
+** If zSuper is a NULL pointer (occurs for a single database transaction),
|
|
** this call is a no-op.
|
|
*/
|
|
-static int writeMasterJournal(Pager *pPager, const char *zMaster){
|
|
+static int writeSuperJournal(Pager *pPager, const char *zSuper){
|
|
int rc; /* Return code */
|
|
- int nMaster; /* Length of string zMaster */
|
|
+ int nSuper; /* Length of string zSuper */
|
|
i64 iHdrOff; /* Offset of header in journal file */
|
|
i64 jrnlSize; /* Size of journal file on disk */
|
|
- u32 cksum = 0; /* Checksum of string zMaster */
|
|
+ u32 cksum = 0; /* Checksum of string zSuper */
|
|
|
|
- assert( pPager->setMaster==0 );
|
|
+ assert( pPager->setSuper==0 );
|
|
assert( !pagerUseWal(pPager) );
|
|
|
|
- if( !zMaster
|
|
- || pPager->journalMode==PAGER_JOURNALMODE_MEMORY
|
|
+ if( !zSuper
|
|
+ || pPager->journalMode==PAGER_JOURNALMODE_MEMORY
|
|
|| !isOpen(pPager->jfd)
|
|
){
|
|
return SQLITE_OK;
|
|
}
|
|
- pPager->setMaster = 1;
|
|
+ pPager->setSuper = 1;
|
|
assert( pPager->journalHdr <= pPager->journalOff );
|
|
|
|
- /* Calculate the length in bytes and the checksum of zMaster */
|
|
- for(nMaster=0; zMaster[nMaster]; nMaster++){
|
|
- cksum += zMaster[nMaster];
|
|
+ /* Calculate the length in bytes and the checksum of zSuper */
|
|
+ for(nSuper=0; zSuper[nSuper]; nSuper++){
|
|
+ cksum += zSuper[nSuper];
|
|
}
|
|
|
|
/* If in full-sync mode, advance to the next disk sector before writing
|
|
- ** the master journal name. This is in case the previous page written to
|
|
+ ** the super-journal name. This is in case the previous page written to
|
|
** the journal has already been synced.
|
|
*/
|
|
if( pPager->fullSync ){
|
|
@@ -53136,30 +57201,30 @@ static int writeMasterJournal(Pager *pPager, const char *zMaster){
|
|
}
|
|
iHdrOff = pPager->journalOff;
|
|
|
|
- /* Write the master journal data to the end of the journal file. If
|
|
+ /* Write the super-journal data to the end of the journal file. If
|
|
** an error occurs, return the error code to the caller.
|
|
*/
|
|
- if( (0 != (rc = write32bits(pPager->jfd, iHdrOff, PAGER_MJ_PGNO(pPager))))
|
|
- || (0 != (rc = sqlite3OsWrite(pPager->jfd, zMaster, nMaster, iHdrOff+4)))
|
|
- || (0 != (rc = write32bits(pPager->jfd, iHdrOff+4+nMaster, nMaster)))
|
|
- || (0 != (rc = write32bits(pPager->jfd, iHdrOff+4+nMaster+4, cksum)))
|
|
+ if( (0 != (rc = write32bits(pPager->jfd, iHdrOff, PAGER_SJ_PGNO(pPager))))
|
|
+ || (0 != (rc = sqlite3OsWrite(pPager->jfd, zSuper, nSuper, iHdrOff+4)))
|
|
+ || (0 != (rc = write32bits(pPager->jfd, iHdrOff+4+nSuper, nSuper)))
|
|
+ || (0 != (rc = write32bits(pPager->jfd, iHdrOff+4+nSuper+4, cksum)))
|
|
|| (0 != (rc = sqlite3OsWrite(pPager->jfd, aJournalMagic, 8,
|
|
- iHdrOff+4+nMaster+8)))
|
|
+ iHdrOff+4+nSuper+8)))
|
|
){
|
|
return rc;
|
|
}
|
|
- pPager->journalOff += (nMaster+20);
|
|
+ pPager->journalOff += (nSuper+20);
|
|
|
|
- /* If the pager is in peristent-journal mode, then the physical
|
|
- ** journal-file may extend past the end of the master-journal name
|
|
- ** and 8 bytes of magic data just written to the file. This is
|
|
+ /* If the pager is in peristent-journal mode, then the physical
|
|
+ ** journal-file may extend past the end of the super-journal name
|
|
+ ** and 8 bytes of magic data just written to the file. This is
|
|
** dangerous because the code to rollback a hot-journal file
|
|
- ** will not be able to find the master-journal name to determine
|
|
- ** whether or not the journal is hot.
|
|
+ ** will not be able to find the super-journal name to determine
|
|
+ ** whether or not the journal is hot.
|
|
**
|
|
- ** Easiest thing to do in this scenario is to truncate the journal
|
|
+ ** Easiest thing to do in this scenario is to truncate the journal
|
|
** file to the required size.
|
|
- */
|
|
+ */
|
|
if( SQLITE_OK==(rc = sqlite3OsFileSize(pPager->jfd, &jrnlSize))
|
|
&& jrnlSize>pPager->journalOff
|
|
){
|
|
@@ -53204,7 +57269,7 @@ static void releaseAllSavepoints(Pager *pPager){
|
|
}
|
|
|
|
/*
|
|
-** Set the bit number pgno in the PagerSavepoint.pInSavepoint
|
|
+** Set the bit number pgno in the PagerSavepoint.pInSavepoint
|
|
** bitvecs of all open savepoints. Return SQLITE_OK if successful
|
|
** or SQLITE_NOMEM if a malloc failure occurs.
|
|
*/
|
|
@@ -53233,8 +57298,8 @@ static int addToSavepointBitvecs(Pager *pPager, Pgno pgno){
|
|
** not exhibit the UNDELETABLE_WHEN_OPEN property, the journal file is
|
|
** closed (if it is open).
|
|
**
|
|
-** If the pager is in ERROR state when this function is called, the
|
|
-** contents of the pager cache are discarded before switching back to
|
|
+** If the pager is in ERROR state when this function is called, the
|
|
+** contents of the pager cache are discarded before switching back to
|
|
** the OPEN state. Regardless of whether the pager is in exclusive-mode
|
|
** or not, any journal file left in the file-system will be treated
|
|
** as a hot-journal and rolled back the next time a read-transaction
|
|
@@ -53242,9 +57307,9 @@ static int addToSavepointBitvecs(Pager *pPager, Pgno pgno){
|
|
*/
|
|
static void pager_unlock(Pager *pPager){
|
|
|
|
- assert( pPager->eState==PAGER_READER
|
|
- || pPager->eState==PAGER_OPEN
|
|
- || pPager->eState==PAGER_ERROR
|
|
+ assert( pPager->eState==PAGER_READER
|
|
+ || pPager->eState==PAGER_OPEN
|
|
+ || pPager->eState==PAGER_ERROR
|
|
);
|
|
|
|
sqlite3BitvecDestroy(pPager->pInJournal);
|
|
@@ -53315,23 +57380,23 @@ static void pager_unlock(Pager *pPager){
|
|
|
|
pPager->journalOff = 0;
|
|
pPager->journalHdr = 0;
|
|
- pPager->setMaster = 0;
|
|
+ pPager->setSuper = 0;
|
|
}
|
|
|
|
/*
|
|
** This function is called whenever an IOERR or FULL error that requires
|
|
** the pager to transition into the ERROR state may ahve occurred.
|
|
-** The first argument is a pointer to the pager structure, the second
|
|
-** the error-code about to be returned by a pager API function. The
|
|
-** value returned is a copy of the second argument to this function.
|
|
+** 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.
|
|
**
|
|
** If the second argument is SQLITE_FULL, SQLITE_IOERR or one of the
|
|
** IOERR sub-codes, the pager enters the ERROR state and the error code
|
|
** is stored in Pager.errCode. While the pager remains in the ERROR state,
|
|
** all major API calls on the Pager will immediately return Pager.errCode.
|
|
**
|
|
-** The ERROR state indicates that the contents of the pager-cache
|
|
-** cannot be trusted. This state can be cleared by completely discarding
|
|
+** The ERROR state indicates that the contents of the pager-cache
|
|
+** cannot be trusted. This state can be cleared by completely discarding
|
|
** the contents of the pager-cache. If a transaction was active when
|
|
** the persistent error occurred, then the rollback journal may need
|
|
** to be replayed to restore the contents of the database file (as if
|
|
@@ -53379,27 +57444,27 @@ static int pagerFlushOnCommit(Pager *pPager, int bCommit){
|
|
}
|
|
|
|
/*
|
|
-** This routine ends a transaction. A transaction is usually ended by
|
|
-** either a COMMIT or a ROLLBACK operation. This routine may be called
|
|
+** This routine ends a transaction. A transaction is usually ended by
|
|
+** either a COMMIT or a ROLLBACK operation. This routine may be called
|
|
** after rollback of a hot-journal, or if an error occurs while opening
|
|
** the journal file or writing the very first journal-header of a
|
|
** database transaction.
|
|
-**
|
|
+**
|
|
** This routine is never called in PAGER_ERROR state. If it is called
|
|
** in PAGER_NONE or PAGER_SHARED state and the lock held is less
|
|
** exclusive than a RESERVED lock, it is a no-op.
|
|
**
|
|
** Otherwise, any active savepoints are released.
|
|
**
|
|
-** If the journal file is open, then it is "finalized". Once a journal
|
|
-** file has been finalized it is not possible to use it to roll back a
|
|
+** If the journal file is open, then it is "finalized". Once a journal
|
|
+** file has been finalized it is not possible to use it to roll back a
|
|
** transaction. Nor will it be considered to be a hot-journal by this
|
|
** or any other database connection. Exactly how a journal is finalized
|
|
** depends on whether or not the pager is running in exclusive mode and
|
|
** the current journal-mode (Pager.journalMode value), as follows:
|
|
**
|
|
** journalMode==MEMORY
|
|
-** Journal file descriptor is simply closed. This destroys an
|
|
+** Journal file descriptor is simply closed. This destroys an
|
|
** in-memory journal.
|
|
**
|
|
** journalMode==TRUNCATE
|
|
@@ -53419,19 +57484,19 @@ static int pagerFlushOnCommit(Pager *pPager, int bCommit){
|
|
** journalMode==PERSIST is used instead.
|
|
**
|
|
** After the journal is finalized, the pager moves to PAGER_READER state.
|
|
-** If running in non-exclusive rollback mode, the lock on the file is
|
|
+** If running in non-exclusive rollback mode, the lock on the file is
|
|
** downgraded to a SHARED_LOCK.
|
|
**
|
|
** SQLITE_OK is returned if no error occurs. If an error occurs during
|
|
** any of the IO operations to finalize the journal file or unlock the
|
|
-** database then the IO error code is returned to the user. If the
|
|
+** database then the IO error code is returned to the user. If the
|
|
** operation to finalize the journal file fails, then the code still
|
|
** tries to unlock the database file if not in exclusive mode. If the
|
|
** unlock operation fails as well, then the first error code related
|
|
** to the first error encountered (the journal finalization one) is
|
|
** returned.
|
|
*/
|
|
-static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
|
|
+static int pager_end_transaction(Pager *pPager, int hasSuper, int bCommit){
|
|
int rc = SQLITE_OK; /* Error code from journal finalization operation */
|
|
int rc2 = SQLITE_OK; /* Error code from db file unlock operation */
|
|
|
|
@@ -53443,9 +57508,9 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
|
|
** 1. After a successful hot-journal rollback, it is called with
|
|
** eState==PAGER_NONE and eLock==EXCLUSIVE_LOCK.
|
|
**
|
|
- ** 2. If a connection with locking_mode=exclusive holding an EXCLUSIVE
|
|
+ ** 2. If a connection with locking_mode=exclusive holding an EXCLUSIVE
|
|
** lock switches back to locking_mode=normal and then executes a
|
|
- ** read-transaction, this function is called with eState==PAGER_READER
|
|
+ ** read-transaction, this function is called with eState==PAGER_READER
|
|
** and eLock==EXCLUSIVE_LOCK when the read-transaction is closed.
|
|
*/
|
|
assert( assert_pager_state(pPager) );
|
|
@@ -53455,7 +57520,7 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
|
|
}
|
|
|
|
releaseAllSavepoints(pPager);
|
|
- assert( isOpen(pPager->jfd) || pPager->pInJournal==0
|
|
+ assert( isOpen(pPager->jfd) || pPager->pInJournal==0
|
|
|| (sqlite3OsDeviceCharacteristics(pPager->fd)&SQLITE_IOCAP_BATCH_ATOMIC)
|
|
);
|
|
if( isOpen(pPager->jfd) ){
|
|
@@ -53483,7 +57548,7 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
|
|
}else if( pPager->journalMode==PAGER_JOURNALMODE_PERSIST
|
|
|| (pPager->exclusiveMode && pPager->journalMode!=PAGER_JOURNALMODE_WAL)
|
|
){
|
|
- rc = zeroJournalHdr(pPager, hasMaster||pPager->tempFile);
|
|
+ rc = zeroJournalHdr(pPager, hasSuper||pPager->tempFile);
|
|
pPager->journalOff = 0;
|
|
}else{
|
|
/* This branch may be executed with Pager.journalMode==MEMORY if
|
|
@@ -53493,9 +57558,9 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
|
|
*/
|
|
int bDelete = !pPager->tempFile;
|
|
assert( sqlite3JournalIsInMemory(pPager->jfd)==0 );
|
|
- assert( pPager->journalMode==PAGER_JOURNALMODE_DELETE
|
|
- || pPager->journalMode==PAGER_JOURNALMODE_MEMORY
|
|
- || pPager->journalMode==PAGER_JOURNALMODE_WAL
|
|
+ assert( pPager->journalMode==PAGER_JOURNALMODE_DELETE
|
|
+ || pPager->journalMode==PAGER_JOURNALMODE_MEMORY
|
|
+ || pPager->journalMode==PAGER_JOURNALMODE_WAL
|
|
);
|
|
sqlite3OsClose(pPager->jfd);
|
|
if( bDelete ){
|
|
@@ -53528,8 +57593,8 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
|
|
}
|
|
|
|
if( pagerUseWal(pPager) ){
|
|
- /* Drop the WAL write-lock, if any. Also, if the connection was in
|
|
- ** locking_mode=exclusive mode but is no longer, drop the EXCLUSIVE
|
|
+ /* Drop the WAL write-lock, if any. Also, if the connection was in
|
|
+ ** locking_mode=exclusive mode but is no longer, drop the EXCLUSIVE
|
|
** lock held on the database file.
|
|
*/
|
|
rc2 = sqlite3WalEndWriteTransaction(pPager->pWal);
|
|
@@ -53537,7 +57602,7 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
|
|
}else if( rc==SQLITE_OK && bCommit && pPager->dbFileSize>pPager->dbSize ){
|
|
/* This branch is taken when committing a transaction in rollback-journal
|
|
** mode if the database file on disk is larger than the database image.
|
|
- ** At this point the journal has been finalized and the transaction
|
|
+ ** At this point the journal has been finalized and the transaction
|
|
** successfully committed, but the EXCLUSIVE lock is still held on the
|
|
** file. So it is safe to truncate the database file to its minimum
|
|
** required size. */
|
|
@@ -53550,31 +57615,31 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
|
|
if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK;
|
|
}
|
|
|
|
- if( !pPager->exclusiveMode
|
|
+ if( !pPager->exclusiveMode
|
|
&& (!pagerUseWal(pPager) || sqlite3WalExclusiveMode(pPager->pWal, 0))
|
|
){
|
|
rc2 = pagerUnlockDb(pPager, SHARED_LOCK);
|
|
}
|
|
pPager->eState = PAGER_READER;
|
|
- pPager->setMaster = 0;
|
|
+ pPager->setSuper = 0;
|
|
|
|
return (rc==SQLITE_OK?rc2:rc);
|
|
}
|
|
|
|
/*
|
|
-** Execute a rollback if a transaction is active and unlock the
|
|
-** database file.
|
|
+** Execute a rollback if a transaction is active and unlock the
|
|
+** database file.
|
|
**
|
|
-** If the pager has already entered the ERROR state, do not attempt
|
|
+** If the pager has already entered the ERROR state, do not attempt
|
|
** the rollback at this time. Instead, pager_unlock() is called. The
|
|
** call to pager_unlock() will discard all in-memory pages, unlock
|
|
-** the database file and move the pager back to OPEN state. If this
|
|
-** means that there is a hot-journal left in the file-system, the next
|
|
-** connection to obtain a shared lock on the pager (which may be this one)
|
|
+** the database file and move the pager back to OPEN state. If this
|
|
+** means that there is a hot-journal left in the file-system, the next
|
|
+** connection to obtain a shared lock on the pager (which may be this one)
|
|
** will roll it back.
|
|
**
|
|
** If the pager has not already entered the ERROR state, but an IO or
|
|
-** malloc error occurs during a rollback, then this will itself cause
|
|
+** malloc error occurs during a rollback, then this will itself cause
|
|
** the pager to enter the ERROR state. Which will be cleared by the
|
|
** call to pager_unlock(), as described above.
|
|
*/
|
|
@@ -53595,10 +57660,10 @@ static void pagerUnlockAndRollback(Pager *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 ont the contents of the
|
|
** page of data and the current value of pPager->cksumInit.
|
|
**
|
|
-** This is not a real checksum. It is really just the sum of the
|
|
+** This is not a real checksum. It is really just the sum of the
|
|
** random initial value (pPager->cksumInit) and every 200th byte
|
|
** of the page data, starting with byte offset (pPager->pageSize%200).
|
|
** Each byte is interpreted as an 8-bit unsigned integer.
|
|
@@ -53606,8 +57671,8 @@ static void pagerUnlockAndRollback(Pager *pPager){
|
|
** Changing the formula used to compute this checksum results in an
|
|
** incompatible journal file format.
|
|
**
|
|
-** If journal corruption occurs due to a power failure, the most likely
|
|
-** scenario is that one end or the other of the record will be changed.
|
|
+** If journal corruption occurs due to a power failure, the most likely
|
|
+** scenario is that one end or the other of the record will be changed.
|
|
** It is much less likely that the two ends of the journal record will be
|
|
** correct and the middle be corrupt. Thus, this "checksum" scheme,
|
|
** though fast and simple, catches the mostly likely kind of corruption.
|
|
@@ -53622,42 +57687,13 @@ static u32 pager_cksum(Pager *pPager, const u8 *aData){
|
|
return cksum;
|
|
}
|
|
|
|
-/*
|
|
-** Report the current page size and number of reserved bytes back
|
|
-** to the codec.
|
|
-*/
|
|
-#ifdef SQLITE_HAS_CODEC
|
|
-static void pagerReportSize(Pager *pPager){
|
|
- if( pPager->xCodecSizeChng ){
|
|
- pPager->xCodecSizeChng(pPager->pCodec, pPager->pageSize,
|
|
- (int)pPager->nReserve);
|
|
- }
|
|
-}
|
|
-#else
|
|
-# define pagerReportSize(X) /* No-op if we do not support a codec */
|
|
-#endif
|
|
-
|
|
-#ifdef SQLITE_HAS_CODEC
|
|
-/*
|
|
-** Make sure the number of reserved bits is the same in the destination
|
|
-** pager as it is in the source. This comes up when a VACUUM changes the
|
|
-** number of reserved bits to the "optimal" amount.
|
|
-*/
|
|
-SQLITE_PRIVATE void sqlite3PagerAlignReserve(Pager *pDest, Pager *pSrc){
|
|
- if( pDest->nReserve!=pSrc->nReserve ){
|
|
- pDest->nReserve = pSrc->nReserve;
|
|
- pagerReportSize(pDest);
|
|
- }
|
|
-}
|
|
-#endif
|
|
-
|
|
/*
|
|
** Read a single page from either the journal file (if isMainJrnl==1) or
|
|
** from the sub-journal (if isMainJrnl==0) and playback that page.
|
|
** The page begins at offset *pOffset into the file. The *pOffset
|
|
** value is increased to the start of the next page in the journal.
|
|
**
|
|
-** The main rollback journal uses checksums - the statement journal does
|
|
+** The main rollback journal uses checksums - the statement journal does
|
|
** not.
|
|
**
|
|
** If the page number of the page record read from the (sub-)journal file
|
|
@@ -53677,8 +57713,8 @@ SQLITE_PRIVATE void sqlite3PagerAlignReserve(Pager *pDest, Pager *pSrc){
|
|
** is successfully read from the (sub-)journal file but appears to be
|
|
** corrupted, SQLITE_DONE is returned. Data is considered corrupted in
|
|
** two circumstances:
|
|
-**
|
|
-** * If the record page-number is illegal (0 or PAGER_MJ_PGNO), or
|
|
+**
|
|
+** * If the record page-number is illegal (0 or PAGER_SJ_PGNO), or
|
|
** * If the record is being rolled back from the main journal file
|
|
** and the checksum field does not match the record content.
|
|
**
|
|
@@ -53702,11 +57738,6 @@ static int pager_playback_one_page(
|
|
char *aData; /* Temporary storage for the page */
|
|
sqlite3_file *jfd; /* The file descriptor for the journal file */
|
|
int isSynced; /* True if journal page is synced */
|
|
-#ifdef SQLITE_HAS_CODEC
|
|
- /* The jrnlEnc flag is true if Journal pages should be passed through
|
|
- ** the codec. It is false for pure in-memory journals. */
|
|
- const int jrnlEnc = (isMainJrnl || pPager->subjInMemory==0);
|
|
-#endif
|
|
|
|
assert( (isMainJrnl&~1)==0 ); /* isMainJrnl is 0 or 1 */
|
|
assert( (isSavepnt&~1)==0 ); /* isSavepnt is 0 or 1 */
|
|
@@ -53717,7 +57748,7 @@ static int pager_playback_one_page(
|
|
assert( aData ); /* Temp storage must have already been allocated */
|
|
assert( pagerUseWal(pPager)==0 || (!isMainJrnl && isSavepnt) );
|
|
|
|
- /* Either the state is greater than PAGER_WRITER_CACHEMOD (a transaction
|
|
+ /* Either the state is greater than PAGER_WRITER_CACHEMOD (a transaction
|
|
** or savepoint rollback done at the request of the caller) or this is
|
|
** a hot-journal rollback. If it is a hot-journal rollback, the pager
|
|
** is in state OPEN and holds an EXCLUSIVE lock. Hot-journal rollback
|
|
@@ -53743,7 +57774,7 @@ static int pager_playback_one_page(
|
|
** it could cause invalid data to be written into the journal. We need to
|
|
** detect this invalid data (with high probability) and ignore it.
|
|
*/
|
|
- if( pgno==0 || pgno==PAGER_MJ_PGNO(pPager) ){
|
|
+ if( pgno==0 || pgno==PAGER_SJ_PGNO(pPager) ){
|
|
assert( !isSavepnt );
|
|
return SQLITE_DONE;
|
|
}
|
|
@@ -53769,7 +57800,6 @@ static int pager_playback_one_page(
|
|
*/
|
|
if( pgno==1 && pPager->nReserve!=((u8*)aData)[20] ){
|
|
pPager->nReserve = ((u8*)aData)[20];
|
|
- pagerReportSize(pPager);
|
|
}
|
|
|
|
/* If the pager is in CACHEMOD state, then there must be a copy of this
|
|
@@ -53784,7 +57814,7 @@ static int pager_playback_one_page(
|
|
** assert()able.
|
|
**
|
|
** If in WRITER_DBMOD, WRITER_FINISHED or OPEN state, then we update the
|
|
- ** pager cache if it exists and the main file. The page is then marked
|
|
+ ** pager cache if it exists and the main file. The page is then marked
|
|
** not dirty. Since this code is only executed in PAGER_OPEN state for
|
|
** a hot-journal rollback, it is guaranteed that the page-cache is empty
|
|
** if the pager is in OPEN state.
|
|
@@ -53837,43 +57867,29 @@ static int pager_playback_one_page(
|
|
** is if the data was just read from an in-memory sub-journal. In that
|
|
** case it must be encrypted here before it is copied into the database
|
|
** file. */
|
|
-#ifdef SQLITE_HAS_CODEC
|
|
- if( !jrnlEnc ){
|
|
- CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM_BKPT, aData);
|
|
- rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst);
|
|
- CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM_BKPT);
|
|
- }else
|
|
-#endif
|
|
rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst);
|
|
|
|
if( pgno>pPager->dbFileSize ){
|
|
pPager->dbFileSize = pgno;
|
|
}
|
|
if( pPager->pBackup ){
|
|
-#ifdef SQLITE_HAS_CODEC
|
|
- if( jrnlEnc ){
|
|
- CODEC1(pPager, aData, pgno, 3, rc=SQLITE_NOMEM_BKPT);
|
|
- sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData);
|
|
- CODEC2(pPager, aData, pgno, 7, rc=SQLITE_NOMEM_BKPT,aData);
|
|
- }else
|
|
-#endif
|
|
sqlite3BackupUpdate(pPager->pBackup, pgno, (u8*)aData);
|
|
}
|
|
}else if( !isMainJrnl && pPg==0 ){
|
|
/* If this is a rollback of a savepoint and data was not written to
|
|
** the database and the page is not in-memory, there is a potential
|
|
- ** problem. When the page is next fetched by the b-tree layer, it
|
|
- ** will be read from the database file, which may or may not be
|
|
- ** current.
|
|
+ ** problem. When the page is next fetched by the b-tree layer, it
|
|
+ ** will be read from the database file, which may or may not be
|
|
+ ** current.
|
|
**
|
|
** There are a couple of different ways this can happen. All are quite
|
|
- ** obscure. When running in synchronous mode, this can only happen
|
|
+ ** obscure. When running in synchronous mode, this can only happen
|
|
** if the page is on the free-list at the start of the transaction, then
|
|
** populated, then moved using sqlite3PagerMovepage().
|
|
**
|
|
** The solution is to add an in-memory page to the cache containing
|
|
- ** the data just read from the sub-journal. Mark the page as dirty
|
|
- ** and if the pager requires a journal-sync, then mark the page as
|
|
+ ** the data just read from the sub-journal. Mark the page as dirty
|
|
+ ** and if the pager requires a journal-sync, then mark the page as
|
|
** requiring a journal-sync before it is written.
|
|
*/
|
|
assert( isSavepnt );
|
|
@@ -53907,165 +57923,167 @@ static int pager_playback_one_page(
|
|
if( pgno==1 ){
|
|
memcpy(&pPager->dbFileVers, &((u8*)pData)[24],sizeof(pPager->dbFileVers));
|
|
}
|
|
-
|
|
- /* Decode the page just read from disk */
|
|
-#if SQLITE_HAS_CODEC
|
|
- if( jrnlEnc ){ CODEC1(pPager, pData, pPg->pgno, 3, rc=SQLITE_NOMEM_BKPT); }
|
|
-#endif
|
|
sqlite3PcacheRelease(pPg);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
-** Parameter zMaster is the name of a master journal file. A single journal
|
|
-** file that referred to the master journal file has just been rolled back.
|
|
-** This routine checks if it is possible to delete the master journal file,
|
|
+** Parameter zSuper is the name of a super-journal file. A single journal
|
|
+** file that referred to the super-journal file has just been rolled back.
|
|
+** This routine checks if it is possible to delete the super-journal file,
|
|
** and does so if it is.
|
|
**
|
|
-** Argument zMaster may point to Pager.pTmpSpace. So that buffer is not
|
|
+** Argument zSuper may point to Pager.pTmpSpace. So that buffer is not
|
|
** available for use within this function.
|
|
**
|
|
-** When a master journal file is created, it is populated with the names
|
|
-** of all of its child journals, one after another, formatted as utf-8
|
|
-** encoded text. The end of each child journal file is marked with a
|
|
-** nul-terminator byte (0x00). i.e. the entire contents of a master journal
|
|
+** When a super-journal file is created, it is populated with the names
|
|
+** of all of its child journals, one after another, formatted as utf-8
|
|
+** encoded text. The end of each child journal file is marked with a
|
|
+** nul-terminator byte (0x00). i.e. the entire contents of a super-journal
|
|
** file for a transaction involving two databases might be:
|
|
**
|
|
** "/home/bill/a.db-journal\x00/home/bill/b.db-journal\x00"
|
|
**
|
|
-** A master journal file may only be deleted once all of its child
|
|
+** A super-journal file may only be deleted once all of its child
|
|
** journals have been rolled back.
|
|
**
|
|
-** This function reads the contents of the master-journal file into
|
|
+** This function reads the contents of the super-journal file into
|
|
** memory and loops through each of the child journal names. For
|
|
** each child journal, it checks if:
|
|
**
|
|
** * if the child journal exists, and if so
|
|
-** * if the child journal contains a reference to master journal
|
|
-** file zMaster
|
|
+** * if the child journal contains a reference to super-journal
|
|
+** file zSuper
|
|
**
|
|
** If a child journal can be found that matches both of the criteria
|
|
** above, this function returns without doing anything. Otherwise, if
|
|
-** no such child journal can be found, file zMaster is deleted from
|
|
+** no such child journal can be found, file zSuper is deleted from
|
|
** the file-system using sqlite3OsDelete().
|
|
**
|
|
** If an IO error within this function, an error code is returned. This
|
|
** function allocates memory by calling sqlite3Malloc(). If an allocation
|
|
-** fails, SQLITE_NOMEM is returned. Otherwise, if no IO or malloc errors
|
|
+** fails, SQLITE_NOMEM is returned. Otherwise, if no IO or malloc errors
|
|
** occur, SQLITE_OK is returned.
|
|
**
|
|
** TODO: This function allocates a single block of memory to load
|
|
-** the entire contents of the master journal file. This could be
|
|
-** a couple of kilobytes or so - potentially larger than the page
|
|
+** the entire contents of the super-journal file. This could be
|
|
+** a couple of kilobytes or so - potentially larger than the page
|
|
** size.
|
|
*/
|
|
-static int pager_delmaster(Pager *pPager, const char *zMaster){
|
|
+static int pager_delsuper(Pager *pPager, const char *zSuper){
|
|
sqlite3_vfs *pVfs = pPager->pVfs;
|
|
int rc; /* Return code */
|
|
- sqlite3_file *pMaster; /* Malloc'd master-journal file descriptor */
|
|
+ sqlite3_file *pSuper; /* Malloc'd super-journal file descriptor */
|
|
sqlite3_file *pJournal; /* Malloc'd child-journal file descriptor */
|
|
- char *zMasterJournal = 0; /* Contents of master journal file */
|
|
- i64 nMasterJournal; /* Size of master journal file */
|
|
+ char *zSuperJournal = 0; /* Contents of super-journal file */
|
|
+ i64 nSuperJournal; /* Size of super-journal file */
|
|
char *zJournal; /* Pointer to one journal within MJ file */
|
|
- char *zMasterPtr; /* Space to hold MJ filename from a journal file */
|
|
- int nMasterPtr; /* Amount of space allocated to zMasterPtr[] */
|
|
+ char *zSuperPtr; /* Space to hold super-journal filename */
|
|
+ char *zFree = 0; /* Free this buffer */
|
|
+ int nSuperPtr; /* Amount of space allocated to zSuperPtr[] */
|
|
|
|
- /* Allocate space for both the pJournal and pMaster file descriptors.
|
|
- ** If successful, open the master journal file for reading.
|
|
+ /* Allocate space for both the pJournal and pSuper file descriptors.
|
|
+ ** If successful, open the super-journal file for reading.
|
|
*/
|
|
- pMaster = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile * 2);
|
|
- pJournal = (sqlite3_file *)(((u8 *)pMaster) + pVfs->szOsFile);
|
|
- if( !pMaster ){
|
|
+ pSuper = (sqlite3_file *)sqlite3MallocZero(pVfs->szOsFile * 2);
|
|
+ if( !pSuper ){
|
|
rc = SQLITE_NOMEM_BKPT;
|
|
+ pJournal = 0;
|
|
}else{
|
|
- const int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_MASTER_JOURNAL);
|
|
- rc = sqlite3OsOpen(pVfs, zMaster, pMaster, flags, 0);
|
|
+ const int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_SUPER_JOURNAL);
|
|
+ rc = sqlite3OsOpen(pVfs, zSuper, pSuper, flags, 0);
|
|
+ pJournal = (sqlite3_file *)(((u8 *)pSuper) + pVfs->szOsFile);
|
|
}
|
|
- if( rc!=SQLITE_OK ) goto delmaster_out;
|
|
+ if( rc!=SQLITE_OK ) goto delsuper_out;
|
|
|
|
- /* Load the entire master journal file into space obtained from
|
|
- ** sqlite3_malloc() and pointed to by zMasterJournal. Also obtain
|
|
- ** sufficient space (in zMasterPtr) to hold the names of master
|
|
- ** journal files extracted from regular rollback-journals.
|
|
+ /* Load the entire super-journal file into space obtained from
|
|
+ ** sqlite3_malloc() and pointed to by zSuperJournal. Also obtain
|
|
+ ** sufficient space (in zSuperPtr) to hold the names of super-journal
|
|
+ ** files extracted from regular rollback-journals.
|
|
*/
|
|
- rc = sqlite3OsFileSize(pMaster, &nMasterJournal);
|
|
- if( rc!=SQLITE_OK ) goto delmaster_out;
|
|
- nMasterPtr = pVfs->mxPathname+1;
|
|
- zMasterJournal = sqlite3Malloc(nMasterJournal + nMasterPtr + 2);
|
|
- if( !zMasterJournal ){
|
|
+ rc = sqlite3OsFileSize(pSuper, &nSuperJournal);
|
|
+ if( rc!=SQLITE_OK ) goto delsuper_out;
|
|
+ nSuperPtr = pVfs->mxPathname+1;
|
|
+ zFree = sqlite3Malloc(4 + nSuperJournal + nSuperPtr + 2);
|
|
+ if( !zFree ){
|
|
rc = SQLITE_NOMEM_BKPT;
|
|
- goto delmaster_out;
|
|
- }
|
|
- zMasterPtr = &zMasterJournal[nMasterJournal+2];
|
|
- rc = sqlite3OsRead(pMaster, zMasterJournal, (int)nMasterJournal, 0);
|
|
- if( rc!=SQLITE_OK ) goto delmaster_out;
|
|
- zMasterJournal[nMasterJournal] = 0;
|
|
- zMasterJournal[nMasterJournal+1] = 0;
|
|
-
|
|
- zJournal = zMasterJournal;
|
|
- while( (zJournal-zMasterJournal)<nMasterJournal ){
|
|
+ goto delsuper_out;
|
|
+ }
|
|
+ zFree[0] = zFree[1] = zFree[2] = zFree[3] = 0;
|
|
+ zSuperJournal = &zFree[4];
|
|
+ zSuperPtr = &zSuperJournal[nSuperJournal+2];
|
|
+ rc = sqlite3OsRead(pSuper, zSuperJournal, (int)nSuperJournal, 0);
|
|
+ if( rc!=SQLITE_OK ) goto delsuper_out;
|
|
+ zSuperJournal[nSuperJournal] = 0;
|
|
+ zSuperJournal[nSuperJournal+1] = 0;
|
|
+
|
|
+ zJournal = zSuperJournal;
|
|
+ while( (zJournal-zSuperJournal)<nSuperJournal ){
|
|
int exists;
|
|
rc = sqlite3OsAccess(pVfs, zJournal, SQLITE_ACCESS_EXISTS, &exists);
|
|
if( rc!=SQLITE_OK ){
|
|
- goto delmaster_out;
|
|
+ goto delsuper_out;
|
|
}
|
|
if( exists ){
|
|
- /* One of the journals pointed to by the master journal exists.
|
|
- ** Open it and check if it points at the master journal. If
|
|
- ** so, return without deleting the master journal file.
|
|
+ /* One of the journals pointed to by the super-journal exists.
|
|
+ ** Open it and check if it points at the super-journal. If
|
|
+ ** so, return without deleting the super-journal file.
|
|
+ ** NB: zJournal is really a MAIN_JOURNAL. But call it a
|
|
+ ** SUPER_JOURNAL here so that the VFS will not send the zJournal
|
|
+ ** name into sqlite3_database_file_object().
|
|
*/
|
|
int c;
|
|
- int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL);
|
|
+ int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_SUPER_JOURNAL);
|
|
rc = sqlite3OsOpen(pVfs, zJournal, pJournal, flags, 0);
|
|
if( rc!=SQLITE_OK ){
|
|
- goto delmaster_out;
|
|
+ goto delsuper_out;
|
|
}
|
|
|
|
- rc = readMasterJournal(pJournal, zMasterPtr, nMasterPtr);
|
|
+ rc = readSuperJournal(pJournal, zSuperPtr, nSuperPtr);
|
|
sqlite3OsClose(pJournal);
|
|
if( rc!=SQLITE_OK ){
|
|
- goto delmaster_out;
|
|
+ goto delsuper_out;
|
|
}
|
|
|
|
- c = zMasterPtr[0]!=0 && strcmp(zMasterPtr, zMaster)==0;
|
|
+ c = zSuperPtr[0]!=0 && strcmp(zSuperPtr, zSuper)==0;
|
|
if( c ){
|
|
- /* We have a match. Do not delete the master journal file. */
|
|
- goto delmaster_out;
|
|
+ /* We have a match. Do not delete the super-journal file. */
|
|
+ goto delsuper_out;
|
|
}
|
|
}
|
|
zJournal += (sqlite3Strlen30(zJournal)+1);
|
|
}
|
|
-
|
|
- sqlite3OsClose(pMaster);
|
|
- rc = sqlite3OsDelete(pVfs, zMaster, 0);
|
|
|
|
-delmaster_out:
|
|
- sqlite3_free(zMasterJournal);
|
|
- if( pMaster ){
|
|
- sqlite3OsClose(pMaster);
|
|
+ sqlite3OsClose(pSuper);
|
|
+ rc = sqlite3OsDelete(pVfs, zSuper, 0);
|
|
+
|
|
+delsuper_out:
|
|
+ sqlite3_free(zFree);
|
|
+ if( pSuper ){
|
|
+ sqlite3OsClose(pSuper);
|
|
assert( !isOpen(pJournal) );
|
|
- sqlite3_free(pMaster);
|
|
+ sqlite3_free(pSuper);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*
|
|
-** This function is used to change the actual size of the database
|
|
+** This function is used to change the actual size of the database
|
|
** file in the file-system. This only happens when committing a transaction,
|
|
** or rolling back a transaction (including rolling back a hot-journal).
|
|
**
|
|
** If the main database file is not open, or the pager is not in either
|
|
-** DBMOD or OPEN state, this function is a no-op. Otherwise, the size
|
|
-** of the file is changed to nPage pages (nPage*pPager->pageSize bytes).
|
|
+** DBMOD or OPEN state, this function is a no-op. Otherwise, the size
|
|
+** of the file is changed to nPage pages (nPage*pPager->pageSize bytes).
|
|
** If the file on disk is currently larger than nPage pages, then use the VFS
|
|
** xTruncate() method to truncate it.
|
|
**
|
|
-** Or, it might be the case that the file on disk is smaller than
|
|
-** nPage pages. Some operating system implementations can get confused if
|
|
-** you try to truncate a file to some size that is larger than it
|
|
-** currently is, so detect this case and write a single zero byte to
|
|
+** Or, it might be the case that the file on disk is smaller than
|
|
+** nPage pages. Some operating system implementations can get confused if
|
|
+** you try to truncate a file to some size that is larger than it
|
|
+** currently is, so detect this case and write a single zero byte to
|
|
** the end of the new file instead.
|
|
**
|
|
** If successful, return SQLITE_OK. If an IO error occurs while modifying
|
|
@@ -54075,9 +58093,9 @@ static int pager_truncate(Pager *pPager, Pgno nPage){
|
|
int rc = SQLITE_OK;
|
|
assert( pPager->eState!=PAGER_ERROR );
|
|
assert( pPager->eState!=PAGER_READER );
|
|
-
|
|
- if( isOpen(pPager->fd)
|
|
- && (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN)
|
|
+
|
|
+ if( isOpen(pPager->fd)
|
|
+ && (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN)
|
|
){
|
|
i64 currentSize, newSize;
|
|
int szPage = pPager->pageSize;
|
|
@@ -54093,6 +58111,7 @@ static int pager_truncate(Pager *pPager, Pgno nPage){
|
|
memset(pTmp, 0, szPage);
|
|
testcase( (newSize-szPage) == currentSize );
|
|
testcase( (newSize-szPage) > currentSize );
|
|
+ sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_SIZE_HINT, &newSize);
|
|
rc = sqlite3OsWrite(pPager->fd, pTmp, szPage, newSize-szPage);
|
|
}
|
|
if( rc==SQLITE_OK ){
|
|
@@ -54121,9 +58140,9 @@ SQLITE_PRIVATE int sqlite3SectorSize(sqlite3_file *pFile){
|
|
/*
|
|
** Set the value of the Pager.sectorSize variable for the given
|
|
** pager based on the value returned by the xSectorSize method
|
|
-** of the open database file. The sector size will be used
|
|
-** to determine the size and alignment of journal header and
|
|
-** master journal pointers within created journal files.
|
|
+** of the open database file. The sector size will be used
|
|
+** to determine the size and alignment of journal header and
|
|
+** super-journal pointers within created journal files.
|
|
**
|
|
** For temporary files the effective sector size is always 512 bytes.
|
|
**
|
|
@@ -54145,7 +58164,7 @@ static void setSectorSize(Pager *pPager){
|
|
assert( isOpen(pPager->fd) || pPager->tempFile );
|
|
|
|
if( pPager->tempFile
|
|
- || (sqlite3OsDeviceCharacteristics(pPager->fd) &
|
|
+ || (sqlite3OsDeviceCharacteristics(pPager->fd) &
|
|
SQLITE_IOCAP_POWERSAFE_OVERWRITE)!=0
|
|
){
|
|
/* Sector size doesn't matter for temporary files. Also, the file
|
|
@@ -54159,15 +58178,15 @@ static void setSectorSize(Pager *pPager){
|
|
|
|
/*
|
|
** Playback the journal and thus restore the database file to
|
|
-** the state it was in before we started making changes.
|
|
+** the state it was in before we started making changes.
|
|
**
|
|
-** The journal file format is as follows:
|
|
+** The journal file format is as follows:
|
|
**
|
|
** (1) 8 byte prefix. A copy of aJournalMagic[].
|
|
** (2) 4 byte big-endian integer which is the number of valid page records
|
|
** in the journal. If this value is 0xffffffff, then compute the
|
|
** number of page records from the journal size.
|
|
-** (3) 4 byte big-endian integer which is the initial value for the
|
|
+** (3) 4 byte big-endian integer which is the initial value for the
|
|
** sanity checksum.
|
|
** (4) 4 byte integer which is the number of pages to truncate the
|
|
** database to during a rollback.
|
|
@@ -54196,7 +58215,7 @@ static void setSectorSize(Pager *pPager){
|
|
** from the file size. This value is used when the user selects the
|
|
** no-sync option for the journal. A power failure could lead to corruption
|
|
** in this case. But for things like temporary table (which will be
|
|
-** deleted when the power is restored) we don't care.
|
|
+** deleted when the power is restored) we don't care.
|
|
**
|
|
** If the file opened as the journal file is not a well-formed
|
|
** journal file then all pages up to the first corrupted page are rolled
|
|
@@ -54208,7 +58227,7 @@ static void setSectorSize(Pager *pPager){
|
|
** and an error code is returned.
|
|
**
|
|
** The isHot parameter indicates that we are trying to rollback a journal
|
|
-** that might be a hot journal. Or, it could be that the journal is
|
|
+** that might be a hot journal. Or, it could be that the journal is
|
|
** preserved because of JOURNALMODE_PERSIST or JOURNALMODE_TRUNCATE.
|
|
** If the journal really is hot, reset the pager cache prior rolling
|
|
** back any content. If the journal is merely persistent, no reset is
|
|
@@ -54222,7 +58241,7 @@ static int pager_playback(Pager *pPager, int isHot){
|
|
Pgno mxPg = 0; /* Size of the original file in pages */
|
|
int rc; /* Result code of a subroutine */
|
|
int res = 1; /* Value returned by sqlite3OsAccess() */
|
|
- char *zMaster = 0; /* Name of master journal file if any */
|
|
+ char *zSuper = 0; /* Name of super-journal file if any */
|
|
int needPagerReset; /* True to reset page prior to first page rollback */
|
|
int nPlayback = 0; /* Total number of pages restored from journal */
|
|
u32 savedPageSize = pPager->pageSize;
|
|
@@ -54236,8 +58255,8 @@ static int pager_playback(Pager *pPager, int isHot){
|
|
goto end_playback;
|
|
}
|
|
|
|
- /* Read the master journal name from the journal, if it is present.
|
|
- ** If a master journal file name is specified, but the file is not
|
|
+ /* Read the super-journal name from the journal, if it is present.
|
|
+ ** If a super-journal file name is specified, but the file is not
|
|
** present on disk, then the journal is not hot and does not need to be
|
|
** played back.
|
|
**
|
|
@@ -54247,21 +58266,21 @@ static int pager_playback(Pager *pPager, int isHot){
|
|
** mxPathname is 512, which is the same as the minimum allowable value
|
|
** for pageSize.
|
|
*/
|
|
- zMaster = pPager->pTmpSpace;
|
|
- rc = readMasterJournal(pPager->jfd, zMaster, pPager->pVfs->mxPathname+1);
|
|
- if( rc==SQLITE_OK && zMaster[0] ){
|
|
- rc = sqlite3OsAccess(pVfs, zMaster, SQLITE_ACCESS_EXISTS, &res);
|
|
+ zSuper = pPager->pTmpSpace;
|
|
+ rc = readSuperJournal(pPager->jfd, zSuper, pPager->pVfs->mxPathname+1);
|
|
+ if( rc==SQLITE_OK && zSuper[0] ){
|
|
+ rc = sqlite3OsAccess(pVfs, zSuper, SQLITE_ACCESS_EXISTS, &res);
|
|
}
|
|
- zMaster = 0;
|
|
+ zSuper = 0;
|
|
if( rc!=SQLITE_OK || !res ){
|
|
goto end_playback;
|
|
}
|
|
pPager->journalOff = 0;
|
|
needPagerReset = isHot;
|
|
|
|
- /* This loop terminates either when a readJournalHdr() or
|
|
- ** pager_playback_one_page() call returns SQLITE_DONE or an IO error
|
|
- ** occurs.
|
|
+ /* This loop terminates either when a readJournalHdr() or
|
|
+ ** pager_playback_one_page() call returns SQLITE_DONE or an IO error
|
|
+ ** occurs.
|
|
*/
|
|
while( 1 ){
|
|
/* Read the next journal header from the journal file. If there are
|
|
@@ -54270,7 +58289,7 @@ static int pager_playback(Pager *pPager, int isHot){
|
|
** This indicates nothing more needs to be rolled back.
|
|
*/
|
|
rc = readJournalHdr(pPager, isHot, szJ, &nRec, &mxPg);
|
|
- if( rc!=SQLITE_OK ){
|
|
+ if( rc!=SQLITE_OK ){
|
|
if( rc==SQLITE_DONE ){
|
|
rc = SQLITE_OK;
|
|
}
|
|
@@ -54298,7 +58317,7 @@ static int pager_playback(Pager *pPager, int isHot){
|
|
** chunk of the journal contains zero pages to be rolled back. But
|
|
** when doing a ROLLBACK and the nRec==0 chunk is the last chunk in
|
|
** the journal, it means that the journal might contain additional
|
|
- ** pages that need to be rolled back and that the number of pages
|
|
+ ** pages that need to be rolled back and that the number of pages
|
|
** should be computed based on the journal file size.
|
|
*/
|
|
if( nRec==0 && !isHot &&
|
|
@@ -54315,9 +58334,12 @@ static int pager_playback(Pager *pPager, int isHot){
|
|
goto end_playback;
|
|
}
|
|
pPager->dbSize = mxPg;
|
|
+ if( pPager->mxPgno<mxPg ){
|
|
+ pPager->mxPgno = mxPg;
|
|
+ }
|
|
}
|
|
|
|
- /* Copy original pages out of the journal and back into the
|
|
+ /* Copy original pages out of the journal and back into the
|
|
** database file and/or page cache.
|
|
*/
|
|
for(u=0; u<nRec; u++){
|
|
@@ -54367,10 +58389,10 @@ static int pager_playback(Pager *pPager, int isHot){
|
|
sqlite3OsFileControlHint(pPager->fd,SQLITE_FCNTL_DB_UNCHANGED,0);
|
|
#endif
|
|
|
|
- /* If this playback is happening automatically as a result of an IO or
|
|
- ** malloc error that occurred after the change-counter was updated but
|
|
- ** before the transaction was committed, then the change-counter
|
|
- ** modification may just have been reverted. If this happens in exclusive
|
|
+ /* If this playback is happening automatically as a result of an IO or
|
|
+ ** malloc error that occurred after the change-counter was updated but
|
|
+ ** before the transaction was committed, then the change-counter
|
|
+ ** modification may just have been reverted. If this happens in exclusive
|
|
** mode, then subsequent transactions performed by the connection will not
|
|
** update the change-counter at all. This may lead to cache inconsistency
|
|
** problems for other processes at some point in the future. So, just
|
|
@@ -54379,8 +58401,12 @@ static int pager_playback(Pager *pPager, int isHot){
|
|
pPager->changeCountDone = pPager->tempFile;
|
|
|
|
if( rc==SQLITE_OK ){
|
|
- zMaster = pPager->pTmpSpace;
|
|
- rc = readMasterJournal(pPager->jfd, zMaster, pPager->pVfs->mxPathname+1);
|
|
+ /* Leave 4 bytes of space before the super-journal filename in memory.
|
|
+ ** This is because it may end up being passed to sqlite3OsOpen(), in
|
|
+ ** which case it requires 4 0x00 bytes in memory immediately before
|
|
+ ** the filename. */
|
|
+ zSuper = &pPager->pTmpSpace[4];
|
|
+ rc = readSuperJournal(pPager->jfd, zSuper, pPager->pVfs->mxPathname+1);
|
|
testcase( rc!=SQLITE_OK );
|
|
}
|
|
if( rc==SQLITE_OK
|
|
@@ -54389,14 +58415,16 @@ static int pager_playback(Pager *pPager, int isHot){
|
|
rc = sqlite3PagerSync(pPager, 0);
|
|
}
|
|
if( rc==SQLITE_OK ){
|
|
- rc = pager_end_transaction(pPager, zMaster[0]!='\0', 0);
|
|
+ rc = pager_end_transaction(pPager, zSuper[0]!='\0', 0);
|
|
testcase( rc!=SQLITE_OK );
|
|
}
|
|
- if( rc==SQLITE_OK && zMaster[0] && res ){
|
|
- /* If there was a master journal and this routine will return success,
|
|
- ** see if it is possible to delete the master journal.
|
|
+ if( rc==SQLITE_OK && zSuper[0] && res ){
|
|
+ /* If there was a super-journal and this routine will return success,
|
|
+ ** see if it is possible to delete the super-journal.
|
|
*/
|
|
- rc = pager_delmaster(pPager, zMaster);
|
|
+ assert( zSuper==&pPager->pTmpSpace[4] );
|
|
+ memset(pPager->pTmpSpace, 0, 4);
|
|
+ rc = pager_delsuper(pPager, zSuper);
|
|
testcase( rc!=SQLITE_OK );
|
|
}
|
|
if( isHot && nPlayback ){
|
|
@@ -54415,7 +58443,7 @@ static int pager_playback(Pager *pPager, int isHot){
|
|
|
|
/*
|
|
** Read the content for page pPg out of the database file (or out of
|
|
-** the WAL if that is where the most recent copy if found) into
|
|
+** the WAL if that is where the most recent copy if found) into
|
|
** pPg->pData. A shared lock or greater must be held on the database
|
|
** file before this function is called.
|
|
**
|
|
@@ -54471,8 +58499,6 @@ static int readDbPage(PgHdr *pPg){
|
|
memcpy(&pPager->dbFileVers, dbFileVers, sizeof(pPager->dbFileVers));
|
|
}
|
|
}
|
|
- CODEC1(pPager, pPg->pData, pPg->pgno, 3, rc = SQLITE_NOMEM_BKPT);
|
|
-
|
|
PAGER_INCR(sqlite3_pager_readdb_count);
|
|
PAGER_INCR(pPager->nRead);
|
|
IOTRACE(("PGIN %p %d\n", pPager, pPg->pgno));
|
|
@@ -54492,6 +58518,7 @@ static int readDbPage(PgHdr *pPg){
|
|
*/
|
|
static void pager_write_changecounter(PgHdr *pPg){
|
|
u32 change_counter;
|
|
+ if( NEVER(pPg==0) ) return;
|
|
|
|
/* Increment the value just read and write it back to byte 24. */
|
|
change_counter = sqlite3Get4byte((u8*)pPg->pPager->dbFileVers)+1;
|
|
@@ -54506,15 +58533,15 @@ static void pager_write_changecounter(PgHdr *pPg){
|
|
|
|
#ifndef SQLITE_OMIT_WAL
|
|
/*
|
|
-** This function is invoked once for each page that has already been
|
|
+** This function is invoked once for each page that has already been
|
|
** written into the log file when a WAL transaction is rolled back.
|
|
-** Parameter iPg is the page number of said page. The pCtx argument
|
|
+** Parameter iPg is the page number of said page. The pCtx argument
|
|
** is actually a pointer to the Pager structure.
|
|
**
|
|
** If page iPg is present in the cache, and has no outstanding references,
|
|
** it is discarded. Otherwise, if there are one or more outstanding
|
|
** references, the page content is reloaded from the database. If the
|
|
-** attempt to reload content from the database is required and fails,
|
|
+** attempt to reload content from the database is required and fails,
|
|
** return an SQLite error code. Otherwise, SQLITE_OK.
|
|
*/
|
|
static int pagerUndoCallback(void *pCtx, Pgno iPg){
|
|
@@ -54540,7 +58567,7 @@ static int pagerUndoCallback(void *pCtx, Pgno iPg){
|
|
** updated as data is copied out of the rollback journal and into the
|
|
** database. This is not generally possible with a WAL database, as
|
|
** rollback involves simply truncating the log file. Therefore, if one
|
|
- ** or more frames have already been written to the log (and therefore
|
|
+ ** or more frames have already been written to the log (and therefore
|
|
** also copied into the backup databases) as part of this transaction,
|
|
** the backups must be restarted.
|
|
*/
|
|
@@ -54557,7 +58584,7 @@ static int pagerRollbackWal(Pager *pPager){
|
|
PgHdr *pList; /* List of dirty pages to revert */
|
|
|
|
/* For all pages in the cache that are currently dirty or have already
|
|
- ** been written (but not committed) to the log file, do one of the
|
|
+ ** been written (but not committed) to the log file, do one of the
|
|
** following:
|
|
**
|
|
** + Discard the cached page (if refcount==0), or
|
|
@@ -54579,11 +58606,11 @@ static int pagerRollbackWal(Pager *pPager){
|
|
** This function is a wrapper around sqlite3WalFrames(). As well as logging
|
|
** the contents of the list of pages headed by pList (connected by pDirty),
|
|
** this function notifies any active backup processes that the pages have
|
|
-** changed.
|
|
+** changed.
|
|
**
|
|
** The list of pages passed into this routine is always sorted by page number.
|
|
** Hence, if page 1 appears anywhere on the list, it will be the first page.
|
|
-*/
|
|
+*/
|
|
static int pagerWalFrames(
|
|
Pager *pPager, /* Pager object */
|
|
PgHdr *pList, /* List of frames to log */
|
|
@@ -54624,7 +58651,7 @@ static int pagerWalFrames(
|
|
pPager->aStat[PAGER_STAT_WRITE] += nList;
|
|
|
|
if( pList->pgno==1 ) pager_write_changecounter(pList);
|
|
- rc = sqlite3WalFrames(pPager->pWal,
|
|
+ rc = sqlite3WalFrames(pPager->pWal,
|
|
pPager->pageSize, pList, nTruncate, isCommit, pPager->walSyncFlags
|
|
);
|
|
if( rc==SQLITE_OK && pPager->pBackup ){
|
|
@@ -54739,9 +58766,9 @@ static int pagerPagecount(Pager *pPager, Pgno *pnPage){
|
|
** Return SQLITE_OK or an error code.
|
|
**
|
|
** The caller must hold a SHARED lock on the database file to call this
|
|
-** function. Because an EXCLUSIVE lock on the db file is required to delete
|
|
-** a WAL on a none-empty database, this ensures there is no race condition
|
|
-** between the xAccess() below and an xDelete() being executed by some
|
|
+** function. Because an EXCLUSIVE lock on the db file is required to delete
|
|
+** a WAL on a none-empty database, this ensures there is no race condition
|
|
+** between the xAccess() below and an xDelete() being executed by some
|
|
** other connection.
|
|
*/
|
|
static int pagerOpenWalIfPresent(Pager *pPager){
|
|
@@ -54777,21 +58804,21 @@ static int pagerOpenWalIfPresent(Pager *pPager){
|
|
|
|
/*
|
|
** Playback savepoint pSavepoint. Or, if pSavepoint==NULL, then playback
|
|
-** the entire master journal file. The case pSavepoint==NULL occurs when
|
|
-** a ROLLBACK TO command is invoked on a SAVEPOINT that is a transaction
|
|
+** the entire super-journal file. The case pSavepoint==NULL occurs when
|
|
+** a ROLLBACK TO command is invoked on a SAVEPOINT that is a transaction
|
|
** savepoint.
|
|
**
|
|
-** When pSavepoint is not NULL (meaning a non-transaction savepoint is
|
|
+** When pSavepoint is not NULL (meaning a non-transaction savepoint is
|
|
** being rolled back), then the rollback consists of up to three stages,
|
|
** performed in the order specified:
|
|
**
|
|
** * Pages are played back from the main journal starting at byte
|
|
-** offset PagerSavepoint.iOffset and continuing to
|
|
+** offset PagerSavepoint.iOffset and continuing to
|
|
** PagerSavepoint.iHdrOffset, or to the end of the main journal
|
|
** file if PagerSavepoint.iHdrOffset is zero.
|
|
**
|
|
** * If PagerSavepoint.iHdrOffset is not zero, then pages are played
|
|
-** back starting from the journal header immediately following
|
|
+** back starting from the journal header immediately following
|
|
** PagerSavepoint.iHdrOffset to the end of the main journal file.
|
|
**
|
|
** * Pages are then played back from the sub-journal file, starting
|
|
@@ -54807,7 +58834,7 @@ static int pagerOpenWalIfPresent(Pager *pPager){
|
|
** journal file. There is no need for a bitvec in this case.
|
|
**
|
|
** In either case, before playback commences the Pager.dbSize variable
|
|
-** is reset to the value that it held at the start of the savepoint
|
|
+** is reset to the value that it held at the start of the savepoint
|
|
** (or transaction). No page with a page-number greater than this value
|
|
** is played back. If one is encountered it is simply skipped.
|
|
*/
|
|
@@ -54828,7 +58855,7 @@ static int pagerPlaybackSavepoint(Pager *pPager, PagerSavepoint *pSavepoint){
|
|
}
|
|
}
|
|
|
|
- /* Set the database size back to the value it was before the savepoint
|
|
+ /* Set the database size back to the value it was before the savepoint
|
|
** being reverted was opened.
|
|
*/
|
|
pPager->dbSize = pSavepoint ? pSavepoint->nOrig : pPager->dbOrigSize;
|
|
@@ -54881,7 +58908,7 @@ static int pagerPlaybackSavepoint(Pager *pPager, PagerSavepoint *pSavepoint){
|
|
** test is related to ticket #2565. See the discussion in the
|
|
** pager_playback() function for additional information.
|
|
*/
|
|
- if( nJRec==0
|
|
+ if( nJRec==0
|
|
&& pPager->journalHdr+JOURNAL_HDR_SZ(pPager)==pPager->journalOff
|
|
){
|
|
nJRec = (u32)((szJ - pPager->journalOff)/JOURNAL_PG_SZ(pPager));
|
|
@@ -55017,7 +59044,6 @@ SQLITE_PRIVATE void sqlite3PagerShrink(Pager *pPager){
|
|
** Numeric values associated with these states are OFF==1, NORMAL=2,
|
|
** and FULL=3.
|
|
*/
|
|
-#ifndef SQLITE_OMIT_PAGER_PRAGMAS
|
|
SQLITE_PRIVATE void sqlite3PagerSetFlags(
|
|
Pager *pPager, /* The pager to set safety level for */
|
|
unsigned pgFlags /* Various flags */
|
|
@@ -55052,12 +59078,11 @@ SQLITE_PRIVATE void sqlite3PagerSetFlags(
|
|
pPager->doNotSpill |= SPILLFLAG_OFF;
|
|
}
|
|
}
|
|
-#endif
|
|
|
|
/*
|
|
** The following global variable is incremented whenever the library
|
|
** attempts to open a temporary file. This information is used for
|
|
-** testing and analysis only.
|
|
+** testing and analysis only.
|
|
*/
|
|
#ifdef SQLITE_TEST
|
|
SQLITE_API int sqlite3_opentemp_count = 0;
|
|
@@ -55066,8 +59091,8 @@ SQLITE_API int sqlite3_opentemp_count = 0;
|
|
/*
|
|
** Open a temporary file.
|
|
**
|
|
-** Write the file descriptor into *pFile. Return SQLITE_OK on success
|
|
-** or some other error code if we fail. The OS will automatically
|
|
+** Write the file descriptor into *pFile. Return SQLITE_OK on success
|
|
+** or some other error code if we fail. The OS will automatically
|
|
** delete the temporary file when it is closed.
|
|
**
|
|
** The flags passed to the VFS layer xOpen() call are those specified
|
|
@@ -55099,9 +59124,9 @@ static int pagerOpentemp(
|
|
/*
|
|
** Set the busy handler function.
|
|
**
|
|
-** The pager invokes the busy-handler if sqlite3OsLock() returns
|
|
+** The pager invokes the busy-handler if sqlite3OsLock() returns
|
|
** SQLITE_BUSY when trying to upgrade from no-lock to a SHARED lock,
|
|
-** or when trying to upgrade from a RESERVED lock to an EXCLUSIVE
|
|
+** or when trying to upgrade from a RESERVED lock to an EXCLUSIVE
|
|
** lock. It does *not* invoke the busy handler when upgrading from
|
|
** SHARED to RESERVED, or when upgrading from SHARED to EXCLUSIVE
|
|
** (which occurs during hot-journal rollback). Summary:
|
|
@@ -55113,7 +59138,7 @@ static int pagerOpentemp(
|
|
** SHARED_LOCK -> EXCLUSIVE_LOCK | No
|
|
** RESERVED_LOCK -> EXCLUSIVE_LOCK | Yes
|
|
**
|
|
-** If the busy-handler callback returns non-zero, the lock is
|
|
+** If the busy-handler callback returns non-zero, the lock is
|
|
** retried. If it returns zero, then the SQLITE_BUSY error is
|
|
** returned to the caller of the pager API function.
|
|
*/
|
|
@@ -55132,16 +59157,16 @@ SQLITE_PRIVATE void sqlite3PagerSetBusyHandler(
|
|
}
|
|
|
|
/*
|
|
-** Change the page size used by the Pager object. The new page size
|
|
+** Change the page size used by the Pager object. The new page size
|
|
** is passed in *pPageSize.
|
|
**
|
|
** If the pager is in the error state when this function is called, it
|
|
-** is a no-op. The value returned is the error state error code (i.e.
|
|
+** is a no-op. The value returned is the error state error code (i.e.
|
|
** one of SQLITE_IOERR, an SQLITE_IOERR_xxx sub-code or SQLITE_FULL).
|
|
**
|
|
** Otherwise, if all of the following are true:
|
|
**
|
|
-** * the new page size (value of *pPageSize) is valid (a power
|
|
+** * the new page size (value of *pPageSize) is valid (a power
|
|
** of two between 512 and SQLITE_MAX_PAGE_SIZE, inclusive), and
|
|
**
|
|
** * there are no outstanding page references, and
|
|
@@ -55151,14 +59176,14 @@ SQLITE_PRIVATE void sqlite3PagerSetBusyHandler(
|
|
**
|
|
** then the pager object page size is set to *pPageSize.
|
|
**
|
|
-** If the page size is changed, then this function uses sqlite3PagerMalloc()
|
|
-** to obtain a new Pager.pTmpSpace buffer. If this allocation attempt
|
|
-** fails, SQLITE_NOMEM is returned and the page size remains unchanged.
|
|
+** If the page size is changed, then this function uses sqlite3PagerMalloc()
|
|
+** to obtain a new Pager.pTmpSpace buffer. If this allocation attempt
|
|
+** fails, SQLITE_NOMEM is returned and the page size remains unchanged.
|
|
** In all other cases, SQLITE_OK is returned.
|
|
**
|
|
** If the page size is not changed, either because one of the enumerated
|
|
** conditions above is not true, the pager was in error state when this
|
|
-** function was called, or because the memory allocation attempt failed,
|
|
+** function was called, or because the memory allocation attempt failed,
|
|
** then *pPageSize is set to the old, retained page size before returning.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager *pPager, u32 *pPageSize, int nReserve){
|
|
@@ -55168,7 +59193,7 @@ SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager *pPager, u32 *pPageSize, int nR
|
|
** function may be called from within PagerOpen(), before the state
|
|
** of the Pager object is internally consistent.
|
|
**
|
|
- ** At one point this function returned an error if the pager was in
|
|
+ ** At one point this function returned an error if the pager was in
|
|
** PAGER_ERROR state. But since PAGER_ERROR state guarantees that
|
|
** there is at least one outstanding page reference, this function
|
|
** is a no-op for that case anyhow.
|
|
@@ -55177,8 +59202,8 @@ SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager *pPager, u32 *pPageSize, int nR
|
|
u32 pageSize = *pPageSize;
|
|
assert( pageSize==0 || (pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE) );
|
|
if( (pPager->memDb==0 || pPager->dbSize==0)
|
|
- && sqlite3PcacheRefCount(pPager->pPCache)==0
|
|
- && pageSize && pageSize!=(u32)pPager->pageSize
|
|
+ && sqlite3PcacheRefCount(pPager->pPCache)==0
|
|
+ && pageSize && pageSize!=(u32)pPager->pageSize
|
|
){
|
|
char *pNew = NULL; /* New temp space */
|
|
i64 nByte = 0;
|
|
@@ -55206,6 +59231,7 @@ SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager *pPager, u32 *pPageSize, int nR
|
|
pPager->pTmpSpace = pNew;
|
|
pPager->dbSize = (Pgno)((nByte+pageSize-1)/pageSize);
|
|
pPager->pageSize = pageSize;
|
|
+ pPager->lckPgno = (Pgno)(PENDING_BYTE/pageSize) + 1;
|
|
}else{
|
|
sqlite3PageFree(pNew);
|
|
}
|
|
@@ -55216,7 +59242,6 @@ SQLITE_PRIVATE int sqlite3PagerSetPagesize(Pager *pPager, u32 *pPageSize, int nR
|
|
if( nReserve<0 ) nReserve = pPager->nReserve;
|
|
assert( nReserve>=0 && nReserve<1000 );
|
|
pPager->nReserve = (i16)nReserve;
|
|
- pagerReportSize(pPager);
|
|
pagerFixMaplimit(pPager);
|
|
}
|
|
return rc;
|
|
@@ -55235,13 +59260,13 @@ SQLITE_PRIVATE void *sqlite3PagerTempSpace(Pager *pPager){
|
|
}
|
|
|
|
/*
|
|
-** Attempt to set the maximum database page count if mxPage is positive.
|
|
+** Attempt to set the maximum database page count if mxPage is positive.
|
|
** Make no changes if mxPage is zero or negative. And never reduce the
|
|
** maximum page count below the current size of the database.
|
|
**
|
|
** Regardless of mxPage, return the current maximum page count.
|
|
*/
|
|
-SQLITE_PRIVATE int sqlite3PagerMaxPageCount(Pager *pPager, int mxPage){
|
|
+SQLITE_PRIVATE Pgno sqlite3PagerMaxPageCount(Pager *pPager, Pgno mxPage){
|
|
if( mxPage>0 ){
|
|
pPager->mxPgno = mxPage;
|
|
}
|
|
@@ -55279,11 +59304,11 @@ void enable_simulated_io_errors(void){
|
|
|
|
/*
|
|
** Read the first N bytes from the beginning of the file into memory
|
|
-** that pDest points to.
|
|
+** that pDest points to.
|
|
**
|
|
** If the pager was opened on a transient file (zFilename==""), or
|
|
** opened on a file less than N bytes in size, the output buffer is
|
|
-** zeroed and SQLITE_OK returned. The rationale for this is that this
|
|
+** zeroed and SQLITE_OK returned. The rationale for this is that this
|
|
** function is used to read database headers, and a new transient or
|
|
** zero sized database has a header than consists entirely of zeroes.
|
|
**
|
|
@@ -55316,7 +59341,7 @@ SQLITE_PRIVATE int sqlite3PagerReadFileheader(Pager *pPager, int N, unsigned cha
|
|
** This function may only be called when a read-transaction is open on
|
|
** the pager. It returns the total number of pages in the database.
|
|
**
|
|
-** However, if the file is between 1 and <page-size> bytes in size, then
|
|
+** However, if the file is between 1 and <page-size> bytes in size, then
|
|
** this is considered a 1 page file.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3PagerPagecount(Pager *pPager, int *pnPage){
|
|
@@ -55331,19 +59356,19 @@ SQLITE_PRIVATE void sqlite3PagerPagecount(Pager *pPager, int *pnPage){
|
|
** a similar or greater lock is already held, this function is a no-op
|
|
** (returning SQLITE_OK immediately).
|
|
**
|
|
-** Otherwise, attempt to obtain the lock using sqlite3OsLock(). Invoke
|
|
-** the busy callback if the lock is currently not available. Repeat
|
|
-** until the busy callback returns false or until the attempt to
|
|
+** Otherwise, attempt to obtain the lock using sqlite3OsLock(). Invoke
|
|
+** the busy callback if the lock is currently not available. Repeat
|
|
+** until the busy callback returns false or until the attempt to
|
|
** obtain the lock succeeds.
|
|
**
|
|
** Return SQLITE_OK on success and an error code if we cannot obtain
|
|
-** the lock. If the lock is obtained successfully, set the Pager.state
|
|
+** the lock. If the lock is obtained successfully, set the Pager.state
|
|
** variable to locktype before returning.
|
|
*/
|
|
static int pager_wait_on_lock(Pager *pPager, int locktype){
|
|
int rc; /* Return code */
|
|
|
|
- /* Check that this is either a no-op (because the requested lock is
|
|
+ /* Check that this is either a no-op (because the requested lock is
|
|
** already held), or one of the transitions that the busy-handler
|
|
** may be invoked during, according to the comment above
|
|
** sqlite3PagerSetBusyhandler().
|
|
@@ -55360,15 +59385,14 @@ static int pager_wait_on_lock(Pager *pPager, int locktype){
|
|
}
|
|
|
|
/*
|
|
-** Function assertTruncateConstraint(pPager) checks that one of the
|
|
+** Function assertTruncateConstraint(pPager) checks that one of the
|
|
** following is true for all dirty pages currently in the page-cache:
|
|
**
|
|
-** a) The page number is less than or equal to the size of the
|
|
+** a) The page number is less than or equal to the size of the
|
|
** current database image, in pages, OR
|
|
**
|
|
** b) if the page content were written at this time, it would not
|
|
-** be necessary to write the current content out to the sub-journal
|
|
-** (as determined by function subjRequiresPage()).
|
|
+** be necessary to write the current content out to the sub-journal.
|
|
**
|
|
** If the condition asserted by this function were not true, and the
|
|
** dirty page were to be discarded from the cache via the pagerStress()
|
|
@@ -55376,15 +59400,23 @@ static int pager_wait_on_lock(Pager *pPager, int locktype){
|
|
** the database file. If a savepoint transaction were rolled back after
|
|
** this happened, the correct behavior would be to restore the current
|
|
** content of the page. However, since this content is not present in either
|
|
-** the database file or the portion of the rollback journal and
|
|
+** the database file or the portion of the rollback journal and
|
|
** sub-journal rolled back the content could not be restored and the
|
|
-** database image would become corrupt. It is therefore fortunate that
|
|
+** database image would become corrupt. It is therefore fortunate that
|
|
** this circumstance cannot arise.
|
|
*/
|
|
#if defined(SQLITE_DEBUG)
|
|
static void assertTruncateConstraintCb(PgHdr *pPg){
|
|
+ Pager *pPager = pPg->pPager;
|
|
assert( pPg->flags&PGHDR_DIRTY );
|
|
- assert( !subjRequiresPage(pPg) || pPg->pgno<=pPg->pPager->dbSize );
|
|
+ if( pPg->pgno>pPager->dbSize ){ /* if (a) is false */
|
|
+ Pgno pgno = pPg->pgno;
|
|
+ int i;
|
|
+ for(i=0; i<pPg->pPager->nSavepoint; i++){
|
|
+ PagerSavepoint *p = &pPager->aSavepoint[i];
|
|
+ assert( p->nOrig<pgno || sqlite3BitvecTestNotNull(p->pInSavepoint,pgno) );
|
|
+ }
|
|
+ }
|
|
}
|
|
static void assertTruncateConstraint(Pager *pPager){
|
|
sqlite3PcacheIterateDirty(pPager->pPCache, assertTruncateConstraintCb);
|
|
@@ -55394,9 +59426,9 @@ static void assertTruncateConstraint(Pager *pPager){
|
|
#endif
|
|
|
|
/*
|
|
-** Truncate the in-memory database file image to nPage pages. This
|
|
-** function does not actually modify the database file on disk. It
|
|
-** just sets the internal state of the pager object so that the
|
|
+** Truncate the in-memory database file image to nPage pages. This
|
|
+** function does not actually modify the database file on disk. It
|
|
+** just sets the internal state of the pager object so that the
|
|
** truncation will be done when the current transaction is committed.
|
|
**
|
|
** This function is only called right before committing a transaction.
|
|
@@ -55405,17 +59437,17 @@ static void assertTruncateConstraint(Pager *pPager){
|
|
** then continue writing to the database.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager *pPager, Pgno nPage){
|
|
- assert( pPager->dbSize>=nPage );
|
|
+ assert( pPager->dbSize>=nPage || CORRUPT_DB );
|
|
assert( pPager->eState>=PAGER_WRITER_CACHEMOD );
|
|
pPager->dbSize = nPage;
|
|
|
|
/* At one point the code here called assertTruncateConstraint() to
|
|
** ensure that all pages being truncated away by this operation are,
|
|
- ** if one or more savepoints are open, present in the savepoint
|
|
+ ** if one or more savepoints are open, present in the savepoint
|
|
** journal so that they can be restored if the savepoint is rolled
|
|
** back. This is no longer necessary as this function is now only
|
|
- ** called right before committing a transaction. So although the
|
|
- ** Pager object may still have open savepoints (Pager.nSavepoint!=0),
|
|
+ ** called right before committing a transaction. So although the
|
|
+ ** Pager object may still have open savepoints (Pager.nSavepoint!=0),
|
|
** they cannot be rolled back. So the assertTruncateConstraint() call
|
|
** is no longer correct. */
|
|
}
|
|
@@ -55427,12 +59459,12 @@ SQLITE_PRIVATE void sqlite3PagerTruncateImage(Pager *pPager, Pgno nPage){
|
|
** size of the journal file so that the pager_playback() routine knows
|
|
** that the entire journal file has been synced.
|
|
**
|
|
-** Syncing a hot-journal to disk before attempting to roll it back ensures
|
|
+** Syncing a hot-journal to disk before attempting to roll it back ensures
|
|
** that if a power-failure occurs during the rollback, the process that
|
|
** attempts rollback following system recovery sees the same journal
|
|
** content as this process.
|
|
**
|
|
-** If everything goes as planned, SQLITE_OK is returned. Otherwise,
|
|
+** If everything goes as planned, SQLITE_OK is returned. Otherwise,
|
|
** an SQLite error code.
|
|
*/
|
|
static int pagerSyncHotJournal(Pager *pPager){
|
|
@@ -55448,7 +59480,7 @@ static int pagerSyncHotJournal(Pager *pPager){
|
|
|
|
#if SQLITE_MAX_MMAP_SIZE>0
|
|
/*
|
|
-** Obtain a reference to a memory mapped page object for page number pgno.
|
|
+** Obtain a reference to a memory mapped page object for page number pgno.
|
|
** The new object will use the pointer pData, obtained from xFetch().
|
|
** If successful, set *ppPage to point to the new page reference
|
|
** and return SQLITE_OK. Otherwise, return an SQLite error code and set
|
|
@@ -55464,7 +59496,7 @@ static int pagerAcquireMapPage(
|
|
PgHdr **ppPage /* OUT: Acquired page object */
|
|
){
|
|
PgHdr *p; /* Memory mapped page to return */
|
|
-
|
|
+
|
|
if( pPager->pMmapFreelist ){
|
|
*ppPage = p = pPager->pMmapFreelist;
|
|
pPager->pMmapFreelist = p->pDirty;
|
|
@@ -55498,7 +59530,7 @@ static int pagerAcquireMapPage(
|
|
#endif
|
|
|
|
/*
|
|
-** Release a reference to page pPg. pPg must have been returned by an
|
|
+** Release a reference to page pPg. pPg must have been returned by an
|
|
** earlier call to pagerAcquireMapPage().
|
|
*/
|
|
static void pagerReleaseMapPage(PgHdr *pPg){
|
|
@@ -55558,7 +59590,7 @@ static int databaseIsUnmoved(Pager *pPager){
|
|
** result in a coredump.
|
|
**
|
|
** This function always succeeds. If a transaction is active an attempt
|
|
-** is made to roll it back. If an error occurs during the rollback
|
|
+** is made to roll it back. If an error occurs during the rollback
|
|
** a hot journal may be left in the filesystem but no error is returned
|
|
** to the caller.
|
|
*/
|
|
@@ -55575,7 +59607,7 @@ SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3 *db){
|
|
{
|
|
u8 *a = 0;
|
|
assert( db || pPager->pWal==0 );
|
|
- if( db && 0==(db->flags & SQLITE_NoCkptOnClose)
|
|
+ if( db && 0==(db->flags & SQLITE_NoCkptOnClose)
|
|
&& SQLITE_OK==databaseIsUnmoved(pPager)
|
|
){
|
|
a = pTmp;
|
|
@@ -55589,8 +59621,8 @@ SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3 *db){
|
|
pager_unlock(pPager);
|
|
}else{
|
|
/* If it is open, sync the journal file before calling UnlockAndRollback.
|
|
- ** If this is not done, then an unsynced portion of the open journal
|
|
- ** file may be played back into the database. If a power failure occurs
|
|
+ ** If this is not done, then an unsynced portion of the open journal
|
|
+ ** file may be played back into the database. If a power failure occurs
|
|
** while this is happening, the database could become corrupt.
|
|
**
|
|
** If an error occurs while trying to sync the journal, shift the pager
|
|
@@ -55612,11 +59644,6 @@ SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3 *db){
|
|
sqlite3OsClose(pPager->fd);
|
|
sqlite3PageFree(pTmp);
|
|
sqlite3PcacheClose(pPager->pPCache);
|
|
-
|
|
-#ifdef SQLITE_HAS_CODEC
|
|
- if( pPager->xCodecFree ) pPager->xCodecFree(pPager->pCodec);
|
|
-#endif
|
|
-
|
|
assert( !pPager->aSavepoint && !pPager->pInJournal );
|
|
assert( !isOpen(pPager->jfd) && !isOpen(pPager->sjfd) );
|
|
|
|
@@ -55646,7 +59673,7 @@ SQLITE_PRIVATE void sqlite3PagerRef(DbPage *pPg){
|
|
** disk and can be restored in the event of a hot-journal rollback.
|
|
**
|
|
** If the Pager.noSync flag is set, then this function is a no-op.
|
|
-** Otherwise, the actions required depend on the journal-mode and the
|
|
+** Otherwise, the actions required depend on the journal-mode and the
|
|
** device characteristics of the file-system, as follows:
|
|
**
|
|
** * If the journal file is an in-memory journal file, no action need
|
|
@@ -55658,7 +59685,7 @@ SQLITE_PRIVATE void sqlite3PagerRef(DbPage *pPg){
|
|
** been written following it. If the pager is operating in full-sync
|
|
** mode, then the journal file is synced before this field is updated.
|
|
**
|
|
-** * If the device does not support the SEQUENTIAL property, then
|
|
+** * If the device does not support the SEQUENTIAL property, then
|
|
** journal file is synced.
|
|
**
|
|
** Or, in pseudo-code:
|
|
@@ -55667,11 +59694,11 @@ SQLITE_PRIVATE void sqlite3PagerRef(DbPage *pPg){
|
|
** if( NOT SAFE_APPEND ){
|
|
** if( <full-sync mode> ) xSync(<journal file>);
|
|
** <update nRec field>
|
|
-** }
|
|
+** }
|
|
** if( NOT SEQUENTIAL ) xSync(<journal file>);
|
|
** }
|
|
**
|
|
-** If successful, this routine clears the PGHDR_NEED_SYNC flag of every
|
|
+** If successful, this routine clears the PGHDR_NEED_SYNC flag of every
|
|
** page currently held in memory before returning SQLITE_OK. If an IO
|
|
** error is encountered, then the IO error code is returned to the caller.
|
|
*/
|
|
@@ -55699,10 +59726,10 @@ static int syncJournal(Pager *pPager, int newHdr){
|
|
** mode, then the journal file may at this point actually be larger
|
|
** than Pager.journalOff bytes. If the next thing in the journal
|
|
** file happens to be a journal-header (written as part of the
|
|
- ** previous connection's transaction), and a crash or power-failure
|
|
- ** occurs after nRec is updated but before this connection writes
|
|
- ** anything else to the journal file (or commits/rolls back its
|
|
- ** transaction), then SQLite may become confused when doing the
|
|
+ ** previous connection's transaction), and a crash or power-failure
|
|
+ ** occurs after nRec is updated but before this connection writes
|
|
+ ** anything else to the journal file (or commits/rolls back its
|
|
+ ** transaction), then SQLite may become confused when doing the
|
|
** hot-journal rollback following recovery. It may roll back all
|
|
** of this connections data, then proceed to rolling back the old,
|
|
** out-of-date data that follows it. Database corruption.
|
|
@@ -55712,7 +59739,7 @@ static int syncJournal(Pager *pPager, int newHdr){
|
|
** byte to the start of it to prevent it from being recognized.
|
|
**
|
|
** Variable iNextHdrOffset is set to the offset at which this
|
|
- ** problematic header will occur, if it exists. aMagic is used
|
|
+ ** problematic header will occur, if it exists. aMagic is used
|
|
** as a temporary buffer to inspect the first couple of bytes of
|
|
** the potential journal header.
|
|
*/
|
|
@@ -55739,7 +59766,7 @@ static int syncJournal(Pager *pPager, int newHdr){
|
|
** it as a candidate for rollback.
|
|
**
|
|
** This is not required if the persistent media supports the
|
|
- ** SAFE_APPEND property. Because in this case it is not possible
|
|
+ ** SAFE_APPEND property. Because in this case it is not possible
|
|
** for garbage data to be appended to the file, the nRec field
|
|
** is populated with 0xFFFFFFFF when the journal header is written
|
|
** and never needs to be updated.
|
|
@@ -55759,7 +59786,7 @@ static int syncJournal(Pager *pPager, int newHdr){
|
|
if( 0==(iDc&SQLITE_IOCAP_SEQUENTIAL) ){
|
|
PAGERTRACE(("SYNC journal of %d\n", PAGERID(pPager)));
|
|
IOTRACE(("JSYNC %p\n", pPager))
|
|
- rc = sqlite3OsSync(pPager->jfd, pPager->syncFlags|
|
|
+ rc = sqlite3OsSync(pPager->jfd, pPager->syncFlags|
|
|
(pPager->syncFlags==SQLITE_SYNC_FULL?SQLITE_SYNC_DATAONLY:0)
|
|
);
|
|
if( rc!=SQLITE_OK ) return rc;
|
|
@@ -55776,8 +59803,8 @@ static int syncJournal(Pager *pPager, int newHdr){
|
|
}
|
|
}
|
|
|
|
- /* Unless the pager is in noSync mode, the journal file was just
|
|
- ** successfully synced. Either way, clear the PGHDR_NEED_SYNC flag on
|
|
+ /* Unless the pager is in noSync mode, the journal file was just
|
|
+ ** successfully synced. Either way, clear the PGHDR_NEED_SYNC flag on
|
|
** all pages.
|
|
*/
|
|
sqlite3PcacheClearSyncFlags(pPager->pPCache);
|
|
@@ -55797,9 +59824,9 @@ static int syncJournal(Pager *pPager, int newHdr){
|
|
** is called. Before writing anything to the database file, this lock
|
|
** is upgraded to an EXCLUSIVE lock. If the lock cannot be obtained,
|
|
** SQLITE_BUSY is returned and no data is written to the database file.
|
|
-**
|
|
+**
|
|
** If the pager is a temp-file pager and the actual file-system file
|
|
-** is not yet open, it is created and opened before any data is
|
|
+** is not yet open, it is created and opened before any data is
|
|
** written out.
|
|
**
|
|
** Once the lock has been upgraded and, if necessary, the file opened,
|
|
@@ -55814,7 +59841,7 @@ static int syncJournal(Pager *pPager, int newHdr){
|
|
** in Pager.dbFileVers[] is updated to match the new value stored in
|
|
** the database file.
|
|
**
|
|
-** If everything is successful, SQLITE_OK is returned. If an IO error
|
|
+** If everything is successful, SQLITE_OK is returned. If an IO error
|
|
** occurs, an IO error code is returned. Or, if the EXCLUSIVE lock cannot
|
|
** be obtained, SQLITE_BUSY is returned.
|
|
*/
|
|
@@ -55840,7 +59867,7 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){
|
|
** file size will be.
|
|
*/
|
|
assert( rc!=SQLITE_OK || isOpen(pPager->fd) );
|
|
- if( rc==SQLITE_OK
|
|
+ if( rc==SQLITE_OK
|
|
&& pPager->dbHintSize<pPager->dbSize
|
|
&& (pList->pDirty || pList->pgno>pPager->dbHintSize)
|
|
){
|
|
@@ -55862,20 +59889,19 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){
|
|
*/
|
|
if( pgno<=pPager->dbSize && 0==(pList->flags&PGHDR_DONT_WRITE) ){
|
|
i64 offset = (pgno-1)*(i64)pPager->pageSize; /* Offset to write */
|
|
- char *pData; /* Data to write */
|
|
+ char *pData; /* Data to write */
|
|
|
|
assert( (pList->flags&PGHDR_NEED_SYNC)==0 );
|
|
if( pList->pgno==1 ) pager_write_changecounter(pList);
|
|
|
|
- /* Encode the database */
|
|
- CODEC2(pPager, pList->pData, pgno, 6, return SQLITE_NOMEM_BKPT, pData);
|
|
+ pData = pList->pData;
|
|
|
|
/* Write out the page data. */
|
|
rc = sqlite3OsWrite(pPager->fd, pData, pPager->pageSize, offset);
|
|
|
|
/* If page 1 was just written, update Pager.dbFileVers to match
|
|
- ** the value now stored in the database file. If writing this
|
|
- ** page caused the database file to grow, update dbFileSize.
|
|
+ ** the value now stored in the database file. If writing this
|
|
+ ** page caused the database file to grow, update dbFileSize.
|
|
*/
|
|
if( pgno==1 ){
|
|
memcpy(&pPager->dbFileVers, &pData[24], sizeof(pPager->dbFileVers));
|
|
@@ -55903,18 +59929,18 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){
|
|
}
|
|
|
|
/*
|
|
-** Ensure that the sub-journal file is open. If it is already open, this
|
|
+** Ensure that the sub-journal file is open. If it is already open, this
|
|
** function is a no-op.
|
|
**
|
|
-** SQLITE_OK is returned if everything goes according to plan. An
|
|
-** SQLITE_IOERR_XXX error code is returned if a call to sqlite3OsOpen()
|
|
+** SQLITE_OK is returned if everything goes according to plan. An
|
|
+** SQLITE_IOERR_XXX error code is returned if a call to sqlite3OsOpen()
|
|
** fails.
|
|
*/
|
|
static int openSubJournal(Pager *pPager){
|
|
int rc = SQLITE_OK;
|
|
if( !isOpen(pPager->sjfd) ){
|
|
- const int flags = SQLITE_OPEN_SUBJOURNAL | SQLITE_OPEN_READWRITE
|
|
- | SQLITE_OPEN_CREATE | SQLITE_OPEN_EXCLUSIVE
|
|
+ const int flags = SQLITE_OPEN_SUBJOURNAL | SQLITE_OPEN_READWRITE
|
|
+ | SQLITE_OPEN_CREATE | SQLITE_OPEN_EXCLUSIVE
|
|
| SQLITE_OPEN_DELETEONCLOSE;
|
|
int nStmtSpill = sqlite3Config.nStmtSpill;
|
|
if( pPager->journalMode==PAGER_JOURNALMODE_MEMORY || pPager->subjInMemory ){
|
|
@@ -55926,13 +59952,13 @@ static int openSubJournal(Pager *pPager){
|
|
}
|
|
|
|
/*
|
|
-** Append a record of the current state of page pPg to the sub-journal.
|
|
+** Append a record of the current state of page pPg to the sub-journal.
|
|
**
|
|
** If successful, set the bit corresponding to pPg->pgno in the bitvecs
|
|
** for all open savepoints before returning.
|
|
**
|
|
** This function returns SQLITE_OK if everything is successful, an IO
|
|
-** error code if the attempt to write to the sub-journal fails, or
|
|
+** error code if the attempt to write to the sub-journal fails, or
|
|
** SQLITE_NOMEM if a malloc fails while setting a bit in a savepoint
|
|
** bitvec.
|
|
*/
|
|
@@ -55945,9 +59971,9 @@ static int subjournalPage(PgHdr *pPg){
|
|
assert( pPager->useJournal );
|
|
assert( isOpen(pPager->jfd) || pagerUseWal(pPager) );
|
|
assert( isOpen(pPager->sjfd) || pPager->nSubRec==0 );
|
|
- assert( pagerUseWal(pPager)
|
|
- || pageInJournal(pPager, pPg)
|
|
- || pPg->pgno>pPager->dbOrigSize
|
|
+ assert( pagerUseWal(pPager)
|
|
+ || pageInJournal(pPager, pPg)
|
|
+ || pPg->pgno>pPager->dbOrigSize
|
|
);
|
|
rc = openSubJournal(pPager);
|
|
|
|
@@ -55957,12 +59983,6 @@ static int subjournalPage(PgHdr *pPg){
|
|
void *pData = pPg->pData;
|
|
i64 offset = (i64)pPager->nSubRec*(4+pPager->pageSize);
|
|
char *pData2;
|
|
-
|
|
-#if SQLITE_HAS_CODEC
|
|
- if( !pPager->subjInMemory ){
|
|
- CODEC2(pPager, pData, pPg->pgno, 7, return SQLITE_NOMEM_BKPT, pData2);
|
|
- }else
|
|
-#endif
|
|
pData2 = pData;
|
|
PAGERTRACE(("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno));
|
|
rc = write32bits(pPager->sjfd, offset, pPg->pgno);
|
|
@@ -55990,14 +60010,14 @@ static int subjournalPageIfRequired(PgHdr *pPg){
|
|
** This function is called by the pcache layer when it has reached some
|
|
** soft memory limit. The first argument is a pointer to a Pager object
|
|
** (cast as a void*). The pager is always 'purgeable' (not an in-memory
|
|
-** database). The second argument is a reference to a page that is
|
|
+** database). The second argument is a reference to a page that is
|
|
** currently dirty but has no outstanding references. The page
|
|
-** is always associated with the Pager object passed as the first
|
|
+** is always associated with the Pager object passed as the first
|
|
** argument.
|
|
**
|
|
** The job of this function is to make pPg clean by writing its contents
|
|
** out to the database file, if possible. This may involve syncing the
|
|
-** journal file.
|
|
+** journal file.
|
|
**
|
|
** If successful, sqlite3PcacheMakeClean() is called on the page and
|
|
** SQLITE_OK returned. If an IO error occurs while trying to make the
|
|
@@ -56022,7 +60042,7 @@ static int pagerStress(void *p, PgHdr *pPg){
|
|
** a rollback or by user request, respectively.
|
|
**
|
|
** Spilling is also prohibited when in an error state since that could
|
|
- ** lead to database corruption. In the current implementation it
|
|
+ ** lead to database corruption. In the current implementation it
|
|
** is impossible for sqlite3PcacheFetch() to be called with createFlag==3
|
|
** while in the error state, hence it is impossible for this routine to
|
|
** be called in the error state. Nevertheless, we include a NEVER()
|
|
@@ -56043,26 +60063,26 @@ static int pagerStress(void *p, PgHdr *pPg){
|
|
pPg->pDirty = 0;
|
|
if( pagerUseWal(pPager) ){
|
|
/* Write a single frame for this page to the log. */
|
|
- rc = subjournalPageIfRequired(pPg);
|
|
+ rc = subjournalPageIfRequired(pPg);
|
|
if( rc==SQLITE_OK ){
|
|
rc = pagerWalFrames(pPager, pPg, 0, 0);
|
|
}
|
|
}else{
|
|
-
|
|
+
|
|
#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
|
|
if( pPager->tempFile==0 ){
|
|
rc = sqlite3JournalCreate(pPager->jfd);
|
|
if( rc!=SQLITE_OK ) return pager_error(pPager, rc);
|
|
}
|
|
#endif
|
|
-
|
|
+
|
|
/* Sync the journal file if required. */
|
|
- if( pPg->flags&PGHDR_NEED_SYNC
|
|
+ if( pPg->flags&PGHDR_NEED_SYNC
|
|
|| pPager->eState==PAGER_WRITER_CACHEMOD
|
|
){
|
|
rc = syncJournal(pPager, 1);
|
|
}
|
|
-
|
|
+
|
|
/* Write the contents of the page out to the database file. */
|
|
if( rc==SQLITE_OK ){
|
|
assert( (pPg->flags&PGHDR_NEED_SYNC)==0 );
|
|
@@ -56076,7 +60096,7 @@ static int pagerStress(void *p, PgHdr *pPg){
|
|
sqlite3PcacheMakeClean(pPg);
|
|
}
|
|
|
|
- return pager_error(pPager, rc);
|
|
+ return pager_error(pPager, rc);
|
|
}
|
|
|
|
/*
|
|
@@ -56107,8 +60127,8 @@ SQLITE_PRIVATE int sqlite3PagerFlush(Pager *pPager){
|
|
** The zFilename argument is the path to the database file to open.
|
|
** If zFilename is NULL then a randomly-named temporary file is created
|
|
** and used as the file to be cached. Temporary files are be deleted
|
|
-** automatically when they are closed. If zFilename is ":memory:" then
|
|
-** all information is held in cache. It is never written to disk.
|
|
+** automatically when they are closed. If zFilename is ":memory:" then
|
|
+** all information is held in cache. It is never written to disk.
|
|
** This can be used to implement an in-memory database.
|
|
**
|
|
** The nExtra parameter specifies the number of bytes of space allocated
|
|
@@ -56122,13 +60142,13 @@ SQLITE_PRIVATE int sqlite3PagerFlush(Pager *pPager){
|
|
** of the PAGER_* flags.
|
|
**
|
|
** The vfsFlags parameter is a bitmask to pass to the flags parameter
|
|
-** of the xOpen() method of the supplied VFS when opening files.
|
|
+** of the xOpen() method of the supplied VFS when opening files.
|
|
**
|
|
-** If the pager object is allocated and the specified file opened
|
|
+** If the pager object is allocated and the specified file opened
|
|
** successfully, SQLITE_OK is returned and *ppPager set to point to
|
|
** the new pager object. If an error occurs, *ppPager is set to NULL
|
|
** and error code returned. This function may return SQLITE_NOMEM
|
|
-** (sqlite3Malloc() is used to allocate memory), SQLITE_CANTOPEN or
|
|
+** (sqlite3Malloc() is used to allocate memory), SQLITE_CANTOPEN or
|
|
** various SQLITE_IO_XXX errors.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3PagerOpen(
|
|
@@ -56145,7 +60165,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 */
|
|
-#ifdef SQLITE_ENABLE_DESERIALIZE
|
|
+#ifndef SQLITE_OMIT_DESERIALIZE
|
|
int memJM = 0; /* Memory journal mode */
|
|
#else
|
|
# define memJM 0
|
|
@@ -56159,7 +60179,6 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
|
|
u32 szPageDflt = SQLITE_DEFAULT_PAGE_SIZE; /* Default page size */
|
|
const char *zUri = 0; /* URI args to copy */
|
|
int nUriByte = 1; /* Number of bytes of URI args at *zUri */
|
|
- int nUri = 0; /* Number of URI parameters */
|
|
|
|
/* Figure out how much space is required for each journal file-handle
|
|
** (there are two of them, the main journal and the sub-journal). */
|
|
@@ -56207,7 +60226,6 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
|
|
while( *z ){
|
|
z += strlen(z)+1;
|
|
z += strlen(z)+1;
|
|
- nUri++;
|
|
}
|
|
nUriByte = (int)(&z[1] - zUri);
|
|
assert( nUriByte>=1 );
|
|
@@ -56227,7 +60245,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
|
|
}
|
|
|
|
/* Allocate memory for the Pager structure, PCache object, the
|
|
- ** three file descriptors, the database file name and the journal
|
|
+ ** three file descriptors, the database file name and the journal
|
|
** file name. The layout in memory is as follows:
|
|
**
|
|
** Pager object (sizeof(Pager) bytes)
|
|
@@ -56235,6 +60253,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
|
|
** Database file handle (pVfs->szOsFile bytes)
|
|
** Sub-journal file handle (journalFileSize bytes)
|
|
** Main journal file handle (journalFileSize bytes)
|
|
+ ** Ptr back to the Pager (sizeof(Pager*) bytes)
|
|
** \0\0\0\0 database prefix (4 bytes)
|
|
** Database file name (nPathname+1 bytes)
|
|
** URI query parameters (nUriByte bytes)
|
|
@@ -56263,12 +60282,18 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
|
|
** - \0
|
|
** - WAL Path (zWALName)
|
|
** - \0
|
|
+ **
|
|
+ ** The sqlite3_create_filename() interface and the databaseFilename() utility
|
|
+ ** that is used by sqlite3_filename_database() and kin also depend on the
|
|
+ ** specific formatting and order of the various filenames, so if the format
|
|
+ ** changes here, be sure to change it there as well.
|
|
*/
|
|
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 */
|
|
4 + /* Database prefix */
|
|
nPathname + 1 + /* database filename */
|
|
nUriByte + /* query parameters */
|
|
@@ -56289,6 +60314,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
|
|
pPager->sjfd = (sqlite3_file*)pPtr; pPtr += journalFileSize;
|
|
pPager->jfd = (sqlite3_file*)pPtr; pPtr += journalFileSize;
|
|
assert( EIGHT_BYTE_ALIGNMENT(pPager->jfd) );
|
|
+ memcpy(pPtr, &pPager, sizeof(pPager)); pPtr += sizeof(pPager);
|
|
|
|
/* Fill in the Pager.zFilename and pPager.zQueryParam fields */
|
|
pPtr += 4; /* Skip zero prefix */
|
|
@@ -56330,6 +60356,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
|
|
pPager->zWal = 0;
|
|
}
|
|
#endif
|
|
+ (void)pPtr; /* Suppress warning about unused pPtr value */
|
|
|
|
if( nPathname ) sqlite3DbFree(0, zPathname);
|
|
pPager->pVfs = pVfs;
|
|
@@ -56341,8 +60368,8 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
|
|
int fout = 0; /* VFS flags returned by xOpen() */
|
|
rc = sqlite3OsOpen(pVfs, pPager->zFilename, pPager->fd, vfsFlags, &fout);
|
|
assert( !memDb );
|
|
-#ifdef SQLITE_ENABLE_DESERIALIZE
|
|
- memJM = (fout&SQLITE_OPEN_MEMORY)!=0;
|
|
+#ifndef SQLITE_OMIT_DESERIALIZE
|
|
+ pPager->memVfs = memJM = (fout&SQLITE_OPEN_MEMORY)!=0;
|
|
#endif
|
|
readOnly = (fout&SQLITE_OPEN_READONLY)!=0;
|
|
|
|
@@ -56397,7 +60424,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
|
|
** disk and uses an in-memory rollback journal.
|
|
**
|
|
** This branch also runs for files marked as immutable.
|
|
- */
|
|
+ */
|
|
act_like_temp_file:
|
|
tempFile = 1;
|
|
pPager->eState = PAGER_READER; /* Pretend we already have a lock */
|
|
@@ -56406,7 +60433,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
|
|
readOnly = (vfsFlags&SQLITE_OPEN_READONLY);
|
|
}
|
|
|
|
- /* The following call to PagerSetPagesize() serves to set the value of
|
|
+ /* The following call to PagerSetPagesize() serves to set the value of
|
|
** Pager.pageSize and to allocate the Pager.pTmpSpace buffer.
|
|
*/
|
|
if( rc==SQLITE_OK ){
|
|
@@ -56446,26 +60473,15 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
|
|
/* pPager->state = PAGER_UNLOCK; */
|
|
/* pPager->errMask = 0; */
|
|
pPager->tempFile = (u8)tempFile;
|
|
- assert( tempFile==PAGER_LOCKINGMODE_NORMAL
|
|
+ assert( tempFile==PAGER_LOCKINGMODE_NORMAL
|
|
|| tempFile==PAGER_LOCKINGMODE_EXCLUSIVE );
|
|
assert( PAGER_LOCKINGMODE_EXCLUSIVE==1 );
|
|
- pPager->exclusiveMode = (u8)tempFile;
|
|
+ pPager->exclusiveMode = (u8)tempFile;
|
|
pPager->changeCountDone = pPager->tempFile;
|
|
pPager->memDb = (u8)memDb;
|
|
pPager->readOnly = (u8)readOnly;
|
|
assert( useJournal || pPager->tempFile );
|
|
- pPager->noSync = pPager->tempFile;
|
|
- if( pPager->noSync ){
|
|
- assert( pPager->fullSync==0 );
|
|
- assert( pPager->extraSync==0 );
|
|
- assert( pPager->syncFlags==0 );
|
|
- assert( pPager->walSyncFlags==0 );
|
|
- }else{
|
|
- pPager->fullSync = 1;
|
|
- pPager->extraSync = 0;
|
|
- pPager->syncFlags = SQLITE_SYNC_NORMAL;
|
|
- pPager->walSyncFlags = SQLITE_SYNC_NORMAL | (SQLITE_SYNC_NORMAL<<2);
|
|
- }
|
|
+ sqlite3PagerSetFlags(pPager, (SQLITE_DEFAULT_SYNCHRONOUS+1)|PAGER_CACHESPILL);
|
|
/* pPager->pFirst = 0; */
|
|
/* pPager->pFirstSynced = 0; */
|
|
/* pPager->pLast = 0; */
|
|
@@ -56489,12 +60505,25 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
+/*
|
|
+** Return the sqlite3_file for the main database given the name
|
|
+** of the corresonding WAL or Journal name as passed into
|
|
+** xOpen.
|
|
+*/
|
|
+SQLITE_API sqlite3_file *sqlite3_database_file_object(const char *zName){
|
|
+ Pager *pPager;
|
|
+ while( zName[-1]!=0 || zName[-2]!=0 || zName[-3]!=0 || zName[-4]!=0 ){
|
|
+ zName--;
|
|
+ }
|
|
+ pPager = *(Pager**)(zName - 4 - sizeof(Pager*));
|
|
+ return pPager->fd;
|
|
+}
|
|
|
|
|
|
/*
|
|
** This function is called after transitioning from PAGER_UNLOCK to
|
|
** PAGER_SHARED state. It tests if there is a hot journal present in
|
|
-** the file-system for the given pager. A hot journal is one that
|
|
+** the file-system for the given pager. A hot journal is one that
|
|
** needs to be played back. According to this function, a hot-journal
|
|
** file exists if the following criteria are met:
|
|
**
|
|
@@ -56509,14 +60538,14 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
|
|
** just deleted using OsDelete, *pExists is set to 0 and SQLITE_OK
|
|
** is returned.
|
|
**
|
|
-** This routine does not check if there is a master journal filename
|
|
-** at the end of the file. If there is, and that master journal file
|
|
+** This routine does not check if there is a super-journal filename
|
|
+** at the end of the file. If there is, and that super-journal file
|
|
** does not exist, then the journal file is not really hot. In this
|
|
** case this routine will return a false-positive. The pager_playback()
|
|
-** routine will discover that the journal file is not really hot and
|
|
-** will not roll it back.
|
|
+** routine will discover that the journal file is not really hot and
|
|
+** will not roll it back.
|
|
**
|
|
-** If a hot-journal file is found to exist, *pExists is set to 1 and
|
|
+** If a hot-journal file is found to exist, *pExists is set to 1 and
|
|
** SQLITE_OK returned. If no hot-journal file is present, *pExists is
|
|
** set to 0 and SQLITE_OK returned. If an IO error occurs while trying
|
|
** to determine whether or not a hot-journal file exists, the IO error
|
|
@@ -56544,7 +60573,7 @@ static int hasHotJournal(Pager *pPager, int *pExists){
|
|
int locked = 0; /* True if some process holds a RESERVED lock */
|
|
|
|
/* Race condition here: Another process might have been holding the
|
|
- ** the RESERVED lock and have a journal open at the sqlite3OsAccess()
|
|
+ ** the RESERVED lock and have a journal open at the sqlite3OsAccess()
|
|
** call above, but then delete the journal and drop the lock before
|
|
** we get to the following sqlite3OsCheckReservedLock() call. If that
|
|
** is the case, this routine might think there is a hot journal when
|
|
@@ -56577,7 +60606,7 @@ static int hasHotJournal(Pager *pPager, int *pExists){
|
|
/* The journal file exists and no other connection has a reserved
|
|
** or greater lock on the database file. Now check that there is
|
|
** at least one non-zero bytes at the start of the journal file.
|
|
- ** If there is, then we consider this journal to be hot. If not,
|
|
+ ** If there is, then we consider this journal to be hot. If not,
|
|
** it can be ignored.
|
|
*/
|
|
if( !jrnlOpen ){
|
|
@@ -56627,7 +60656,7 @@ static int hasHotJournal(Pager *pPager, int *pExists){
|
|
** on the database file), then an attempt is made to obtain a
|
|
** SHARED lock on the database file. Immediately after obtaining
|
|
** the SHARED lock, the file-system is checked for a hot-journal,
|
|
-** which is played back if present. Following any hot-journal
|
|
+** which is played back if present. Following any hot-journal
|
|
** rollback, the contents of the cache are validated by checking
|
|
** the 'change-counter' field of the database file header and
|
|
** discarded if they are found to be invalid.
|
|
@@ -56638,8 +60667,8 @@ static int hasHotJournal(Pager *pPager, int *pExists){
|
|
** the contents of the page cache and rolling back any open journal
|
|
** file.
|
|
**
|
|
-** If everything is successful, SQLITE_OK is returned. If an IO error
|
|
-** occurs while locking the database, checking for a hot-journal file or
|
|
+** If everything is successful, SQLITE_OK is returned. If an IO error
|
|
+** occurs while locking the database, checking for a hot-journal file or
|
|
** rolling back a journal file, the IO error code is returned.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
|
|
@@ -56647,7 +60676,7 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
|
|
|
|
/* This routine is only called from b-tree and only when there are no
|
|
** outstanding pages. This implies that the pager state should either
|
|
- ** be OPEN or READER. READER is only possible if the pager is or was in
|
|
+ ** be OPEN or READER. READER is only possible if the pager is or was in
|
|
** exclusive access mode. */
|
|
assert( sqlite3PcacheRefCount(pPager->pPCache)==0 );
|
|
assert( assert_pager_state(pPager) );
|
|
@@ -56685,12 +60714,12 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
|
|
** important that a RESERVED lock is not obtained on the way to the
|
|
** EXCLUSIVE lock. If it were, another process might open the
|
|
** database file, detect the RESERVED lock, and conclude that the
|
|
- ** database is safe to read while this process is still rolling the
|
|
+ ** database is safe to read while this process is still rolling the
|
|
** hot-journal back.
|
|
- **
|
|
+ **
|
|
** Because the intermediate RESERVED lock is not requested, any
|
|
- ** other process attempting to access the database file will get to
|
|
- ** this point in the code and fail to obtain its own EXCLUSIVE lock
|
|
+ ** other process attempting to access the database file will get to
|
|
+ ** this point in the code and fail to obtain its own EXCLUSIVE lock
|
|
** on the database file.
|
|
**
|
|
** Unless the pager is in locking_mode=exclusive mode, the lock is
|
|
@@ -56700,21 +60729,21 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
|
|
if( rc!=SQLITE_OK ){
|
|
goto failed;
|
|
}
|
|
-
|
|
- /* If it is not already open and the file exists on disk, open the
|
|
- ** journal for read/write access. Write access is required because
|
|
- ** in exclusive-access mode the file descriptor will be kept open
|
|
- ** and possibly used for a transaction later on. Also, write-access
|
|
- ** is usually required to finalize the journal in journal_mode=persist
|
|
+
|
|
+ /* If it is not already open and the file exists on disk, open the
|
|
+ ** journal for read/write access. Write access is required because
|
|
+ ** in exclusive-access mode the file descriptor will be kept open
|
|
+ ** and possibly used for a transaction later on. Also, write-access
|
|
+ ** is usually required to finalize the journal in journal_mode=persist
|
|
** mode (and also for journal_mode=truncate on some systems).
|
|
**
|
|
- ** If the journal does not exist, it usually means that some
|
|
- ** other connection managed to get in and roll it back before
|
|
- ** this connection obtained the exclusive lock above. Or, it
|
|
+ ** If the journal does not exist, it usually means that some
|
|
+ ** other connection managed to get in and roll it back before
|
|
+ ** this connection obtained the exclusive lock above. Or, it
|
|
** may mean that the pager was in the error-state when this
|
|
** function was called and the journal file does not exist.
|
|
*/
|
|
- if( !isOpen(pPager->jfd) ){
|
|
+ if( !isOpen(pPager->jfd) && pPager->journalMode!=PAGER_JOURNALMODE_OFF ){
|
|
sqlite3_vfs * const pVfs = pPager->pVfs;
|
|
int bExists; /* True if journal file exists */
|
|
rc = sqlite3OsAccess(
|
|
@@ -56731,7 +60760,7 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
|
|
}
|
|
}
|
|
}
|
|
-
|
|
+
|
|
/* Playback and delete the journal. Drop the database write
|
|
** lock and reacquire the read lock. Purge the cache before
|
|
** playing back the hot-journal so that we don't end up with
|
|
@@ -56756,8 +60785,8 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
|
|
** or roll back a hot-journal while holding an EXCLUSIVE lock. The
|
|
** pager_unlock() routine will be called before returning to unlock
|
|
** the file. If the unlock attempt fails, then Pager.eLock must be
|
|
- ** set to UNKNOWN_LOCK (see the comment above the #define for
|
|
- ** UNKNOWN_LOCK above for an explanation).
|
|
+ ** set to UNKNOWN_LOCK (see the comment above the #define for
|
|
+ ** UNKNOWN_LOCK above for an explanation).
|
|
**
|
|
** In order to get pager_unlock() to do this, set Pager.eState to
|
|
** PAGER_ERROR now. This is not actually counted as a transition
|
|
@@ -56765,7 +60794,7 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
|
|
** since we know that the same call to pager_unlock() will very
|
|
** shortly transition the pager object to the OPEN state. Calling
|
|
** assert_pager_state() would fail now, as it should not be possible
|
|
- ** to be in ERROR state when there are zero outstanding page
|
|
+ ** to be in ERROR state when there are zero outstanding page
|
|
** references.
|
|
*/
|
|
pager_error(pPager, rc);
|
|
@@ -56790,8 +60819,8 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
|
|
** a 32-bit counter that is incremented with each change. The
|
|
** other bytes change randomly with each file change when
|
|
** a codec is in use.
|
|
- **
|
|
- ** There is a vanishingly small chance that a change will not be
|
|
+ **
|
|
+ ** There is a vanishingly small chance that a change will not be
|
|
** detected. The chance of an undetected change is so small that
|
|
** it can be neglected.
|
|
*/
|
|
@@ -56858,7 +60887,7 @@ SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager){
|
|
** Except, in locking_mode=EXCLUSIVE when there is nothing to in
|
|
** the rollback journal, the unlock is not performed and there is
|
|
** nothing to rollback, so this routine is a no-op.
|
|
-*/
|
|
+*/
|
|
static void pagerUnlockIfUnused(Pager *pPager){
|
|
if( sqlite3PcacheRefCount(pPager->pPCache)==0 ){
|
|
assert( pPager->nMmapOut==0 ); /* because page1 is never memory mapped */
|
|
@@ -56868,7 +60897,7 @@ static void pagerUnlockIfUnused(Pager *pPager){
|
|
|
|
/*
|
|
** The page getter methods each try to acquire a reference to a
|
|
-** page with page number pgno. If the requested reference is
|
|
+** page with page number pgno. If the requested reference is
|
|
** successfully obtained, it is copied to *ppPage and SQLITE_OK returned.
|
|
**
|
|
** There are different implementations of the getter method depending
|
|
@@ -56878,22 +60907,22 @@ static void pagerUnlockIfUnused(Pager *pPager){
|
|
** getPageError() -- Used if the pager is in an error state
|
|
** getPageMmap() -- Used if memory-mapped I/O is enabled
|
|
**
|
|
-** If the requested page is already in the cache, it is returned.
|
|
+** If the requested page is already in the cache, it is returned.
|
|
** Otherwise, a new page object is allocated and populated with data
|
|
** read from the database file. In some cases, the pcache module may
|
|
** choose not to allocate a new page object and may reuse an existing
|
|
** object with no outstanding references.
|
|
**
|
|
-** The extra data appended to a page is always initialized to zeros the
|
|
-** first time a page is loaded into memory. If the page requested is
|
|
+** The extra data appended to a page is always initialized to zeros the
|
|
+** first time a page is loaded into memory. If the page requested is
|
|
** already in the cache when this function is called, then the extra
|
|
** data is left as it was when the page object was last used.
|
|
**
|
|
-** If the database image is smaller than the requested page or if
|
|
-** the flags parameter contains the PAGER_GET_NOCONTENT bit and the
|
|
-** requested page is not already stored in the cache, then no
|
|
-** actual disk read occurs. In this case the memory image of the
|
|
-** page is initialized to all zeros.
|
|
+** If the database image is smaller than the requested page or if
|
|
+** the flags parameter contains the PAGER_GET_NOCONTENT bit and the
|
|
+** requested page is not already stored in the cache, then no
|
|
+** actual disk read occurs. In this case the memory image of the
|
|
+** page is initialized to all zeros.
|
|
**
|
|
** If PAGER_GET_NOCONTENT is true, it means that we do not care about
|
|
** the contents of the page. This occurs in two scenarios:
|
|
@@ -56959,18 +60988,18 @@ static int getPageNormal(
|
|
if( pPg->pPager && !noContent ){
|
|
/* In this case the pcache already contains an initialized copy of
|
|
** the page. Return without further ado. */
|
|
- assert( pgno<=PAGER_MAX_PGNO && pgno!=PAGER_MJ_PGNO(pPager) );
|
|
+ assert( pgno!=PAGER_SJ_PGNO(pPager) );
|
|
pPager->aStat[PAGER_STAT_HIT]++;
|
|
return SQLITE_OK;
|
|
|
|
}else{
|
|
- /* The pager cache has created a new page. Its content needs to
|
|
+ /* The pager cache has created a new page. Its content needs to
|
|
** be initialized. But first some error checks:
|
|
**
|
|
- ** (1) The maximum page number is 2^31
|
|
+ ** (*) obsolete. Was: maximum page number is 2^31
|
|
** (2) Never try to fetch the locking page
|
|
*/
|
|
- if( pgno>PAGER_MAX_PGNO || pgno==PAGER_MJ_PGNO(pPager) ){
|
|
+ if( pgno==PAGER_SJ_PGNO(pPager) ){
|
|
rc = SQLITE_CORRUPT_BKPT;
|
|
goto pager_acquire_err;
|
|
}
|
|
@@ -56985,9 +61014,9 @@ static int getPageNormal(
|
|
}
|
|
if( noContent ){
|
|
/* Failure to set the bits in the InJournal bit-vectors is benign.
|
|
- ** It merely means that we might do some extra work to journal a
|
|
- ** page that does not need to be journaled. Nevertheless, be sure
|
|
- ** to test the case where a malloc error occurs while trying to set
|
|
+ ** It merely means that we might do some extra work to journal a
|
|
+ ** page that does not need to be journaled. Nevertheless, be sure
|
|
+ ** to test the case where a malloc error occurs while trying to set
|
|
** a bit in a bit vector.
|
|
*/
|
|
sqlite3BeginBenignMalloc();
|
|
@@ -57037,16 +61066,13 @@ static int getPageMMap(
|
|
|
|
/* It is acceptable to use a read-only (mmap) page for any page except
|
|
** page 1 if there is no write-transaction open or the ACQUIRE_READONLY
|
|
- ** flag was specified by the caller. And so long as the db is not a
|
|
+ ** flag was specified by the caller. And so long as the db is not a
|
|
** temporary or in-memory database. */
|
|
const int bMmapOk = (pgno>1
|
|
&& (pPager->eState==PAGER_READER || (flags & PAGER_GET_READONLY))
|
|
);
|
|
|
|
assert( USEFETCH(pPager) );
|
|
-#ifdef SQLITE_HAS_CODEC
|
|
- assert( pPager->xCodec==0 );
|
|
-#endif
|
|
|
|
/* Optimization note: Adding the "pgno<=1" term before "pgno==0" here
|
|
** allows the compiler optimizer to reuse the results of the "pgno>1"
|
|
@@ -57069,7 +61095,7 @@ static int getPageMMap(
|
|
}
|
|
if( bMmapOk && iFrame==0 ){
|
|
void *pData = 0;
|
|
- rc = sqlite3OsFetch(pPager->fd,
|
|
+ rc = sqlite3OsFetch(pPager->fd,
|
|
(i64)(pgno-1) * pPager->pageSize, pPager->pageSize, &pData
|
|
);
|
|
if( rc==SQLITE_OK && pData ){
|
|
@@ -57119,18 +61145,19 @@ 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); */
|
|
return pPager->xGet(pPager, pgno, ppPage, flags);
|
|
}
|
|
|
|
/*
|
|
** Acquire a page if it is already in the in-memory cache. Do
|
|
** not read the page from disk. Return a pointer to the page,
|
|
-** or 0 if the page is not in cache.
|
|
+** or 0 if the page is not in cache.
|
|
**
|
|
** See also sqlite3PagerGet(). The difference between this routine
|
|
** and sqlite3PagerGet() is that _get() will go to the disk and read
|
|
** in the page if the page is not already in cache. This routine
|
|
-** returns NULL if the page is not in cache or if a disk I/O error
|
|
+** returns NULL if the page is not in cache or if a disk I/O error
|
|
** has ever happened.
|
|
*/
|
|
SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){
|
|
@@ -57177,31 +61204,30 @@ SQLITE_PRIVATE void sqlite3PagerUnrefPageOne(DbPage *pPg){
|
|
assert( pPg->pgno==1 );
|
|
assert( (pPg->flags & PGHDR_MMAP)==0 ); /* Page1 is never memory mapped */
|
|
pPager = pPg->pPager;
|
|
- sqlite3PagerResetLockTimeout(pPager);
|
|
sqlite3PcacheRelease(pPg);
|
|
pagerUnlockIfUnused(pPager);
|
|
}
|
|
|
|
/*
|
|
** This function is called at the start of every write transaction.
|
|
-** There must already be a RESERVED or EXCLUSIVE lock on the database
|
|
+** There must already be a RESERVED or EXCLUSIVE lock on the database
|
|
** file when this routine is called.
|
|
**
|
|
** Open the journal file for pager pPager and write a journal header
|
|
** to the start of it. If there are active savepoints, open the sub-journal
|
|
-** as well. This function is only used when the journal file is being
|
|
-** opened to write a rollback log for a transaction. It is not used
|
|
+** as well. This function is only used when the journal file is being
|
|
+** opened to write a rollback log for a transaction. It is not used
|
|
** when opening a hot journal file to roll it back.
|
|
**
|
|
** If the journal file is already open (as it may be in exclusive mode),
|
|
** then this function just writes a journal header to the start of the
|
|
-** already open file.
|
|
+** already open file.
|
|
**
|
|
** Whether or not the journal file is opened by this function, the
|
|
** Pager.pInJournal bitvec structure is allocated.
|
|
**
|
|
-** Return SQLITE_OK if everything is successful. Otherwise, return
|
|
-** SQLITE_NOMEM if the attempt to allocate Pager.pInJournal fails, or
|
|
+** Return SQLITE_OK if everything is successful. Otherwise, return
|
|
+** SQLITE_NOMEM if the attempt to allocate Pager.pInJournal fails, or
|
|
** an IO error code if opening or writing the journal file fails.
|
|
*/
|
|
static int pager_open_journal(Pager *pPager){
|
|
@@ -57211,7 +61237,7 @@ static int pager_open_journal(Pager *pPager){
|
|
assert( pPager->eState==PAGER_WRITER_LOCKED );
|
|
assert( assert_pager_state(pPager) );
|
|
assert( pPager->pInJournal==0 );
|
|
-
|
|
+
|
|
/* If already in the error state, this function is a no-op. But on
|
|
** the other hand, this routine is never called if we are already in
|
|
** an error state. */
|
|
@@ -57222,7 +61248,7 @@ static int pager_open_journal(Pager *pPager){
|
|
if( pPager->pInJournal==0 ){
|
|
return SQLITE_NOMEM_BKPT;
|
|
}
|
|
-
|
|
+
|
|
/* Open the journal file if it is not already open. */
|
|
if( !isOpen(pPager->jfd) ){
|
|
if( pPager->journalMode==PAGER_JOURNALMODE_MEMORY ){
|
|
@@ -57233,12 +61259,13 @@ static int pager_open_journal(Pager *pPager){
|
|
|
|
if( pPager->tempFile ){
|
|
flags |= (SQLITE_OPEN_DELETEONCLOSE|SQLITE_OPEN_TEMP_JOURNAL);
|
|
+ flags |= SQLITE_OPEN_EXCLUSIVE;
|
|
nSpill = sqlite3Config.nStmtSpill;
|
|
}else{
|
|
flags |= SQLITE_OPEN_MAIN_JOURNAL;
|
|
nSpill = jrnlBufferSize(pPager);
|
|
}
|
|
-
|
|
+
|
|
/* Verify that the database still has the same name as it did when
|
|
** it was originally opened. */
|
|
rc = databaseIsUnmoved(pPager);
|
|
@@ -57250,16 +61277,16 @@ static int pager_open_journal(Pager *pPager){
|
|
}
|
|
assert( rc!=SQLITE_OK || isOpen(pPager->jfd) );
|
|
}
|
|
-
|
|
-
|
|
- /* Write the first journal header to the journal file and open
|
|
+
|
|
+
|
|
+ /* Write the first journal header to the journal file and open
|
|
** the sub-journal if necessary.
|
|
*/
|
|
if( rc==SQLITE_OK ){
|
|
/* TODO: Check if all of these are really required. */
|
|
pPager->nRec = 0;
|
|
pPager->journalOff = 0;
|
|
- pPager->setMaster = 0;
|
|
+ pPager->setSuper = 0;
|
|
pPager->journalHdr = 0;
|
|
rc = writeJournalHdr(pPager);
|
|
}
|
|
@@ -57268,6 +61295,7 @@ static int pager_open_journal(Pager *pPager){
|
|
if( rc!=SQLITE_OK ){
|
|
sqlite3BitvecDestroy(pPager->pInJournal);
|
|
pPager->pInJournal = 0;
|
|
+ pPager->journalOff = 0;
|
|
}else{
|
|
assert( pPager->eState==PAGER_WRITER_LOCKED );
|
|
pPager->eState = PAGER_WRITER_CACHEMOD;
|
|
@@ -57277,12 +61305,12 @@ static int pager_open_journal(Pager *pPager){
|
|
}
|
|
|
|
/*
|
|
-** Begin a write-transaction on the specified pager object. If a
|
|
+** Begin a write-transaction on the specified pager object. If a
|
|
** write-transaction has already been opened, this function is a no-op.
|
|
**
|
|
** If the exFlag argument is false, then acquire at least a RESERVED
|
|
** lock on the database file. If exFlag is true, then acquire at least
|
|
-** an EXCLUSIVE lock. If such a lock is already held, no locking
|
|
+** an EXCLUSIVE lock. If such a lock is already held, no locking
|
|
** functions need be called.
|
|
**
|
|
** If the subjInMemory argument is non-zero, then any sub-journal opened
|
|
@@ -57290,7 +61318,7 @@ static int pager_open_journal(Pager *pPager){
|
|
** has no effect if the sub-journal is already opened (as it may be when
|
|
** running in exclusive mode) or if the transaction does not require a
|
|
** sub-journal. If the subjInMemory argument is zero, then any required
|
|
-** sub-journal is implemented in-memory if pPager is an in-memory database,
|
|
+** sub-journal is implemented in-memory if pPager is an in-memory database,
|
|
** or using a temporary file otherwise.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory){
|
|
@@ -57300,7 +61328,7 @@ SQLITE_PRIVATE int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory
|
|
assert( pPager->eState>=PAGER_READER && pPager->eState<PAGER_ERROR );
|
|
pPager->subjInMemory = (u8)subjInMemory;
|
|
|
|
- if( ALWAYS(pPager->eState==PAGER_READER) ){
|
|
+ if( pPager->eState==PAGER_READER ){
|
|
assert( pPager->pInJournal==0 );
|
|
|
|
if( pagerUseWal(pPager) ){
|
|
@@ -57338,9 +61366,9 @@ SQLITE_PRIVATE int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory
|
|
**
|
|
** WAL mode sets Pager.eState to PAGER_WRITER_LOCKED or CACHEMOD
|
|
** when it has an open transaction, but never to DBMOD or FINISHED.
|
|
- ** This is because in those states the code to roll back savepoint
|
|
- ** transactions may copy data from the sub-journal into the database
|
|
- ** file as well as into the page cache. Which would be incorrect in
|
|
+ ** This is because in those states the code to roll back savepoint
|
|
+ ** transactions may copy data from the sub-journal into the database
|
|
+ ** file as well as into the page cache. Which would be incorrect in
|
|
** WAL mode.
|
|
*/
|
|
pPager->eState = PAGER_WRITER_LOCKED;
|
|
@@ -57372,10 +61400,10 @@ static SQLITE_NOINLINE int pagerAddPageToRollbackJournal(PgHdr *pPg){
|
|
/* We should never write to the journal file the page that
|
|
** contains the database locks. The following assert verifies
|
|
** that we do not. */
|
|
- assert( pPg->pgno!=PAGER_MJ_PGNO(pPager) );
|
|
+ assert( pPg->pgno!=PAGER_SJ_PGNO(pPager) );
|
|
|
|
assert( pPager->journalHdr<=pPager->journalOff );
|
|
- CODEC2(pPager, pPg->pData, pPg->pgno, 7, return SQLITE_NOMEM_BKPT, pData2);
|
|
+ pData2 = pPg->pData;
|
|
cksum = pager_cksum(pPager, (u8*)pData2);
|
|
|
|
/* Even if an IO or diskfull error occurs while journalling the
|
|
@@ -57394,11 +61422,11 @@ static SQLITE_NOINLINE int pagerAddPageToRollbackJournal(PgHdr *pPg){
|
|
rc = write32bits(pPager->jfd, iOff+pPager->pageSize+4, cksum);
|
|
if( rc!=SQLITE_OK ) return rc;
|
|
|
|
- IOTRACE(("JOUT %p %d %lld %d\n", pPager, pPg->pgno,
|
|
+ IOTRACE(("JOUT %p %d %lld %d\n", pPager, pPg->pgno,
|
|
pPager->journalOff, pPager->pageSize));
|
|
PAGER_INCR(sqlite3_pager_writej_count);
|
|
PAGERTRACE(("JOURNAL %d page %d needSync=%d hash(%08x)\n",
|
|
- PAGERID(pPager), pPg->pgno,
|
|
+ PAGERID(pPager), pPg->pgno,
|
|
((pPg->flags&PGHDR_NEED_SYNC)?1:0), pager_pagehash(pPg)));
|
|
|
|
pPager->journalOff += 8 + pPager->pageSize;
|
|
@@ -57413,9 +61441,9 @@ static SQLITE_NOINLINE int pagerAddPageToRollbackJournal(PgHdr *pPg){
|
|
}
|
|
|
|
/*
|
|
-** Mark a single data page as writeable. The page is written into the
|
|
+** Mark a single data page as writeable. The page is written into the
|
|
** main journal or sub-journal as required. If the page is written into
|
|
-** one of the journals, the corresponding bit is set in the
|
|
+** one of the journals, the corresponding bit is set in the
|
|
** Pager.pInJournal bitvec and the PagerSavepoint.pInSavepoint bitvecs
|
|
** of any open savepoints as appropriate.
|
|
*/
|
|
@@ -57423,7 +61451,7 @@ static int pager_write(PgHdr *pPg){
|
|
Pager *pPager = pPg->pPager;
|
|
int rc = SQLITE_OK;
|
|
|
|
- /* This routine is not called unless a write-transaction has already
|
|
+ /* This routine is not called unless a write-transaction has already
|
|
** been started. The journal file may or may not be open at this point.
|
|
** It is never called in the ERROR state.
|
|
*/
|
|
@@ -57440,7 +61468,7 @@ static int pager_write(PgHdr *pPg){
|
|
** obtained the necessary locks to begin the write-transaction, but the
|
|
** rollback journal might not yet be open. Open it now if this is the case.
|
|
**
|
|
- ** This is done before calling sqlite3PcacheMakeDirty() on the page.
|
|
+ ** This is done before calling sqlite3PcacheMakeDirty() on the page.
|
|
** Otherwise, if it were done after calling sqlite3PcacheMakeDirty(), then
|
|
** an error might occur and the pager would end up in WRITER_LOCKED state
|
|
** with pages marked as dirty in the cache.
|
|
@@ -57485,7 +61513,7 @@ static int pager_write(PgHdr *pPg){
|
|
** PGHDR_WRITEABLE bit that indicates that the page can be safely modified.
|
|
*/
|
|
pPg->flags |= PGHDR_WRITEABLE;
|
|
-
|
|
+
|
|
/* If the statement journal is open and the page is not in it,
|
|
** then write the page into the statement journal.
|
|
*/
|
|
@@ -57551,7 +61579,7 @@ static SQLITE_NOINLINE int pagerWriteLargeSector(PgHdr *pPg){
|
|
Pgno pg = pg1+ii;
|
|
PgHdr *pPage;
|
|
if( pg==pPg->pgno || !sqlite3BitvecTest(pPager->pInJournal, pg) ){
|
|
- if( pg!=PAGER_MJ_PGNO(pPager) ){
|
|
+ if( pg!=PAGER_SJ_PGNO(pPager) ){
|
|
rc = sqlite3PagerGet(pPager, pg, &pPage, 0);
|
|
if( rc==SQLITE_OK ){
|
|
rc = pager_write(pPage);
|
|
@@ -57569,7 +61597,7 @@ static SQLITE_NOINLINE int pagerWriteLargeSector(PgHdr *pPg){
|
|
}
|
|
}
|
|
|
|
- /* If the PGHDR_NEED_SYNC flag is set for any of the nPage pages
|
|
+ /* If the PGHDR_NEED_SYNC flag is set for any of the nPage pages
|
|
** starting at pg1, then it needs to be set for all of them. Because
|
|
** writing to any of these nPage pages may damage the others, the
|
|
** journal file must contain sync()ed copies of all of them
|
|
@@ -57592,9 +61620,9 @@ static SQLITE_NOINLINE int pagerWriteLargeSector(PgHdr *pPg){
|
|
}
|
|
|
|
/*
|
|
-** Mark a data page as writeable. This routine must be called before
|
|
-** making changes to a page. The caller must check the return value
|
|
-** of this function and be careful not to change any page data unless
|
|
+** Mark a data page as writeable. This routine must be called before
|
|
+** making changes to a page. The caller must check the return value
|
|
+** of this function and be careful not to change any page data unless
|
|
** this routine returns SQLITE_OK.
|
|
**
|
|
** The difference between this function and pager_write() is that this
|
|
@@ -57645,13 +61673,13 @@ SQLITE_PRIVATE int sqlite3PagerIswriteable(DbPage *pPg){
|
|
** on the given page is unused. The pager marks the page as clean so
|
|
** that it does not get written to disk.
|
|
**
|
|
-** Tests show that this optimization can quadruple the speed of large
|
|
+** Tests show that this optimization can quadruple the speed of large
|
|
** DELETE operations.
|
|
**
|
|
** This optimization cannot be used with a temp-file, as the page may
|
|
** have been dirty at the start of the transaction. In that case, if
|
|
-** memory pressure forces page pPg out of the cache, the data does need
|
|
-** to be written out to disk so that it may be read back in if the
|
|
+** memory pressure forces page pPg out of the cache, the data does need
|
|
+** to be written out to disk so that it may be read back in if the
|
|
** current transaction is rolled back.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3PagerDontWrite(PgHdr *pPg){
|
|
@@ -57667,17 +61695,17 @@ SQLITE_PRIVATE void sqlite3PagerDontWrite(PgHdr *pPg){
|
|
}
|
|
|
|
/*
|
|
-** This routine is called to increment the value of the database file
|
|
-** change-counter, stored as a 4-byte big-endian integer starting at
|
|
+** This routine is called to increment the value of the database file
|
|
+** change-counter, stored as a 4-byte big-endian integer starting at
|
|
** byte offset 24 of the pager file. The secondary change counter at
|
|
** 92 is also updated, as is the SQLite version number at offset 96.
|
|
**
|
|
** But this only happens if the pPager->changeCountDone flag is false.
|
|
** To avoid excess churning of page 1, the update only happens once.
|
|
-** See also the pager_write_changecounter() routine that does an
|
|
+** See also the pager_write_changecounter() routine that does an
|
|
** unconditional update of the change counters.
|
|
**
|
|
-** If the isDirectMode flag is zero, then this is done by calling
|
|
+** If the isDirectMode flag is zero, then this is done by calling
|
|
** sqlite3PagerWrite() on page 1, then modifying the contents of the
|
|
** page data. In this case the file will be updated when the current
|
|
** transaction is committed.
|
|
@@ -57685,7 +61713,7 @@ SQLITE_PRIVATE void sqlite3PagerDontWrite(PgHdr *pPg){
|
|
** The isDirectMode flag may only be non-zero if the library was compiled
|
|
** with the SQLITE_ENABLE_ATOMIC_WRITE macro defined. In this case,
|
|
** if isDirect is non-zero, then the database file is updated directly
|
|
-** by writing an updated version of page 1 using a call to the
|
|
+** by writing an updated version of page 1 using a call to the
|
|
** sqlite3OsWrite() function.
|
|
*/
|
|
static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
|
|
@@ -57714,7 +61742,7 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
|
|
# define DIRECT_MODE isDirectMode
|
|
#endif
|
|
|
|
- if( !pPager->changeCountDone && ALWAYS(pPager->dbSize>0) ){
|
|
+ if( !pPager->changeCountDone && pPager->dbSize>0 ){
|
|
PgHdr *pPgHdr; /* Reference to page 1 */
|
|
|
|
assert( !pPager->tempFile && isOpen(pPager->fd) );
|
|
@@ -57724,7 +61752,7 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
|
|
assert( pPgHdr==0 || rc==SQLITE_OK );
|
|
|
|
/* If page one was fetched successfully, and this function is not
|
|
- ** operating in direct-mode, make page 1 writable. When not in
|
|
+ ** operating in direct-mode, make page 1 writable. When not in
|
|
** direct mode, page 1 is always held in cache and hence the PagerGet()
|
|
** above is always successful - hence the ALWAYS on rc==SQLITE_OK.
|
|
*/
|
|
@@ -57740,7 +61768,7 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
|
|
if( DIRECT_MODE ){
|
|
const void *zBuf;
|
|
assert( pPager->dbFileSize>0 );
|
|
- CODEC2(pPager, pPgHdr->pData, 1, 6, rc=SQLITE_NOMEM_BKPT, zBuf);
|
|
+ zBuf = pPgHdr->pData;
|
|
if( rc==SQLITE_OK ){
|
|
rc = sqlite3OsWrite(pPager->fd, zBuf, pPager->pageSize, 0);
|
|
pPager->aStat[PAGER_STAT_WRITE]++;
|
|
@@ -57771,9 +61799,9 @@ static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
|
|
** If successful, or if called on a pager for which it is a no-op, this
|
|
** function returns SQLITE_OK. Otherwise, an IO error code is returned.
|
|
*/
|
|
-SQLITE_PRIVATE int sqlite3PagerSync(Pager *pPager, const char *zMaster){
|
|
+SQLITE_PRIVATE int sqlite3PagerSync(Pager *pPager, const char *zSuper){
|
|
int rc = SQLITE_OK;
|
|
- void *pArg = (void*)zMaster;
|
|
+ void *pArg = (void*)zSuper;
|
|
rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_SYNC, pArg);
|
|
if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK;
|
|
if( rc==SQLITE_OK && !pPager->noSync ){
|
|
@@ -57785,22 +61813,22 @@ SQLITE_PRIVATE int sqlite3PagerSync(Pager *pPager, const char *zMaster){
|
|
|
|
/*
|
|
** This function may only be called while a write-transaction is active in
|
|
-** rollback. If the connection is in WAL mode, this call is a no-op.
|
|
-** Otherwise, if the connection does not already have an EXCLUSIVE lock on
|
|
+** rollback. If the connection is in WAL mode, this call is a no-op.
|
|
+** Otherwise, if the connection does not already have an EXCLUSIVE lock on
|
|
** the database file, an attempt is made to obtain one.
|
|
**
|
|
** If the EXCLUSIVE lock is already held or the attempt to obtain it is
|
|
** successful, or the connection is in WAL mode, SQLITE_OK is returned.
|
|
-** Otherwise, either SQLITE_BUSY or an SQLITE_IOERR_XXX error code is
|
|
+** Otherwise, either SQLITE_BUSY or an SQLITE_IOERR_XXX error code is
|
|
** returned.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3PagerExclusiveLock(Pager *pPager){
|
|
int rc = pPager->errCode;
|
|
assert( assert_pager_state(pPager) );
|
|
if( rc==SQLITE_OK ){
|
|
- assert( pPager->eState==PAGER_WRITER_CACHEMOD
|
|
- || pPager->eState==PAGER_WRITER_DBMOD
|
|
- || pPager->eState==PAGER_WRITER_LOCKED
|
|
+ assert( pPager->eState==PAGER_WRITER_CACHEMOD
|
|
+ || pPager->eState==PAGER_WRITER_DBMOD
|
|
+ || pPager->eState==PAGER_WRITER_LOCKED
|
|
);
|
|
assert( assert_pager_state(pPager) );
|
|
if( 0==pagerUseWal(pPager) ){
|
|
@@ -57811,24 +61839,24 @@ SQLITE_PRIVATE int sqlite3PagerExclusiveLock(Pager *pPager){
|
|
}
|
|
|
|
/*
|
|
-** Sync the database file for the pager pPager. zMaster points to the name
|
|
-** of a master journal file that should be written into the individual
|
|
-** journal file. zMaster may be NULL, which is interpreted as no master
|
|
-** journal (a single database transaction).
|
|
+** Sync the database file for the pager pPager. zSuper points to the name
|
|
+** of a super-journal file that should be written into the individual
|
|
+** journal file. zSuper may be NULL, which is interpreted as no
|
|
+** super-journal (a single database transaction).
|
|
**
|
|
** This routine ensures that:
|
|
**
|
|
** * The database file change-counter is updated,
|
|
** * the journal is synced (unless the atomic-write optimization is used),
|
|
-** * all dirty pages are written to the database file,
|
|
+** * all dirty pages are written to the database file,
|
|
** * the database file is truncated (if required), and
|
|
-** * the database file synced.
|
|
+** * the database file synced.
|
|
**
|
|
-** The only thing that remains to commit the transaction is to finalize
|
|
-** (delete, truncate or zero the first part of) the journal file (or
|
|
-** delete the master journal file if specified).
|
|
+** The only thing that remains to commit the transaction is to finalize
|
|
+** (delete, truncate or zero the first part of) the journal file (or
|
|
+** delete the super-journal file if specified).
|
|
**
|
|
-** Note that if zMaster==NULL, this does not overwrite a previous value
|
|
+** Note that if zSuper==NULL, this does not overwrite a previous value
|
|
** passed to an sqlite3PagerCommitPhaseOne() call.
|
|
**
|
|
** If the final parameter - noSync - is true, then the database file itself
|
|
@@ -57838,7 +61866,7 @@ SQLITE_PRIVATE int sqlite3PagerExclusiveLock(Pager *pPager){
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
|
|
Pager *pPager, /* Pager object */
|
|
- const char *zMaster, /* If not NULL, the master journal name */
|
|
+ const char *zSuper, /* If not NULL, the super-journal name */
|
|
int noSync /* True to omit the xSync on the db file */
|
|
){
|
|
int rc = SQLITE_OK; /* Return code */
|
|
@@ -57856,8 +61884,8 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
|
|
/* Provide the ability to easily simulate an I/O error during testing */
|
|
if( sqlite3FaultSim(400) ) return SQLITE_IOERR;
|
|
|
|
- PAGERTRACE(("DATABASE SYNC: File=%s zMaster=%s nSize=%d\n",
|
|
- pPager->zFilename, zMaster, pPager->dbSize));
|
|
+ PAGERTRACE(("DATABASE SYNC: File=%s zSuper=%s nSize=%d\n",
|
|
+ pPager->zFilename, zSuper, pPager->dbSize));
|
|
|
|
/* If no database changes have been made, return early. */
|
|
if( pPager->eState<PAGER_WRITER_CACHEMOD ) return SQLITE_OK;
|
|
@@ -57896,7 +61924,7 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
|
|
*/
|
|
#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
|
|
sqlite3_file *fd = pPager->fd;
|
|
- int bBatch = zMaster==0 /* An SQLITE_IOCAP_BATCH_ATOMIC commit */
|
|
+ int bBatch = zSuper==0 /* An SQLITE_IOCAP_BATCH_ATOMIC commit */
|
|
&& (sqlite3OsDeviceCharacteristics(fd) & SQLITE_IOCAP_BATCH_ATOMIC)
|
|
&& !pPager->noSync
|
|
&& sqlite3JournalIsInMemory(pPager->jfd);
|
|
@@ -57907,11 +61935,11 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
|
|
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
|
|
/* The following block updates the change-counter. Exactly how it
|
|
** does this depends on whether or not the atomic-update optimization
|
|
- ** was enabled at compile time, and if this transaction meets the
|
|
- ** runtime criteria to use the operation:
|
|
+ ** was enabled at compile time, and if this transaction meets the
|
|
+ ** runtime criteria to use the operation:
|
|
**
|
|
** * The file-system supports the atomic-write property for
|
|
- ** blocks of size page-size, and
|
|
+ ** blocks of size page-size, and
|
|
** * This commit is not part of a multi-file transaction, and
|
|
** * Exactly one page has been modified and store in the journal file.
|
|
**
|
|
@@ -57921,7 +61949,7 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
|
|
** is not applicable to this transaction, call sqlite3JournalCreate()
|
|
** to make sure the journal file has actually been created, then call
|
|
** pager_incr_changecounter() to update the change-counter in indirect
|
|
- ** mode.
|
|
+ ** mode.
|
|
**
|
|
** Otherwise, if the optimization is both enabled and applicable,
|
|
** then call pager_incr_changecounter() to update the change-counter
|
|
@@ -57930,19 +61958,19 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
|
|
*/
|
|
if( bBatch==0 ){
|
|
PgHdr *pPg;
|
|
- assert( isOpen(pPager->jfd)
|
|
- || pPager->journalMode==PAGER_JOURNALMODE_OFF
|
|
- || pPager->journalMode==PAGER_JOURNALMODE_WAL
|
|
+ assert( isOpen(pPager->jfd)
|
|
+ || pPager->journalMode==PAGER_JOURNALMODE_OFF
|
|
+ || pPager->journalMode==PAGER_JOURNALMODE_WAL
|
|
);
|
|
- if( !zMaster && isOpen(pPager->jfd)
|
|
- && pPager->journalOff==jrnlBufferSize(pPager)
|
|
+ if( !zSuper && isOpen(pPager->jfd)
|
|
+ && pPager->journalOff==jrnlBufferSize(pPager)
|
|
&& pPager->dbSize>=pPager->dbOrigSize
|
|
&& (!(pPg = sqlite3PcacheDirtyList(pPager->pPCache)) || 0==pPg->pDirty)
|
|
){
|
|
- /* Update the db file change counter via the direct-write method. The
|
|
- ** following call will modify the in-memory representation of page 1
|
|
- ** to include the updated change counter and then write page 1
|
|
- ** directly to the database file. Because of the atomic-write
|
|
+ /* Update the db file change counter via the direct-write method. The
|
|
+ ** following call will modify the in-memory representation of page 1
|
|
+ ** to include the updated change counter and then write page 1
|
|
+ ** directly to the database file. Because of the atomic-write
|
|
** property of the host file-system, this is safe.
|
|
*/
|
|
rc = pager_incr_changecounter(pPager, 1);
|
|
@@ -57955,7 +61983,7 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
|
|
}
|
|
#else /* SQLITE_ENABLE_ATOMIC_WRITE */
|
|
#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
|
|
- if( zMaster ){
|
|
+ if( zSuper ){
|
|
rc = sqlite3JournalCreate(pPager->jfd);
|
|
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
|
|
assert( bBatch==0 );
|
|
@@ -57964,24 +61992,24 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
|
|
rc = pager_incr_changecounter(pPager, 0);
|
|
#endif /* !SQLITE_ENABLE_ATOMIC_WRITE */
|
|
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
|
|
-
|
|
- /* Write the master journal name into the journal file. If a master
|
|
- ** journal file name has already been written to the journal file,
|
|
- ** or if zMaster is NULL (no master journal), then this call is a no-op.
|
|
+
|
|
+ /* Write the super-journal name into the journal file. If a
|
|
+ ** super-journal file name has already been written to the journal file,
|
|
+ ** or if zSuper is NULL (no super-journal), then this call is a no-op.
|
|
*/
|
|
- rc = writeMasterJournal(pPager, zMaster);
|
|
+ rc = writeSuperJournal(pPager, zSuper);
|
|
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
|
|
-
|
|
+
|
|
/* Sync the journal file and write all dirty pages to the database.
|
|
- ** If the atomic-update optimization is being used, this sync will not
|
|
+ ** If the atomic-update optimization is being used, this sync will not
|
|
** create the journal file or perform any real IO.
|
|
**
|
|
** Because the change-counter page was just modified, unless the
|
|
** atomic-update optimization is used it is almost certain that the
|
|
** journal requires a sync here. However, in locking_mode=exclusive
|
|
- ** on a system under memory pressure it is just possible that this is
|
|
+ ** on a system under memory pressure it is just possible that this is
|
|
** not the case. In this case it is likely enough that the redundant
|
|
- ** xSync() call will be changed to a no-op by the OS anyhow.
|
|
+ ** xSync() call will be changed to a no-op by the OS anyhow.
|
|
*/
|
|
rc = syncJournal(pPager, 0);
|
|
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
|
|
@@ -58022,22 +62050,22 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
|
|
}
|
|
sqlite3PcacheCleanAll(pPager->pPCache);
|
|
|
|
- /* If the file on disk is smaller than the database image, use
|
|
+ /* If the file on disk is smaller than the database image, use
|
|
** pager_truncate to grow the file here. This can happen if the database
|
|
** image was extended as part of the current transaction and then the
|
|
** last page in the db image moved to the free-list. In this case the
|
|
** last page is never written out to disk, leaving the database file
|
|
** undersized. Fix this now if it is the case. */
|
|
if( pPager->dbSize>pPager->dbFileSize ){
|
|
- Pgno nNew = pPager->dbSize - (pPager->dbSize==PAGER_MJ_PGNO(pPager));
|
|
+ Pgno nNew = pPager->dbSize - (pPager->dbSize==PAGER_SJ_PGNO(pPager));
|
|
assert( pPager->eState==PAGER_WRITER_DBMOD );
|
|
rc = pager_truncate(pPager, nNew);
|
|
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
|
|
}
|
|
-
|
|
+
|
|
/* Finally, sync the database file. */
|
|
if( !noSync ){
|
|
- rc = sqlite3PagerSync(pPager, zMaster);
|
|
+ rc = sqlite3PagerSync(pPager, zSuper);
|
|
}
|
|
IOTRACE(("DBSYNC %p\n", pPager))
|
|
}
|
|
@@ -58054,12 +62082,12 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
|
|
/*
|
|
** When this function is called, the database file has been completely
|
|
** updated to reflect the changes made by the current transaction and
|
|
-** synced to disk. The journal file still exists in the file-system
|
|
+** synced to disk. The journal file still exists in the file-system
|
|
** though, and if a failure occurs at this point it will eventually
|
|
** be used as a hot-journal and the current transaction rolled back.
|
|
**
|
|
-** This function finalizes the journal file, either by deleting,
|
|
-** truncating or partially zeroing it, so that it cannot be used
|
|
+** This function finalizes the journal file, either by deleting,
|
|
+** truncating or partially zeroing it, so that it cannot be used
|
|
** for hot-journal rollback. Once this is done the transaction is
|
|
** irrevocably committed.
|
|
**
|
|
@@ -58085,15 +62113,15 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager *pPager){
|
|
** this transaction, the pager is running in exclusive-mode and is
|
|
** using persistent journals, then this function is a no-op.
|
|
**
|
|
- ** The start of the journal file currently contains a single journal
|
|
+ ** The start of the journal file currently contains a single journal
|
|
** header with the nRec field set to 0. If such a journal is used as
|
|
** a hot-journal during hot-journal rollback, 0 changes will be made
|
|
- ** to the database file. So there is no need to zero the journal
|
|
+ ** to the database file. So there is no need to zero the journal
|
|
** header. Since the pager is in exclusive mode, there is no need
|
|
** to drop any locks either.
|
|
*/
|
|
- if( pPager->eState==PAGER_WRITER_LOCKED
|
|
- && pPager->exclusiveMode
|
|
+ if( pPager->eState==PAGER_WRITER_LOCKED
|
|
+ && pPager->exclusiveMode
|
|
&& pPager->journalMode==PAGER_JOURNALMODE_PERSIST
|
|
){
|
|
assert( pPager->journalOff==JOURNAL_HDR_SZ(pPager) || !pPager->journalOff );
|
|
@@ -58102,12 +62130,12 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager *pPager){
|
|
}
|
|
|
|
PAGERTRACE(("COMMIT %d\n", PAGERID(pPager)));
|
|
- rc = pager_end_transaction(pPager, pPager->setMaster, 1);
|
|
+ rc = pager_end_transaction(pPager, pPager->setSuper, 1);
|
|
return pager_error(pPager, rc);
|
|
}
|
|
|
|
/*
|
|
-** If a write transaction is open, then all changes made within the
|
|
+** If a write transaction is open, then all changes made within the
|
|
** transaction are reverted and the current write-transaction is closed.
|
|
** The pager falls back to PAGER_READER state if successful, or PAGER_ERROR
|
|
** state if an error occurs.
|
|
@@ -58117,14 +62145,14 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager *pPager){
|
|
**
|
|
** Otherwise, in rollback mode, this function performs two functions:
|
|
**
|
|
-** 1) It rolls back the journal file, restoring all database file and
|
|
+** 1) It rolls back the journal file, restoring all database file and
|
|
** in-memory cache pages to the state they were in when the transaction
|
|
** was opened, and
|
|
**
|
|
** 2) It finalizes the journal file, so that it is not used for hot
|
|
** rollback at any point in the future.
|
|
**
|
|
-** Finalization of the journal file (task 2) is only performed if the
|
|
+** Finalization of the journal file (task 2) is only performed if the
|
|
** rollback is successful.
|
|
**
|
|
** In WAL mode, all cache-entries containing data modified within the
|
|
@@ -58137,7 +62165,7 @@ SQLITE_PRIVATE int sqlite3PagerRollback(Pager *pPager){
|
|
PAGERTRACE(("ROLLBACK %d\n", PAGERID(pPager)));
|
|
|
|
/* PagerRollback() is a no-op if called in READER or OPEN state. If
|
|
- ** the pager is already in the ERROR state, the rollback is not
|
|
+ ** the pager is already in the ERROR state, the rollback is not
|
|
** attempted here. Instead, the error code is returned to the caller.
|
|
*/
|
|
assert( assert_pager_state(pPager) );
|
|
@@ -58147,13 +62175,13 @@ SQLITE_PRIVATE int sqlite3PagerRollback(Pager *pPager){
|
|
if( pagerUseWal(pPager) ){
|
|
int rc2;
|
|
rc = sqlite3PagerSavepoint(pPager, SAVEPOINT_ROLLBACK, -1);
|
|
- rc2 = pager_end_transaction(pPager, pPager->setMaster, 0);
|
|
+ rc2 = pager_end_transaction(pPager, pPager->setSuper, 0);
|
|
if( rc==SQLITE_OK ) rc = rc2;
|
|
}else if( !isOpen(pPager->jfd) || pPager->eState==PAGER_WRITER_LOCKED ){
|
|
int eState = pPager->eState;
|
|
rc = pager_end_transaction(pPager, 0, 0);
|
|
if( !MEMDB && eState>PAGER_WRITER_LOCKED ){
|
|
- /* This can happen using journal_mode=off. Move the pager to the error
|
|
+ /* This can happen using journal_mode=off. Move the pager to the error
|
|
** state to indicate that the contents of the cache may not be trusted.
|
|
** Any active readers will get SQLITE_ABORT.
|
|
*/
|
|
@@ -58168,7 +62196,7 @@ SQLITE_PRIVATE int sqlite3PagerRollback(Pager *pPager){
|
|
|
|
assert( pPager->eState==PAGER_READER || rc!=SQLITE_OK );
|
|
assert( rc==SQLITE_OK || rc==SQLITE_FULL || rc==SQLITE_CORRUPT
|
|
- || rc==SQLITE_NOMEM || (rc&0xFF)==SQLITE_IOERR
|
|
+ || rc==SQLITE_NOMEM || (rc&0xFF)==SQLITE_IOERR
|
|
|| rc==SQLITE_CANTOPEN
|
|
);
|
|
|
|
@@ -58200,8 +62228,8 @@ SQLITE_PRIVATE int sqlite3PagerRefcount(Pager *pPager){
|
|
** used by the pager and its associated cache.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3PagerMemUsed(Pager *pPager){
|
|
- int perPageSize = pPager->pageSize + pPager->nExtra + sizeof(PgHdr)
|
|
- + 5*sizeof(void*);
|
|
+ int perPageSize = pPager->pageSize + pPager->nExtra
|
|
+ + (int)(sizeof(PgHdr) + 5*sizeof(void*));
|
|
return perPageSize*sqlite3PcachePagecount(pPager->pPCache)
|
|
+ sqlite3MallocSize(pPager)
|
|
+ pPager->pageSize;
|
|
@@ -58242,8 +62270,8 @@ SQLITE_PRIVATE int *sqlite3PagerStats(Pager *pPager){
|
|
** it was added later.
|
|
**
|
|
** Before returning, *pnVal is incremented by the
|
|
-** current cache hit or miss count, according to the value of eStat. If the
|
|
-** reset parameter is non-zero, the cache hit or miss count is zeroed before
|
|
+** current cache hit or miss count, according to the value of eStat. If the
|
|
+** reset parameter is non-zero, the cache hit or miss count is zeroed before
|
|
** returning.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *pPager, int eStat, int reset, int *pnVal){
|
|
@@ -58270,7 +62298,7 @@ SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *pPager, int eStat, int reset, i
|
|
** Return true if this is an in-memory or temp-file backed pager.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager *pPager){
|
|
- return pPager->tempFile;
|
|
+ return pPager->tempFile || pPager->memVfs;
|
|
}
|
|
|
|
/*
|
|
@@ -58279,7 +62307,7 @@ SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager *pPager){
|
|
** to make up the difference. If the number of savepoints is already
|
|
** equal to nSavepoint, then this function is a no-op.
|
|
**
|
|
-** If a memory allocation fails, SQLITE_NOMEM is returned. If an error
|
|
+** If a memory allocation fails, SQLITE_NOMEM is returned. If an error
|
|
** occurs while opening the sub-journal file, then an IO error code is
|
|
** returned. Otherwise, SQLITE_OK.
|
|
*/
|
|
@@ -58294,7 +62322,7 @@ static SQLITE_NOINLINE int pagerOpenSavepoint(Pager *pPager, int nSavepoint){
|
|
assert( nSavepoint>nCurrent && pPager->useJournal );
|
|
|
|
/* Grow the Pager.aSavepoint array using realloc(). Return SQLITE_NOMEM
|
|
- ** if the allocation fails. Otherwise, zero the new portion in case a
|
|
+ ** if the allocation fails. Otherwise, zero the new portion in case a
|
|
** malloc failure occurs while populating it in the for(...) loop below.
|
|
*/
|
|
aNew = (PagerSavepoint *)sqlite3Realloc(
|
|
@@ -58316,6 +62344,7 @@ static SQLITE_NOINLINE int pagerOpenSavepoint(Pager *pPager, int nSavepoint){
|
|
}
|
|
aNew[ii].iSubRec = pPager->nSubRec;
|
|
aNew[ii].pInSavepoint = sqlite3BitvecCreate(pPager->dbSize);
|
|
+ aNew[ii].bTruncateOnRelease = 1;
|
|
if( !aNew[ii].pInSavepoint ){
|
|
return SQLITE_NOMEM_BKPT;
|
|
}
|
|
@@ -58342,7 +62371,7 @@ SQLITE_PRIVATE int sqlite3PagerOpenSavepoint(Pager *pPager, int nSavepoint){
|
|
|
|
/*
|
|
** This function is called to rollback or release (commit) a savepoint.
|
|
-** The savepoint to release or rollback need not be the most recently
|
|
+** The savepoint to release or rollback need not be the most recently
|
|
** created savepoint.
|
|
**
|
|
** Parameter op is always either SAVEPOINT_ROLLBACK or SAVEPOINT_RELEASE.
|
|
@@ -58350,29 +62379,29 @@ SQLITE_PRIVATE int sqlite3PagerOpenSavepoint(Pager *pPager, int nSavepoint){
|
|
** index iSavepoint. If it is SAVEPOINT_ROLLBACK, then rollback all changes
|
|
** that have occurred since the specified savepoint was created.
|
|
**
|
|
-** The savepoint to rollback or release is identified by parameter
|
|
+** The savepoint to rollback or release is identified by parameter
|
|
** iSavepoint. A value of 0 means to operate on the outermost savepoint
|
|
** (the first created). A value of (Pager.nSavepoint-1) means operate
|
|
** on the most recently created savepoint. If iSavepoint is greater than
|
|
** (Pager.nSavepoint-1), then this function is a no-op.
|
|
**
|
|
** If a negative value is passed to this function, then the current
|
|
-** transaction is rolled back. This is different to calling
|
|
+** transaction is rolled back. This is different to calling
|
|
** sqlite3PagerRollback() because this function does not terminate
|
|
-** the transaction or unlock the database, it just restores the
|
|
-** contents of the database to its original state.
|
|
+** the transaction or unlock the database, it just restores the
|
|
+** contents of the database to its original state.
|
|
**
|
|
-** In any case, all savepoints with an index greater than iSavepoint
|
|
+** In any case, all savepoints with an index greater than iSavepoint
|
|
** are destroyed. If this is a release operation (op==SAVEPOINT_RELEASE),
|
|
** then savepoint iSavepoint is also destroyed.
|
|
**
|
|
** This function may return SQLITE_NOMEM if a memory allocation fails,
|
|
-** or an IO error code if an IO error occurs while rolling back a
|
|
+** or an IO error code if an IO error occurs while rolling back a
|
|
** savepoint. If no errors occur, SQLITE_OK is returned.
|
|
-*/
|
|
+*/
|
|
SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){
|
|
int rc = pPager->errCode;
|
|
-
|
|
+
|
|
#ifdef SQLITE_ENABLE_ZIPVFS
|
|
if( op==SAVEPOINT_RELEASE ) rc = SQLITE_OK;
|
|
#endif
|
|
@@ -58385,7 +62414,7 @@ SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){
|
|
int nNew; /* Number of remaining savepoints after this op. */
|
|
|
|
/* Figure out how many savepoints will still be active after this
|
|
- ** operation. Store this value in nNew. Then free resources associated
|
|
+ ** operation. Store this value in nNew. Then free resources associated
|
|
** with any savepoints that are destroyed by this operation.
|
|
*/
|
|
nNew = iSavepoint + (( op==SAVEPOINT_RELEASE ) ? 0 : 1);
|
|
@@ -58394,16 +62423,18 @@ SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){
|
|
}
|
|
pPager->nSavepoint = nNew;
|
|
|
|
- /* If this is a release of the outermost savepoint, truncate
|
|
- ** the sub-journal to zero bytes in size. */
|
|
+ /* Truncate the sub-journal so that it only includes the parts
|
|
+ ** that are still in use. */
|
|
if( op==SAVEPOINT_RELEASE ){
|
|
- if( nNew==0 && isOpen(pPager->sjfd) ){
|
|
+ PagerSavepoint *pRel = &pPager->aSavepoint[nNew];
|
|
+ if( pRel->bTruncateOnRelease && isOpen(pPager->sjfd) ){
|
|
/* Only truncate if it is an in-memory sub-journal. */
|
|
if( sqlite3JournalIsInMemory(pPager->sjfd) ){
|
|
- rc = sqlite3OsTruncate(pPager->sjfd, 0);
|
|
+ i64 sz = (pPager->pageSize+4)*(i64)pRel->iSubRec;
|
|
+ rc = sqlite3OsTruncate(pPager->sjfd, sz);
|
|
assert( rc==SQLITE_OK );
|
|
}
|
|
- pPager->nSubRec = 0;
|
|
+ pPager->nSubRec = pRel->iSubRec;
|
|
}
|
|
}
|
|
/* Else this is a rollback operation, playback the specified savepoint.
|
|
@@ -58416,14 +62447,14 @@ SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){
|
|
rc = pagerPlaybackSavepoint(pPager, pSavepoint);
|
|
assert(rc!=SQLITE_DONE);
|
|
}
|
|
-
|
|
+
|
|
#ifdef SQLITE_ENABLE_ZIPVFS
|
|
- /* If the cache has been modified but the savepoint cannot be rolled
|
|
+ /* If the cache has been modified but the savepoint cannot be rolled
|
|
** back journal_mode=off, put the pager in the error state. This way,
|
|
** if the VFS used by this pager includes ZipVFS, the entire transaction
|
|
** can be rolled back at the ZipVFS level. */
|
|
- else if(
|
|
- pPager->journalMode==PAGER_JOURNALMODE_OFF
|
|
+ else if(
|
|
+ pPager->journalMode==PAGER_JOURNALMODE_OFF
|
|
&& pPager->eState>=PAGER_WRITER_CACHEMOD
|
|
){
|
|
pPager->errCode = SQLITE_ABORT;
|
|
@@ -58450,8 +62481,12 @@ SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint){
|
|
** sqlite3_uri_parameter() and sqlite3_filename_database() and friends.
|
|
*/
|
|
SQLITE_PRIVATE const char *sqlite3PagerFilename(const Pager *pPager, int nullIfMemDb){
|
|
- static const char zFake[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
|
- return (nullIfMemDb && pPager->memDb) ? &zFake[4] : pPager->zFilename;
|
|
+ static const char zFake[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
+ if( nullIfMemDb && (pPager->memDb || sqlite3IsMemdb(pPager->pVfs)) ){
|
|
+ return &zFake[4];
|
|
+ }else{
|
|
+ return pPager->zFilename;
|
|
+ }
|
|
}
|
|
|
|
/*
|
|
@@ -58470,16 +62505,6 @@ SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager *pPager){
|
|
return pPager->fd;
|
|
}
|
|
|
|
-#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
|
-/*
|
|
-** Reset the lock timeout for pager.
|
|
-*/
|
|
-SQLITE_PRIVATE void sqlite3PagerResetLockTimeout(Pager *pPager){
|
|
- int x = 0;
|
|
- sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_LOCK_TIMEOUT, &x);
|
|
-}
|
|
-#endif
|
|
-
|
|
/*
|
|
** Return the file handle for the journal file (if it exists).
|
|
** This will be either the rollback journal or the WAL file.
|
|
@@ -58499,54 +62524,6 @@ SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager *pPager){
|
|
return pPager->zJournal;
|
|
}
|
|
|
|
-#ifdef SQLITE_HAS_CODEC
|
|
-/*
|
|
-** Set or retrieve the codec for this pager
|
|
-*/
|
|
-SQLITE_PRIVATE void sqlite3PagerSetCodec(
|
|
- Pager *pPager,
|
|
- void *(*xCodec)(void*,void*,Pgno,int),
|
|
- void (*xCodecSizeChng)(void*,int,int),
|
|
- void (*xCodecFree)(void*),
|
|
- void *pCodec
|
|
-){
|
|
- if( pPager->xCodecFree ){
|
|
- pPager->xCodecFree(pPager->pCodec);
|
|
- }else{
|
|
- pager_reset(pPager);
|
|
- }
|
|
- pPager->xCodec = pPager->memDb ? 0 : xCodec;
|
|
- pPager->xCodecSizeChng = xCodecSizeChng;
|
|
- pPager->xCodecFree = xCodecFree;
|
|
- pPager->pCodec = pCodec;
|
|
- setGetterMethod(pPager);
|
|
- pagerReportSize(pPager);
|
|
-}
|
|
-SQLITE_PRIVATE void *sqlite3PagerGetCodec(Pager *pPager){
|
|
- return pPager->pCodec;
|
|
-}
|
|
-
|
|
-/*
|
|
-** This function is called by the wal module when writing page content
|
|
-** into the log file.
|
|
-**
|
|
-** This function returns a pointer to a buffer containing the encrypted
|
|
-** page content. If a malloc fails, this function may return NULL.
|
|
-*/
|
|
-SQLITE_PRIVATE void *sqlite3PagerCodec(PgHdr *pPg){
|
|
- void *aData = 0;
|
|
- CODEC2(pPg->pPager, pPg->pData, pPg->pgno, 6, return 0, aData);
|
|
- return aData;
|
|
-}
|
|
-
|
|
-/*
|
|
-** Return the current pager state
|
|
-*/
|
|
-SQLITE_PRIVATE int sqlite3PagerState(Pager *pPager){
|
|
- return pPager->eState;
|
|
-}
|
|
-#endif /* SQLITE_HAS_CODEC */
|
|
-
|
|
#ifndef SQLITE_OMIT_AUTOVACUUM
|
|
/*
|
|
** Move the page pPg to location pgno in the file.
|
|
@@ -58566,8 +62543,8 @@ SQLITE_PRIVATE int sqlite3PagerState(Pager *pPager){
|
|
** transaction is active).
|
|
**
|
|
** If the fourth argument, isCommit, is non-zero, then this page is being
|
|
-** moved as part of a database reorganization just before the transaction
|
|
-** is being committed. In this case, it is guaranteed that the database page
|
|
+** moved as part of a database reorganization just before the transaction
|
|
+** is being committed. In this case, it is guaranteed that the database page
|
|
** pPg refers to will not be written to again within this transaction.
|
|
**
|
|
** This function may return SQLITE_NOMEM or an IO error code if an error
|
|
@@ -58595,7 +62572,7 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i
|
|
}
|
|
|
|
/* If the page being moved is dirty and has not been saved by the latest
|
|
- ** savepoint, then save the current contents of the page into the
|
|
+ ** savepoint, then save the current contents of the page into the
|
|
** sub-journal now. This is required to handle the following scenario:
|
|
**
|
|
** BEGIN;
|
|
@@ -58618,7 +62595,7 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i
|
|
return rc;
|
|
}
|
|
|
|
- PAGERTRACE(("MOVE %d page %d (needSync=%d) moves to %d\n",
|
|
+ PAGERTRACE(("MOVE %d page %d (needSync=%d) moves to %d\n",
|
|
PAGERID(pPager), pPg->pgno, (pPg->flags&PGHDR_NEED_SYNC)?1:0, pgno));
|
|
IOTRACE(("MOVE %p %d %d\n", pPager, pPg->pgno, pgno))
|
|
|
|
@@ -58626,7 +62603,7 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i
|
|
** be written to, store pPg->pgno in local variable needSyncPgno.
|
|
**
|
|
** If the isCommit flag is set, there is no need to remember that
|
|
- ** the journal needs to be sync()ed before database page pPg->pgno
|
|
+ ** the journal needs to be sync()ed before database page pPg->pgno
|
|
** can be written to. The caller has already promised not to write to it.
|
|
*/
|
|
if( (pPg->flags&PGHDR_NEED_SYNC) && !isCommit ){
|
|
@@ -58637,15 +62614,15 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i
|
|
}
|
|
|
|
/* If the cache contains a page with page-number pgno, remove it
|
|
- ** from its hash chain. Also, if the PGHDR_NEED_SYNC flag was set for
|
|
- ** page pgno before the 'move' operation, it needs to be retained
|
|
+ ** from its hash chain. Also, if the PGHDR_NEED_SYNC flag was set for
|
|
+ ** page pgno before the 'move' operation, it needs to be retained
|
|
** for the page moved there.
|
|
*/
|
|
pPg->flags &= ~PGHDR_NEED_SYNC;
|
|
pPgOld = sqlite3PagerLookup(pPager, pgno);
|
|
assert( !pPgOld || pPgOld->nRef==1 || CORRUPT_DB );
|
|
if( pPgOld ){
|
|
- if( pPgOld->nRef>1 ){
|
|
+ if( NEVER(pPgOld->nRef>1) ){
|
|
sqlite3PagerUnrefNotNull(pPgOld);
|
|
return SQLITE_CORRUPT_BKPT;
|
|
}
|
|
@@ -58673,9 +62650,9 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i
|
|
}
|
|
|
|
if( needSyncPgno ){
|
|
- /* If needSyncPgno is non-zero, then the journal file needs to be
|
|
+ /* If needSyncPgno is non-zero, then the journal file needs to be
|
|
** sync()ed before any data is written to database file page needSyncPgno.
|
|
- ** Currently, no such page exists in the page-cache and the
|
|
+ ** Currently, no such page exists in the page-cache and the
|
|
** "is journaled" bitvec flag has been set. This needs to be remedied by
|
|
** loading the page into the pager-cache and setting the PGHDR_NEED_SYNC
|
|
** flag.
|
|
@@ -58706,9 +62683,9 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i
|
|
#endif
|
|
|
|
/*
|
|
-** The page handle passed as the first argument refers to a dirty page
|
|
-** with a page number other than iNew. This function changes the page's
|
|
-** page number to iNew and sets the value of the PgHdr.flags field to
|
|
+** The page handle passed as the first argument refers to a dirty page
|
|
+** with a page number other than iNew. This function changes the page's
|
|
+** page number to iNew and sets the value of the PgHdr.flags field to
|
|
** the value passed as the third parameter.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3PagerRekey(DbPage *pPg, Pgno iNew, u16 flags){
|
|
@@ -58726,7 +62703,7 @@ SQLITE_PRIVATE void *sqlite3PagerGetData(DbPage *pPg){
|
|
}
|
|
|
|
/*
|
|
-** Return a pointer to the Pager.nExtra bytes of "extra" space
|
|
+** Return a pointer to the Pager.nExtra bytes of "extra" space
|
|
** allocated along with the specified page.
|
|
*/
|
|
SQLITE_PRIVATE void *sqlite3PagerGetExtra(DbPage *pPg){
|
|
@@ -58735,7 +62712,7 @@ SQLITE_PRIVATE void *sqlite3PagerGetExtra(DbPage *pPg){
|
|
|
|
/*
|
|
** Get/set the locking-mode for this pager. Parameter eMode must be one
|
|
-** of PAGER_LOCKINGMODE_QUERY, PAGER_LOCKINGMODE_NORMAL or
|
|
+** of PAGER_LOCKINGMODE_QUERY, PAGER_LOCKINGMODE_NORMAL or
|
|
** PAGER_LOCKINGMODE_EXCLUSIVE. If the parameter is not _QUERY, then
|
|
** the locking-mode is set to the value specified.
|
|
**
|
|
@@ -58780,12 +62757,12 @@ SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *pPager, int eMode){
|
|
u8 eOld = pPager->journalMode; /* Prior journalmode */
|
|
|
|
/* The eMode parameter is always valid */
|
|
- assert( eMode==PAGER_JOURNALMODE_DELETE
|
|
- || eMode==PAGER_JOURNALMODE_TRUNCATE
|
|
- || eMode==PAGER_JOURNALMODE_PERSIST
|
|
- || eMode==PAGER_JOURNALMODE_OFF
|
|
- || eMode==PAGER_JOURNALMODE_WAL
|
|
- || eMode==PAGER_JOURNALMODE_MEMORY );
|
|
+ assert( eMode==PAGER_JOURNALMODE_DELETE /* 0 */
|
|
+ || eMode==PAGER_JOURNALMODE_PERSIST /* 1 */
|
|
+ || eMode==PAGER_JOURNALMODE_OFF /* 2 */
|
|
+ || eMode==PAGER_JOURNALMODE_TRUNCATE /* 3 */
|
|
+ || eMode==PAGER_JOURNALMODE_MEMORY /* 4 */
|
|
+ || eMode==PAGER_JOURNALMODE_WAL /* 5 */ );
|
|
|
|
/* This routine is only called from the OP_JournalMode opcode, and
|
|
** the logic there will never allow a temporary file to be changed
|
|
@@ -58822,7 +62799,6 @@ SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *pPager, int eMode){
|
|
|
|
assert( isOpen(pPager->fd) || pPager->exclusiveMode );
|
|
if( !pPager->exclusiveMode && (eOld & 5)==1 && (eMode & 1)==0 ){
|
|
-
|
|
/* In this case we would like to delete the journal file. If it is
|
|
** not possible, then that is not a problem. Deleting the journal file
|
|
** here is an optimization only.
|
|
@@ -58934,6 +62910,18 @@ 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 ){
|
|
+ /* 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
|
|
+ ** a transaction to initialize pWal. The PRAGMA table_list statement is
|
|
+ ** used for this since it starts transactions on every database file,
|
|
+ ** including all ATTACHed databases. This seems expensive for a single
|
|
+ ** sqlite3_wal_checkpoint() call, but it happens very rarely.
|
|
+ ** https://sqlite.org/forum/forumpost/fd0f19d229156939
|
|
+ */
|
|
+ sqlite3_exec(db, "PRAGMA table_list",0,0,0);
|
|
+ }
|
|
if( pPager->pWal ){
|
|
rc = sqlite3WalCheckpoint(pPager->pWal, db, eMode,
|
|
(eMode==SQLITE_CHECKPOINT_PASSIVE ? 0 : pPager->xBusyHandler),
|
|
@@ -58941,7 +62929,6 @@ SQLITE_PRIVATE int sqlite3PagerCheckpoint(
|
|
pPager->walSyncFlags, pPager->pageSize, (u8 *)pPager->pTmpSpace,
|
|
pnLog, pnCkpt
|
|
);
|
|
- sqlite3PagerResetLockTimeout(pPager);
|
|
}
|
|
return rc;
|
|
}
|
|
@@ -58970,7 +62957,7 @@ static int pagerExclusiveLock(Pager *pPager){
|
|
assert( pPager->eLock==SHARED_LOCK || pPager->eLock==EXCLUSIVE_LOCK );
|
|
rc = pagerLockDb(pPager, EXCLUSIVE_LOCK);
|
|
if( rc!=SQLITE_OK ){
|
|
- /* If the attempt to grab the exclusive lock failed, release the
|
|
+ /* If the attempt to grab the exclusive lock failed, release the
|
|
** pending lock that may have been obtained instead. */
|
|
pagerUnlockDb(pPager, SHARED_LOCK);
|
|
}
|
|
@@ -58979,7 +62966,7 @@ static int pagerExclusiveLock(Pager *pPager){
|
|
}
|
|
|
|
/*
|
|
-** Call sqlite3WalOpen() to open the WAL handle. If the pager is in
|
|
+** Call sqlite3WalOpen() to open the WAL handle. If the pager is in
|
|
** exclusive-locking mode when this function is called, take an EXCLUSIVE
|
|
** lock on the database file and use heap-memory to store the wal-index
|
|
** in. Otherwise, use the normal shared-memory.
|
|
@@ -58990,8 +62977,8 @@ static int pagerOpenWal(Pager *pPager){
|
|
assert( pPager->pWal==0 && 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
|
|
- ** heap-memory for the wal-index instead of the VFS shared-memory
|
|
+ /* If the pager is already in exclusive-mode, the WAL module will use
|
|
+ ** heap-memory for the wal-index instead of the VFS shared-memory
|
|
** implementation. Take the exclusive lock now, before opening the WAL
|
|
** file, to make sure this is safe.
|
|
*/
|
|
@@ -58999,7 +62986,7 @@ static int pagerOpenWal(Pager *pPager){
|
|
rc = pagerExclusiveLock(pPager);
|
|
}
|
|
|
|
- /* Open the connection to the log file. If this operation fails,
|
|
+ /* 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 ){
|
|
@@ -59021,7 +63008,7 @@ static int pagerOpenWal(Pager *pPager){
|
|
** If the pager passed as the first argument is open on a real database
|
|
** file (not a temp file or an in-memory database), and the WAL file
|
|
** is not already open, make an attempt to open it now. If successful,
|
|
-** return SQLITE_OK. If an error occurs or the VFS used by the pager does
|
|
+** return SQLITE_OK. If an error occurs or the VFS used by the pager does
|
|
** not support the xShmXXX() methods, return an error code. *pbOpen is
|
|
** not modified in either case.
|
|
**
|
|
@@ -59063,7 +63050,7 @@ SQLITE_PRIVATE int sqlite3PagerOpenWal(
|
|
** This function is called to close the connection to the log file prior
|
|
** to switching from WAL to rollback mode.
|
|
**
|
|
-** Before closing the log file, this function attempts to take an
|
|
+** Before closing the log file, this function attempts to take an
|
|
** EXCLUSIVE lock on the database file. If this cannot be obtained, an
|
|
** error (SQLITE_BUSY) is returned and the log connection is not closed.
|
|
** If successful, the EXCLUSIVE lock is not released before returning.
|
|
@@ -59089,7 +63076,7 @@ SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager, sqlite3 *db){
|
|
rc = pagerOpenWal(pPager);
|
|
}
|
|
}
|
|
-
|
|
+
|
|
/* Checkpoint and close the log. Because an EXCLUSIVE lock is held on
|
|
** the database file, the log and log-summary files will be deleted.
|
|
*/
|
|
@@ -59106,7 +63093,31 @@ SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager, sqlite3 *db){
|
|
return rc;
|
|
}
|
|
|
|
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
|
+/*
|
|
+** If pager pPager is a wal-mode database not in exclusive locking mode,
|
|
+** invoke the sqlite3WalWriteLock() function on the associated Wal object
|
|
+** with the same db and bLock parameters as were passed to this function.
|
|
+** Return an SQLite error code if an error occurs, or SQLITE_OK otherwise.
|
|
+*/
|
|
+SQLITE_PRIVATE int sqlite3PagerWalWriteLock(Pager *pPager, int bLock){
|
|
+ int rc = SQLITE_OK;
|
|
+ if( pagerUseWal(pPager) && pPager->exclusiveMode==0 ){
|
|
+ rc = sqlite3WalWriteLock(pPager->pWal, bLock);
|
|
+ }
|
|
+ return rc;
|
|
+}
|
|
|
|
+/*
|
|
+** Set the database handle used by the wal layer to determine if
|
|
+** blocking locks are required.
|
|
+*/
|
|
+SQLITE_PRIVATE void sqlite3PagerWalDb(Pager *pPager, sqlite3 *db){
|
|
+ if( pagerUseWal(pPager) ){
|
|
+ sqlite3WalDb(pPager->pWal, db);
|
|
+ }
|
|
+}
|
|
+#endif
|
|
|
|
#ifdef SQLITE_ENABLE_SNAPSHOT
|
|
/*
|
|
@@ -59123,10 +63134,13 @@ SQLITE_PRIVATE int sqlite3PagerSnapshotGet(Pager *pPager, sqlite3_snapshot **ppS
|
|
|
|
/*
|
|
** If this is a WAL database, store a pointer to pSnapshot. Next time a
|
|
-** read transaction is opened, attempt to read from the snapshot it
|
|
+** read transaction is opened, attempt to read from the snapshot it
|
|
** identifies. If this is not a WAL database, return an error.
|
|
*/
|
|
-SQLITE_PRIVATE int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSnapshot){
|
|
+SQLITE_PRIVATE int sqlite3PagerSnapshotOpen(
|
|
+ Pager *pPager,
|
|
+ sqlite3_snapshot *pSnapshot
|
|
+){
|
|
int rc = SQLITE_OK;
|
|
if( pPager->pWal ){
|
|
sqlite3WalSnapshotOpen(pPager->pWal, pSnapshot);
|
|
@@ -59137,7 +63151,7 @@ SQLITE_PRIVATE int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSn
|
|
}
|
|
|
|
/*
|
|
-** If this is a WAL database, call sqlite3WalSnapshotRecover(). If this
|
|
+** If this is a WAL database, call sqlite3WalSnapshotRecover(). If this
|
|
** is not a WAL database, return an error.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3PagerSnapshotRecover(Pager *pPager){
|
|
@@ -59154,7 +63168,7 @@ SQLITE_PRIVATE int sqlite3PagerSnapshotRecover(Pager *pPager){
|
|
** The caller currently has a read transaction open on the database.
|
|
** If this is not a WAL database, SQLITE_ERROR is returned. Otherwise,
|
|
** this function takes a SHARED lock on the CHECKPOINTER slot and then
|
|
-** checks if the snapshot passed as the second argument is still
|
|
+** checks if the snapshot passed as the second argument is still
|
|
** available. If so, SQLITE_OK is returned.
|
|
**
|
|
** If the snapshot is not available, SQLITE_ERROR is returned. Or, if
|
|
@@ -59214,7 +63228,7 @@ SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){
|
|
**
|
|
*************************************************************************
|
|
**
|
|
-** This file contains the implementation of a write-ahead log (WAL) used in
|
|
+** This file contains the implementation of a write-ahead log (WAL) used in
|
|
** "journal_mode=WAL" mode.
|
|
**
|
|
** WRITE-AHEAD LOG (WAL) FILE FORMAT
|
|
@@ -59223,7 +63237,7 @@ SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){
|
|
** Each frame records the revised content of a single page from the
|
|
** database file. All changes to the database are recorded by writing
|
|
** frames into the WAL. Transactions commit when a frame is written that
|
|
-** contains a commit marker. A single WAL can and usually does record
|
|
+** contains a commit marker. A single WAL can and usually does record
|
|
** multiple transactions. Periodically, the content of the WAL is
|
|
** transferred back into the database file in an operation called a
|
|
** "checkpoint".
|
|
@@ -59249,11 +63263,11 @@ SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){
|
|
**
|
|
** Immediately following the wal-header are zero or more frames. Each
|
|
** frame consists of a 24-byte frame-header followed by a <page-size> bytes
|
|
-** of page data. The frame-header is six big-endian 32-bit unsigned
|
|
+** of page data. The frame-header is six big-endian 32-bit unsigned
|
|
** integer values, as follows:
|
|
**
|
|
** 0: Page number.
|
|
-** 4: For commit records, the size of the database image in pages
|
|
+** 4: For commit records, the size of the database image in pages
|
|
** after the commit. For all other records, zero.
|
|
** 8: Salt-1 (copied from the header)
|
|
** 12: Salt-2 (copied from the header)
|
|
@@ -59279,7 +63293,7 @@ SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){
|
|
** the checksum. The checksum is computed by interpreting the input as
|
|
** an even number of unsigned 32-bit integers: x[0] through x[N]. The
|
|
** algorithm used for the checksum is as follows:
|
|
-**
|
|
+**
|
|
** for i from 0 to n-1 step 2:
|
|
** s0 += x[i] + s1;
|
|
** s1 += x[i+1] + s0;
|
|
@@ -59287,7 +63301,7 @@ SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){
|
|
**
|
|
** Note that s0 and s1 are both weighted checksums using fibonacci weights
|
|
** in reverse order (the largest fibonacci weight occurs on the first element
|
|
-** of the sequence being summed.) The s1 value spans all 32-bit
|
|
+** of the sequence being summed.) The s1 value spans all 32-bit
|
|
** terms of the sequence whereas s0 omits the final term.
|
|
**
|
|
** On a checkpoint, the WAL is first VFS.xSync-ed, then valid content of the
|
|
@@ -59320,19 +63334,19 @@ SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){
|
|
** multiple concurrent readers to view different versions of the database
|
|
** content simultaneously.
|
|
**
|
|
-** The reader algorithm in the previous paragraphs works correctly, but
|
|
+** The reader algorithm in the previous paragraphs works correctly, but
|
|
** because frames for page P can appear anywhere within the WAL, the
|
|
** reader has to scan the entire WAL looking for page P frames. If the
|
|
** WAL is large (multiple megabytes is typical) that scan can be slow,
|
|
** and read performance suffers. To overcome this problem, a separate
|
|
** data structure called the wal-index is maintained to expedite the
|
|
** search for frames of a particular page.
|
|
-**
|
|
+**
|
|
** WAL-INDEX FORMAT
|
|
**
|
|
** Conceptually, the wal-index is shared memory, though VFS implementations
|
|
** might choose to implement the wal-index using a mmapped file. Because
|
|
-** the wal-index is shared memory, SQLite does not support journal_mode=WAL
|
|
+** the wal-index is shared memory, SQLite does not support journal_mode=WAL
|
|
** on a network filesystem. All users of the database must be able to
|
|
** share memory.
|
|
**
|
|
@@ -59350,28 +63364,31 @@ SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){
|
|
** byte order of the host computer.
|
|
**
|
|
** The purpose of the wal-index is to answer this question quickly: Given
|
|
-** a page number P and a maximum frame index M, return the index of the
|
|
+** a page number P and a maximum frame index M, return the index of the
|
|
** last frame in the wal before frame M for page P in the WAL, or return
|
|
** NULL if there are no frames for page P in the WAL prior to M.
|
|
**
|
|
** The wal-index consists of a header region, followed by an one or
|
|
-** more index blocks.
|
|
+** more index blocks.
|
|
**
|
|
** The wal-index header contains the total number of frames within the WAL
|
|
** in the mxFrame field.
|
|
**
|
|
-** Each index block except for the first contains information on
|
|
+** Each index block except for the first contains information on
|
|
** HASHTABLE_NPAGE frames. The first index block contains information on
|
|
-** HASHTABLE_NPAGE_ONE frames. The values of HASHTABLE_NPAGE_ONE and
|
|
+** HASHTABLE_NPAGE_ONE frames. The values of HASHTABLE_NPAGE_ONE and
|
|
** HASHTABLE_NPAGE are selected so that together the wal-index header and
|
|
** first index block are the same size as all other index blocks in the
|
|
-** wal-index.
|
|
+** wal-index. The values are:
|
|
+**
|
|
+** HASHTABLE_NPAGE 4096
|
|
+** HASHTABLE_NPAGE_ONE 4062
|
|
**
|
|
** Each index block contains two sections, a page-mapping that contains the
|
|
-** database page number associated with each wal frame, and a hash-table
|
|
+** database page number associated with each wal frame, and a hash-table
|
|
** that allows readers to query an index block for a specific page number.
|
|
** The page-mapping is an array of HASHTABLE_NPAGE (or HASHTABLE_NPAGE_ONE
|
|
-** for the first index block) 32-bit page numbers. The first entry in the
|
|
+** for the first index block) 32-bit page numbers. The first entry in the
|
|
** first index-block contains the database page number corresponding to the
|
|
** first frame in the WAL file. The first entry in the second index block
|
|
** in the WAL file corresponds to the (HASHTABLE_NPAGE_ONE+1)th frame in
|
|
@@ -59392,8 +63409,8 @@ SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){
|
|
**
|
|
** The hash table consists of HASHTABLE_NSLOT 16-bit unsigned integers.
|
|
** HASHTABLE_NSLOT = 2*HASHTABLE_NPAGE, and there is one entry in the
|
|
-** hash table for each page number in the mapping section, so the hash
|
|
-** table is never more than half full. The expected number of collisions
|
|
+** hash table for each page number in the mapping section, so the hash
|
|
+** table is never more than half full. The expected number of collisions
|
|
** prior to finding a match is 1. Each entry of the hash table is an
|
|
** 1-based index of an entry in the mapping section of the same
|
|
** index block. Let K be the 1-based index of the largest entry in
|
|
@@ -59412,12 +63429,12 @@ SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){
|
|
** reached) until an unused hash slot is found. Let the first unused slot
|
|
** be at index iUnused. (iUnused might be less than iKey if there was
|
|
** wrap-around.) Because the hash table is never more than half full,
|
|
-** the search is guaranteed to eventually hit an unused entry. Let
|
|
+** the search is guaranteed to eventually hit an unused entry. Let
|
|
** iMax be the value between iKey and iUnused, closest to iUnused,
|
|
** where aHash[iMax]==P. If there is no iMax entry (if there exists
|
|
** no hash slot such that aHash[i]==p) then page P is not in the
|
|
** current index block. Otherwise the iMax-th mapping entry of the
|
|
-** current index block corresponds to the last entry that references
|
|
+** current index block corresponds to the last entry that references
|
|
** page P.
|
|
**
|
|
** A hash search begins with the last index block and moves toward the
|
|
@@ -59442,7 +63459,7 @@ SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){
|
|
** if no values greater than K0 had ever been inserted into the hash table
|
|
** in the first place - which is what reader one wants. Meanwhile, the
|
|
** second reader using K1 will see additional values that were inserted
|
|
-** later, which is exactly what reader two wants.
|
|
+** later, which is exactly what reader two wants.
|
|
**
|
|
** When a rollback occurs, the value of K is decreased. Hash table entries
|
|
** that correspond to frames greater than the new K value are removed
|
|
@@ -59462,18 +63479,6 @@ SQLITE_PRIVATE int sqlite3WalTrace = 0;
|
|
# define WALTRACE(X)
|
|
#endif
|
|
|
|
-/*
|
|
-** WAL mode depends on atomic aligned 32-bit loads and stores in a few
|
|
-** places. The following macros try to make this explicit.
|
|
-*/
|
|
-#if GCC_VESRION>=5004000
|
|
-# define AtomicLoad(PTR) __atomic_load_n((PTR),__ATOMIC_RELAXED)
|
|
-# define AtomicStore(PTR,VAL) __atomic_store_n((PTR),(VAL),__ATOMIC_RELAXED)
|
|
-#else
|
|
-# define AtomicLoad(PTR) (*(PTR))
|
|
-# define AtomicStore(PTR,VAL) (*(PTR) = (VAL))
|
|
-#endif
|
|
-
|
|
/*
|
|
** The maximum (and only) versions of the wal and wal-index formats
|
|
** that may be interpreted by this version of SQLite.
|
|
@@ -59482,7 +63487,7 @@ SQLITE_PRIVATE int sqlite3WalTrace = 0;
|
|
** values in the wal-header are correct and (b) the version field is not
|
|
** WAL_MAX_VERSION, recovery fails and SQLite returns SQLITE_CANTOPEN.
|
|
**
|
|
-** Similarly, if a client successfully reads a wal-index header (i.e. the
|
|
+** Similarly, if a client successfully reads a wal-index header (i.e. the
|
|
** checksum test is successful) and finds that the version field is not
|
|
** WALINDEX_MAX_VERSION, then no read-transaction is opened and SQLite
|
|
** returns SQLITE_CANTOPEN.
|
|
@@ -59529,7 +63534,7 @@ typedef struct WalCkptInfo WalCkptInfo;
|
|
**
|
|
** The szPage value can be any power of 2 between 512 and 32768, inclusive.
|
|
** Or it can be 1 to represent a 65536-byte page. The latter case was
|
|
-** added in 3.7.1 when support for 64K pages was added.
|
|
+** added in 3.7.1 when support for 64K pages was added.
|
|
*/
|
|
struct WalIndexHdr {
|
|
u32 iVersion; /* Wal-index version */
|
|
@@ -59571,7 +63576,7 @@ struct WalIndexHdr {
|
|
** There is one entry in aReadMark[] for each reader lock. If a reader
|
|
** holds read-lock K, then the value in aReadMark[K] is no greater than
|
|
** the mxFrame for that reader. The value READMARK_NOT_USED (0xffffffff)
|
|
-** for any aReadMark[] means that entry is unused. aReadMark[0] is
|
|
+** 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
|
|
** WAL_READ_LOCK(0) always ignore the entire WAL and read all content
|
|
@@ -59591,7 +63596,7 @@ struct WalIndexHdr {
|
|
** previous sentence is when nBackfill equals mxFrame (meaning that everything
|
|
** in the WAL has been backfilled into the database) then new readers
|
|
** will choose aReadMark[0] which has value 0 and hence such reader will
|
|
-** get all their all content directly from the database file and ignore
|
|
+** get all their all content directly from the database file and ignore
|
|
** the WAL.
|
|
**
|
|
** Writers normally append new frames to the end of the WAL. However,
|
|
@@ -59613,6 +63618,70 @@ struct WalCkptInfo {
|
|
};
|
|
#define READMARK_NOT_USED 0xffffffff
|
|
|
|
+/*
|
|
+** This is a schematic view of the complete 136-byte header of the
|
|
+** wal-index file (also known as the -shm file):
|
|
+**
|
|
+** +-----------------------------+
|
|
+** 0: | iVersion | \
|
|
+** +-----------------------------+ |
|
|
+** 4: | (unused padding) | |
|
|
+** +-----------------------------+ |
|
|
+** 8: | iChange | |
|
|
+** +-------+-------+-------------+ |
|
|
+** 12: | bInit | bBig | szPage | |
|
|
+** +-------+-------+-------------+ |
|
|
+** 16: | mxFrame | | First copy of the
|
|
+** +-----------------------------+ | WalIndexHdr object
|
|
+** 20: | nPage | |
|
|
+** +-----------------------------+ |
|
|
+** 24: | aFrameCksum | |
|
|
+** | | |
|
|
+** +-----------------------------+ |
|
|
+** 32: | aSalt | |
|
|
+** | | |
|
|
+** +-----------------------------+ |
|
|
+** 40: | aCksum | |
|
|
+** | | /
|
|
+** +-----------------------------+
|
|
+** 48: | iVersion | \
|
|
+** +-----------------------------+ |
|
|
+** 52: | (unused padding) | |
|
|
+** +-----------------------------+ |
|
|
+** 56: | iChange | |
|
|
+** +-------+-------+-------------+ |
|
|
+** 60: | bInit | bBig | szPage | |
|
|
+** +-------+-------+-------------+ | Second copy of the
|
|
+** 64: | mxFrame | | WalIndexHdr
|
|
+** +-----------------------------+ |
|
|
+** 68: | nPage | |
|
|
+** +-----------------------------+ |
|
|
+** 72: | aFrameCksum | |
|
|
+** | | |
|
|
+** +-----------------------------+ |
|
|
+** 80: | aSalt | |
|
|
+** | | |
|
|
+** +-----------------------------+ |
|
|
+** 88: | aCksum | |
|
|
+** | | /
|
|
+** +-----------------------------+
|
|
+** 96: | nBackfill |
|
|
+** +-----------------------------+
|
|
+** 100: | 5 read marks |
|
|
+** | |
|
|
+** | |
|
|
+** | |
|
|
+** | |
|
|
+** +-------+-------+------+------+
|
|
+** 120: | Write | Ckpt | Rcvr | Rd0 | \
|
|
+** +-------+-------+------+------+ ) 8 lock bytes
|
|
+** | Read1 | Read2 | Rd3 | Rd4 | /
|
|
+** +-------+-------+------+------+
|
|
+** 128: | nBackfillAttempted |
|
|
+** +-----------------------------+
|
|
+** 132: | (unused padding) |
|
|
+** +-----------------------------+
|
|
+*/
|
|
|
|
/* A block of WALINDEX_LOCK_RESERVED bytes beginning at
|
|
** WALINDEX_LOCK_OFFSET is reserved for locks. Since some systems
|
|
@@ -59633,14 +63702,14 @@ struct WalCkptInfo {
|
|
** big-endian format in the first 4 bytes of a WAL file.
|
|
**
|
|
** If the LSB is set, then the checksums for each frame within the WAL
|
|
-** file are calculated by treating all data as an array of 32-bit
|
|
-** big-endian words. Otherwise, they are calculated by interpreting
|
|
+** file are calculated by treating all data as an array of 32-bit
|
|
+** big-endian words. Otherwise, they are calculated by interpreting
|
|
** all data as 32-bit little-endian words.
|
|
*/
|
|
#define WAL_MAGIC 0x377f0682
|
|
|
|
/*
|
|
-** Return the offset of frame iFrame in the write-ahead log file,
|
|
+** Return the offset of frame iFrame in the write-ahead log file,
|
|
** assuming a database page size of szPage bytes. The offset returned
|
|
** is to the start of the write-ahead log frame-header.
|
|
*/
|
|
@@ -59683,13 +63752,16 @@ struct Wal {
|
|
#ifdef SQLITE_ENABLE_SNAPSHOT
|
|
WalIndexHdr *pSnapshot; /* Start transaction here if not NULL */
|
|
#endif
|
|
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
|
+ sqlite3 *db;
|
|
+#endif
|
|
};
|
|
|
|
/*
|
|
** Candidate values for Wal.exclusiveMode.
|
|
*/
|
|
#define WAL_NORMAL_MODE 0
|
|
-#define WAL_EXCLUSIVE_MODE 1
|
|
+#define WAL_EXCLUSIVE_MODE 1
|
|
#define WAL_HEAPMEMORY_MODE 2
|
|
|
|
/*
|
|
@@ -59708,7 +63780,7 @@ typedef u16 ht_slot;
|
|
/*
|
|
** This structure is used to implement an iterator that loops through
|
|
** all frames in the WAL in database page order. Where two or more frames
|
|
-** correspond to the same database page, the iterator visits only the
|
|
+** correspond to the same database page, the iterator visits only the
|
|
** frame most recently written to the WAL (in other words, the frame with
|
|
** the largest index).
|
|
**
|
|
@@ -59721,7 +63793,7 @@ typedef u16 ht_slot;
|
|
** This functionality is used by the checkpoint code (see walCheckpoint()).
|
|
*/
|
|
struct WalIterator {
|
|
- int iPrior; /* Last result returned from the iterator */
|
|
+ u32 iPrior; /* Last result returned from the iterator */
|
|
int nSegment; /* Number of entries in aSegment[] */
|
|
struct WalSegment {
|
|
int iNext; /* Next slot in aIndex[] not yet returned */
|
|
@@ -59744,7 +63816,7 @@ struct WalIterator {
|
|
#define HASHTABLE_HASH_1 383 /* Should be prime */
|
|
#define HASHTABLE_NSLOT (HASHTABLE_NPAGE*2) /* Must be a power of 2 */
|
|
|
|
-/*
|
|
+/*
|
|
** The block of page numbers associated with the first hash-table in a
|
|
** wal-index is smaller than usual. This is so that there is a complete
|
|
** hash-table on each aligned 32KB page of the wal-index.
|
|
@@ -59766,9 +63838,13 @@ struct WalIterator {
|
|
** so. It is safe to enlarge the wal-index if pWal->writeLock is true
|
|
** or pWal->exclusiveMode==WAL_HEAPMEMORY_MODE.
|
|
**
|
|
-** If this call is successful, *ppPage is set to point to the wal-index
|
|
-** page and SQLITE_OK is returned. If an error (an OOM or VFS error) occurs,
|
|
-** then an SQLite error code is returned and *ppPage is set to 0.
|
|
+** Three possible result scenarios:
|
|
+**
|
|
+** (1) rc==SQLITE_OK and *ppPage==Requested-Wal-Index-Page
|
|
+** (2) rc>=SQLITE_ERROR and *ppPage==NULL
|
|
+** (3) rc==SQLITE_OK and *ppPage==NULL // only if iPage==0
|
|
+**
|
|
+** Scenario (3) can only occur when pWal->writeLock is false and iPage==0
|
|
*/
|
|
static SQLITE_NOINLINE int walIndexPageRealloc(
|
|
Wal *pWal, /* The WAL context */
|
|
@@ -59781,7 +63857,7 @@ static SQLITE_NOINLINE int walIndexPageRealloc(
|
|
if( pWal->nWiData<=iPage ){
|
|
sqlite3_int64 nByte = sizeof(u32*)*(iPage+1);
|
|
volatile u32 **apNew;
|
|
- apNew = (volatile u32 **)sqlite3_realloc64((void *)pWal->apWiData, nByte);
|
|
+ apNew = (volatile u32 **)sqlite3Realloc((void *)pWal->apWiData, nByte);
|
|
if( !apNew ){
|
|
*ppPage = 0;
|
|
return SQLITE_NOMEM_BKPT;
|
|
@@ -59798,12 +63874,16 @@ static SQLITE_NOINLINE int walIndexPageRealloc(
|
|
pWal->apWiData[iPage] = (u32 volatile *)sqlite3MallocZero(WALINDEX_PGSZ);
|
|
if( !pWal->apWiData[iPage] ) rc = SQLITE_NOMEM_BKPT;
|
|
}else{
|
|
- rc = sqlite3OsShmMap(pWal->pDbFd, iPage, WALINDEX_PGSZ,
|
|
+ rc = sqlite3OsShmMap(pWal->pDbFd, iPage, WALINDEX_PGSZ,
|
|
pWal->writeLock, (void volatile **)&pWal->apWiData[iPage]
|
|
);
|
|
- assert( pWal->apWiData[iPage]!=0 || rc!=SQLITE_OK || pWal->writeLock==0 );
|
|
+ assert( pWal->apWiData[iPage]!=0
|
|
+ || rc!=SQLITE_OK
|
|
+ || (pWal->writeLock==0 && iPage==0) );
|
|
testcase( pWal->apWiData[iPage]==0 && rc==SQLITE_OK );
|
|
- if( (rc&0xff)==SQLITE_READONLY ){
|
|
+ if( rc==SQLITE_OK ){
|
|
+ if( iPage>0 && sqlite3FaultSim(600) ) rc = SQLITE_NOMEM;
|
|
+ }else if( (rc&0xff)==SQLITE_READONLY ){
|
|
pWal->readOnly |= WAL_SHM_RDONLY;
|
|
if( rc==SQLITE_READONLY ){
|
|
rc = SQLITE_OK;
|
|
@@ -59855,7 +63935,7 @@ static volatile WalIndexHdr *walIndexHdr(Wal *pWal){
|
|
)
|
|
|
|
/*
|
|
-** Generate or extend an 8 byte checksum based on the data in
|
|
+** Generate or extend an 8 byte checksum based on the data in
|
|
** array aByte[] and the initial values of aIn[0] and aIn[1] (or
|
|
** initial values of 0 and 0 if aIn==NULL).
|
|
**
|
|
@@ -59902,18 +63982,35 @@ static void walChecksumBytes(
|
|
aOut[1] = s2;
|
|
}
|
|
|
|
+/*
|
|
+** If there is the possibility of concurrent access to the SHM file
|
|
+** from multiple threads and/or processes, then do a memory barrier.
|
|
+*/
|
|
static void walShmBarrier(Wal *pWal){
|
|
if( pWal->exclusiveMode!=WAL_HEAPMEMORY_MODE ){
|
|
sqlite3OsShmBarrier(pWal->pDbFd);
|
|
}
|
|
}
|
|
|
|
+/*
|
|
+** Add the SQLITE_NO_TSAN as part of the return-type of a function
|
|
+** definition as a hint that the function contains constructs that
|
|
+** might give false-positive TSAN warnings.
|
|
+**
|
|
+** See tag-20200519-1.
|
|
+*/
|
|
+#if defined(__clang__) && !defined(SQLITE_NO_TSAN)
|
|
+# define SQLITE_NO_TSAN __attribute__((no_sanitize_thread))
|
|
+#else
|
|
+# define SQLITE_NO_TSAN
|
|
+#endif
|
|
+
|
|
/*
|
|
** Write the header information in pWal->hdr into the wal-index.
|
|
**
|
|
** The checksum on pWal->hdr is updated before it is written.
|
|
*/
|
|
-static void walIndexWriteHdr(Wal *pWal){
|
|
+static SQLITE_NO_TSAN void walIndexWriteHdr(Wal *pWal){
|
|
volatile WalIndexHdr *aHdr = walIndexHdr(pWal);
|
|
const int nCksum = offsetof(WalIndexHdr, aCksum);
|
|
|
|
@@ -59921,6 +64018,7 @@ static void walIndexWriteHdr(Wal *pWal){
|
|
pWal->hdr.isInit = 1;
|
|
pWal->hdr.iVersion = WALINDEX_MAX_VERSION;
|
|
walChecksumBytes(1, (u8*)&pWal->hdr, nCksum, 0, pWal->hdr.aCksum);
|
|
+ /* Possible TSAN false-positive. See tag-20200519-1 */
|
|
memcpy((void*)&aHdr[1], (const void*)&pWal->hdr, sizeof(WalIndexHdr));
|
|
walShmBarrier(pWal);
|
|
memcpy((void*)&aHdr[0], (const void*)&pWal->hdr, sizeof(WalIndexHdr));
|
|
@@ -59928,11 +64026,11 @@ static void walIndexWriteHdr(Wal *pWal){
|
|
|
|
/*
|
|
** This function encodes a single frame header and writes it to a buffer
|
|
-** supplied by the caller. A frame-header is made up of a series of
|
|
+** supplied by the caller. A frame-header is made up of a series of
|
|
** 4-byte big-endian integers, as follows:
|
|
**
|
|
** 0: Page number.
|
|
-** 4: For commit records, the size of the database image in pages
|
|
+** 4: For commit records, the size of the database image in pages
|
|
** after the commit. For all other records, zero.
|
|
** 8: Salt-1 (copied from the wal-header)
|
|
** 12: Salt-2 (copied from the wal-header)
|
|
@@ -59983,7 +64081,7 @@ static int walDecodeFrame(
|
|
assert( WAL_FRAME_HDRSIZE==24 );
|
|
|
|
/* A frame is only valid if the salt values in the frame-header
|
|
- ** match the salt values in the wal-header.
|
|
+ ** match the salt values in the wal-header.
|
|
*/
|
|
if( memcmp(&pWal->hdr.aSalt, &aFrame[8], 8)!=0 ){
|
|
return 0;
|
|
@@ -59997,15 +64095,15 @@ static int walDecodeFrame(
|
|
}
|
|
|
|
/* A frame is only valid if a checksum of the WAL header,
|
|
- ** all prior frams, the first 16 bytes of this frame-header,
|
|
- ** and the frame-data matches the checksum in the last 8
|
|
+ ** all prior frams, the first 16 bytes of this frame-header,
|
|
+ ** and the frame-data matches the checksum in the last 8
|
|
** bytes of this frame-header.
|
|
*/
|
|
nativeCksum = (pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN);
|
|
walChecksumBytes(nativeCksum, aFrame, 8, aCksum, aCksum);
|
|
walChecksumBytes(nativeCksum, aData, pWal->szPage, aCksum, aCksum);
|
|
- if( aCksum[0]!=sqlite3Get4byte(&aFrame[16])
|
|
- || aCksum[1]!=sqlite3Get4byte(&aFrame[20])
|
|
+ if( aCksum[0]!=sqlite3Get4byte(&aFrame[16])
|
|
+ || aCksum[1]!=sqlite3Get4byte(&aFrame[20])
|
|
){
|
|
/* Checksum failed. */
|
|
return 0;
|
|
@@ -60040,7 +64138,7 @@ static const char *walLockName(int lockIdx){
|
|
}
|
|
}
|
|
#endif /*defined(SQLITE_TEST) || defined(SQLITE_DEBUG) */
|
|
-
|
|
+
|
|
|
|
/*
|
|
** Set or release locks on the WAL. Locks are either shared or exclusive.
|
|
@@ -60056,7 +64154,7 @@ static int walLockShared(Wal *pWal, int lockIdx){
|
|
SQLITE_SHM_LOCK | SQLITE_SHM_SHARED);
|
|
WALTRACE(("WAL%p: acquire SHARED-%s %s\n", pWal,
|
|
walLockName(lockIdx), rc ? "failed" : "ok"));
|
|
- VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && rc!=SQLITE_BUSY); )
|
|
+ VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && (rc&0xFF)!=SQLITE_BUSY); )
|
|
return rc;
|
|
}
|
|
static void walUnlockShared(Wal *pWal, int lockIdx){
|
|
@@ -60072,7 +64170,7 @@ static int walLockExclusive(Wal *pWal, int lockIdx, int n){
|
|
SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE);
|
|
WALTRACE(("WAL%p: acquire EXCLUSIVE-%s cnt=%d %s\n", pWal,
|
|
walLockName(lockIdx), n, rc ? "failed" : "ok"));
|
|
- VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && rc!=SQLITE_BUSY); )
|
|
+ VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && (rc&0xFF)!=SQLITE_BUSY); )
|
|
return rc;
|
|
}
|
|
static void walUnlockExclusive(Wal *pWal, int lockIdx, int n){
|
|
@@ -60109,19 +64207,19 @@ struct WalHashLoc {
|
|
u32 iZero; /* One less than the frame number of first indexed*/
|
|
};
|
|
|
|
-/*
|
|
+/*
|
|
** Return pointers to the hash table and page number array stored on
|
|
** page iHash of the wal-index. The wal-index is broken into 32KB pages
|
|
** numbered starting from 0.
|
|
**
|
|
** Set output variable pLoc->aHash to point to the start of the hash table
|
|
-** in the wal-index file. Set pLoc->iZero to one less than the frame
|
|
+** in the wal-index file. Set pLoc->iZero to one less than the frame
|
|
** number of the first frame indexed by this hash table. If a
|
|
-** slot in the hash table is set to N, it refers to frame number
|
|
+** slot in the hash table is set to N, it refers to frame number
|
|
** (pLoc->iZero+N) in the log.
|
|
**
|
|
-** Finally, set pLoc->aPgno so that pLoc->aPgno[1] is the page number of the
|
|
-** first frame indexed by the hash table, frame (pLoc->iZero+1).
|
|
+** Finally, set pLoc->aPgno so that pLoc->aPgno[0] is the page number of the
|
|
+** first frame indexed by the hash table, frame (pLoc->iZero).
|
|
*/
|
|
static int walHashGet(
|
|
Wal *pWal, /* WAL handle */
|
|
@@ -60133,7 +64231,7 @@ static int walHashGet(
|
|
rc = walIndexPage(pWal, iHash, &pLoc->aPgno);
|
|
assert( rc==SQLITE_OK || iHash>0 );
|
|
|
|
- if( rc==SQLITE_OK ){
|
|
+ if( pLoc->aPgno ){
|
|
pLoc->aHash = (volatile ht_slot *)&pLoc->aPgno[HASHTABLE_NPAGE];
|
|
if( iHash==0 ){
|
|
pLoc->aPgno = &pLoc->aPgno[WALINDEX_HDR_SIZE/sizeof(u32)];
|
|
@@ -60141,7 +64239,8 @@ static int walHashGet(
|
|
}else{
|
|
pLoc->iZero = HASHTABLE_NPAGE_ONE + (iHash-1)*HASHTABLE_NPAGE;
|
|
}
|
|
- pLoc->aPgno = &pLoc->aPgno[-1];
|
|
+ }else if( NEVER(rc==SQLITE_OK) ){
|
|
+ rc = SQLITE_ERROR;
|
|
}
|
|
return rc;
|
|
}
|
|
@@ -60149,7 +64248,7 @@ static int walHashGet(
|
|
/*
|
|
** Return the number of the wal-index page that contains the hash-table
|
|
** and page-number array that contain entries corresponding to WAL frame
|
|
-** iFrame. The wal-index is broken up into 32KB pages. Wal-index pages
|
|
+** iFrame. The wal-index is broken up into 32KB pages. Wal-index pages
|
|
** are numbered starting from 0.
|
|
*/
|
|
static int walFramePage(u32 iFrame){
|
|
@@ -60160,6 +64259,7 @@ static int walFramePage(u32 iFrame){
|
|
&& (iHash>=2 || iFrame<=HASHTABLE_NPAGE_ONE+HASHTABLE_NPAGE)
|
|
&& (iHash<=2 || iFrame>(HASHTABLE_NPAGE_ONE+2*HASHTABLE_NPAGE))
|
|
);
|
|
+ assert( iHash>=0 );
|
|
return iHash;
|
|
}
|
|
|
|
@@ -60191,7 +64291,6 @@ static void walCleanupHash(Wal *pWal){
|
|
int iLimit = 0; /* Zero values greater than this */
|
|
int nByte; /* Number of bytes to zero in aPgno[] */
|
|
int i; /* Used to iterate through aHash[] */
|
|
- int rc; /* Return code form walHashGet() */
|
|
|
|
assert( pWal->writeLock );
|
|
testcase( pWal->hdr.mxFrame==HASHTABLE_NPAGE_ONE-1 );
|
|
@@ -60200,14 +64299,14 @@ static void walCleanupHash(Wal *pWal){
|
|
|
|
if( pWal->hdr.mxFrame==0 ) return;
|
|
|
|
- /* Obtain pointers to the hash-table and page-number array containing
|
|
+ /* Obtain pointers to the hash-table and page-number array containing
|
|
** the entry that corresponds to frame pWal->hdr.mxFrame. It is guaranteed
|
|
** that the page said hash-table and array reside on is already mapped.(1)
|
|
*/
|
|
assert( pWal->nWiData>walFramePage(pWal->hdr.mxFrame) );
|
|
assert( pWal->apWiData[walFramePage(pWal->hdr.mxFrame)] );
|
|
- rc = walHashGet(pWal, walFramePage(pWal->hdr.mxFrame), &sLoc);
|
|
- if( NEVER(rc) ) return; /* Defense-in-depth, in case (1) above is wrong */
|
|
+ i = walHashGet(pWal, walFramePage(pWal->hdr.mxFrame), &sLoc);
|
|
+ if( NEVER(i) ) return; /* Defense-in-depth, in case (1) above is wrong */
|
|
|
|
/* Zero all hash-table entries that correspond to frame numbers greater
|
|
** than pWal->hdr.mxFrame.
|
|
@@ -60219,12 +64318,13 @@ static void walCleanupHash(Wal *pWal){
|
|
sLoc.aHash[i] = 0;
|
|
}
|
|
}
|
|
-
|
|
+
|
|
/* Zero the entries in the aPgno array that correspond to frames with
|
|
- ** frame numbers greater than pWal->hdr.mxFrame.
|
|
+ ** frame numbers greater than pWal->hdr.mxFrame.
|
|
*/
|
|
- nByte = (int)((char *)sLoc.aHash - (char *)&sLoc.aPgno[iLimit+1]);
|
|
- memset((void *)&sLoc.aPgno[iLimit+1], 0, nByte);
|
|
+ nByte = (int)((char *)sLoc.aHash - (char *)&sLoc.aPgno[iLimit]);
|
|
+ assert( nByte>=0 );
|
|
+ memset((void *)&sLoc.aPgno[iLimit], 0, nByte);
|
|
|
|
#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
|
|
/* Verify that the every entry in the mapping region is still reachable
|
|
@@ -60233,11 +64333,11 @@ static void walCleanupHash(Wal *pWal){
|
|
if( iLimit ){
|
|
int j; /* Loop counter */
|
|
int iKey; /* Hash key */
|
|
- for(j=1; j<=iLimit; j++){
|
|
+ for(j=0; j<iLimit; j++){
|
|
for(iKey=walHash(sLoc.aPgno[j]);sLoc.aHash[iKey];iKey=walNextHash(iKey)){
|
|
- if( sLoc.aHash[iKey]==j ) break;
|
|
+ if( sLoc.aHash[iKey]==j+1 ) break;
|
|
}
|
|
- assert( sLoc.aHash[iKey]==j );
|
|
+ assert( sLoc.aHash[iKey]==j+1 );
|
|
}
|
|
}
|
|
#endif /* SQLITE_ENABLE_EXPENSIVE_ASSERT */
|
|
@@ -60264,25 +64364,25 @@ static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){
|
|
|
|
idx = iFrame - sLoc.iZero;
|
|
assert( idx <= HASHTABLE_NSLOT/2 + 1 );
|
|
-
|
|
+
|
|
/* If this is the first entry to be added to this hash-table, zero the
|
|
- ** entire hash table and aPgno[] array before proceeding.
|
|
+ ** entire hash table and aPgno[] array before proceeding.
|
|
*/
|
|
if( idx==1 ){
|
|
- int nByte = (int)((u8 *)&sLoc.aHash[HASHTABLE_NSLOT]
|
|
- - (u8 *)&sLoc.aPgno[1]);
|
|
- memset((void*)&sLoc.aPgno[1], 0, nByte);
|
|
+ int nByte = (int)((u8*)&sLoc.aHash[HASHTABLE_NSLOT] - (u8*)sLoc.aPgno);
|
|
+ assert( nByte>=0 );
|
|
+ memset((void*)sLoc.aPgno, 0, nByte);
|
|
}
|
|
|
|
/* If the entry in aPgno[] is already set, then the previous writer
|
|
** must have exited unexpectedly in the middle of a transaction (after
|
|
- ** writing one or more dirty pages to the WAL to free up memory).
|
|
- ** Remove the remnants of that writers uncommitted transaction from
|
|
+ ** writing one or more dirty pages to the WAL to free up memory).
|
|
+ ** Remove the remnants of that writers uncommitted transaction from
|
|
** the hash-table before writing any new entries.
|
|
*/
|
|
- if( sLoc.aPgno[idx] ){
|
|
+ if( sLoc.aPgno[idx-1] ){
|
|
walCleanupHash(pWal);
|
|
- assert( !sLoc.aPgno[idx] );
|
|
+ assert( !sLoc.aPgno[idx-1] );
|
|
}
|
|
|
|
/* Write the aPgno[] array entry and the hash-table slot. */
|
|
@@ -60290,8 +64390,8 @@ static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){
|
|
for(iKey=walHash(iPage); sLoc.aHash[iKey]; iKey=walNextHash(iKey)){
|
|
if( (nCollide--)==0 ) return SQLITE_CORRUPT_BKPT;
|
|
}
|
|
- sLoc.aPgno[idx] = iPage;
|
|
- sLoc.aHash[iKey] = (ht_slot)idx;
|
|
+ sLoc.aPgno[idx-1] = iPage;
|
|
+ AtomicStore(&sLoc.aHash[iKey], (ht_slot)idx);
|
|
|
|
#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
|
|
/* Verify that the number of entries in the hash table exactly equals
|
|
@@ -60311,25 +64411,24 @@ static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){
|
|
*/
|
|
if( (idx&0x3ff)==0 ){
|
|
int i; /* Loop counter */
|
|
- for(i=1; i<=idx; i++){
|
|
+ for(i=0; i<idx; i++){
|
|
for(iKey=walHash(sLoc.aPgno[i]);
|
|
sLoc.aHash[iKey];
|
|
iKey=walNextHash(iKey)){
|
|
- if( sLoc.aHash[iKey]==i ) break;
|
|
+ if( sLoc.aHash[iKey]==i+1 ) break;
|
|
}
|
|
- assert( sLoc.aHash[iKey]==i );
|
|
+ assert( sLoc.aHash[iKey]==i+1 );
|
|
}
|
|
}
|
|
#endif /* SQLITE_ENABLE_EXPENSIVE_ASSERT */
|
|
}
|
|
|
|
-
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*
|
|
-** Recover the wal-index by reading the write-ahead log file.
|
|
+** Recover the wal-index by reading the write-ahead log file.
|
|
**
|
|
** This routine first tries to establish an exclusive lock on the
|
|
** wal-index to prevent other threads/processes from doing anything
|
|
@@ -60356,12 +64455,6 @@ static int walIndexRecover(Wal *pWal){
|
|
assert( pWal->writeLock );
|
|
iLock = WAL_ALL_BUT_WRITE + pWal->ckptLock;
|
|
rc = walLockExclusive(pWal, iLock, WAL_READ_LOCK(0)-iLock);
|
|
- if( rc==SQLITE_OK ){
|
|
- rc = walLockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
|
|
- if( rc!=SQLITE_OK ){
|
|
- walUnlockExclusive(pWal, iLock, WAL_READ_LOCK(0)-iLock);
|
|
- }
|
|
- }
|
|
if( rc ){
|
|
return rc;
|
|
}
|
|
@@ -60377,15 +64470,16 @@ static int walIndexRecover(Wal *pWal){
|
|
|
|
if( nSize>WAL_HDRSIZE ){
|
|
u8 aBuf[WAL_HDRSIZE]; /* Buffer to load WAL header into */
|
|
+ u32 *aPrivate = 0; /* Heap copy of *-shm hash being populated */
|
|
u8 *aFrame = 0; /* Malloc'd buffer to load entire frame */
|
|
int szFrame; /* Number of bytes in buffer aFrame[] */
|
|
u8 *aData; /* Pointer to data part of aFrame buffer */
|
|
- int iFrame; /* Index of last frame read */
|
|
- i64 iOffset; /* Next offset to read from log file */
|
|
int szPage; /* Page size according to the log */
|
|
u32 magic; /* Magic value read from WAL header */
|
|
u32 version; /* Magic value read from WAL header */
|
|
int isValid; /* True if this frame is valid */
|
|
+ u32 iPg; /* Current 32KB wal-index page */
|
|
+ u32 iLastFrame; /* Last frame in wal, based on nSize alone */
|
|
|
|
/* Read in the WAL header. */
|
|
rc = sqlite3OsRead(pWal->pWalFd, aBuf, WAL_HDRSIZE, 0);
|
|
@@ -60394,16 +64488,16 @@ static int walIndexRecover(Wal *pWal){
|
|
}
|
|
|
|
/* If the database page size is not a power of two, or is greater than
|
|
- ** SQLITE_MAX_PAGE_SIZE, conclude that the WAL file contains no valid
|
|
+ ** SQLITE_MAX_PAGE_SIZE, conclude that the WAL file contains no valid
|
|
** data. Similarly, if the 'magic' value is invalid, ignore the whole
|
|
** WAL file.
|
|
*/
|
|
magic = sqlite3Get4byte(&aBuf[0]);
|
|
szPage = sqlite3Get4byte(&aBuf[8]);
|
|
- if( (magic&0xFFFFFFFE)!=WAL_MAGIC
|
|
- || szPage&(szPage-1)
|
|
- || szPage>SQLITE_MAX_PAGE_SIZE
|
|
- || szPage<512
|
|
+ if( (magic&0xFFFFFFFE)!=WAL_MAGIC
|
|
+ || szPage&(szPage-1)
|
|
+ || szPage>SQLITE_MAX_PAGE_SIZE
|
|
+ || szPage<512
|
|
){
|
|
goto finished;
|
|
}
|
|
@@ -60413,7 +64507,7 @@ static int walIndexRecover(Wal *pWal){
|
|
memcpy(&pWal->hdr.aSalt, &aBuf[16], 8);
|
|
|
|
/* Verify that the WAL header checksum is correct */
|
|
- walChecksumBytes(pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN,
|
|
+ walChecksumBytes(pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN,
|
|
aBuf, WAL_HDRSIZE-2*4, 0, pWal->hdr.aFrameCksum
|
|
);
|
|
if( pWal->hdr.aFrameCksum[0]!=sqlite3Get4byte(&aBuf[24])
|
|
@@ -60432,38 +64526,83 @@ static int walIndexRecover(Wal *pWal){
|
|
|
|
/* Malloc a buffer to read frames into. */
|
|
szFrame = szPage + WAL_FRAME_HDRSIZE;
|
|
- aFrame = (u8 *)sqlite3_malloc64(szFrame);
|
|
+ aFrame = (u8 *)sqlite3_malloc64(szFrame + WALINDEX_PGSZ);
|
|
if( !aFrame ){
|
|
rc = SQLITE_NOMEM_BKPT;
|
|
goto recovery_error;
|
|
}
|
|
aData = &aFrame[WAL_FRAME_HDRSIZE];
|
|
+ aPrivate = (u32*)&aData[szPage];
|
|
|
|
/* Read all frames from the log file. */
|
|
- iFrame = 0;
|
|
- for(iOffset=WAL_HDRSIZE; (iOffset+szFrame)<=nSize; iOffset+=szFrame){
|
|
- u32 pgno; /* Database page number for frame */
|
|
- u32 nTruncate; /* dbsize field from frame header */
|
|
-
|
|
- /* Read and decode the next log frame. */
|
|
- iFrame++;
|
|
- rc = sqlite3OsRead(pWal->pWalFd, aFrame, szFrame, iOffset);
|
|
- if( rc!=SQLITE_OK ) break;
|
|
- isValid = walDecodeFrame(pWal, &pgno, &nTruncate, aData, aFrame);
|
|
- if( !isValid ) break;
|
|
- rc = walIndexAppend(pWal, iFrame, pgno);
|
|
- if( rc!=SQLITE_OK ) break;
|
|
-
|
|
- /* If nTruncate is non-zero, this is a commit record. */
|
|
- if( nTruncate ){
|
|
- pWal->hdr.mxFrame = iFrame;
|
|
- pWal->hdr.nPage = nTruncate;
|
|
- pWal->hdr.szPage = (u16)((szPage&0xff00) | (szPage>>16));
|
|
- testcase( szPage<=32768 );
|
|
- testcase( szPage>=65536 );
|
|
- aFrameCksum[0] = pWal->hdr.aFrameCksum[0];
|
|
- aFrameCksum[1] = pWal->hdr.aFrameCksum[1];
|
|
+ iLastFrame = (nSize - WAL_HDRSIZE) / szFrame;
|
|
+ for(iPg=0; iPg<=(u32)walFramePage(iLastFrame); iPg++){
|
|
+ u32 *aShare;
|
|
+ u32 iFrame; /* Index of last frame read */
|
|
+ u32 iLast = MIN(iLastFrame, HASHTABLE_NPAGE_ONE+iPg*HASHTABLE_NPAGE);
|
|
+ u32 iFirst = 1 + (iPg==0?0:HASHTABLE_NPAGE_ONE+(iPg-1)*HASHTABLE_NPAGE);
|
|
+ u32 nHdr, nHdr32;
|
|
+ rc = walIndexPage(pWal, iPg, (volatile u32**)&aShare);
|
|
+ assert( aShare!=0 || rc!=SQLITE_OK );
|
|
+ if( aShare==0 ) break;
|
|
+ pWal->apWiData[iPg] = aPrivate;
|
|
+
|
|
+ for(iFrame=iFirst; iFrame<=iLast; iFrame++){
|
|
+ i64 iOffset = walFrameOffset(iFrame, szPage);
|
|
+ u32 pgno; /* Database page number for frame */
|
|
+ u32 nTruncate; /* dbsize field from frame header */
|
|
+
|
|
+ /* Read and decode the next log frame. */
|
|
+ rc = sqlite3OsRead(pWal->pWalFd, aFrame, szFrame, iOffset);
|
|
+ if( rc!=SQLITE_OK ) break;
|
|
+ isValid = walDecodeFrame(pWal, &pgno, &nTruncate, aData, aFrame);
|
|
+ if( !isValid ) break;
|
|
+ rc = walIndexAppend(pWal, iFrame, pgno);
|
|
+ if( NEVER(rc!=SQLITE_OK) ) break;
|
|
+
|
|
+ /* If nTruncate is non-zero, this is a commit record. */
|
|
+ if( nTruncate ){
|
|
+ pWal->hdr.mxFrame = iFrame;
|
|
+ pWal->hdr.nPage = nTruncate;
|
|
+ pWal->hdr.szPage = (u16)((szPage&0xff00) | (szPage>>16));
|
|
+ testcase( szPage<=32768 );
|
|
+ testcase( szPage>=65536 );
|
|
+ aFrameCksum[0] = pWal->hdr.aFrameCksum[0];
|
|
+ aFrameCksum[1] = pWal->hdr.aFrameCksum[1];
|
|
+ }
|
|
+ }
|
|
+ pWal->apWiData[iPg] = aShare;
|
|
+ nHdr = (iPg==0 ? WALINDEX_HDR_SIZE : 0);
|
|
+ nHdr32 = nHdr / sizeof(u32);
|
|
+#ifndef SQLITE_SAFER_WALINDEX_RECOVERY
|
|
+ /* Memcpy() should work fine here, on all reasonable implementations.
|
|
+ ** Technically, memcpy() might change the destination to some
|
|
+ ** intermediate value before setting to the final value, and that might
|
|
+ ** cause a concurrent reader to malfunction. Memcpy() is allowed to
|
|
+ ** do that, according to the spec, but no memcpy() implementation that
|
|
+ ** we know of actually does that, which is why we say that memcpy()
|
|
+ ** is safe for this. Memcpy() is certainly a lot faster.
|
|
+ */
|
|
+ memcpy(&aShare[nHdr32], &aPrivate[nHdr32], WALINDEX_PGSZ-nHdr);
|
|
+#else
|
|
+ /* In the event that some platform is found for which memcpy()
|
|
+ ** changes the destination to some intermediate value before
|
|
+ ** setting the final value, this alternative copy routine is
|
|
+ ** provided.
|
|
+ */
|
|
+ {
|
|
+ int i;
|
|
+ for(i=nHdr32; i<WALINDEX_PGSZ/sizeof(u32); i++){
|
|
+ if( aShare[i]!=aPrivate[i] ){
|
|
+ /* Atomic memory operations are not required here because if
|
|
+ ** the value needs to be changed, that means it is not being
|
|
+ ** accessed concurrently. */
|
|
+ aShare[i] = aPrivate[i];
|
|
+ }
|
|
+ }
|
|
}
|
|
+#endif
|
|
+ if( iFrame<=iLast ) break;
|
|
}
|
|
|
|
sqlite3_free(aFrame);
|
|
@@ -60477,16 +64616,27 @@ static int walIndexRecover(Wal *pWal){
|
|
pWal->hdr.aFrameCksum[1] = aFrameCksum[1];
|
|
walIndexWriteHdr(pWal);
|
|
|
|
- /* Reset the checkpoint-header. This is safe because this thread is
|
|
- ** currently holding locks that exclude all other readers, writers and
|
|
- ** checkpointers.
|
|
+ /* Reset the checkpoint-header. This is safe because this thread is
|
|
+ ** currently holding locks that exclude all other writers and
|
|
+ ** checkpointers. Then set the values of read-mark slots 1 through N.
|
|
*/
|
|
pInfo = walCkptInfo(pWal);
|
|
pInfo->nBackfill = 0;
|
|
pInfo->nBackfillAttempted = pWal->hdr.mxFrame;
|
|
pInfo->aReadMark[0] = 0;
|
|
- for(i=1; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED;
|
|
- if( pWal->hdr.mxFrame ) pInfo->aReadMark[1] = pWal->hdr.mxFrame;
|
|
+ for(i=1; i<WAL_NREADER; i++){
|
|
+ rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1);
|
|
+ if( rc==SQLITE_OK ){
|
|
+ if( i==1 && pWal->hdr.mxFrame ){
|
|
+ pInfo->aReadMark[i] = pWal->hdr.mxFrame;
|
|
+ }else{
|
|
+ pInfo->aReadMark[i] = READMARK_NOT_USED;
|
|
+ }
|
|
+ walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
|
|
+ }else if( rc!=SQLITE_BUSY ){
|
|
+ goto recovery_error;
|
|
+ }
|
|
+ }
|
|
|
|
/* If more than one frame was recovered from the log file, report an
|
|
** event via sqlite3_log(). This is to help with identifying performance
|
|
@@ -60504,7 +64654,6 @@ static int walIndexRecover(Wal *pWal){
|
|
recovery_error:
|
|
WALTRACE(("WAL%p: recovery %s\n", pWal, rc ? "failed" : "ok"));
|
|
walUnlockExclusive(pWal, iLock, WAL_READ_LOCK(0)-iLock);
|
|
- walUnlockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
|
|
return rc;
|
|
}
|
|
|
|
@@ -60524,8 +64673,8 @@ static void walIndexClose(Wal *pWal, int isDelete){
|
|
}
|
|
}
|
|
|
|
-/*
|
|
-** Open a connection to the WAL file zWalName. The database file must
|
|
+/*
|
|
+** 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.
|
|
**
|
|
@@ -60535,7 +64684,7 @@ static void walIndexClose(Wal *pWal, int isDelete){
|
|
** 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
|
|
+** 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.
|
|
*/
|
|
@@ -60554,14 +64703,43 @@ SQLITE_PRIVATE int sqlite3WalOpen(
|
|
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.
|
|
*/
|
|
- assert( 120==WALINDEX_LOCK_OFFSET );
|
|
- assert( 136==WALINDEX_HDR_SIZE );
|
|
#ifdef WIN_SHM_BASE
|
|
assert( WIN_SHM_BASE==WALINDEX_LOCK_OFFSET );
|
|
#endif
|
|
@@ -60699,7 +64877,7 @@ static void walMerge(
|
|
ht_slot logpage;
|
|
Pgno dbpage;
|
|
|
|
- if( (iLeft<nLeft)
|
|
+ if( (iLeft<nLeft)
|
|
&& (iRight>=nRight || aContent[aLeft[iLeft]]<aContent[aRight[iRight]])
|
|
){
|
|
logpage = aLeft[iLeft++];
|
|
@@ -60797,7 +64975,7 @@ static void walMergesort(
|
|
#endif
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** Free an iterator allocated by walIteratorInit().
|
|
*/
|
|
static void walIteratorFree(WalIterator *p){
|
|
@@ -60805,7 +64983,7 @@ static void walIteratorFree(WalIterator *p){
|
|
}
|
|
|
|
/*
|
|
-** Construct a WalInterator object that can be used to loop over all
|
|
+** Construct a WalInterator object that can be used to loop over all
|
|
** pages in the WAL following frame nBackfill in ascending order. Frames
|
|
** nBackfill or earlier may be included - excluding them is an optimization
|
|
** only. The caller must hold the checkpoint lock.
|
|
@@ -60834,7 +65012,7 @@ static int walIteratorInit(Wal *pWal, u32 nBackfill, WalIterator **pp){
|
|
|
|
/* Allocate space for the WalIterator object. */
|
|
nSegment = walFramePage(iLast) + 1;
|
|
- nByte = sizeof(WalIterator)
|
|
+ nByte = sizeof(WalIterator)
|
|
+ (nSegment-1)*sizeof(struct WalSegment)
|
|
+ iLast*sizeof(ht_slot);
|
|
p = (WalIterator *)sqlite3_malloc64(nByte);
|
|
@@ -60863,7 +65041,6 @@ static int walIteratorInit(Wal *pWal, u32 nBackfill, WalIterator **pp){
|
|
int nEntry; /* Number of entries in this segment */
|
|
ht_slot *aIndex; /* Sorted index for this segment */
|
|
|
|
- sLoc.aPgno++;
|
|
if( (i+1)==nSegment ){
|
|
nEntry = (int)(iLast - sLoc.iZero);
|
|
}else{
|
|
@@ -60871,7 +65048,7 @@ static int walIteratorInit(Wal *pWal, u32 nBackfill, WalIterator **pp){
|
|
}
|
|
aIndex = &((ht_slot *)&p->aSegment[p->nSegment])[sLoc.iZero];
|
|
sLoc.iZero++;
|
|
-
|
|
+
|
|
for(j=0; j<nEntry; j++){
|
|
aIndex[j] = (ht_slot)j;
|
|
}
|
|
@@ -60892,6 +65069,89 @@ static int walIteratorInit(Wal *pWal, u32 nBackfill, WalIterator **pp){
|
|
return rc;
|
|
}
|
|
|
|
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
|
+/*
|
|
+** Attempt to enable blocking locks. Blocking locks are enabled only if (a)
|
|
+** they are supported by the VFS, and (b) the database handle is configured
|
|
+** with a busy-timeout. Return 1 if blocking locks are successfully enabled,
|
|
+** or 0 otherwise.
|
|
+*/
|
|
+static int walEnableBlocking(Wal *pWal){
|
|
+ int res = 0;
|
|
+ if( pWal->db ){
|
|
+ int tmout = pWal->db->busyTimeout;
|
|
+ if( tmout ){
|
|
+ int rc;
|
|
+ rc = sqlite3OsFileControl(
|
|
+ pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout
|
|
+ );
|
|
+ res = (rc==SQLITE_OK);
|
|
+ }
|
|
+ }
|
|
+ return res;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Disable blocking locks.
|
|
+*/
|
|
+static void walDisableBlocking(Wal *pWal){
|
|
+ int tmout = 0;
|
|
+ sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout);
|
|
+}
|
|
+
|
|
+/*
|
|
+** If parameter bLock is true, attempt to enable blocking locks, take
|
|
+** the WRITER lock, and then disable blocking locks. If blocking locks
|
|
+** cannot be enabled, no attempt to obtain the WRITER lock is made. Return
|
|
+** an SQLite error code if an error occurs, or SQLITE_OK otherwise. It is not
|
|
+** an error if blocking locks can not be enabled.
|
|
+**
|
|
+** If the bLock parameter is false and the WRITER lock is held, release it.
|
|
+*/
|
|
+SQLITE_PRIVATE int sqlite3WalWriteLock(Wal *pWal, int bLock){
|
|
+ int rc = SQLITE_OK;
|
|
+ assert( pWal->readLock<0 || bLock==0 );
|
|
+ if( bLock ){
|
|
+ assert( pWal->db );
|
|
+ if( walEnableBlocking(pWal) ){
|
|
+ rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1);
|
|
+ if( rc==SQLITE_OK ){
|
|
+ pWal->writeLock = 1;
|
|
+ }
|
|
+ walDisableBlocking(pWal);
|
|
+ }
|
|
+ }else if( pWal->writeLock ){
|
|
+ walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
|
|
+ pWal->writeLock = 0;
|
|
+ }
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Set the database handle used to determine if blocking locks are required.
|
|
+*/
|
|
+SQLITE_PRIVATE void sqlite3WalDb(Wal *pWal, sqlite3 *db){
|
|
+ pWal->db = db;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Take an exclusive WRITE lock. Blocking if so configured.
|
|
+*/
|
|
+static int walLockWriter(Wal *pWal){
|
|
+ int rc;
|
|
+ walEnableBlocking(pWal);
|
|
+ rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1);
|
|
+ walDisableBlocking(pWal);
|
|
+ return rc;
|
|
+}
|
|
+#else
|
|
+# define walEnableBlocking(x) 0
|
|
+# define walDisableBlocking(x)
|
|
+# define walLockWriter(pWal) walLockExclusive((pWal), WAL_WRITE_LOCK, 1)
|
|
+# define sqlite3WalDb(pWal, db)
|
|
+#endif /* ifdef SQLITE_ENABLE_SETLK_TIMEOUT */
|
|
+
|
|
+
|
|
/*
|
|
** Attempt to obtain the exclusive WAL lock defined by parameters lockIdx and
|
|
** n. If the attempt fails and parameter xBusy is not NULL, then it is a
|
|
@@ -60909,6 +65169,12 @@ static int walBusyLock(
|
|
do {
|
|
rc = walLockExclusive(pWal, lockIdx, n);
|
|
}while( xBusy && rc==SQLITE_BUSY && xBusy(pBusyArg) );
|
|
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
|
+ if( rc==SQLITE_BUSY_TIMEOUT ){
|
|
+ walDisableBlocking(pWal);
|
|
+ rc = SQLITE_BUSY;
|
|
+ }
|
|
+#endif
|
|
return rc;
|
|
}
|
|
|
|
@@ -60933,8 +65199,8 @@ static int walPagesize(Wal *pWal){
|
|
** client to write to the database (which may be this one) does so by
|
|
** writing frames into the start of the log file.
|
|
**
|
|
-** The value of parameter salt1 is used as the aSalt[1] value in the
|
|
-** new wal-index header. It should be passed a pseudo-random value (i.e.
|
|
+** The value of parameter salt1 is used as the aSalt[1] value in the
|
|
+** new wal-index header. It should be passed a pseudo-random value (i.e.
|
|
** one obtained from sqlite3_randomness()).
|
|
*/
|
|
static void walRestartHdr(Wal *pWal, u32 salt1){
|
|
@@ -60946,7 +65212,7 @@ static void walRestartHdr(Wal *pWal, u32 salt1){
|
|
sqlite3Put4byte((u8*)&aSalt[0], 1 + sqlite3Get4byte((u8*)&aSalt[0]));
|
|
memcpy(&pWal->hdr.aSalt[1], &salt1, 4);
|
|
walIndexWriteHdr(pWal);
|
|
- pInfo->nBackfill = 0;
|
|
+ AtomicStore(&pInfo->nBackfill, 0);
|
|
pInfo->nBackfillAttempted = 0;
|
|
pInfo->aReadMark[1] = 0;
|
|
for(i=2; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED;
|
|
@@ -60962,8 +65228,8 @@ static void walRestartHdr(Wal *pWal, u32 salt1){
|
|
** that a concurrent reader might be using.
|
|
**
|
|
** All I/O barrier operations (a.k.a fsyncs) occur in this routine when
|
|
-** SQLite is in WAL-mode in synchronous=NORMAL. That means that if
|
|
-** checkpoints are always run by a background thread or background
|
|
+** SQLite is in WAL-mode in synchronous=NORMAL. That means that if
|
|
+** checkpoints are always run by a background thread or background
|
|
** process, foreground threads will never block on a lengthy fsync call.
|
|
**
|
|
** Fsync is called on the WAL before writing content out of the WAL and
|
|
@@ -60976,7 +65242,7 @@ static void walRestartHdr(Wal *pWal, u32 salt1){
|
|
** database file.
|
|
**
|
|
** This routine uses and updates the nBackfill field of the wal-index header.
|
|
-** This is the only routine that will increase the value of nBackfill.
|
|
+** This is the only routine that will increase the value of nBackfill.
|
|
** (A WAL reset or recovery will revert nBackfill to zero, but not increase
|
|
** its value.)
|
|
**
|
|
@@ -61021,32 +65287,13 @@ static int walCheckpoint(
|
|
mxSafeFrame = pWal->hdr.mxFrame;
|
|
mxPage = pWal->hdr.nPage;
|
|
for(i=1; i<WAL_NREADER; i++){
|
|
- /* Thread-sanitizer reports that the following is an unsafe read,
|
|
- ** as some other thread may be in the process of updating the value
|
|
- ** of the aReadMark[] slot. The assumption here is that if that is
|
|
- ** happening, the other client may only be increasing the value,
|
|
- ** not decreasing it. So assuming either that either the "old" or
|
|
- ** "new" version of the value is read, and not some arbitrary value
|
|
- ** that would never be written by a real client, things are still
|
|
- ** safe.
|
|
- **
|
|
- ** Astute readers have pointed out that the assumption stated in the
|
|
- ** last sentence of the previous paragraph is not guaranteed to be
|
|
- ** true for all conforming systems. However, the assumption is true
|
|
- ** for all compilers and architectures in common use today (circa
|
|
- ** 2019-11-27) and the alternatives are both slow and complex, and
|
|
- ** so we will continue to go with the current design for now. If this
|
|
- ** bothers you, or if you really are running on a system where aligned
|
|
- ** 32-bit reads and writes are not atomic, then you can simply avoid
|
|
- ** the use of WAL mode, or only use WAL mode together with
|
|
- ** PRAGMA locking_mode=EXCLUSIVE and all will be well.
|
|
- */
|
|
- u32 y = pInfo->aReadMark[i];
|
|
+ u32 y = AtomicLoad(pInfo->aReadMark+i);
|
|
if( mxSafeFrame>y ){
|
|
assert( y<=pWal->hdr.mxFrame );
|
|
rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1);
|
|
if( rc==SQLITE_OK ){
|
|
- pInfo->aReadMark[i] = (i==1 ? mxSafeFrame : READMARK_NOT_USED);
|
|
+ u32 iMark = (i==1 ? mxSafeFrame : READMARK_NOT_USED);
|
|
+ AtomicStore(pInfo->aReadMark+i, iMark);
|
|
walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
|
|
}else if( rc==SQLITE_BUSY ){
|
|
mxSafeFrame = y;
|
|
@@ -61064,7 +65311,7 @@ static int walCheckpoint(
|
|
}
|
|
|
|
if( pIter
|
|
- && (rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(0),1))==SQLITE_OK
|
|
+ && (rc = walBusyLock(pWal,xBusy,pBusyArg,WAL_READ_LOCK(0),1))==SQLITE_OK
|
|
){
|
|
u32 nBackfill = pInfo->nBackfill;
|
|
|
|
@@ -61079,18 +65326,27 @@ static int walCheckpoint(
|
|
if( rc==SQLITE_OK ){
|
|
i64 nReq = ((i64)mxPage * szPage);
|
|
i64 nSize; /* Current size of database file */
|
|
+ sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_CKPT_START, 0);
|
|
rc = sqlite3OsFileSize(pWal->pDbFd, &nSize);
|
|
if( rc==SQLITE_OK && nSize<nReq ){
|
|
- sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq);
|
|
+ if( (nSize+65536+(i64)pWal->hdr.mxFrame*szPage)<nReq ){
|
|
+ /* If the size of the final database is larger than the current
|
|
+ ** database plus the amount of data in the wal file, plus the
|
|
+ ** maximum size of the pending-byte page (65536 bytes), then
|
|
+ ** must be corruption somewhere. */
|
|
+ rc = SQLITE_CORRUPT_BKPT;
|
|
+ }else{
|
|
+ sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT,&nReq);
|
|
+ }
|
|
}
|
|
- }
|
|
|
|
+ }
|
|
|
|
/* Iterate through the contents of the WAL, copying data to the db file */
|
|
while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
|
|
i64 iOffset;
|
|
assert( walFramePgno(pWal, iFrame)==iDbpage );
|
|
- if( db->u1.isInterrupted ){
|
|
+ if( AtomicLoad(&db->u1.isInterrupted) ){
|
|
rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_INTERRUPT;
|
|
break;
|
|
}
|
|
@@ -61106,6 +65362,7 @@ static int walCheckpoint(
|
|
rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset);
|
|
if( rc!=SQLITE_OK ) break;
|
|
}
|
|
+ sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_CKPT_DONE, 0);
|
|
|
|
/* If work was actually accomplished... */
|
|
if( rc==SQLITE_OK ){
|
|
@@ -61118,11 +65375,7 @@ static int walCheckpoint(
|
|
}
|
|
}
|
|
if( rc==SQLITE_OK ){
|
|
- rc = sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_CKPT_DONE, 0);
|
|
- if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK;
|
|
- }
|
|
- if( rc==SQLITE_OK ){
|
|
- pInfo->nBackfill = mxSafeFrame;
|
|
+ AtomicStore(&pInfo->nBackfill, mxSafeFrame);
|
|
}
|
|
}
|
|
|
|
@@ -61138,8 +65391,8 @@ static int walCheckpoint(
|
|
}
|
|
|
|
/* If this is an SQLITE_CHECKPOINT_RESTART or TRUNCATE operation, and the
|
|
- ** entire wal file has been copied into the database file, then block
|
|
- ** until all readers have finished using the wal file. This ensures that
|
|
+ ** entire wal file has been copied into the database file, then block
|
|
+ ** until all readers have finished using the wal file. This ensures that
|
|
** the next process to write to the database restarts the wal file.
|
|
*/
|
|
if( rc==SQLITE_OK && eMode!=SQLITE_CHECKPOINT_PASSIVE ){
|
|
@@ -61163,7 +65416,7 @@ static int walCheckpoint(
|
|
** writer clients should see that the entire log file has been
|
|
** checkpointed and behave accordingly. This seems unsafe though,
|
|
** as it would leave the system in a state where the contents of
|
|
- ** the wal-index header do not match the contents of the
|
|
+ ** the wal-index header do not match the contents of the
|
|
** file-system. To avoid this, update the wal-index header to
|
|
** indicate that the log file contains zero valid frames. */
|
|
walRestartHdr(pWal, salt1);
|
|
@@ -61225,7 +65478,7 @@ SQLITE_PRIVATE int sqlite3WalClose(
|
|
if( pWal->exclusiveMode==WAL_NORMAL_MODE ){
|
|
pWal->exclusiveMode = WAL_EXCLUSIVE_MODE;
|
|
}
|
|
- rc = sqlite3WalCheckpoint(pWal, db,
|
|
+ rc = sqlite3WalCheckpoint(pWal, db,
|
|
SQLITE_CHECKPOINT_PASSIVE, 0, 0, sync_flags, nBuf, zBuf, 0, 0
|
|
);
|
|
if( rc==SQLITE_OK ){
|
|
@@ -61281,7 +65534,7 @@ SQLITE_PRIVATE int sqlite3WalClose(
|
|
** If the checksum cannot be verified return non-zero. If the header
|
|
** is read successfully and the checksum verified, return zero.
|
|
*/
|
|
-static int walIndexTryHdr(Wal *pWal, int *pChanged){
|
|
+static SQLITE_NO_TSAN int walIndexTryHdr(Wal *pWal, int *pChanged){
|
|
u32 aCksum[2]; /* Checksum on the header content */
|
|
WalIndexHdr h1, h2; /* Two copies of the header content */
|
|
WalIndexHdr volatile *aHdr; /* Header in shared memory */
|
|
@@ -61294,19 +65547,25 @@ static int walIndexTryHdr(Wal *pWal, int *pChanged){
|
|
** meaning it is possible that an inconsistent snapshot is read
|
|
** from the file. If this happens, return non-zero.
|
|
**
|
|
+ ** tag-20200519-1:
|
|
** There are two copies of the header at the beginning of the wal-index.
|
|
** When reading, read [0] first then [1]. Writes are in the reverse order.
|
|
** Memory barriers are used to prevent the compiler or the hardware from
|
|
- ** reordering the reads and writes.
|
|
+ ** reordering the reads and writes. TSAN and similar tools can sometimes
|
|
+ ** 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
|
|
+ ** reliably in that environment.
|
|
*/
|
|
aHdr = walIndexHdr(pWal);
|
|
- memcpy(&h1, (void *)&aHdr[0], sizeof(h1));
|
|
+ memcpy(&h1, (void *)&aHdr[0], sizeof(h1)); /* Possible TSAN false-positive */
|
|
walShmBarrier(pWal);
|
|
memcpy(&h2, (void *)&aHdr[1], sizeof(h2));
|
|
|
|
if( memcmp(&h1, &h2, sizeof(h1))!=0 ){
|
|
return 1; /* Dirty read */
|
|
- }
|
|
+ }
|
|
if( h1.isInit==0 ){
|
|
return 1; /* Malformed header - probably all zeros */
|
|
}
|
|
@@ -61342,7 +65601,7 @@ static int walIndexTryHdr(Wal *pWal, int *pChanged){
|
|
** changed by this operation. If pWal->hdr is unchanged, set *pChanged
|
|
** to 0.
|
|
**
|
|
-** If the wal-index header is successfully read, return SQLITE_OK.
|
|
+** If the wal-index header is successfully read, return SQLITE_OK.
|
|
** Otherwise an SQLite error code.
|
|
*/
|
|
static int walIndexReadHdr(Wal *pWal, int *pChanged){
|
|
@@ -61350,7 +65609,7 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){
|
|
int badHdr; /* True if a header read failed */
|
|
volatile u32 *page0; /* Chunk of wal-index containing header */
|
|
|
|
- /* Ensure that page 0 of the wal-index (the page that contains the
|
|
+ /* Ensure that page 0 of the wal-index (the page that contains the
|
|
** wal-index header) is mapped. Return early if an error occurs here.
|
|
*/
|
|
assert( pChanged );
|
|
@@ -61382,7 +65641,7 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){
|
|
|
|
/* If the first page of the wal-index has been mapped, try to read the
|
|
** wal-index header immediately, without holding any lock. This usually
|
|
- ** works, but may fail if the wal-index header is corrupt or currently
|
|
+ ** works, but may fail if the wal-index header is corrupt or currently
|
|
** being modified by another thread or process.
|
|
*/
|
|
badHdr = (page0 ? walIndexTryHdr(pWal, pChanged) : 1);
|
|
@@ -61390,28 +65649,32 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){
|
|
/* If the first attempt failed, it might have been due to a race
|
|
** with a writer. So get a WRITE lock and try again.
|
|
*/
|
|
- assert( badHdr==0 || pWal->writeLock==0 );
|
|
if( badHdr ){
|
|
if( pWal->bShmUnreliable==0 && (pWal->readOnly & WAL_SHM_RDONLY) ){
|
|
if( SQLITE_OK==(rc = walLockShared(pWal, WAL_WRITE_LOCK)) ){
|
|
walUnlockShared(pWal, WAL_WRITE_LOCK);
|
|
rc = SQLITE_READONLY_RECOVERY;
|
|
}
|
|
- }else if( SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1)) ){
|
|
- pWal->writeLock = 1;
|
|
- if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){
|
|
- badHdr = walIndexTryHdr(pWal, pChanged);
|
|
- if( badHdr ){
|
|
- /* If the wal-index header is still malformed even while holding
|
|
- ** a WRITE lock, it can only mean that the header is corrupted and
|
|
- ** needs to be reconstructed. So run recovery to do exactly that.
|
|
- */
|
|
- rc = walIndexRecover(pWal);
|
|
- *pChanged = 1;
|
|
+ }else{
|
|
+ int bWriteLock = pWal->writeLock;
|
|
+ if( bWriteLock || SQLITE_OK==(rc = walLockWriter(pWal)) ){
|
|
+ pWal->writeLock = 1;
|
|
+ if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){
|
|
+ badHdr = walIndexTryHdr(pWal, pChanged);
|
|
+ if( badHdr ){
|
|
+ /* If the wal-index header is still malformed even while holding
|
|
+ ** a WRITE lock, it can only mean that the header is corrupted and
|
|
+ ** needs to be reconstructed. So run recovery to do exactly that.
|
|
+ */
|
|
+ rc = walIndexRecover(pWal);
|
|
+ *pChanged = 1;
|
|
+ }
|
|
+ }
|
|
+ if( bWriteLock==0 ){
|
|
+ pWal->writeLock = 0;
|
|
+ walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
|
|
}
|
|
}
|
|
- pWal->writeLock = 0;
|
|
- walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
|
|
}
|
|
}
|
|
|
|
@@ -61453,15 +65716,15 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){
|
|
**
|
|
** The *-wal file has been read and an appropriate wal-index has been
|
|
** constructed in pWal->apWiData[] using heap memory instead of shared
|
|
-** memory.
|
|
+** memory.
|
|
**
|
|
** If this function returns SQLITE_OK, then the read transaction has
|
|
-** been successfully opened. In this case output variable (*pChanged)
|
|
+** been successfully opened. In this case output variable (*pChanged)
|
|
** is set to true before returning if the caller should discard the
|
|
-** contents of the page cache before proceeding. Or, if it returns
|
|
-** WAL_RETRY, then the heap memory wal-index has been discarded and
|
|
-** the caller should retry opening the read transaction from the
|
|
-** beginning (including attempting to map the *-shm file).
|
|
+** contents of the page cache before proceeding. Or, if it returns
|
|
+** WAL_RETRY, then the heap memory wal-index has been discarded and
|
|
+** the caller should retry opening the read transaction from the
|
|
+** beginning (including attempting to map the *-shm file).
|
|
**
|
|
** If an error occurs, an SQLite error code is returned.
|
|
*/
|
|
@@ -61558,7 +65821,9 @@ static int walBeginShmUnreliable(Wal *pWal, int *pChanged){
|
|
}
|
|
|
|
/* Allocate a buffer to read frames into */
|
|
- szFrame = pWal->hdr.szPage + WAL_FRAME_HDRSIZE;
|
|
+ assert( (pWal->szPage & (pWal->szPage-1))==0 );
|
|
+ assert( pWal->szPage>=512 && pWal->szPage<=65536 );
|
|
+ szFrame = pWal->szPage + WAL_FRAME_HDRSIZE;
|
|
aFrame = (u8 *)sqlite3_malloc64(szFrame);
|
|
if( aFrame==0 ){
|
|
rc = SQLITE_NOMEM_BKPT;
|
|
@@ -61572,8 +65837,8 @@ static int walBeginShmUnreliable(Wal *pWal, int *pChanged){
|
|
** the caller. */
|
|
aSaveCksum[0] = pWal->hdr.aFrameCksum[0];
|
|
aSaveCksum[1] = pWal->hdr.aFrameCksum[1];
|
|
- for(iOffset=walFrameOffset(pWal->hdr.mxFrame+1, pWal->hdr.szPage);
|
|
- iOffset+szFrame<=szWal;
|
|
+ for(iOffset=walFrameOffset(pWal->hdr.mxFrame+1, pWal->szPage);
|
|
+ iOffset+szFrame<=szWal;
|
|
iOffset+=szFrame
|
|
){
|
|
u32 pgno; /* Database page number for frame */
|
|
@@ -61621,10 +65886,10 @@ static int walBeginShmUnreliable(Wal *pWal, int *pChanged){
|
|
**
|
|
** The useWal parameter is true to force the use of the WAL and disable
|
|
** the case where the WAL is bypassed because it has been completely
|
|
-** checkpointed. If useWal==0 then this routine calls walIndexReadHdr()
|
|
-** to make a copy of the wal-index header into pWal->hdr. If the
|
|
-** wal-index header has changed, *pChanged is set to 1 (as an indication
|
|
-** to the caller that the local page cache is obsolete and needs to be
|
|
+** checkpointed. If useWal==0 then this routine calls walIndexReadHdr()
|
|
+** to make a copy of the wal-index header into pWal->hdr. If the
|
|
+** wal-index header has changed, *pChanged is set to 1 (as an indication
|
|
+** to the caller that the local page cache is obsolete and needs to be
|
|
** flushed.) When useWal==1, the wal-index header is assumed to already
|
|
** be loaded and the pChanged parameter is unused.
|
|
**
|
|
@@ -61639,7 +65904,7 @@ static int walBeginShmUnreliable(Wal *pWal, int *pChanged){
|
|
** bad luck when there is lots of contention for the wal-index, but that
|
|
** possibility is so small that it can be safely neglected, we believe.
|
|
**
|
|
-** On success, this routine obtains a read lock on
|
|
+** On success, this routine obtains a read lock on
|
|
** WAL_READ_LOCK(pWal->readLock). The pWal->readLock integer is
|
|
** in the range 0 <= pWal->readLock < WAL_NREADER. If pWal->readLock==(-1)
|
|
** that means the Wal does not hold any read lock. The reader must not
|
|
@@ -61677,16 +65942,16 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
|
|
**
|
|
** Circumstances that cause a RETRY should only last for the briefest
|
|
** instances of time. No I/O or other system calls are done while the
|
|
- ** locks are held, so the locks should not be held for very long. But
|
|
+ ** locks are held, so the locks should not be held for very long. But
|
|
** if we are unlucky, another process that is holding a lock might get
|
|
- ** paged out or take a page-fault that is time-consuming to resolve,
|
|
+ ** paged out or take a page-fault that is time-consuming to resolve,
|
|
** during the few nanoseconds that it is holding the lock. In that case,
|
|
** it might take longer than normal for the lock to free.
|
|
**
|
|
** After 5 RETRYs, we begin calling sqlite3OsSleep(). The first few
|
|
** calls to sqlite3OsSleep() have a delay of 1 microsecond. Really this
|
|
** is more of a scheduler yield than an actual delay. But on the 10th
|
|
- ** an subsequent retries, the delays start becoming longer and longer,
|
|
+ ** an subsequent retries, the delays start becoming longer and longer,
|
|
** so that on the 100th (and last) RETRY we delay for 323 milliseconds.
|
|
** The total delay time before giving up is less than 10 seconds.
|
|
*/
|
|
@@ -61717,9 +65982,9 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
|
|
if( pWal->apWiData[0]==0 ){
|
|
/* This branch is taken when the xShmMap() method returns SQLITE_BUSY.
|
|
** We assume this is a transient condition, so return WAL_RETRY. The
|
|
- ** xShmMap() implementation used by the default unix and win32 VFS
|
|
- ** modules may return SQLITE_BUSY due to a race condition in the
|
|
- ** code that determines whether or not the shared-memory region
|
|
+ ** xShmMap() implementation used by the default unix and win32 VFS
|
|
+ ** modules may return SQLITE_BUSY due to a race condition in the
|
|
+ ** code that determines whether or not the shared-memory region
|
|
** must be zeroed before the requested page is returned.
|
|
*/
|
|
rc = WAL_RETRY;
|
|
@@ -61741,7 +66006,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
|
|
assert( pWal->nWiData>0 );
|
|
assert( pWal->apWiData[0]!=0 );
|
|
pInfo = walCkptInfo(pWal);
|
|
- if( !useWal && pInfo->nBackfill==pWal->hdr.mxFrame
|
|
+ if( !useWal && AtomicLoad(&pInfo->nBackfill)==pWal->hdr.mxFrame
|
|
#ifdef SQLITE_ENABLE_SNAPSHOT
|
|
&& (pWal->pSnapshot==0 || pWal->hdr.mxFrame==0)
|
|
#endif
|
|
@@ -61760,7 +66025,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
|
|
** snapshot. Since holding READ_LOCK(0) prevents a checkpoint from
|
|
** happening, this is usually correct.
|
|
**
|
|
- ** However, if frames have been appended to the log (or if the log
|
|
+ ** However, if frames have been appended to the log (or if the log
|
|
** is wrapped and written for that matter) before the READ_LOCK(0)
|
|
** is obtained, that is not necessarily true. A checkpointer may
|
|
** have started to backfill the appended frames but crashed before
|
|
@@ -61803,7 +66068,8 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
|
|
for(i=1; i<WAL_NREADER; i++){
|
|
rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1);
|
|
if( rc==SQLITE_OK ){
|
|
- mxReadMark = AtomicStore(pInfo->aReadMark+i,mxFrame);
|
|
+ AtomicStore(pInfo->aReadMark+i,mxFrame);
|
|
+ mxReadMark = mxFrame;
|
|
mxI = i;
|
|
walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
|
|
break;
|
|
@@ -61841,9 +66107,9 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
|
|
** to read any frames earlier than minFrame from the wal file - they
|
|
** can be safely read directly from the database file.
|
|
**
|
|
- ** Because a ShmBarrier() call is made between taking the copy of
|
|
+ ** Because a ShmBarrier() call is made between taking the copy of
|
|
** nBackfill and checking that the wal-header in shared-memory still
|
|
- ** matches the one cached in pWal->hdr, it is guaranteed that the
|
|
+ ** matches the one cached in pWal->hdr, it is guaranteed that the
|
|
** checkpointer that set nBackfill was not working with a wal-index
|
|
** header newer than that cached in pWal->hdr. If it were, that could
|
|
** cause a problem. The checkpointer could omit to checkpoint
|
|
@@ -61871,15 +66137,15 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
|
|
|
|
#ifdef SQLITE_ENABLE_SNAPSHOT
|
|
/*
|
|
-** Attempt to reduce the value of the WalCkptInfo.nBackfillAttempted
|
|
+** Attempt to reduce the value of the WalCkptInfo.nBackfillAttempted
|
|
** variable so that older snapshots can be accessed. To do this, loop
|
|
-** through all wal frames from nBackfillAttempted to (nBackfill+1),
|
|
+** through all wal frames from nBackfillAttempted to (nBackfill+1),
|
|
** comparing their content to the corresponding page with the database
|
|
** file, if any. Set nBackfillAttempted to the frame number of the
|
|
** first frame for which the wal file content matches the db file.
|
|
**
|
|
-** This is only really safe if the file-system is such that any page
|
|
-** writes made by earlier checkpointers were atomic operations, which
|
|
+** This is only really safe if the file-system is such that any page
|
|
+** writes made by earlier checkpointers were atomic operations, which
|
|
** is not always true. It is also possible that nBackfillAttempted
|
|
** may be left set to a value larger than expected, if a wal frame
|
|
** contains content that duplicate of an earlier version of the same
|
|
@@ -61907,7 +66173,7 @@ SQLITE_PRIVATE int sqlite3WalSnapshotRecover(Wal *pWal){
|
|
rc = SQLITE_NOMEM;
|
|
}else{
|
|
u32 i = pInfo->nBackfillAttempted;
|
|
- for(i=pInfo->nBackfillAttempted; i>pInfo->nBackfill; i--){
|
|
+ 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 */
|
|
@@ -61915,7 +66181,8 @@ SQLITE_PRIVATE int sqlite3WalSnapshotRecover(Wal *pWal){
|
|
|
|
rc = walHashGet(pWal, walFramePage(i), &sLoc);
|
|
if( rc!=SQLITE_OK ) break;
|
|
- pgno = sLoc.aPgno[i-sLoc.iZero];
|
|
+ assert( i - sLoc.iZero - 1 >=0 );
|
|
+ pgno = sLoc.aPgno[i-sLoc.iZero-1];
|
|
iDbOff = (i64)(pgno-1) * szPage;
|
|
|
|
if( iDbOff+szPage<=szDb ){
|
|
@@ -61962,12 +66229,35 @@ SQLITE_PRIVATE int sqlite3WalSnapshotRecover(Wal *pWal){
|
|
SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
|
|
int rc; /* Return code */
|
|
int cnt = 0; /* Number of TryBeginRead attempts */
|
|
-
|
|
#ifdef SQLITE_ENABLE_SNAPSHOT
|
|
int bChanged = 0;
|
|
WalIndexHdr *pSnapshot = pWal->pSnapshot;
|
|
- if( pSnapshot && memcmp(pSnapshot, &pWal->hdr, sizeof(WalIndexHdr))!=0 ){
|
|
- bChanged = 1;
|
|
+#endif
|
|
+
|
|
+ assert( pWal->ckptLock==0 );
|
|
+
|
|
+#ifdef SQLITE_ENABLE_SNAPSHOT
|
|
+ if( pSnapshot ){
|
|
+ if( memcmp(pSnapshot, &pWal->hdr, sizeof(WalIndexHdr))!=0 ){
|
|
+ bChanged = 1;
|
|
+ }
|
|
+
|
|
+ /* It is possible that there is a checkpointer thread running
|
|
+ ** concurrent with this code. If this is the case, it may be that the
|
|
+ ** checkpointer has already determined that it will checkpoint
|
|
+ ** snapshot X, where X is later in the wal file than pSnapshot, but
|
|
+ ** has not yet set the pInfo->nBackfillAttempted variable to indicate
|
|
+ ** its intent. To avoid the race condition this leads to, ensure that
|
|
+ ** there is no checkpointer process by taking a shared CKPT lock
|
|
+ ** before checking pInfo->nBackfillAttempted. */
|
|
+ (void)walEnableBlocking(pWal);
|
|
+ rc = walLockShared(pWal, WAL_CKPT_LOCK);
|
|
+ walDisableBlocking(pWal);
|
|
+
|
|
+ if( rc!=SQLITE_OK ){
|
|
+ return rc;
|
|
+ }
|
|
+ pWal->ckptLock = 1;
|
|
}
|
|
#endif
|
|
|
|
@@ -62000,48 +66290,42 @@ SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
|
|
assert( pWal->readLock>0 || pWal->hdr.mxFrame==0 );
|
|
assert( pInfo->aReadMark[pWal->readLock]<=pSnapshot->mxFrame );
|
|
|
|
- /* It is possible that there is a checkpointer thread running
|
|
- ** concurrent with this code. If this is the case, it may be that the
|
|
- ** checkpointer has already determined that it will checkpoint
|
|
- ** snapshot X, where X is later in the wal file than pSnapshot, but
|
|
- ** has not yet set the pInfo->nBackfillAttempted variable to indicate
|
|
- ** its intent. To avoid the race condition this leads to, ensure that
|
|
- ** there is no checkpointer process by taking a shared CKPT lock
|
|
- ** before checking pInfo->nBackfillAttempted.
|
|
- **
|
|
- ** TODO: Does the aReadMark[] lock prevent a checkpointer from doing
|
|
- ** this already?
|
|
- */
|
|
- rc = walLockShared(pWal, WAL_CKPT_LOCK);
|
|
-
|
|
- if( rc==SQLITE_OK ){
|
|
- /* Check that the wal file has not been wrapped. Assuming that it has
|
|
- ** not, also check that no checkpointer has attempted to checkpoint any
|
|
- ** frames beyond pSnapshot->mxFrame. If either of these conditions are
|
|
- ** true, return SQLITE_ERROR_SNAPSHOT. Otherwise, overwrite pWal->hdr
|
|
- ** with *pSnapshot and set *pChanged as appropriate for opening the
|
|
- ** snapshot. */
|
|
- if( !memcmp(pSnapshot->aSalt, pWal->hdr.aSalt, sizeof(pWal->hdr.aSalt))
|
|
- && pSnapshot->mxFrame>=pInfo->nBackfillAttempted
|
|
- ){
|
|
- assert( pWal->readLock>0 );
|
|
- memcpy(&pWal->hdr, pSnapshot, sizeof(WalIndexHdr));
|
|
- *pChanged = bChanged;
|
|
- }else{
|
|
- rc = SQLITE_ERROR_SNAPSHOT;
|
|
- }
|
|
-
|
|
- /* Release the shared CKPT lock obtained above. */
|
|
- walUnlockShared(pWal, WAL_CKPT_LOCK);
|
|
- pWal->minFrame = 1;
|
|
+ /* Check that the wal file has not been wrapped. Assuming that it has
|
|
+ ** not, also check that no checkpointer has attempted to checkpoint any
|
|
+ ** frames beyond pSnapshot->mxFrame. If either of these conditions are
|
|
+ ** true, return SQLITE_ERROR_SNAPSHOT. Otherwise, overwrite pWal->hdr
|
|
+ ** with *pSnapshot and set *pChanged as appropriate for opening the
|
|
+ ** snapshot. */
|
|
+ if( !memcmp(pSnapshot->aSalt, pWal->hdr.aSalt, sizeof(pWal->hdr.aSalt))
|
|
+ && pSnapshot->mxFrame>=pInfo->nBackfillAttempted
|
|
+ ){
|
|
+ assert( pWal->readLock>0 );
|
|
+ memcpy(&pWal->hdr, pSnapshot, sizeof(WalIndexHdr));
|
|
+ *pChanged = bChanged;
|
|
+ }else{
|
|
+ rc = SQLITE_ERROR_SNAPSHOT;
|
|
}
|
|
|
|
+ /* A client using a non-current snapshot may not ignore any frames
|
|
+ ** from the start of the wal file. This is because, for a system
|
|
+ ** where (minFrame < iSnapshot < maxFrame), a checkpointer may
|
|
+ ** have omitted to checkpoint a frame earlier than minFrame in
|
|
+ ** the file because there exists a frame after iSnapshot that
|
|
+ ** is the same database page. */
|
|
+ pWal->minFrame = 1;
|
|
|
|
if( rc!=SQLITE_OK ){
|
|
sqlite3WalEndReadTransaction(pWal);
|
|
}
|
|
}
|
|
}
|
|
+
|
|
+ /* Release the shared CKPT lock obtained above. */
|
|
+ if( pWal->ckptLock ){
|
|
+ assert( pSnapshot );
|
|
+ walUnlockShared(pWal, WAL_CKPT_LOCK);
|
|
+ pWal->ckptLock = 0;
|
|
+ }
|
|
#endif
|
|
return rc;
|
|
}
|
|
@@ -62081,8 +66365,8 @@ SQLITE_PRIVATE int sqlite3WalFindFrame(
|
|
|
|
/* If the "last page" field of the wal-index header snapshot is 0, then
|
|
** no data will be read from the wal under any circumstances. Return early
|
|
- ** in this case as an optimization. Likewise, if pWal->readLock==0,
|
|
- ** then the WAL is ignored by the reader so return early, as if the
|
|
+ ** in this case as an optimization. Likewise, if pWal->readLock==0,
|
|
+ ** then the WAL is ignored by the reader so return early, as if the
|
|
** WAL were empty.
|
|
*/
|
|
if( iLast==0 || (pWal->readLock==0 && pWal->bShmUnreliable==0) ){
|
|
@@ -62095,9 +66379,9 @@ SQLITE_PRIVATE int sqlite3WalFindFrame(
|
|
** hash table (each hash table indexes up to HASHTABLE_NPAGE frames).
|
|
**
|
|
** This code might run concurrently to the code in walIndexAppend()
|
|
- ** that adds entries to the wal-index (and possibly to this hash
|
|
- ** table). This means the value just read from the hash
|
|
- ** slot (aHash[iKey]) may have been added before or after the
|
|
+ ** that adds entries to the wal-index (and possibly to this hash
|
|
+ ** table). This means the value just read from the hash
|
|
+ ** slot (aHash[iKey]) may have been added before or after the
|
|
** current read transaction was opened. Values added after the
|
|
** read transaction was opened may have been written incorrectly -
|
|
** i.e. these slots may contain garbage data. However, we assume
|
|
@@ -62105,13 +66389,13 @@ SQLITE_PRIVATE int sqlite3WalFindFrame(
|
|
** opened remain unmodified.
|
|
**
|
|
** For the reasons above, the if(...) condition featured in the inner
|
|
- ** loop of the following block is more stringent that would be required
|
|
+ ** loop of the following block is more stringent that would be required
|
|
** if we had exclusive access to the hash-table:
|
|
**
|
|
- ** (aPgno[iFrame]==pgno):
|
|
+ ** (aPgno[iFrame]==pgno):
|
|
** This condition filters out normal hash-table collisions.
|
|
**
|
|
- ** (iFrame<=iLast):
|
|
+ ** (iFrame<=iLast):
|
|
** This condition filters out entries that were added to the hash
|
|
** table after the current read-transaction had started.
|
|
*/
|
|
@@ -62121,22 +66405,24 @@ SQLITE_PRIVATE int sqlite3WalFindFrame(
|
|
int iKey; /* Hash slot index */
|
|
int nCollide; /* Number of hash collisions remaining */
|
|
int rc; /* Error code */
|
|
+ u32 iH;
|
|
|
|
rc = walHashGet(pWal, iHash, &sLoc);
|
|
if( rc!=SQLITE_OK ){
|
|
return rc;
|
|
}
|
|
nCollide = HASHTABLE_NSLOT;
|
|
- for(iKey=walHash(pgno); sLoc.aHash[iKey]; iKey=walNextHash(iKey)){
|
|
- u32 iH = sLoc.aHash[iKey];
|
|
+ iKey = walHash(pgno);
|
|
+ while( (iH = AtomicLoad(&sLoc.aHash[iKey]))!=0 ){
|
|
u32 iFrame = iH + sLoc.iZero;
|
|
- if( iFrame<=iLast && iFrame>=pWal->minFrame && sLoc.aPgno[iH]==pgno ){
|
|
+ if( iFrame<=iLast && iFrame>=pWal->minFrame && sLoc.aPgno[iH-1]==pgno ){
|
|
assert( iFrame>iRead || CORRUPT_DB );
|
|
iRead = iFrame;
|
|
}
|
|
if( (nCollide--)==0 ){
|
|
return SQLITE_CORRUPT_BKPT;
|
|
}
|
|
+ iKey = walNextHash(iKey);
|
|
}
|
|
if( iRead ) break;
|
|
}
|
|
@@ -62185,7 +66471,7 @@ SQLITE_PRIVATE int sqlite3WalReadFrame(
|
|
return sqlite3OsRead(pWal->pWalFd, pOut, (nOut>sz ? sz : nOut), iOffset);
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** Return the size of the database in pages (or zero, if unknown).
|
|
*/
|
|
SQLITE_PRIVATE Pgno sqlite3WalDbsize(Wal *pWal){
|
|
@@ -62196,7 +66482,7 @@ SQLITE_PRIVATE Pgno sqlite3WalDbsize(Wal *pWal){
|
|
}
|
|
|
|
|
|
-/*
|
|
+/*
|
|
** This function starts a write transaction on the WAL.
|
|
**
|
|
** A read transaction must have already been started by a prior call
|
|
@@ -62212,6 +66498,16 @@ SQLITE_PRIVATE Pgno sqlite3WalDbsize(Wal *pWal){
|
|
SQLITE_PRIVATE int sqlite3WalBeginWriteTransaction(Wal *pWal){
|
|
int rc;
|
|
|
|
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
|
+ /* If the write-lock is already held, then it was obtained before the
|
|
+ ** read-transaction was even opened, making this call a no-op.
|
|
+ ** Return early. */
|
|
+ if( pWal->writeLock ){
|
|
+ assert( !memcmp(&pWal->hdr,(void *)walIndexHdr(pWal),sizeof(WalIndexHdr)) );
|
|
+ return SQLITE_OK;
|
|
+ }
|
|
+#endif
|
|
+
|
|
/* Cannot start a write transaction without first holding a read
|
|
** transaction. */
|
|
assert( pWal->readLock>=0 );
|
|
@@ -62274,18 +66570,18 @@ SQLITE_PRIVATE int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *p
|
|
if( ALWAYS(pWal->writeLock) ){
|
|
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.
|
|
+ ** 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;
|
|
+ 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
|
|
+ ** 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).
|
|
@@ -62303,10 +66599,10 @@ SQLITE_PRIVATE int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *p
|
|
return rc;
|
|
}
|
|
|
|
-/*
|
|
-** Argument aWalData must point to an array of WAL_SAVEPOINT_NDATA u32
|
|
-** values. This function populates the array with values required to
|
|
-** "rollback" the write position of the WAL handle back to the current
|
|
+/*
|
|
+** Argument aWalData must point to an array of WAL_SAVEPOINT_NDATA u32
|
|
+** values. This function populates the array with values required to
|
|
+** "rollback" the write position of the WAL handle back to the current
|
|
** point in the event of a savepoint rollback (via WalSavepointUndo()).
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3WalSavepoint(Wal *pWal, u32 *aWalData){
|
|
@@ -62317,7 +66613,7 @@ SQLITE_PRIVATE void sqlite3WalSavepoint(Wal *pWal, u32 *aWalData){
|
|
aWalData[3] = pWal->nCkpt;
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** Move the write position of the WAL back to the point identified by
|
|
** the values in the aWalData[] array. aWalData must point to an array
|
|
** of WAL_SAVEPOINT_NDATA u32 values that has been previously populated
|
|
@@ -62457,11 +66753,7 @@ static int walWriteOneFrame(
|
|
int rc; /* Result code from subfunctions */
|
|
void *pData; /* Data actually written */
|
|
u8 aFrame[WAL_FRAME_HDRSIZE]; /* Buffer to assemble frame-header in */
|
|
-#if defined(SQLITE_HAS_CODEC)
|
|
- if( (pData = sqlite3PagerCodec(pPage))==0 ) return SQLITE_NOMEM_BKPT;
|
|
-#else
|
|
pData = pPage->pData;
|
|
-#endif
|
|
walEncodeFrame(p->pWal, pPage->pgno, nTruncate, pData, aFrame);
|
|
rc = walWriteToLog(p, aFrame, sizeof(aFrame), iOffset);
|
|
if( rc ) return rc;
|
|
@@ -62523,7 +66815,7 @@ static int walRewriteChecksums(Wal *pWal, u32 iLast){
|
|
return rc;
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** Write a set of frames to the log. The caller must hold the write-lock
|
|
** on the log file (obtained using sqlite3WalBeginWriteTransaction()).
|
|
*/
|
|
@@ -62590,7 +66882,7 @@ SQLITE_PRIVATE int sqlite3WalFrames(
|
|
walChecksumBytes(1, aWalHdr, WAL_HDRSIZE-2*4, 0, aCksum);
|
|
sqlite3Put4byte(&aWalHdr[24], aCksum[0]);
|
|
sqlite3Put4byte(&aWalHdr[28], aCksum[1]);
|
|
-
|
|
+
|
|
pWal->szPage = szPage;
|
|
pWal->hdr.bigEndCksum = SQLITE_BIGENDIAN;
|
|
pWal->hdr.aFrameCksum[0] = aCksum[0];
|
|
@@ -62632,7 +66924,7 @@ SQLITE_PRIVATE int sqlite3WalFrames(
|
|
|
|
/* Check if this page has already been written into the wal file by
|
|
** the current transaction. If so, overwrite the existing frame and
|
|
- ** set Wal.writeLock to WAL_WRITELOCK_RECKSUM - indicating that
|
|
+ ** set Wal.writeLock to WAL_WRITELOCK_RECKSUM - indicating that
|
|
** checksums must be recomputed when the transaction is committed. */
|
|
if( iFirst && (p->pDirty || isCommit==0) ){
|
|
u32 iWrite = 0;
|
|
@@ -62644,11 +66936,7 @@ SQLITE_PRIVATE int sqlite3WalFrames(
|
|
if( pWal->iReCksum==0 || iWrite<pWal->iReCksum ){
|
|
pWal->iReCksum = iWrite;
|
|
}
|
|
-#if defined(SQLITE_HAS_CODEC)
|
|
- if( (pData = sqlite3PagerCodec(p))==0 ) return SQLITE_NOMEM;
|
|
-#else
|
|
pData = p->pData;
|
|
-#endif
|
|
rc = sqlite3OsWrite(pWal->pWalFd, pData, szPage, iOff);
|
|
if( rc ) return rc;
|
|
p->flags &= ~PGHDR_WAL_APPEND;
|
|
@@ -62720,7 +67008,7 @@ SQLITE_PRIVATE int sqlite3WalFrames(
|
|
pWal->truncateOnCommit = 0;
|
|
}
|
|
|
|
- /* Append data to the wal-index. It is not necessary to lock the
|
|
+ /* Append data to the wal-index. It is not necessary to lock the
|
|
** wal-index to do this as the SQLITE_SHM_WRITE lock held on the wal-index
|
|
** guarantees that there are no other writers, and no data that may
|
|
** be in use by existing readers is being overwritten.
|
|
@@ -62759,7 +67047,7 @@ SQLITE_PRIVATE int sqlite3WalFrames(
|
|
return rc;
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** This routine is called to implement sqlite3_wal_checkpoint() and
|
|
** related interfaces.
|
|
**
|
|
@@ -62796,45 +67084,52 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint(
|
|
if( pWal->readOnly ) return SQLITE_READONLY;
|
|
WALTRACE(("WAL%p: checkpoint begins\n", pWal));
|
|
|
|
- /* IMPLEMENTATION-OF: R-62028-47212 All calls obtain an exclusive
|
|
- ** "checkpoint" lock on the database file. */
|
|
- rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
|
|
- if( rc ){
|
|
- /* EVIDENCE-OF: R-10421-19736 If any other process is running a
|
|
- ** checkpoint operation at the same time, the lock cannot be obtained and
|
|
- ** SQLITE_BUSY is returned.
|
|
- ** EVIDENCE-OF: R-53820-33897 Even if there is a busy-handler configured,
|
|
- ** it will not be invoked in this case.
|
|
- */
|
|
- testcase( rc==SQLITE_BUSY );
|
|
- testcase( xBusy!=0 );
|
|
- return rc;
|
|
- }
|
|
- pWal->ckptLock = 1;
|
|
+ /* Enable blocking locks, if possible. If blocking locks are successfully
|
|
+ ** enabled, set xBusy2=0 so that the busy-handler is never invoked. */
|
|
+ sqlite3WalDb(pWal, db);
|
|
+ (void)walEnableBlocking(pWal);
|
|
|
|
- /* IMPLEMENTATION-OF: R-59782-36818 The SQLITE_CHECKPOINT_FULL, RESTART and
|
|
- ** TRUNCATE modes also obtain the exclusive "writer" lock on the database
|
|
- ** file.
|
|
- **
|
|
- ** EVIDENCE-OF: R-60642-04082 If the writer lock cannot be obtained
|
|
- ** immediately, and a busy-handler is configured, it is invoked and the
|
|
- ** writer lock retried until either the busy-handler returns 0 or the
|
|
- ** lock is successfully obtained.
|
|
+ /* IMPLEMENTATION-OF: R-62028-47212 All calls obtain an exclusive
|
|
+ ** "checkpoint" lock on the database file.
|
|
+ ** EVIDENCE-OF: R-10421-19736 If any other process is running a
|
|
+ ** checkpoint operation at the same time, the lock cannot be obtained and
|
|
+ ** SQLITE_BUSY is returned.
|
|
+ ** EVIDENCE-OF: R-53820-33897 Even if there is a busy-handler configured,
|
|
+ ** it will not be invoked in this case.
|
|
*/
|
|
- if( eMode!=SQLITE_CHECKPOINT_PASSIVE ){
|
|
- rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_WRITE_LOCK, 1);
|
|
- if( rc==SQLITE_OK ){
|
|
- pWal->writeLock = 1;
|
|
- }else if( rc==SQLITE_BUSY ){
|
|
- eMode2 = SQLITE_CHECKPOINT_PASSIVE;
|
|
- xBusy2 = 0;
|
|
- rc = SQLITE_OK;
|
|
+ rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
|
|
+ testcase( rc==SQLITE_BUSY );
|
|
+ testcase( rc!=SQLITE_OK && xBusy2!=0 );
|
|
+ if( rc==SQLITE_OK ){
|
|
+ pWal->ckptLock = 1;
|
|
+
|
|
+ /* IMPLEMENTATION-OF: R-59782-36818 The SQLITE_CHECKPOINT_FULL, RESTART and
|
|
+ ** TRUNCATE modes also obtain the exclusive "writer" lock on the database
|
|
+ ** file.
|
|
+ **
|
|
+ ** EVIDENCE-OF: R-60642-04082 If the writer lock cannot be obtained
|
|
+ ** immediately, and a busy-handler is configured, it is invoked and the
|
|
+ ** writer lock retried until either the busy-handler returns 0 or the
|
|
+ ** lock is successfully obtained.
|
|
+ */
|
|
+ if( eMode!=SQLITE_CHECKPOINT_PASSIVE ){
|
|
+ rc = walBusyLock(pWal, xBusy2, pBusyArg, WAL_WRITE_LOCK, 1);
|
|
+ if( rc==SQLITE_OK ){
|
|
+ pWal->writeLock = 1;
|
|
+ }else if( rc==SQLITE_BUSY ){
|
|
+ eMode2 = SQLITE_CHECKPOINT_PASSIVE;
|
|
+ xBusy2 = 0;
|
|
+ rc = SQLITE_OK;
|
|
+ }
|
|
}
|
|
}
|
|
|
|
+
|
|
/* 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);
|
|
}
|
|
@@ -62857,7 +67152,7 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint(
|
|
}
|
|
|
|
if( isChanged ){
|
|
- /* If a new wal-index header was loaded before the checkpoint was
|
|
+ /* If a new wal-index header was loaded before the checkpoint was
|
|
** performed, then the pager-cache associated with pWal is now
|
|
** out of date. So zero the cached wal-index header to ensure that
|
|
** next time the pager opens a snapshot on this database it knows that
|
|
@@ -62866,11 +67161,19 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint(
|
|
memset(&pWal->hdr, 0, sizeof(WalIndexHdr));
|
|
}
|
|
|
|
+ walDisableBlocking(pWal);
|
|
+ sqlite3WalDb(pWal, 0);
|
|
+
|
|
/* Release the locks. */
|
|
sqlite3WalEndWriteTransaction(pWal);
|
|
- walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
|
|
- pWal->ckptLock = 0;
|
|
+ if( pWal->ckptLock ){
|
|
+ walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
|
|
+ pWal->ckptLock = 0;
|
|
+ }
|
|
WALTRACE(("WAL%p: checkpoint %s\n", pWal, rc ? "failed" : "ok"));
|
|
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
|
+ if( rc==SQLITE_BUSY_TIMEOUT ) rc = SQLITE_BUSY;
|
|
+#endif
|
|
return (rc==SQLITE_OK && eMode!=eMode2 ? SQLITE_BUSY : rc);
|
|
}
|
|
|
|
@@ -62900,7 +67203,7 @@ SQLITE_PRIVATE int sqlite3WalCallback(Wal *pWal){
|
|
** operation must occur while the pager is still holding the exclusive
|
|
** lock on the main database file.
|
|
**
|
|
-** If op is one, then change from locking_mode=NORMAL into
|
|
+** If op is one, then change from locking_mode=NORMAL into
|
|
** locking_mode=EXCLUSIVE. This means that the pWal->readLock must
|
|
** be released. Return 1 if the transition is made and 0 if the
|
|
** WAL is already in exclusive-locking mode - meaning that this
|
|
@@ -62917,8 +67220,8 @@ SQLITE_PRIVATE int sqlite3WalExclusiveMode(Wal *pWal, int op){
|
|
assert( pWal->writeLock==0 );
|
|
assert( pWal->exclusiveMode!=WAL_HEAPMEMORY_MODE || op==-1 );
|
|
|
|
- /* pWal->readLock is usually set, but might be -1 if there was a
|
|
- ** prior error while attempting to acquire are read-lock. This cannot
|
|
+ /* pWal->readLock is usually set, but might be -1 if there was a
|
|
+ ** prior error while attempting to acquire are read-lock. This cannot
|
|
** happen if the connection is actually in exclusive mode (as no xShmLock
|
|
** locks are taken in this case). Nor should the pager attempt to
|
|
** upgrade to exclusive-mode following such an error.
|
|
@@ -62949,10 +67252,10 @@ SQLITE_PRIVATE int sqlite3WalExclusiveMode(Wal *pWal, int op){
|
|
return rc;
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** 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.
|
|
+** WAL module is using shared-memory, return false.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal){
|
|
return (pWal && pWal->exclusiveMode==WAL_HEAPMEMORY_MODE );
|
|
@@ -62987,11 +67290,14 @@ SQLITE_PRIVATE int sqlite3WalSnapshotGet(Wal *pWal, sqlite3_snapshot **ppSnapsho
|
|
|
|
/* Try to open on pSnapshot when the next read-transaction starts
|
|
*/
|
|
-SQLITE_PRIVATE void sqlite3WalSnapshotOpen(Wal *pWal, sqlite3_snapshot *pSnapshot){
|
|
+SQLITE_PRIVATE void sqlite3WalSnapshotOpen(
|
|
+ Wal *pWal,
|
|
+ sqlite3_snapshot *pSnapshot
|
|
+){
|
|
pWal->pSnapshot = (WalIndexHdr*)pSnapshot;
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** 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.
|
|
*/
|
|
@@ -63011,7 +67317,7 @@ SQLITE_API int sqlite3_snapshot_cmp(sqlite3_snapshot *p1, sqlite3_snapshot *p2){
|
|
/*
|
|
** The caller currently has a read transaction open on the database.
|
|
** This function takes a SHARED lock on the CHECKPOINTER slot and then
|
|
-** checks if the snapshot passed as the second argument is still
|
|
+** checks if the snapshot passed as the second argument is still
|
|
** available. If so, SQLITE_OK is returned.
|
|
**
|
|
** If the snapshot is not available, SQLITE_ERROR is returned. Or, if
|
|
@@ -63118,16 +67424,16 @@ SQLITE_PRIVATE sqlite3_file *sqlite3WalFile(Wal *pWal){
|
|
** on Ptr(N) and its subpages have values greater than Key(N-1). And
|
|
** so forth.
|
|
**
|
|
-** Finding a particular key requires reading O(log(M)) pages from the
|
|
+** Finding a particular key requires reading O(log(M)) pages from the
|
|
** disk where M is the number of entries in the tree.
|
|
**
|
|
-** In this implementation, a single file can hold one or more separate
|
|
+** In this implementation, a single file can hold one or more separate
|
|
** BTrees. Each BTree is identified by the index of its root page. The
|
|
** key and data for any entry are combined to form the "payload". A
|
|
** fixed amount of payload can be carried directly on the database
|
|
** page. If the payload is larger than the preset amount then surplus
|
|
** bytes are stored on overflow pages. The payload for an entry
|
|
-** and the preceding pointer are combined to form a "Cell". Each
|
|
+** and the preceding pointer are combined to form a "Cell". Each
|
|
** page has a small header which contains the Ptr(N) pointer and other
|
|
** information such as the size of key and data.
|
|
**
|
|
@@ -63257,7 +67563,7 @@ SQLITE_PRIVATE sqlite3_file *sqlite3WalFile(Wal *pWal){
|
|
** contiguous or in order, but cell pointers are contiguous and in order.
|
|
**
|
|
** Cell content makes use of variable length integers. A variable
|
|
-** length integer is 1 to 9 bytes where the lower 7 bits of each
|
|
+** length integer is 1 to 9 bytes where the lower 7 bits of each
|
|
** 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.
|
|
@@ -63330,7 +67636,7 @@ typedef struct CellInfo CellInfo;
|
|
** -DSQLITE_FILE_HEADER="..." on the compiler command-line. The
|
|
** header must be exactly 16 bytes including the zero-terminator so
|
|
** the string itself should be 15 characters long. If you change
|
|
-** the header, then your custom library will not be able to read
|
|
+** the header, then your custom library will not be able to read
|
|
** databases generated by the standard tools and the standard tools
|
|
** will not be able to read databases created by your custom library.
|
|
*/
|
|
@@ -63361,7 +67667,6 @@ typedef struct CellInfo CellInfo;
|
|
*/
|
|
struct MemPage {
|
|
u8 isInit; /* True if previously initialized. MUST BE FIRST! */
|
|
- u8 bBusy; /* Prevent endless loops on corrupt database files */
|
|
u8 intKey; /* True if table b-trees. False for index b-trees */
|
|
u8 intKeyLeaf; /* True if the leaf of an intKey table */
|
|
Pgno pgno; /* Page number for this page */
|
|
@@ -63383,7 +67688,9 @@ struct MemPage {
|
|
u8 *apOvfl[4]; /* Pointers to the body of overflow cells */
|
|
BtShared *pBt; /* Pointer to BtShared that this page is part of */
|
|
u8 *aData; /* Pointer to disk image of the page data */
|
|
- u8 *aDataEnd; /* One byte past the end of usable data */
|
|
+ u8 *aDataEnd; /* One byte past the end of the entire page - not just
|
|
+ ** the usable space, the entire page. Used to prevent
|
|
+ ** corruption-induced buffer overflow. */
|
|
u8 *aCellIdx; /* The cell index area */
|
|
u8 *aDataOfst; /* Same as aData for leaves. aData+4 for interior */
|
|
DbPage *pDbPage; /* Pager page handle */
|
|
@@ -63393,7 +67700,7 @@ struct MemPage {
|
|
|
|
/*
|
|
** A linked list of the following structures is stored at BtShared.pLock.
|
|
-** Locks are added (or upgraded from READ_LOCK to WRITE_LOCK) when a cursor
|
|
+** Locks are added (or upgraded from READ_LOCK to WRITE_LOCK) when a cursor
|
|
** is opened on the table with root page BtShared.iTable. Locks are removed
|
|
** from this list when a transaction is committed or rolled back, or when
|
|
** a btree handle is closed.
|
|
@@ -63417,7 +67724,7 @@ struct BtLock {
|
|
** see the internals of this structure and only deals with pointers to
|
|
** this structure.
|
|
**
|
|
-** For some database files, the same underlying database cache might be
|
|
+** For some database files, the same underlying database cache might be
|
|
** shared between multiple connections. In that case, each connection
|
|
** has it own instance of this object. But each instance of this object
|
|
** points to the same BtShared object. The database cache and the
|
|
@@ -63425,7 +67732,7 @@ struct BtLock {
|
|
** the BtShared object.
|
|
**
|
|
** All fields in this structure are accessed under sqlite3.mutex.
|
|
-** The pBt pointer itself may not be changed while there exists cursors
|
|
+** The pBt pointer itself may not be changed while there exists cursors
|
|
** in the referenced BtShared that point back to this Btree since those
|
|
** cursors have to go through this Btree to find their BtShared and
|
|
** they often do so without holding sqlite3.mutex.
|
|
@@ -63439,9 +67746,12 @@ struct Btree {
|
|
u8 hasIncrblobCur; /* True if there are one or more Incrblob cursors */
|
|
int wantToLock; /* Number of nested calls to sqlite3BtreeEnter() */
|
|
int nBackup; /* Number of backup operations reading this btree */
|
|
- u32 iDataVersion; /* Combines with pBt->pPager->iDataVersion */
|
|
+ u32 iBDataVersion; /* Combines with pBt->pPager->iDataVersion */
|
|
Btree *pNext; /* List of other sharable Btrees from the same db */
|
|
Btree *pPrev; /* Back pointer of the same list */
|
|
+#ifdef SQLITE_DEBUG
|
|
+ u64 nSeek; /* Calls to sqlite3BtreeMovetoUnpacked() */
|
|
+#endif
|
|
#ifndef SQLITE_OMIT_SHARED_CACHE
|
|
BtLock lock; /* Object used to lock page 1 */
|
|
#endif
|
|
@@ -63453,14 +67763,28 @@ struct Btree {
|
|
** If the shared-data extension is enabled, there may be multiple users
|
|
** of the Btree structure. At most one of these may open a write transaction,
|
|
** but any number may have active read transactions.
|
|
+**
|
|
+** These values must match SQLITE_TXN_NONE, SQLITE_TXN_READ, and
|
|
+** SQLITE_TXN_WRITE
|
|
*/
|
|
#define TRANS_NONE 0
|
|
#define TRANS_READ 1
|
|
#define TRANS_WRITE 2
|
|
|
|
+#if TRANS_NONE!=SQLITE_TXN_NONE
|
|
+# error wrong numeric code for no-transaction
|
|
+#endif
|
|
+#if TRANS_READ!=SQLITE_TXN_READ
|
|
+# error wrong numeric code for read-transaction
|
|
+#endif
|
|
+#if TRANS_WRITE!=SQLITE_TXN_WRITE
|
|
+# error wrong numeric code for write-transaction
|
|
+#endif
|
|
+
|
|
+
|
|
/*
|
|
** An instance of this object represents a single database file.
|
|
-**
|
|
+**
|
|
** A single database file can be in use at the same time by two
|
|
** or more database connections. When two or more connections are
|
|
** sharing the same database file, each connection has it own
|
|
@@ -63470,7 +67794,7 @@ struct Btree {
|
|
**
|
|
** Fields in this structure are accessed under the BtShared.mutex
|
|
** mutex, except for nRef and pNext which are accessed under the
|
|
-** global SQLITE_MUTEX_STATIC_MASTER mutex. The pPager field
|
|
+** global SQLITE_MUTEX_STATIC_MAIN mutex. The pPager field
|
|
** may not be modified once it is initially set as long as nRef>0.
|
|
** The pSchema field may be set once under BtShared.mutex and
|
|
** thereafter is unchanged as long as nRef>0.
|
|
@@ -63506,9 +67830,7 @@ struct BtShared {
|
|
#endif
|
|
u8 inTransaction; /* Transaction state */
|
|
u8 max1bytePayload; /* Maximum first byte of cell for a 1-byte payload */
|
|
-#ifdef SQLITE_HAS_CODEC
|
|
- u8 optimalReserve; /* Desired amount of reserved space per page */
|
|
-#endif
|
|
+ u8 nReserveWanted; /* Desired number of extra bytes per page */
|
|
u16 btsFlags; /* Boolean parameters. See BTS_* macros below */
|
|
u16 maxLocal; /* Maximum local payload in non-LEAFDATA tables */
|
|
u16 minLocal; /* Minimum local payload in non-LEAFDATA tables */
|
|
@@ -63529,6 +67851,7 @@ struct BtShared {
|
|
Btree *pWriter; /* Btree with currently open write transaction */
|
|
#endif
|
|
u8 *pTmpSpace; /* Temp space sufficient to hold a single cell */
|
|
+ int nPreformatSize; /* Size of last cell written by TransferRow() */
|
|
};
|
|
|
|
/*
|
|
@@ -63580,7 +67903,7 @@ struct CellInfo {
|
|
** particular database connection identified BtCursor.pBtree.db.
|
|
**
|
|
** Fields in this structure are accessed under the BtShared.mutex
|
|
-** found at self->pBt->mutex.
|
|
+** found at self->pBt->mutex.
|
|
**
|
|
** skipNext meaning:
|
|
** The meaning of skipNext depends on the value of eState:
|
|
@@ -63637,7 +67960,7 @@ struct BtCursor {
|
|
** Potential values for BtCursor.eState.
|
|
**
|
|
** CURSOR_INVALID:
|
|
-** Cursor does not point to a valid entry. This can happen (for example)
|
|
+** Cursor does not point to a valid entry. This can happen (for example)
|
|
** because the table is empty or because BtreeCursorFirst() has not been
|
|
** called.
|
|
**
|
|
@@ -63650,9 +67973,9 @@ struct BtCursor {
|
|
** operation should be a no-op.
|
|
**
|
|
** CURSOR_REQUIRESEEK:
|
|
-** The table that this cursor was opened on still exists, but has been
|
|
+** The table that this cursor was opened on still exists, but has been
|
|
** modified since the cursor was last used. The cursor position is saved
|
|
-** in variables BtCursor.pKey and BtCursor.nKey. When a cursor is in
|
|
+** in variables BtCursor.pKey and BtCursor.nKey. When a cursor is in
|
|
** this state, restoreCursorPosition() can be called to attempt to
|
|
** seek the cursor to the saved position.
|
|
**
|
|
@@ -63669,13 +67992,13 @@ struct BtCursor {
|
|
#define CURSOR_REQUIRESEEK 3
|
|
#define CURSOR_FAULT 4
|
|
|
|
-/*
|
|
+/*
|
|
** The database page the PENDING_BYTE occupies. This page is never used.
|
|
*/
|
|
-# define PENDING_BYTE_PAGE(pBt) PAGER_MJ_PGNO(pBt)
|
|
+#define PENDING_BYTE_PAGE(pBt) ((Pgno)((PENDING_BYTE/((pBt)->pageSize))+1))
|
|
|
|
/*
|
|
-** These macros define the location of the pointer-map entry for a
|
|
+** These macros define the location of the pointer-map entry for a
|
|
** database page. The first argument to each is the number of usable
|
|
** bytes on each page of the database (often 1024). The second is the
|
|
** page number to look up in the pointer map.
|
|
@@ -63710,10 +68033,10 @@ struct BtCursor {
|
|
** PTRMAP_ROOTPAGE: The database page is a root-page. The page-number is not
|
|
** used in this case.
|
|
**
|
|
-** PTRMAP_FREEPAGE: The database page is an unused (free) page. The page-number
|
|
+** PTRMAP_FREEPAGE: The database page is an unused (free) page. The page-number
|
|
** is not used in this case.
|
|
**
|
|
-** PTRMAP_OVERFLOW1: The database page is the first page in a list of
|
|
+** PTRMAP_OVERFLOW1: The database page is the first page in a list of
|
|
** overflow pages. The page number identifies the page that
|
|
** contains the cell with a pointer to this overflow page.
|
|
**
|
|
@@ -63735,31 +68058,31 @@ struct BtCursor {
|
|
*/
|
|
#define btreeIntegrity(p) \
|
|
assert( p->pBt->inTransaction!=TRANS_NONE || p->pBt->nTransaction==0 ); \
|
|
- assert( p->pBt->inTransaction>=p->inTrans );
|
|
+ assert( p->pBt->inTransaction>=p->inTrans );
|
|
|
|
|
|
/*
|
|
** The ISAUTOVACUUM macro is used within balance_nonroot() to determine
|
|
** if the database supports auto-vacuum or not. Because it is used
|
|
-** within an expression that is an argument to another macro
|
|
+** within an expression that is an argument to another macro
|
|
** (sqliteMallocRaw), it is not possible to use conditional compilation.
|
|
** So, this macro is defined instead.
|
|
*/
|
|
#ifndef SQLITE_OMIT_AUTOVACUUM
|
|
-#define ISAUTOVACUUM (pBt->autoVacuum)
|
|
+#define ISAUTOVACUUM(pBt) (pBt->autoVacuum)
|
|
#else
|
|
-#define ISAUTOVACUUM 0
|
|
+#define ISAUTOVACUUM(pBt) 0
|
|
#endif
|
|
|
|
|
|
/*
|
|
-** This structure is passed around through all the sanity checking routines
|
|
-** in order to keep track of some global state information.
|
|
+** This structure is passed around through all the PRAGMA integrity_check
|
|
+** checking routines in order to keep track of some global state information.
|
|
**
|
|
** The aRef[] array is allocated so that there is 1 bit for each page in
|
|
** the database. As the integrity-check proceeds, for each page used in
|
|
-** the database the corresponding bit is set. This allows integrity-check to
|
|
-** detect pages that are used twice and orphaned pages (both of which
|
|
+** the database the corresponding bit is set. This allows integrity-check to
|
|
+** detect pages that are used twice and orphaned pages (both of which
|
|
** indicate corruption).
|
|
*/
|
|
typedef struct IntegrityCk IntegrityCk;
|
|
@@ -63770,9 +68093,11 @@ struct IntegrityCk {
|
|
Pgno nPage; /* Number of pages in the database */
|
|
int mxErr; /* Stop accumulating errors when this reaches zero */
|
|
int nErr; /* Number of messages written to zErrMsg so far */
|
|
- int mallocFailed; /* A memory allocation error has occurred */
|
|
+ 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 */
|
|
- int v1, v2; /* Values for up to two %d fields in zPfx */
|
|
+ Pgno v1; /* Value for first %u substitution in zPfx */
|
|
+ int v2; /* Value for second %d substitution in zPfx */
|
|
StrAccum errMsg; /* Accumulate the error message text here */
|
|
u32 *heap; /* Min-heap used for analyzing cell coverage */
|
|
sqlite3 *db; /* Database connection running the check */
|
|
@@ -64039,6 +68364,7 @@ SQLITE_PRIVATE int sqlite3BtreeHoldsAllMutexes(sqlite3 *db){
|
|
SQLITE_PRIVATE int sqlite3SchemaMutexHeld(sqlite3 *db, int iDb, Schema *pSchema){
|
|
Btree *p;
|
|
assert( db!=0 );
|
|
+ if( db->pVfs==0 && db->nDb==0 ) return 1;
|
|
if( pSchema ) iDb = sqlite3SchemaToIndex(db, pSchema);
|
|
assert( iDb>=0 && iDb<db->nDb );
|
|
if( !sqlite3_mutex_held(db->mutex) ) return 0;
|
|
@@ -64076,10 +68402,10 @@ SQLITE_PRIVATE void sqlite3BtreeEnterAll(sqlite3 *db){
|
|
|
|
#ifndef SQLITE_OMIT_INCRBLOB
|
|
/*
|
|
-** Enter a mutex on a Btree given a cursor owned by that Btree.
|
|
+** Enter a mutex on a Btree given a cursor owned by that Btree.
|
|
**
|
|
-** These entry points are used by incremental I/O only. Enter() is required
|
|
-** any time OMIT_SHARED_CACHE is not defined, regardless of whether or not
|
|
+** These entry points are used by incremental I/O only. Enter() is required
|
|
+** any time OMIT_SHARED_CACHE is not defined, regardless of whether or not
|
|
** the build is threadsafe. Leave() is only required by threadsafe builds.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3BtreeEnterCursor(BtCursor *pCur){
|
|
@@ -64149,7 +68475,7 @@ int sqlite3BtreeTrace=1; /* True to enable tracing */
|
|
#define BTALLOC_LE 2 /* Allocate any page <= the parameter */
|
|
|
|
/*
|
|
-** Macro IfNotOmitAV(x) returns (x) if SQLITE_OMIT_AUTOVACUUM is not
|
|
+** Macro IfNotOmitAV(x) returns (x) if SQLITE_OMIT_AUTOVACUUM is not
|
|
** defined, or 0 if it is. For example:
|
|
**
|
|
** bIncrVacuum = IfNotOmitAV(pBtShared->incrVacuum);
|
|
@@ -64164,10 +68490,10 @@ int sqlite3BtreeTrace=1; /* True to enable tracing */
|
|
/*
|
|
** A list of BtShared objects that are eligible for participation
|
|
** in shared cache. This variable has file scope during normal builds,
|
|
-** but the test harness needs to access it so we make it global for
|
|
+** but the test harness needs to access it so we make it global for
|
|
** test builds.
|
|
**
|
|
-** Access to this variable is protected by SQLITE_MUTEX_STATIC_MASTER.
|
|
+** Access to this variable is protected by SQLITE_MUTEX_STATIC_MAIN.
|
|
*/
|
|
#ifdef SQLITE_TEST
|
|
SQLITE_PRIVATE BtShared *SQLITE_WSD sqlite3SharedCacheList = 0;
|
|
@@ -64199,7 +68525,7 @@ SQLITE_API int sqlite3_enable_shared_cache(int enable){
|
|
** manipulate entries in the BtShared.pLock linked list used to store
|
|
** shared-cache table level locks. If the library is compiled with the
|
|
** shared-cache feature disabled, then there is only ever one user
|
|
- ** of each BtShared structure and so this locking is not necessary.
|
|
+ ** of each BtShared structure and so this locking is not necessary.
|
|
** So define the lock related functions as no-ops.
|
|
*/
|
|
#define querySharedCacheTableLock(a,b,c) SQLITE_OK
|
|
@@ -64210,6 +68536,17 @@ SQLITE_API int sqlite3_enable_shared_cache(int enable){
|
|
#define hasReadConflicts(a, b) 0
|
|
#endif
|
|
|
|
+#ifdef SQLITE_DEBUG
|
|
+/*
|
|
+** Return and reset the seek counter for a Btree object.
|
|
+*/
|
|
+SQLITE_PRIVATE sqlite3_uint64 sqlite3BtreeSeekCount(Btree *pBt){
|
|
+ u64 n = pBt->nSeek;
|
|
+ pBt->nSeek = 0;
|
|
+ return n;
|
|
+}
|
|
+#endif
|
|
+
|
|
/*
|
|
** Implementation of the SQLITE_CORRUPT_PAGE() macro. Takes a single
|
|
** (MemPage*) as an argument. The (MemPage*) must not be NULL.
|
|
@@ -64244,15 +68581,15 @@ int corruptPageError(int lineno, MemPage *p){
|
|
/*
|
|
**** This function is only used as part of an assert() statement. ***
|
|
**
|
|
-** Check to see if pBtree holds the required locks to read or write to the
|
|
+** Check to see if pBtree holds the required locks to read or write to the
|
|
** table with root page iRoot. Return 1 if it does and 0 if not.
|
|
**
|
|
-** For example, when writing to a table with root-page iRoot via
|
|
+** For example, when writing to a table with root-page iRoot via
|
|
** Btree connection pBtree:
|
|
**
|
|
** assert( hasSharedCacheTableLock(pBtree, iRoot, 0, WRITE_LOCK) );
|
|
**
|
|
-** When writing to an index that resides in a sharable database, the
|
|
+** When writing to an index that resides in a sharable database, the
|
|
** caller should have first obtained a lock specifying the root page of
|
|
** the corresponding table. This makes things a bit more complicated,
|
|
** as this module treats each table as a separate structure. To determine
|
|
@@ -64274,7 +68611,7 @@ static int hasSharedCacheTableLock(
|
|
BtLock *pLock;
|
|
|
|
/* If this database is not shareable, or if the client is reading
|
|
- ** and has the read-uncommitted flag set, then no lock is required.
|
|
+ ** and has the read-uncommitted flag set, then no lock is required.
|
|
** Return true immediately.
|
|
*/
|
|
if( (pBtree->sharable==0)
|
|
@@ -64298,29 +68635,31 @@ static int hasSharedCacheTableLock(
|
|
** table. */
|
|
if( isIndex ){
|
|
HashElem *p;
|
|
+ int bSeen = 0;
|
|
for(p=sqliteHashFirst(&pSchema->idxHash); p; p=sqliteHashNext(p)){
|
|
Index *pIdx = (Index *)sqliteHashData(p);
|
|
- if( pIdx->tnum==(int)iRoot ){
|
|
- if( iTab ){
|
|
+ if( pIdx->tnum==iRoot ){
|
|
+ if( bSeen ){
|
|
/* Two or more indexes share the same root page. There must
|
|
** be imposter tables. So just return true. The assert is not
|
|
** useful in that case. */
|
|
return 1;
|
|
}
|
|
iTab = pIdx->pTable->tnum;
|
|
+ bSeen = 1;
|
|
}
|
|
}
|
|
}else{
|
|
iTab = iRoot;
|
|
}
|
|
|
|
- /* Search for the required lock. Either a write-lock on root-page iTab, a
|
|
+ /* Search for the required lock. Either a write-lock on root-page iTab, a
|
|
** write-lock on the schema table, or (if the client is reading) a
|
|
** read-lock on iTab will suffice. Return 1 if any of these are found. */
|
|
for(pLock=pBtree->pBt->pLock; pLock; pLock=pLock->pNext){
|
|
- if( pLock->pBtree==pBtree
|
|
+ if( pLock->pBtree==pBtree
|
|
&& (pLock->iTable==iTab || (pLock->eLock==WRITE_LOCK && pLock->iTable==1))
|
|
- && pLock->eLock>=eLockType
|
|
+ && pLock->eLock>=eLockType
|
|
){
|
|
return 1;
|
|
}
|
|
@@ -64353,7 +68692,7 @@ static int hasSharedCacheTableLock(
|
|
static int hasReadConflicts(Btree *pBtree, Pgno iRoot){
|
|
BtCursor *p;
|
|
for(p=pBtree->pBt->pCursor; p; p=p->pNext){
|
|
- if( p->pgnoRoot==iRoot
|
|
+ if( p->pgnoRoot==iRoot
|
|
&& p->pBtree!=pBtree
|
|
&& 0==(p->pBtree->db->flags & SQLITE_ReadUncommit)
|
|
){
|
|
@@ -64365,7 +68704,7 @@ static int hasReadConflicts(Btree *pBtree, Pgno iRoot){
|
|
#endif /* #ifdef SQLITE_DEBUG */
|
|
|
|
/*
|
|
-** Query to see if Btree handle p may obtain a lock of type eLock
|
|
+** Query to see if Btree handle p may obtain a lock of type eLock
|
|
** (READ_LOCK or WRITE_LOCK) on the table with root-page iTab. Return
|
|
** SQLITE_OK if the lock may be obtained (by calling
|
|
** setSharedCacheTableLock()), or SQLITE_LOCKED if not.
|
|
@@ -64378,14 +68717,14 @@ static int querySharedCacheTableLock(Btree *p, Pgno iTab, u8 eLock){
|
|
assert( eLock==READ_LOCK || eLock==WRITE_LOCK );
|
|
assert( p->db!=0 );
|
|
assert( !(p->db->flags&SQLITE_ReadUncommit)||eLock==WRITE_LOCK||iTab==1 );
|
|
-
|
|
+
|
|
/* If requesting a write-lock, then the Btree must have an open write
|
|
- ** transaction on this file. And, obviously, for this to be so there
|
|
+ ** transaction on this file. And, obviously, for this to be so there
|
|
** must be an open write transaction on the file itself.
|
|
*/
|
|
assert( eLock==READ_LOCK || (p==pBt->pWriter && p->inTrans==TRANS_WRITE) );
|
|
assert( eLock==READ_LOCK || pBt->inTransaction==TRANS_WRITE );
|
|
-
|
|
+
|
|
/* This routine is a no-op if the shared-cache is not enabled */
|
|
if( !p->sharable ){
|
|
return SQLITE_OK;
|
|
@@ -64400,7 +68739,7 @@ static int querySharedCacheTableLock(Btree *p, Pgno iTab, u8 eLock){
|
|
}
|
|
|
|
for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){
|
|
- /* The condition (pIter->eLock!=eLock) in the following if(...)
|
|
+ /* The condition (pIter->eLock!=eLock) in the following if(...)
|
|
** statement is a simplification of:
|
|
**
|
|
** (eLock==WRITE_LOCK || pIter->eLock==WRITE_LOCK)
|
|
@@ -64427,7 +68766,7 @@ static int querySharedCacheTableLock(Btree *p, Pgno iTab, u8 eLock){
|
|
#ifndef SQLITE_OMIT_SHARED_CACHE
|
|
/*
|
|
** Add a lock on the table with root-page iTable to the shared-btree used
|
|
-** by Btree handle p. Parameter eLock must be either READ_LOCK or
|
|
+** by Btree handle p. Parameter eLock must be either READ_LOCK or
|
|
** WRITE_LOCK.
|
|
**
|
|
** This function assumes the following:
|
|
@@ -64439,7 +68778,7 @@ static int querySharedCacheTableLock(Btree *p, Pgno iTab, u8 eLock){
|
|
** with the requested lock (i.e. querySharedCacheTableLock() has
|
|
** already been called and returned SQLITE_OK).
|
|
**
|
|
-** SQLITE_OK is returned if the lock is added successfully. SQLITE_NOMEM
|
|
+** SQLITE_OK is returned if the lock is added successfully. SQLITE_NOMEM
|
|
** is returned if a malloc attempt fails.
|
|
*/
|
|
static int setSharedCacheTableLock(Btree *p, Pgno iTable, u8 eLock){
|
|
@@ -64453,11 +68792,11 @@ static int setSharedCacheTableLock(Btree *p, Pgno iTable, u8 eLock){
|
|
|
|
/* A connection with the read-uncommitted flag set will never try to
|
|
** obtain a read-lock using this function. The only read-lock obtained
|
|
- ** by a connection in read-uncommitted mode is on the sqlite_master
|
|
+ ** by a connection in read-uncommitted mode is on the sqlite_schema
|
|
** table, and that lock is obtained in BtreeBeginTrans(). */
|
|
assert( 0==(p->db->flags&SQLITE_ReadUncommit) || eLock==WRITE_LOCK );
|
|
|
|
- /* This function should only be called on a sharable b-tree after it
|
|
+ /* This function should only be called on a sharable b-tree after it
|
|
** has been determined that no other b-tree holds a conflicting lock. */
|
|
assert( p->sharable );
|
|
assert( SQLITE_OK==querySharedCacheTableLock(p, iTable, eLock) );
|
|
@@ -64502,7 +68841,7 @@ static int setSharedCacheTableLock(Btree *p, Pgno iTable, u8 eLock){
|
|
** Release all the table locks (locks obtained via calls to
|
|
** the setSharedCacheTableLock() procedure) held by Btree object p.
|
|
**
|
|
-** This function assumes that Btree p has an open read or write
|
|
+** This function assumes that Btree p has an open read or write
|
|
** transaction. If it does not, then the BTS_PENDING flag
|
|
** may be incorrectly cleared.
|
|
*/
|
|
@@ -64534,7 +68873,7 @@ static void clearAllSharedCacheTableLocks(Btree *p){
|
|
pBt->pWriter = 0;
|
|
pBt->btsFlags &= ~(BTS_EXCLUSIVE|BTS_PENDING);
|
|
}else if( pBt->nTransaction==2 ){
|
|
- /* This function is called when Btree p is concluding its
|
|
+ /* This function is called when Btree p is concluding its
|
|
** transaction. If there currently exists a writer, and p is not
|
|
** that writer, then the number of locks held by connections other
|
|
** than the writer must be about to drop to zero. In this case
|
|
@@ -64580,7 +68919,7 @@ static int cursorHoldsMutex(BtCursor *p){
|
|
}
|
|
|
|
/* Verify that the cursor and the BtShared agree about what is the current
|
|
-** database connetion. This is important in shared-cache mode. If the database
|
|
+** database connetion. This is important in shared-cache mode. If the database
|
|
** connection pointers get out-of-sync, it is possible for routines like
|
|
** btreeInitPage() to reference an stale connection pointer that references a
|
|
** a connection that has already closed. This routine is used inside assert()
|
|
@@ -64632,7 +68971,7 @@ static void invalidateIncrblobCursors(
|
|
int isClearTable /* True if all rows are being deleted */
|
|
){
|
|
BtCursor *p;
|
|
- if( pBtree->hasIncrblobCur==0 ) return;
|
|
+ assert( pBtree->hasIncrblobCur );
|
|
assert( sqlite3BtreeHoldsMutex(pBtree) );
|
|
pBtree->hasIncrblobCur = 0;
|
|
for(p=pBtree->pBt->pCursor; p; p=p->pNext){
|
|
@@ -64651,8 +68990,8 @@ static void invalidateIncrblobCursors(
|
|
#endif /* SQLITE_OMIT_INCRBLOB */
|
|
|
|
/*
|
|
-** Set bit pgno of the BtShared.pHasContent bitvec. This is called
|
|
-** when a page that previously contained data becomes a free-list leaf
|
|
+** Set bit pgno of the BtShared.pHasContent bitvec. This is called
|
|
+** when a page that previously contained data becomes a free-list leaf
|
|
** page.
|
|
**
|
|
** The BtShared.pHasContent bitvec exists to work around an obscure
|
|
@@ -64678,7 +69017,7 @@ static void invalidateIncrblobCursors(
|
|
** may be lost. In the event of a rollback, it may not be possible
|
|
** to restore the database to its original configuration.
|
|
**
|
|
-** The solution is the BtShared.pHasContent bitvec. Whenever a page is
|
|
+** The solution is the BtShared.pHasContent bitvec. Whenever a page is
|
|
** moved to become a free-list leaf page, the corresponding bit is
|
|
** set in the bitvec. Whenever a leaf page is extracted from the free-list,
|
|
** optimization 2 above is omitted if the corresponding bit is already
|
|
@@ -64709,7 +69048,7 @@ static int btreeSetHasContent(BtShared *pBt, Pgno pgno){
|
|
*/
|
|
static int btreeGetHasContent(BtShared *pBt, Pgno pgno){
|
|
Bitvec *p = pBt->pHasContent;
|
|
- return (p && (pgno>sqlite3BitvecSize(p) || sqlite3BitvecTest(p, pgno)));
|
|
+ return p && (pgno>sqlite3BitvecSize(p) || sqlite3BitvecTestNotNull(p, pgno));
|
|
}
|
|
|
|
/*
|
|
@@ -64739,13 +69078,13 @@ static void btreeReleaseAllCursorPages(BtCursor *pCur){
|
|
** The cursor passed as the only argument must point to a valid entry
|
|
** when this function is called (i.e. have eState==CURSOR_VALID). This
|
|
** function saves the current cursor key in variables pCur->nKey and
|
|
-** pCur->pKey. SQLITE_OK is returned if successful or an SQLite error
|
|
+** pCur->pKey. SQLITE_OK is returned if successful or an SQLite error
|
|
** code otherwise.
|
|
**
|
|
** If the cursor is open on an intkey table, then the integer key
|
|
** (the rowid) is stored in pCur->nKey and pCur->pKey is left set to
|
|
-** NULL. If the cursor is open on a non-intkey table, then pCur->pKey is
|
|
-** set to point to a malloced buffer pCur->nKey bytes in size containing
|
|
+** NULL. If the cursor is open on a non-intkey table, then pCur->pKey is
|
|
+** set to point to a malloced buffer pCur->nKey bytes in size containing
|
|
** the key.
|
|
*/
|
|
static int saveCursorKey(BtCursor *pCur){
|
|
@@ -64761,8 +69100,8 @@ static int saveCursorKey(BtCursor *pCur){
|
|
/* For an index btree, save the complete key content. It is possible
|
|
** that the current key is corrupt. In that case, it is possible that
|
|
** the sqlite3VdbeRecordUnpack() function may overread the buffer by
|
|
- ** up to the size of 1 varint plus 1 8-byte value when the cursor
|
|
- ** position is restored. Hence the 17 bytes of padding allocated
|
|
+ ** up to the size of 1 varint plus 1 8-byte value when the cursor
|
|
+ ** position is restored. Hence the 17 bytes of padding allocated
|
|
** below. */
|
|
void *pKey;
|
|
pCur->nKey = sqlite3BtreePayloadSize(pCur);
|
|
@@ -64784,11 +69123,11 @@ static int saveCursorKey(BtCursor *pCur){
|
|
}
|
|
|
|
/*
|
|
-** Save the current cursor position in the variables BtCursor.nKey
|
|
+** Save the current cursor position in the variables BtCursor.nKey
|
|
** and BtCursor.pKey. The cursor's state is set to CURSOR_REQUIRESEEK.
|
|
**
|
|
** The caller must ensure that the cursor is valid (has eState==CURSOR_VALID)
|
|
-** prior to calling this routine.
|
|
+** prior to calling this routine.
|
|
*/
|
|
static int saveCursorPosition(BtCursor *pCur){
|
|
int rc;
|
|
@@ -64827,7 +69166,7 @@ static int SQLITE_NOINLINE saveCursorsOnList(BtCursor*,Pgno,BtCursor*);
|
|
** routine is called just before cursor pExcept is used to modify the
|
|
** table, for example in BtreeDelete() or BtreeInsert().
|
|
**
|
|
-** If there are two or more cursors on the same btree, then all such
|
|
+** If there are two or more cursors on the same btree, then all such
|
|
** cursors should have their BTCF_Multiple flag set. The btreeCursor()
|
|
** routine enforces that rule. This routine only needs to be called in
|
|
** the uncommon case when pExpect has the BTCF_Multiple flag set.
|
|
@@ -64892,7 +69231,7 @@ SQLITE_PRIVATE void sqlite3BtreeClearCursor(BtCursor *pCur){
|
|
/*
|
|
** In this version of BtreeMoveto, pKey is a packed index record
|
|
** such as is generated by the OP_MakeRecord opcode. Unpack the
|
|
-** record and then call BtreeMovetoUnpacked() to do the work.
|
|
+** record and then call sqlite3BtreeIndexMoveto() to do the work.
|
|
*/
|
|
static int btreeMoveto(
|
|
BtCursor *pCur, /* Cursor open on the btree to be searched */
|
|
@@ -64912,24 +69251,22 @@ static int btreeMoveto(
|
|
sqlite3VdbeRecordUnpack(pKeyInfo, (int)nKey, pKey, pIdxKey);
|
|
if( pIdxKey->nField==0 || pIdxKey->nField>pKeyInfo->nAllField ){
|
|
rc = SQLITE_CORRUPT_BKPT;
|
|
- goto moveto_done;
|
|
+ }else{
|
|
+ rc = sqlite3BtreeIndexMoveto(pCur, pIdxKey, pRes);
|
|
}
|
|
+ sqlite3DbFree(pCur->pKeyInfo->db, pIdxKey);
|
|
}else{
|
|
pIdxKey = 0;
|
|
- }
|
|
- rc = sqlite3BtreeMovetoUnpacked(pCur, pIdxKey, nKey, bias, pRes);
|
|
-moveto_done:
|
|
- if( pIdxKey ){
|
|
- sqlite3DbFree(pCur->pKeyInfo->db, pIdxKey);
|
|
+ rc = sqlite3BtreeTableMoveto(pCur, nKey, bias, pRes);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
** Restore the cursor to the position it was in (or as close to as possible)
|
|
-** when saveCursorPosition() was called. Note that this call deletes the
|
|
+** when saveCursorPosition() was called. Note that this call deletes the
|
|
** saved position info stored by saveCursorPosition(), so there can be
|
|
-** at most one effective restoreCursorPosition() call after each
|
|
+** at most one effective restoreCursorPosition() call after each
|
|
** saveCursorPosition().
|
|
*/
|
|
static int btreeRestoreCursorPosition(BtCursor *pCur){
|
|
@@ -64997,7 +69334,7 @@ SQLITE_PRIVATE BtCursor *sqlite3BtreeFakeValidCursor(void){
|
|
/*
|
|
** This routine restores a cursor back to its original position after it
|
|
** has been moved by some outside activity (such as a btree rebalance or
|
|
-** a row having been deleted out from under the cursor).
|
|
+** a row having been deleted out from under the cursor).
|
|
**
|
|
** On success, the *pDifferentRow parameter is false if the cursor is left
|
|
** pointing at exactly the same row. *pDifferntRow is the row the cursor
|
|
@@ -65062,7 +69399,7 @@ static Pgno ptrmapPageno(BtShared *pBt, Pgno pgno){
|
|
if( pgno<2 ) return 0;
|
|
nPagesPerMapPage = (pBt->usableSize/5)+1;
|
|
iPtrMap = (pgno-2)/nPagesPerMapPage;
|
|
- ret = (iPtrMap*nPagesPerMapPage) + 2;
|
|
+ ret = (iPtrMap*nPagesPerMapPage) + 2;
|
|
if( ret==PENDING_BYTE_PAGE(pBt) ){
|
|
ret++;
|
|
}
|
|
@@ -65089,7 +69426,7 @@ static void ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent, int *pRC){
|
|
if( *pRC ) return;
|
|
|
|
assert( sqlite3_mutex_held(pBt->mutex) );
|
|
- /* The master-journal page number must never be used as a pointer map page */
|
|
+ /* The super-journal page number must never be used as a pointer map page */
|
|
assert( 0==PTRMAP_ISPAGE(pBt, PENDING_BYTE_PAGE(pBt)) );
|
|
|
|
assert( pBt->autoVacuum );
|
|
@@ -65228,6 +69565,24 @@ static SQLITE_NOINLINE void btreeParseCellAdjustSizeForOverflow(
|
|
pInfo->nSize = (u16)(&pInfo->pPayload[pInfo->nLocal] - pCell) + 4;
|
|
}
|
|
|
|
+/*
|
|
+** Given a record with nPayload bytes of payload stored within btree
|
|
+** page pPage, return the number of bytes of payload stored locally.
|
|
+*/
|
|
+static int btreePayloadToLocal(MemPage *pPage, i64 nPayload){
|
|
+ int maxLocal; /* Maximum amount of payload held locally */
|
|
+ maxLocal = pPage->maxLocal;
|
|
+ if( nPayload<=maxLocal ){
|
|
+ return nPayload;
|
|
+ }else{
|
|
+ int minLocal; /* Minimum amount of payload held locally */
|
|
+ int surplus; /* Overflow payload available for local storage */
|
|
+ minLocal = pPage->minLocal;
|
|
+ surplus = minLocal + (nPayload - minLocal)%(pPage->pBt->usableSize-4);
|
|
+ return ( surplus <= maxLocal ) ? surplus : minLocal;
|
|
+ }
|
|
+}
|
|
+
|
|
/*
|
|
** The following routines are implementations of the MemPage.xParseCell()
|
|
** method.
|
|
@@ -65294,18 +69649,32 @@ static void btreeParseCellPtr(
|
|
**
|
|
** pIter += getVarint(pIter, (u64*)&pInfo->nKey);
|
|
**
|
|
- ** The code is inlined to avoid a function call.
|
|
+ ** The code is inlined and the loop is unrolled for performance.
|
|
+ ** This routine is a high-runner.
|
|
*/
|
|
iKey = *pIter;
|
|
if( iKey>=0x80 ){
|
|
- u8 *pEnd = &pIter[7];
|
|
- iKey &= 0x7f;
|
|
- while(1){
|
|
- iKey = (iKey<<7) | (*++pIter & 0x7f);
|
|
- if( (*pIter)<0x80 ) break;
|
|
- if( pIter>=pEnd ){
|
|
- iKey = (iKey<<8) | *++pIter;
|
|
- break;
|
|
+ u8 x;
|
|
+ iKey = ((iKey&0x7f)<<7) | ((x = *++pIter) & 0x7f);
|
|
+ if( x>=0x80 ){
|
|
+ iKey = (iKey<<7) | ((x =*++pIter) & 0x7f);
|
|
+ if( x>=0x80 ){
|
|
+ iKey = (iKey<<7) | ((x = *++pIter) & 0x7f);
|
|
+ if( x>=0x80 ){
|
|
+ iKey = (iKey<<7) | ((x = *++pIter) & 0x7f);
|
|
+ if( x>=0x80 ){
|
|
+ iKey = (iKey<<7) | ((x = *++pIter) & 0x7f);
|
|
+ if( x>=0x80 ){
|
|
+ iKey = (iKey<<7) | ((x = *++pIter) & 0x7f);
|
|
+ if( x>=0x80 ){
|
|
+ iKey = (iKey<<7) | ((x = *++pIter) & 0x7f);
|
|
+ if( x>=0x80 ){
|
|
+ iKey = (iKey<<8) | (*++pIter);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
@@ -65315,7 +69684,7 @@ static void btreeParseCellPtr(
|
|
pInfo->nPayload = nPayload;
|
|
pInfo->pPayload = pIter;
|
|
testcase( nPayload==pPage->maxLocal );
|
|
- testcase( nPayload==pPage->maxLocal+1 );
|
|
+ testcase( nPayload==(u32)pPage->maxLocal+1 );
|
|
if( nPayload<=pPage->maxLocal ){
|
|
/* This is the (easy) common case where the entire payload fits
|
|
** on the local page. No overflow is required.
|
|
@@ -65352,7 +69721,7 @@ static void btreeParseCellPtrIndex(
|
|
pInfo->nPayload = nPayload;
|
|
pInfo->pPayload = pIter;
|
|
testcase( nPayload==pPage->maxLocal );
|
|
- testcase( nPayload==pPage->maxLocal+1 );
|
|
+ testcase( nPayload==(u32)pPage->maxLocal+1 );
|
|
if( nPayload<=pPage->maxLocal ){
|
|
/* This is the (easy) common case where the entire payload fits
|
|
** on the local page. No overflow is required.
|
|
@@ -65382,6 +69751,7 @@ static void btreeParseCell(
|
|
** the space used by the cell pointer.
|
|
**
|
|
** cellSizePtrNoPayload() => table internal nodes
|
|
+** cellSizePtrTableLeaf() => table leaf nodes
|
|
** cellSizePtr() => all index nodes & table leaf nodes
|
|
*/
|
|
static u16 cellSizePtr(MemPage *pPage, u8 *pCell){
|
|
@@ -65407,15 +69777,8 @@ static u16 cellSizePtr(MemPage *pPage, u8 *pCell){
|
|
}while( *(pIter)>=0x80 && pIter<pEnd );
|
|
}
|
|
pIter++;
|
|
- if( pPage->intKey ){
|
|
- /* pIter now points at the 64-bit integer key value, a variable length
|
|
- ** integer. The following block moves pIter to point at the first byte
|
|
- ** past the end of the key value. */
|
|
- pEnd = &pIter[9];
|
|
- while( (*pIter++)&0x80 && pIter<pEnd );
|
|
- }
|
|
testcase( nSize==pPage->maxLocal );
|
|
- testcase( nSize==pPage->maxLocal+1 );
|
|
+ testcase( nSize==(u32)pPage->maxLocal+1 );
|
|
if( nSize<=pPage->maxLocal ){
|
|
nSize += (u32)(pIter - pCell);
|
|
if( nSize<4 ) nSize = 4;
|
|
@@ -65423,7 +69786,7 @@ static u16 cellSizePtr(MemPage *pPage, u8 *pCell){
|
|
int minLocal = pPage->minLocal;
|
|
nSize = minLocal + (nSize - minLocal) % (pPage->pBt->usableSize - 4);
|
|
testcase( nSize==pPage->maxLocal );
|
|
- testcase( nSize==pPage->maxLocal+1 );
|
|
+ testcase( nSize==(u32)pPage->maxLocal+1 );
|
|
if( nSize>pPage->maxLocal ){
|
|
nSize = minLocal;
|
|
}
|
|
@@ -65453,6 +69816,58 @@ static u16 cellSizePtrNoPayload(MemPage *pPage, u8 *pCell){
|
|
assert( debuginfo.nSize==(u16)(pIter - pCell) || CORRUPT_DB );
|
|
return (u16)(pIter - pCell);
|
|
}
|
|
+static u16 cellSizePtrTableLeaf(MemPage *pPage, u8 *pCell){
|
|
+ u8 *pIter = pCell; /* For looping over bytes of pCell */
|
|
+ u8 *pEnd; /* End mark for a varint */
|
|
+ u32 nSize; /* Size value to return */
|
|
+
|
|
+#ifdef SQLITE_DEBUG
|
|
+ /* The value returned by this function should always be the same as
|
|
+ ** the (CellInfo.nSize) value found by doing a full parse of the
|
|
+ ** cell. If SQLITE_DEBUG is defined, an assert() at the bottom of
|
|
+ ** this function verifies that this invariant is not violated. */
|
|
+ CellInfo debuginfo;
|
|
+ pPage->xParseCell(pPage, pCell, &debuginfo);
|
|
+#endif
|
|
+
|
|
+ nSize = *pIter;
|
|
+ if( nSize>=0x80 ){
|
|
+ pEnd = &pIter[8];
|
|
+ nSize &= 0x7f;
|
|
+ do{
|
|
+ nSize = (nSize<<7) | (*++pIter & 0x7f);
|
|
+ }while( *(pIter)>=0x80 && pIter<pEnd );
|
|
+ }
|
|
+ pIter++;
|
|
+ /* pIter now points at the 64-bit integer key value, a variable length
|
|
+ ** integer. The following block moves pIter to point at the first byte
|
|
+ ** past the end of the key value. */
|
|
+ if( (*pIter++)&0x80
|
|
+ && (*pIter++)&0x80
|
|
+ && (*pIter++)&0x80
|
|
+ && (*pIter++)&0x80
|
|
+ && (*pIter++)&0x80
|
|
+ && (*pIter++)&0x80
|
|
+ && (*pIter++)&0x80
|
|
+ && (*pIter++)&0x80 ){ pIter++; }
|
|
+ testcase( nSize==pPage->maxLocal );
|
|
+ testcase( nSize==(u32)pPage->maxLocal+1 );
|
|
+ if( nSize<=pPage->maxLocal ){
|
|
+ nSize += (u32)(pIter - pCell);
|
|
+ if( nSize<4 ) nSize = 4;
|
|
+ }else{
|
|
+ int minLocal = pPage->minLocal;
|
|
+ nSize = minLocal + (nSize - minLocal) % (pPage->pBt->usableSize - 4);
|
|
+ testcase( nSize==pPage->maxLocal );
|
|
+ testcase( nSize==(u32)pPage->maxLocal+1 );
|
|
+ if( nSize>pPage->maxLocal ){
|
|
+ nSize = minLocal;
|
|
+ }
|
|
+ nSize += 4 + (u16)(pIter - pCell);
|
|
+ }
|
|
+ assert( nSize==debuginfo.nSize || CORRUPT_DB );
|
|
+ return (u16)nSize;
|
|
+}
|
|
|
|
|
|
#ifdef SQLITE_DEBUG
|
|
@@ -65466,7 +69881,7 @@ static u16 cellSize(MemPage *pPage, int iCell){
|
|
#ifndef SQLITE_OMIT_AUTOVACUUM
|
|
/*
|
|
** The cell pCell is currently part of page pSrc but will ultimately be part
|
|
-** of pPage. (pSrc and pPager are often the same.) If pCell contains a
|
|
+** of pPage. (pSrc and pPage are often the same.) If pCell contains a
|
|
** pointer to an overflow page, insert an entry into the pointer-map for
|
|
** the overflow page that will be valid after pCell has been moved to pPage.
|
|
*/
|
|
@@ -65515,14 +69930,14 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){
|
|
unsigned char *src; /* Source of content */
|
|
int iCellFirst; /* First allowable cell index */
|
|
int iCellLast; /* Last possible cell index */
|
|
+ int iCellStart; /* First cell offset in input */
|
|
|
|
assert( sqlite3PagerIswriteable(pPage->pDbPage) );
|
|
assert( pPage->pBt!=0 );
|
|
assert( pPage->pBt->usableSize <= SQLITE_MAX_PAGE_SIZE );
|
|
assert( pPage->nOverflow==0 );
|
|
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
|
|
- temp = 0;
|
|
- src = data = pPage->aData;
|
|
+ data = pPage->aData;
|
|
hdr = pPage->hdrOffset;
|
|
cellOffset = pPage->cellOffset;
|
|
nCell = pPage->nCell;
|
|
@@ -65533,7 +69948,7 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){
|
|
/* This block handles pages with two or fewer free blocks and nMaxFrag
|
|
** or fewer fragmented bytes. In this case it is faster to move the
|
|
** two (or one) blocks of cells using memmove() and add the required
|
|
- ** offsets to each pointer in the cell-pointer array than it is to
|
|
+ ** offsets to each pointer in the cell-pointer array than it is to
|
|
** reconstruct the entire page. */
|
|
if( (int)data[hdr+7]<=nMaxFrag ){
|
|
int iFree = get2byte(&data[hdr+1]);
|
|
@@ -65547,7 +69962,7 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){
|
|
int sz2 = 0;
|
|
int sz = get2byte(&data[iFree+2]);
|
|
int top = get2byte(&data[hdr+5]);
|
|
- if( NEVER(top>=iFree) ){
|
|
+ if( top>=iFree ){
|
|
return SQLITE_CORRUPT_PAGE(pPage);
|
|
}
|
|
if( iFree2 ){
|
|
@@ -65556,7 +69971,7 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){
|
|
if( iFree2+sz2 > usableSize ) return SQLITE_CORRUPT_PAGE(pPage);
|
|
memmove(&data[iFree+sz+sz2], &data[iFree+sz], iFree2-(iFree+sz));
|
|
sz += sz2;
|
|
- }else if( NEVER(iFree+sz>usableSize) ){
|
|
+ }else if( iFree+sz>usableSize ){
|
|
return SQLITE_CORRUPT_PAGE(pPage);
|
|
}
|
|
|
|
@@ -65575,41 +69990,39 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){
|
|
|
|
cbrk = usableSize;
|
|
iCellLast = usableSize - 4;
|
|
- for(i=0; i<nCell; i++){
|
|
- u8 *pAddr; /* The i-th cell pointer */
|
|
- pAddr = &data[cellOffset + i*2];
|
|
- pc = get2byte(pAddr);
|
|
- testcase( pc==iCellFirst );
|
|
- testcase( pc==iCellLast );
|
|
- /* These conditions have already been verified in btreeInitPage()
|
|
- ** if PRAGMA cell_size_check=ON.
|
|
- */
|
|
- if( pc<iCellFirst || pc>iCellLast ){
|
|
- return SQLITE_CORRUPT_PAGE(pPage);
|
|
- }
|
|
- assert( pc>=iCellFirst && pc<=iCellLast );
|
|
- size = pPage->xCellSize(pPage, &src[pc]);
|
|
- cbrk -= size;
|
|
- if( cbrk<iCellFirst || pc+size>usableSize ){
|
|
- return SQLITE_CORRUPT_PAGE(pPage);
|
|
- }
|
|
- assert( cbrk+size<=usableSize && cbrk>=iCellFirst );
|
|
- testcase( cbrk+size==usableSize );
|
|
- testcase( pc+size==usableSize );
|
|
- put2byte(pAddr, cbrk);
|
|
- if( temp==0 ){
|
|
- int x;
|
|
- if( cbrk==pc ) continue;
|
|
- temp = sqlite3PagerTempSpace(pPage->pBt->pPager);
|
|
- x = get2byte(&data[hdr+5]);
|
|
- memcpy(&temp[x], &data[x], (cbrk+size) - x);
|
|
- src = temp;
|
|
+ iCellStart = get2byte(&data[hdr+5]);
|
|
+ if( nCell>0 ){
|
|
+ temp = sqlite3PagerTempSpace(pPage->pBt->pPager);
|
|
+ memcpy(&temp[iCellStart], &data[iCellStart], usableSize - iCellStart);
|
|
+ src = temp;
|
|
+ for(i=0; i<nCell; i++){
|
|
+ u8 *pAddr; /* The i-th cell pointer */
|
|
+ pAddr = &data[cellOffset + i*2];
|
|
+ pc = get2byte(pAddr);
|
|
+ testcase( pc==iCellFirst );
|
|
+ testcase( pc==iCellLast );
|
|
+ /* These conditions have already been verified in btreeInitPage()
|
|
+ ** if PRAGMA cell_size_check=ON.
|
|
+ */
|
|
+ if( pc<iCellStart || pc>iCellLast ){
|
|
+ return SQLITE_CORRUPT_PAGE(pPage);
|
|
+ }
|
|
+ assert( pc>=iCellStart && pc<=iCellLast );
|
|
+ size = pPage->xCellSize(pPage, &src[pc]);
|
|
+ cbrk -= size;
|
|
+ if( cbrk<iCellStart || pc+size>usableSize ){
|
|
+ return SQLITE_CORRUPT_PAGE(pPage);
|
|
+ }
|
|
+ assert( cbrk+size<=usableSize && cbrk>=iCellStart );
|
|
+ testcase( cbrk+size==usableSize );
|
|
+ testcase( pc+size==usableSize );
|
|
+ put2byte(pAddr, cbrk);
|
|
+ memcpy(&data[cbrk], &src[pc], size);
|
|
}
|
|
- memcpy(&data[cbrk], &src[pc], size);
|
|
}
|
|
data[hdr+7] = 0;
|
|
|
|
- defragment_out:
|
|
+defragment_out:
|
|
assert( pPage->nFree>=0 );
|
|
if( data[hdr+7]+cbrk-iCellFirst!=pPage->nFree ){
|
|
return SQLITE_CORRUPT_PAGE(pPage);
|
|
@@ -65641,7 +70054,8 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){
|
|
const int hdr = pPg->hdrOffset; /* Offset to page header */
|
|
u8 * const aData = pPg->aData; /* Page data */
|
|
int iAddr = hdr + 1; /* Address of ptr to pc */
|
|
- int pc = get2byte(&aData[iAddr]); /* Address of a free slot */
|
|
+ u8 *pTmp = &aData[iAddr]; /* Temporary ptr into aData[] */
|
|
+ int pc = get2byte(pTmp); /* Address of a free slot */
|
|
int x; /* Excess size of the slot */
|
|
int maxPC = pPg->pBt->usableSize - nByte; /* Max address for a usable slot */
|
|
int size; /* Size of the free slot */
|
|
@@ -65651,7 +70065,8 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){
|
|
/* EVIDENCE-OF: R-22710-53328 The third and fourth bytes of each
|
|
** freeblock form a big-endian integer which is the size of the freeblock
|
|
** in bytes, including the 4-byte header. */
|
|
- size = get2byte(&aData[pc+2]);
|
|
+ pTmp = &aData[pc+2];
|
|
+ size = get2byte(pTmp);
|
|
if( (x = size - nByte)>=0 ){
|
|
testcase( x==4 );
|
|
testcase( x==3 );
|
|
@@ -65664,6 +70079,7 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){
|
|
** fragmented bytes within the page. */
|
|
memcpy(&aData[iAddr], &aData[pc], 2);
|
|
aData[hdr+7] += (u8)x;
|
|
+ return &aData[pc];
|
|
}else if( x+pc > maxPC ){
|
|
/* This slot extends off the end of the usable part of the page */
|
|
*pRc = SQLITE_CORRUPT_PAGE(pPg);
|
|
@@ -65676,10 +70092,11 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){
|
|
return &aData[pc + x];
|
|
}
|
|
iAddr = pc;
|
|
- pc = get2byte(&aData[pc]);
|
|
- if( pc<=iAddr+size ){
|
|
+ pTmp = &aData[pc];
|
|
+ pc = get2byte(pTmp);
|
|
+ if( pc<=iAddr ){
|
|
if( pc ){
|
|
- /* The next slot in the chain is not past the end of the current slot */
|
|
+ /* The next slot in the chain comes before the current slot */
|
|
*pRc = SQLITE_CORRUPT_PAGE(pPg);
|
|
}
|
|
return 0;
|
|
@@ -65710,8 +70127,9 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
|
|
u8 * const data = pPage->aData; /* Local cache of pPage->aData */
|
|
int top; /* First byte of cell content area */
|
|
int rc = SQLITE_OK; /* Integer return code */
|
|
+ u8 *pTmp; /* Temp ptr into data[] */
|
|
int gap; /* First byte of gap between cell pointers and cell content */
|
|
-
|
|
+
|
|
assert( sqlite3PagerIswriteable(pPage->pDbPage) );
|
|
assert( pPage->pBt );
|
|
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
|
|
@@ -65728,7 +70146,8 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
|
|
** then the cell content offset of an empty page wants to be 65536.
|
|
** However, that integer is too large to be stored in a 2-byte unsigned
|
|
** integer, so a value of 0 is used in its place. */
|
|
- top = get2byte(&data[hdr+5]);
|
|
+ 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 ){
|
|
@@ -65751,7 +70170,7 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
|
|
int g2;
|
|
assert( pSpace+nByte<=data+pPage->pBt->usableSize );
|
|
*pIdx = g2 = (int)(pSpace-data);
|
|
- if( NEVER(g2<=gap) ){
|
|
+ if( g2<=gap ){
|
|
return SQLITE_CORRUPT_PAGE(pPage);
|
|
}else{
|
|
return SQLITE_OK;
|
|
@@ -65810,6 +70229,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
|
|
u16 x; /* Offset to cell content area */
|
|
u32 iEnd = iStart + iSize; /* First byte past the iStart buffer */
|
|
unsigned char *data = pPage->aData; /* Page content */
|
|
+ u8 *pTmp; /* Temporary ptr into data[] */
|
|
|
|
assert( pPage->pBt!=0 );
|
|
assert( sqlite3PagerIswriteable(pPage->pDbPage) );
|
|
@@ -65819,7 +70239,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
|
|
assert( iSize>=4 ); /* Minimum cell size is 4 */
|
|
assert( iStart<=pPage->pBt->usableSize-4 );
|
|
|
|
- /* The list of freeblocks must be in ascending order. Find the
|
|
+ /* The list of freeblocks must be in ascending order. Find the
|
|
** spot on the list where iStart should be inserted.
|
|
*/
|
|
hdr = pPage->hdrOffset;
|
|
@@ -65828,7 +70248,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
|
|
iFreeBlk = 0; /* Shortcut for the case when the freelist is empty */
|
|
}else{
|
|
while( (iFreeBlk = get2byte(&data[iPtr]))<iStart ){
|
|
- if( iFreeBlk<iPtr+4 ){
|
|
+ if( iFreeBlk<=iPtr ){
|
|
if( iFreeBlk==0 ) break; /* TH3: corrupt082.100 */
|
|
return SQLITE_CORRUPT_PAGE(pPage);
|
|
}
|
|
@@ -65837,8 +70257,8 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
|
|
if( iFreeBlk>pPage->pBt->usableSize-4 ){ /* TH3: corrupt081.100 */
|
|
return SQLITE_CORRUPT_PAGE(pPage);
|
|
}
|
|
- assert( iFreeBlk>iPtr || iFreeBlk==0 );
|
|
-
|
|
+ assert( iFreeBlk>iPtr || iFreeBlk==0 || CORRUPT_DB );
|
|
+
|
|
/* At this point:
|
|
** iFreeBlk: First freeblock after iStart, or zero if none
|
|
** iPtr: The address of a pointer to iFreeBlk
|
|
@@ -65849,13 +70269,13 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
|
|
nFrag = iFreeBlk - iEnd;
|
|
if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_PAGE(pPage);
|
|
iEnd = iFreeBlk + get2byte(&data[iFreeBlk+2]);
|
|
- if( NEVER(iEnd > pPage->pBt->usableSize) ){
|
|
+ if( iEnd > pPage->pBt->usableSize ){
|
|
return SQLITE_CORRUPT_PAGE(pPage);
|
|
}
|
|
iSize = iEnd - iStart;
|
|
iFreeBlk = get2byte(&data[iFreeBlk]);
|
|
}
|
|
-
|
|
+
|
|
/* If iPtr is another freeblock (that is, if iPtr is not the freelist
|
|
** pointer in the page header) then check to see if iStart should be
|
|
** coalesced onto the end of iPtr.
|
|
@@ -65872,13 +70292,14 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
|
|
if( nFrag>data[hdr+7] ) return SQLITE_CORRUPT_PAGE(pPage);
|
|
data[hdr+7] -= nFrag;
|
|
}
|
|
- x = get2byte(&data[hdr+5]);
|
|
+ pTmp = &data[hdr+5];
|
|
+ x = get2byte(pTmp);
|
|
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
|
|
** freelist entry */
|
|
if( iStart<x ) return SQLITE_CORRUPT_PAGE(pPage);
|
|
- if( NEVER(iPtr!=hdr+1) ) return SQLITE_CORRUPT_PAGE(pPage);
|
|
+ if( iPtr!=hdr+1 ) return SQLITE_CORRUPT_PAGE(pPage);
|
|
put2byte(&data[hdr+1], iFreeBlk);
|
|
put2byte(&data[hdr+5], iEnd);
|
|
}else{
|
|
@@ -65903,57 +70324,67 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
|
|
** Only the following combinations are supported. Anything different
|
|
** indicates a corrupt database files:
|
|
**
|
|
-** PTF_ZERODATA
|
|
-** PTF_ZERODATA | PTF_LEAF
|
|
-** PTF_LEAFDATA | PTF_INTKEY
|
|
-** PTF_LEAFDATA | PTF_INTKEY | PTF_LEAF
|
|
+** PTF_ZERODATA (0x02, 2)
|
|
+** PTF_LEAFDATA | PTF_INTKEY (0x05, 5)
|
|
+** PTF_ZERODATA | PTF_LEAF (0x0a, 10)
|
|
+** PTF_LEAFDATA | PTF_INTKEY | PTF_LEAF (0x0d, 13)
|
|
*/
|
|
static int decodeFlags(MemPage *pPage, int flagByte){
|
|
BtShared *pBt; /* A copy of pPage->pBt */
|
|
|
|
assert( pPage->hdrOffset==(pPage->pgno==1 ? 100 : 0) );
|
|
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
|
|
- pPage->leaf = (u8)(flagByte>>3); assert( PTF_LEAF == 1<<3 );
|
|
- flagByte &= ~PTF_LEAF;
|
|
- pPage->childPtrSize = 4-4*pPage->leaf;
|
|
- pPage->xCellSize = cellSizePtr;
|
|
pBt = pPage->pBt;
|
|
- if( flagByte==(PTF_LEAFDATA | PTF_INTKEY) ){
|
|
- /* EVIDENCE-OF: R-07291-35328 A value of 5 (0x05) means the page is an
|
|
- ** interior table b-tree page. */
|
|
- assert( (PTF_LEAFDATA|PTF_INTKEY)==5 );
|
|
- /* EVIDENCE-OF: R-26900-09176 A value of 13 (0x0d) means the page is a
|
|
- ** leaf table b-tree page. */
|
|
- assert( (PTF_LEAFDATA|PTF_INTKEY|PTF_LEAF)==13 );
|
|
- pPage->intKey = 1;
|
|
- if( pPage->leaf ){
|
|
+ pPage->max1bytePayload = pBt->max1bytePayload;
|
|
+ if( flagByte>=(PTF_ZERODATA | PTF_LEAF) ){
|
|
+ pPage->childPtrSize = 0;
|
|
+ pPage->leaf = 1;
|
|
+ if( flagByte==(PTF_LEAFDATA | PTF_INTKEY | PTF_LEAF) ){
|
|
pPage->intKeyLeaf = 1;
|
|
+ pPage->xCellSize = cellSizePtrTableLeaf;
|
|
pPage->xParseCell = btreeParseCellPtr;
|
|
+ pPage->intKey = 1;
|
|
+ pPage->maxLocal = pBt->maxLeaf;
|
|
+ pPage->minLocal = pBt->minLeaf;
|
|
+ }else if( flagByte==(PTF_ZERODATA | PTF_LEAF) ){
|
|
+ pPage->intKey = 0;
|
|
+ pPage->intKeyLeaf = 0;
|
|
+ pPage->xCellSize = cellSizePtr;
|
|
+ pPage->xParseCell = btreeParseCellPtrIndex;
|
|
+ pPage->maxLocal = pBt->maxLocal;
|
|
+ pPage->minLocal = pBt->minLocal;
|
|
}else{
|
|
+ pPage->intKey = 0;
|
|
+ pPage->intKeyLeaf = 0;
|
|
+ pPage->xCellSize = cellSizePtr;
|
|
+ pPage->xParseCell = btreeParseCellPtrIndex;
|
|
+ return SQLITE_CORRUPT_PAGE(pPage);
|
|
+ }
|
|
+ }else{
|
|
+ pPage->childPtrSize = 4;
|
|
+ pPage->leaf = 0;
|
|
+ if( flagByte==(PTF_ZERODATA) ){
|
|
+ pPage->intKey = 0;
|
|
+ pPage->intKeyLeaf = 0;
|
|
+ pPage->xCellSize = cellSizePtr;
|
|
+ pPage->xParseCell = btreeParseCellPtrIndex;
|
|
+ pPage->maxLocal = pBt->maxLocal;
|
|
+ pPage->minLocal = pBt->minLocal;
|
|
+ }else if( flagByte==(PTF_LEAFDATA | PTF_INTKEY) ){
|
|
pPage->intKeyLeaf = 0;
|
|
pPage->xCellSize = cellSizePtrNoPayload;
|
|
pPage->xParseCell = btreeParseCellPtrNoPayload;
|
|
+ pPage->intKey = 1;
|
|
+ pPage->maxLocal = pBt->maxLeaf;
|
|
+ pPage->minLocal = pBt->minLeaf;
|
|
+ }else{
|
|
+ pPage->intKey = 0;
|
|
+ pPage->intKeyLeaf = 0;
|
|
+ pPage->xCellSize = cellSizePtr;
|
|
+ pPage->xParseCell = btreeParseCellPtrIndex;
|
|
+ return SQLITE_CORRUPT_PAGE(pPage);
|
|
}
|
|
- pPage->maxLocal = pBt->maxLeaf;
|
|
- pPage->minLocal = pBt->minLeaf;
|
|
- }else if( flagByte==PTF_ZERODATA ){
|
|
- /* EVIDENCE-OF: R-43316-37308 A value of 2 (0x02) means the page is an
|
|
- ** interior index b-tree page. */
|
|
- assert( (PTF_ZERODATA)==2 );
|
|
- /* EVIDENCE-OF: R-59615-42828 A value of 10 (0x0a) means the page is a
|
|
- ** leaf index b-tree page. */
|
|
- assert( (PTF_ZERODATA|PTF_LEAF)==10 );
|
|
- pPage->intKey = 0;
|
|
- pPage->intKeyLeaf = 0;
|
|
- pPage->xParseCell = btreeParseCellPtrIndex;
|
|
- pPage->maxLocal = pBt->maxLocal;
|
|
- pPage->minLocal = pBt->minLocal;
|
|
- }else{
|
|
- /* EVIDENCE-OF: R-47608-56469 Any other value for the b-tree page type is
|
|
- ** an error. */
|
|
- return SQLITE_CORRUPT_PAGE(pPage);
|
|
}
|
|
- pPage->max1bytePayload = pBt->max1bytePayload;
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
@@ -66002,7 +70433,7 @@ static int btreeComputeFreeSpace(MemPage *pPage){
|
|
/* EVIDENCE-OF: R-55530-52930 In a well-formed b-tree page, there will
|
|
** always be at least one cell before the first freeblock.
|
|
*/
|
|
- return SQLITE_CORRUPT_PAGE(pPage);
|
|
+ return SQLITE_CORRUPT_PAGE(pPage);
|
|
}
|
|
while( 1 ){
|
|
if( pc>iCellLast ){
|
|
@@ -66041,7 +70472,7 @@ static int btreeComputeFreeSpace(MemPage *pPage){
|
|
|
|
/*
|
|
** Do additional sanity check after btreeInitPage() if
|
|
-** PRAGMA cell_size_check=ON
|
|
+** PRAGMA cell_size_check=ON
|
|
*/
|
|
static SQLITE_NOINLINE int btreeCellSizeCheck(MemPage *pPage){
|
|
int iCellFirst; /* First allowable cell or freeblock offset */
|
|
@@ -66079,7 +70510,7 @@ static SQLITE_NOINLINE int btreeCellSizeCheck(MemPage *pPage){
|
|
** Initialize the auxiliary information for a disk block.
|
|
**
|
|
** Return SQLITE_OK on success. If we see that the page does
|
|
-** not contain a well-formed database page, then return
|
|
+** not contain a well-formed database page, then return
|
|
** SQLITE_CORRUPT. Note that a return of SQLITE_OK does not
|
|
** guarantee that the page is well-formed. It only shows that
|
|
** we failed to detect any corruption.
|
|
@@ -66108,7 +70539,7 @@ static int btreeInitPage(MemPage *pPage){
|
|
pPage->nOverflow = 0;
|
|
pPage->cellOffset = pPage->hdrOffset + 8 + pPage->childPtrSize;
|
|
pPage->aCellIdx = data + pPage->childPtrSize + 8;
|
|
- pPage->aDataEnd = pPage->aData + pBt->usableSize;
|
|
+ pPage->aDataEnd = pPage->aData + pBt->pageSize;
|
|
pPage->aDataOfst = pPage->aData + pPage->childPtrSize;
|
|
/* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the
|
|
** number of cells on the page. */
|
|
@@ -66143,7 +70574,7 @@ static void zeroPage(MemPage *pPage, int flags){
|
|
u8 hdr = pPage->hdrOffset;
|
|
u16 first;
|
|
|
|
- assert( sqlite3PagerPagenumber(pPage->pDbPage)==pPage->pgno );
|
|
+ assert( sqlite3PagerPagenumber(pPage->pDbPage)==pPage->pgno || CORRUPT_DB );
|
|
assert( sqlite3PagerGetExtra(pPage->pDbPage) == (void*)pPage );
|
|
assert( sqlite3PagerGetData(pPage->pDbPage) == data );
|
|
assert( sqlite3PagerIswriteable(pPage->pDbPage) );
|
|
@@ -66159,7 +70590,7 @@ static void zeroPage(MemPage *pPage, int flags){
|
|
pPage->nFree = (u16)(pBt->usableSize - first);
|
|
decodeFlags(pPage, flags);
|
|
pPage->cellOffset = first;
|
|
- pPage->aDataEnd = &data[pBt->usableSize];
|
|
+ pPage->aDataEnd = &data[pBt->pageSize];
|
|
pPage->aCellIdx = &data[first];
|
|
pPage->aDataOfst = &data[pPage->childPtrSize];
|
|
pPage->nOverflow = 0;
|
|
@@ -66184,7 +70615,7 @@ static MemPage *btreePageFromDbPage(DbPage *pDbPage, Pgno pgno, BtShared *pBt){
|
|
pPage->hdrOffset = pgno==1 ? 100 : 0;
|
|
}
|
|
assert( pPage->aData==sqlite3PagerGetData(pDbPage) );
|
|
- return pPage;
|
|
+ return pPage;
|
|
}
|
|
|
|
/*
|
|
@@ -66235,12 +70666,11 @@ static MemPage *btreePageLookup(BtShared *pBt, Pgno pgno){
|
|
** error, return ((unsigned int)-1).
|
|
*/
|
|
static Pgno btreePagecount(BtShared *pBt){
|
|
- assert( (pBt->nPage & 0x80000000)==0 || CORRUPT_DB );
|
|
return pBt->nPage;
|
|
}
|
|
-SQLITE_PRIVATE u32 sqlite3BtreeLastPage(Btree *p){
|
|
+SQLITE_PRIVATE Pgno sqlite3BtreeLastPage(Btree *p){
|
|
assert( sqlite3BtreeHoldsMutex(p) );
|
|
- return btreePagecount(p->pBt) & 0x7fffffff;
|
|
+ return btreePagecount(p->pBt);
|
|
}
|
|
|
|
/*
|
|
@@ -66286,7 +70716,7 @@ static int getAndInitPage(
|
|
goto getAndInitPage_error2;
|
|
}
|
|
}
|
|
- assert( (*ppPage)->pgno==pgno );
|
|
+ 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
|
|
@@ -66305,7 +70735,7 @@ static int getAndInitPage(
|
|
pCur->pPage = pCur->apPage[pCur->iPage];
|
|
}
|
|
testcase( pgno==0 );
|
|
- assert( pgno!=0 || rc==SQLITE_CORRUPT );
|
|
+ assert( pgno!=0 || rc!=SQLITE_OK );
|
|
return rc;
|
|
}
|
|
|
|
@@ -66402,17 +70832,16 @@ static int btreeInvokeBusyHandler(void *pArg){
|
|
BtShared *pBt = (BtShared*)pArg;
|
|
assert( pBt->db );
|
|
assert( sqlite3_mutex_held(pBt->db->mutex) );
|
|
- return sqlite3InvokeBusyHandler(&pBt->db->busyHandler,
|
|
- sqlite3PagerFile(pBt->pPager));
|
|
+ return sqlite3InvokeBusyHandler(&pBt->db->busyHandler);
|
|
}
|
|
|
|
/*
|
|
** Open a database file.
|
|
-**
|
|
+**
|
|
** zFilename is the name of the database file. If zFilename is NULL
|
|
** then an ephemeral database is created. The ephemeral database might
|
|
** be exclusively in memory, or it might use a disk-based memory cache.
|
|
-** Either way, the ephemeral database will be automatically deleted
|
|
+** Either way, the ephemeral database will be automatically deleted
|
|
** when sqlite3BtreeClose() is called.
|
|
**
|
|
** If zFilename is ":memory:" then an in-memory database is created
|
|
@@ -66445,7 +70874,7 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
|
|
/* True if opening an ephemeral, temporary database */
|
|
const int isTempDb = zFilename==0 || zFilename[0]==0;
|
|
|
|
- /* Set the variable isMemdb to true for an in-memory database, or
|
|
+ /* Set the variable isMemdb to true for an in-memory database, or
|
|
** false for a file-based database.
|
|
*/
|
|
#ifdef SQLITE_OMIT_MEMORYDB
|
|
@@ -66519,7 +70948,7 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
|
|
#if SQLITE_THREADSAFE
|
|
mutexOpen = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_OPEN);
|
|
sqlite3_mutex_enter(mutexOpen);
|
|
- mutexShared = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
|
|
+ mutexShared = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN);
|
|
sqlite3_mutex_enter(mutexShared);
|
|
#endif
|
|
for(pBt=GLOBAL(BtShared*,sqlite3SharedCacheList); pBt; pBt=pBt->pNext){
|
|
@@ -66568,7 +70997,7 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
|
|
assert( sizeof(u32)==4 );
|
|
assert( sizeof(u16)==2 );
|
|
assert( sizeof(Pgno)==4 );
|
|
-
|
|
+
|
|
pBt = sqlite3MallocZero( sizeof(*pBt) );
|
|
if( pBt==0 ){
|
|
rc = SQLITE_NOMEM_BKPT;
|
|
@@ -66587,7 +71016,7 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
|
|
pBt->db = db;
|
|
sqlite3PagerSetBusyHandler(pBt->pPager, btreeInvokeBusyHandler, pBt);
|
|
p->pBt = pBt;
|
|
-
|
|
+
|
|
pBt->pCursor = 0;
|
|
pBt->pPage1 = 0;
|
|
if( sqlite3PagerIsreadonly(pBt->pPager) ) pBt->btsFlags |= BTS_READ_ONLY;
|
|
@@ -66631,14 +71060,14 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
|
|
if( rc ) goto btree_open_out;
|
|
pBt->usableSize = pBt->pageSize - nReserve;
|
|
assert( (pBt->pageSize & 7)==0 ); /* 8-byte alignment of pageSize */
|
|
-
|
|
+
|
|
#if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO)
|
|
/* Add the new BtShared object to the linked list sharable BtShareds.
|
|
*/
|
|
pBt->nRef = 1;
|
|
if( p->sharable ){
|
|
MUTEX_LOGIC( sqlite3_mutex *mutexShared; )
|
|
- MUTEX_LOGIC( mutexShared = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);)
|
|
+ MUTEX_LOGIC( mutexShared = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN);)
|
|
if( SQLITE_THREADSAFE && sqlite3GlobalConfig.bCoreMutex ){
|
|
pBt->mutex = sqlite3MutexAlloc(SQLITE_MUTEX_FAST);
|
|
if( pBt->mutex==0 ){
|
|
@@ -66703,7 +71132,7 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
|
|
** do not change the pager-cache size.
|
|
*/
|
|
if( sqlite3BtreeSchema(p, 0, 0)==0 ){
|
|
- sqlite3PagerSetCachesize(p->pBt->pPager, SQLITE_DEFAULT_CACHE_SIZE);
|
|
+ sqlite3BtreeSetCacheSize(p, SQLITE_DEFAULT_CACHE_SIZE);
|
|
}
|
|
|
|
pFile = sqlite3PagerFile(pBt->pPager);
|
|
@@ -66727,13 +71156,13 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
|
|
*/
|
|
static int removeFromSharingList(BtShared *pBt){
|
|
#ifndef SQLITE_OMIT_SHARED_CACHE
|
|
- MUTEX_LOGIC( sqlite3_mutex *pMaster; )
|
|
+ MUTEX_LOGIC( sqlite3_mutex *pMainMtx; )
|
|
BtShared *pList;
|
|
int removed = 0;
|
|
|
|
assert( sqlite3_mutex_notheld(pBt->mutex) );
|
|
- MUTEX_LOGIC( pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); )
|
|
- sqlite3_mutex_enter(pMaster);
|
|
+ MUTEX_LOGIC( pMainMtx = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); )
|
|
+ sqlite3_mutex_enter(pMainMtx);
|
|
pBt->nRef--;
|
|
if( pBt->nRef<=0 ){
|
|
if( GLOBAL(BtShared*,sqlite3SharedCacheList)==pBt ){
|
|
@@ -66752,7 +71181,7 @@ static int removeFromSharingList(BtShared *pBt){
|
|
}
|
|
removed = 1;
|
|
}
|
|
- sqlite3_mutex_leave(pMaster);
|
|
+ sqlite3_mutex_leave(pMainMtx);
|
|
return removed;
|
|
#else
|
|
return 1;
|
|
@@ -66760,34 +71189,42 @@ static int removeFromSharingList(BtShared *pBt){
|
|
}
|
|
|
|
/*
|
|
-** Make sure pBt->pTmpSpace points to an allocation of
|
|
+** Make sure pBt->pTmpSpace points to an allocation of
|
|
** MX_CELL_SIZE(pBt) bytes with a 4-byte prefix for a left-child
|
|
** pointer.
|
|
*/
|
|
-static void allocateTempSpace(BtShared *pBt){
|
|
- if( !pBt->pTmpSpace ){
|
|
- pBt->pTmpSpace = sqlite3PageMalloc( pBt->pageSize );
|
|
-
|
|
- /* One of the uses of pBt->pTmpSpace is to format cells before
|
|
- ** inserting them into a leaf page (function fillInCell()). If
|
|
- ** a cell is less than 4 bytes in size, it is rounded up to 4 bytes
|
|
- ** by the various routines that manipulate binary cells. Which
|
|
- ** 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
|
|
- ** data is passed to system call write(). So to avoid this error,
|
|
- ** zero the first 4 bytes of temp space here.
|
|
- **
|
|
- ** Also: Provide four bytes of initialized space before the
|
|
- ** beginning of pTmpSpace as an area available to prepend the
|
|
- ** left-child pointer to the beginning of a cell.
|
|
- */
|
|
- if( pBt->pTmpSpace ){
|
|
- memset(pBt->pTmpSpace, 0, 8);
|
|
- pBt->pTmpSpace += 4;
|
|
- }
|
|
+static SQLITE_NOINLINE int allocateTempSpace(BtShared *pBt){
|
|
+ assert( pBt!=0 );
|
|
+ assert( pBt->pTmpSpace==0 );
|
|
+ /* This routine is called only by btreeCursor() when allocating the
|
|
+ ** first write cursor for the BtShared object */
|
|
+ assert( pBt->pCursor!=0 && (pBt->pCursor->curFlags & BTCF_WriteFlag)!=0 );
|
|
+ pBt->pTmpSpace = sqlite3PageMalloc( pBt->pageSize );
|
|
+ if( pBt->pTmpSpace==0 ){
|
|
+ BtCursor *pCur = pBt->pCursor;
|
|
+ pBt->pCursor = pCur->pNext; /* Unlink the cursor */
|
|
+ memset(pCur, 0, sizeof(*pCur));
|
|
+ return SQLITE_NOMEM_BKPT;
|
|
}
|
|
+
|
|
+ /* One of the uses of pBt->pTmpSpace is to format cells before
|
|
+ ** inserting them into a leaf page (function fillInCell()). If
|
|
+ ** a cell is less than 4 bytes in size, it is rounded up to 4 bytes
|
|
+ ** by the various routines that manipulate binary cells. Which
|
|
+ ** 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
|
|
+ ** data is passed to system call write(). So to avoid this error,
|
|
+ ** zero the first 4 bytes of temp space here.
|
|
+ **
|
|
+ ** Also: Provide four bytes of initialized space before the
|
|
+ ** beginning of pTmpSpace as an area available to prepend the
|
|
+ ** left-child pointer to the beginning of a cell.
|
|
+ */
|
|
+ memset(pBt->pTmpSpace, 0, 8);
|
|
+ pBt->pTmpSpace += 4;
|
|
+ return SQLITE_OK;
|
|
}
|
|
|
|
/*
|
|
@@ -66806,19 +71243,23 @@ static void freeTempSpace(BtShared *pBt){
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3BtreeClose(Btree *p){
|
|
BtShared *pBt = p->pBt;
|
|
- BtCursor *pCur;
|
|
|
|
/* Close all cursors opened via this handle. */
|
|
assert( sqlite3_mutex_held(p->db->mutex) );
|
|
sqlite3BtreeEnter(p);
|
|
- pCur = pBt->pCursor;
|
|
- while( pCur ){
|
|
- BtCursor *pTmp = pCur;
|
|
- pCur = pCur->pNext;
|
|
- if( pTmp->pBtree==p ){
|
|
- sqlite3BtreeCloseCursor(pTmp);
|
|
+
|
|
+ /* Verify that no other cursors have this Btree open */
|
|
+#ifdef SQLITE_DEBUG
|
|
+ {
|
|
+ BtCursor *pCur = pBt->pCursor;
|
|
+ while( pCur ){
|
|
+ BtCursor *pTmp = pCur;
|
|
+ pCur = pCur->pNext;
|
|
+ assert( pTmp->pBtree!=p );
|
|
+
|
|
}
|
|
}
|
|
+#endif
|
|
|
|
/* Rollback any active transaction and free the handle structure.
|
|
** The call to sqlite3BtreeRollback() drops any table-locks held by
|
|
@@ -66828,7 +71269,7 @@ SQLITE_PRIVATE int sqlite3BtreeClose(Btree *p){
|
|
sqlite3BtreeLeave(p);
|
|
|
|
/* If there are still other outstanding references to the shared-btree
|
|
- ** structure, return now. The remainder of this procedure cleans
|
|
+ ** structure, return now. The remainder of this procedure cleans
|
|
** up the shared-btree.
|
|
*/
|
|
assert( p->wantToLock==0 && p->locked==0 );
|
|
@@ -66934,7 +71375,7 @@ SQLITE_PRIVATE int sqlite3BtreeSetPagerFlags(
|
|
|
|
/*
|
|
** Change the default pages size and the number of reserved bytes per page.
|
|
-** Or, if the page size has already been fixed, return SQLITE_READONLY
|
|
+** Or, if the page size has already been fixed, return SQLITE_READONLY
|
|
** without changing anything.
|
|
**
|
|
** The page size must be a power of 2 between 512 and 65536. If the page
|
|
@@ -66954,24 +71395,23 @@ SQLITE_PRIVATE int sqlite3BtreeSetPagerFlags(
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve, int iFix){
|
|
int rc = SQLITE_OK;
|
|
+ int x;
|
|
BtShared *pBt = p->pBt;
|
|
- assert( nReserve>=-1 && nReserve<=255 );
|
|
+ assert( nReserve>=0 && nReserve<=255 );
|
|
sqlite3BtreeEnter(p);
|
|
-#if SQLITE_HAS_CODEC
|
|
- if( nReserve>pBt->optimalReserve ) pBt->optimalReserve = (u8)nReserve;
|
|
-#endif
|
|
+ pBt->nReserveWanted = nReserve;
|
|
+ x = pBt->pageSize - pBt->usableSize;
|
|
+ if( nReserve<x ) nReserve = x;
|
|
if( pBt->btsFlags & BTS_PAGESIZE_FIXED ){
|
|
sqlite3BtreeLeave(p);
|
|
return SQLITE_READONLY;
|
|
}
|
|
- if( nReserve<0 ){
|
|
- nReserve = pBt->pageSize - pBt->usableSize;
|
|
- }
|
|
assert( nReserve>=0 && nReserve<=255 );
|
|
if( pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE &&
|
|
((pageSize-1)&pageSize)==0 ){
|
|
assert( (pageSize & 7)==0 );
|
|
assert( !pBt->pCursor );
|
|
+ if( nReserve>32 && pageSize==512 ) pageSize = 1024;
|
|
pBt->pageSize = (u32)pageSize;
|
|
freeTempSpace(pBt);
|
|
}
|
|
@@ -66995,7 +71435,7 @@ SQLITE_PRIVATE int sqlite3BtreeGetPageSize(Btree *p){
|
|
** held.
|
|
**
|
|
** This is useful in one special case in the backup API code where it is
|
|
-** known that the shared b-tree mutex is held, but the mutex on the
|
|
+** known that the shared b-tree mutex is held, but the mutex on the
|
|
** database handle that owns *p is not. In this case if sqlite3BtreeEnter()
|
|
** were to be called, it might collide with some other operation on the
|
|
** database handle that owns *p, causing undefined behavior.
|
|
@@ -67012,19 +71452,17 @@ SQLITE_PRIVATE int sqlite3BtreeGetReserveNoMutex(Btree *p){
|
|
** are intentually left unused. This is the "reserved" space that is
|
|
** sometimes used by extensions.
|
|
**
|
|
-** If SQLITE_HAS_MUTEX is defined then the number returned is the
|
|
-** greater of the current reserved space and the maximum requested
|
|
-** reserve space.
|
|
+** The value returned is the larger of the current reserve size and
|
|
+** the latest reserve size requested by SQLITE_FILECTRL_RESERVE_BYTES.
|
|
+** The amount of reserve can only grow - never shrink.
|
|
*/
|
|
-SQLITE_PRIVATE int sqlite3BtreeGetOptimalReserve(Btree *p){
|
|
- int n;
|
|
+SQLITE_PRIVATE int sqlite3BtreeGetRequestedReserve(Btree *p){
|
|
+ int n1, n2;
|
|
sqlite3BtreeEnter(p);
|
|
- n = sqlite3BtreeGetReserveNoMutex(p);
|
|
-#ifdef SQLITE_HAS_CODEC
|
|
- if( n<p->pBt->optimalReserve ) n = p->pBt->optimalReserve;
|
|
-#endif
|
|
+ n1 = (int)p->pBt->nReserveWanted;
|
|
+ n2 = sqlite3BtreeGetReserveNoMutex(p);
|
|
sqlite3BtreeLeave(p);
|
|
- return n;
|
|
+ return n1>n2 ? n1 : n2;
|
|
}
|
|
|
|
|
|
@@ -67033,8 +71471,8 @@ SQLITE_PRIVATE int sqlite3BtreeGetOptimalReserve(Btree *p){
|
|
** No changes are made if mxPage is 0 or negative.
|
|
** Regardless of the value of mxPage, return the maximum page count.
|
|
*/
|
|
-SQLITE_PRIVATE int sqlite3BtreeMaxPageCount(Btree *p, int mxPage){
|
|
- int n;
|
|
+SQLITE_PRIVATE Pgno sqlite3BtreeMaxPageCount(Btree *p, Pgno mxPage){
|
|
+ Pgno n;
|
|
sqlite3BtreeEnter(p);
|
|
n = sqlite3PagerMaxPageCount(p->pBt->pPager, mxPage);
|
|
sqlite3BtreeLeave(p);
|
|
@@ -67077,7 +71515,7 @@ SQLITE_PRIVATE int sqlite3BtreeSecureDelete(Btree *p, int newFlag){
|
|
/*
|
|
** Change the 'auto-vacuum' property of the database. If the 'autoVacuum'
|
|
** parameter is non-zero, then auto-vacuum mode is enabled. If zero, it
|
|
-** is disabled. The default value for the auto-vacuum property is
|
|
+** is disabled. The default value for the auto-vacuum property is
|
|
** determined by the SQLITE_DEFAULT_AUTOVACUUM macro.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3BtreeSetAutoVacuum(Btree *p, int autoVacuum){
|
|
@@ -67101,7 +71539,7 @@ SQLITE_PRIVATE int sqlite3BtreeSetAutoVacuum(Btree *p, int autoVacuum){
|
|
}
|
|
|
|
/*
|
|
-** Return the value of the 'auto-vacuum' property. If auto-vacuum is
|
|
+** Return the value of the 'auto-vacuum' property. If auto-vacuum is
|
|
** enabled 1 is returned. Otherwise 0.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3BtreeGetAutoVacuum(Btree *p){
|
|
@@ -67133,9 +71571,9 @@ static void setDefaultSyncFlag(BtShared *pBt, u8 safety_level){
|
|
Db *pDb;
|
|
if( (db=pBt->db)!=0 && (pDb=db->aDb)!=0 ){
|
|
while( pDb->pBt==0 || pDb->pBt->pBt!=pBt ){ pDb++; }
|
|
- if( pDb->bSyncSet==0
|
|
- && pDb->safety_level!=safety_level
|
|
- && pDb!=&db->aDb[1]
|
|
+ if( pDb->bSyncSet==0
|
|
+ && pDb->safety_level!=safety_level
|
|
+ && pDb!=&db->aDb[1]
|
|
){
|
|
pDb->safety_level = safety_level;
|
|
sqlite3PagerSetFlags(pBt->pPager,
|
|
@@ -67158,14 +71596,13 @@ static int newDatabase(BtShared*);
|
|
** SQLITE_OK is returned on success. If the file is not a
|
|
** well-formed database file, then SQLITE_CORRUPT is returned.
|
|
** SQLITE_BUSY is returned if the database is locked. SQLITE_NOMEM
|
|
-** is returned if we run out of memory.
|
|
+** is returned if we run out of memory.
|
|
*/
|
|
static int lockBtree(BtShared *pBt){
|
|
int rc; /* Result code from subfunctions */
|
|
MemPage *pPage1; /* Page 1 of the database file */
|
|
u32 nPage; /* Number of pages in the database */
|
|
u32 nPageFile = 0; /* Number of pages in the database file */
|
|
- u32 nPageHeader; /* Number of pages in the database according to hdr */
|
|
|
|
assert( sqlite3_mutex_held(pBt->mutex) );
|
|
assert( pBt->pPage1==0 );
|
|
@@ -67175,9 +71612,9 @@ static int lockBtree(BtShared *pBt){
|
|
if( rc!=SQLITE_OK ) return rc;
|
|
|
|
/* Do some checking to help insure the file we opened really is
|
|
- ** a valid database file.
|
|
+ ** a valid database file.
|
|
*/
|
|
- nPage = nPageHeader = get4byte(28+(u8*)pPage1->aData);
|
|
+ nPage = get4byte(28+(u8*)pPage1->aData);
|
|
sqlite3PagerPagecount(pBt->pPager, (int*)&nPageFile);
|
|
if( nPage==0 || memcmp(24+(u8*)pPage1->aData, 92+(u8*)pPage1->aData,4)!=0 ){
|
|
nPage = nPageFile;
|
|
@@ -67212,8 +71649,8 @@ static int lockBtree(BtShared *pBt){
|
|
goto page1_init_failed;
|
|
}
|
|
|
|
- /* If the write version is set to 2, this database should be accessed
|
|
- ** in WAL mode. If the log is not already open, open it now. Then
|
|
+ /* If the read version is set to 2, this database should be accessed
|
|
+ ** in WAL mode. If the log is not already open, open it now. Then
|
|
** return SQLITE_OK and return without populating BtShared.pPage1.
|
|
** The caller detects this and calls this function again. This is
|
|
** required as the version of page 1 currently in the page1 buffer
|
|
@@ -67254,8 +71691,8 @@ static int lockBtree(BtShared *pBt){
|
|
/* EVIDENCE-OF: R-25008-21688 The size of a page is a power of two
|
|
** between 512 and 65536 inclusive. */
|
|
if( ((pageSize-1)&pageSize)!=0
|
|
- || pageSize>SQLITE_MAX_PAGE_SIZE
|
|
- || pageSize<=256
|
|
+ || pageSize>SQLITE_MAX_PAGE_SIZE
|
|
+ || pageSize<=256
|
|
){
|
|
goto page1_init_failed;
|
|
}
|
|
@@ -67263,7 +71700,7 @@ static int lockBtree(BtShared *pBt){
|
|
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
|
|
- ** each page to reserve for extensions.
|
|
+ ** each page to reserve for extensions.
|
|
**
|
|
** EVIDENCE-OF: R-37497-42412 The size of the reserved region is
|
|
** determined by the one-byte unsigned integer found at an offset of 20
|
|
@@ -67284,9 +71721,13 @@ static int lockBtree(BtShared *pBt){
|
|
pageSize-usableSize);
|
|
return rc;
|
|
}
|
|
- if( sqlite3WritableSchema(pBt->db)==0 && nPage>nPageFile ){
|
|
- rc = SQLITE_CORRUPT_BKPT;
|
|
- goto page1_init_failed;
|
|
+ if( nPage>nPageFile ){
|
|
+ if( sqlite3WritableSchema(pBt->db)==0 ){
|
|
+ rc = SQLITE_CORRUPT_BKPT;
|
|
+ goto page1_init_failed;
|
|
+ }else{
|
|
+ nPage = nPageFile;
|
|
+ }
|
|
}
|
|
/* EVIDENCE-OF: R-28312-64704 However, the usable size is not allowed to
|
|
** be less than 480. In other words, if the page size is 512, then the
|
|
@@ -67353,7 +71794,7 @@ static int countValidCursors(BtShared *pBt, int wrOnly){
|
|
int r = 0;
|
|
for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
|
|
if( (wrOnly==0 || (pCur->curFlags & BTCF_WriteFlag)!=0)
|
|
- && pCur->eState!=CURSOR_FAULT ) r++;
|
|
+ && pCur->eState!=CURSOR_FAULT ) r++;
|
|
}
|
|
return r;
|
|
}
|
|
@@ -67362,7 +71803,7 @@ static int countValidCursors(BtShared *pBt, int wrOnly){
|
|
/*
|
|
** If there are no outstanding cursors and we are not in the middle
|
|
** of a transaction but there is a read lock on the database, then
|
|
-** this routine unrefs the first page of the database file which
|
|
+** this routine unrefs the first page of the database file which
|
|
** has the effect of releasing the read lock.
|
|
**
|
|
** If there is a transaction in progress, this routine is a no-op.
|
|
@@ -67446,8 +71887,8 @@ SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p){
|
|
** upgraded to exclusive by calling this routine a second time - the
|
|
** exclusivity flag only works for a new transaction.
|
|
**
|
|
-** A write-transaction must be started before attempting any
|
|
-** changes to the database. None of the following routines
|
|
+** A write-transaction must be started before attempting any
|
|
+** changes to the database. None of the following routines
|
|
** will work unless a transaction is started first:
|
|
**
|
|
** sqlite3BtreeCreateTable()
|
|
@@ -67461,7 +71902,7 @@ SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p){
|
|
** If an initial attempt to acquire the lock fails because of lock contention
|
|
** and the database was previously unlocked, then invoke the busy handler
|
|
** if there is one. But if there was previously a read-lock, do not
|
|
-** invoke the busy handler - just return SQLITE_BUSY. SQLITE_BUSY is
|
|
+** invoke the busy handler - just return SQLITE_BUSY. SQLITE_BUSY is
|
|
** returned when there is already a read-lock in order to avoid a deadlock.
|
|
**
|
|
** Suppose there are two processes A and B. A has a read lock and B has
|
|
@@ -67474,6 +71915,7 @@ SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p){
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVersion){
|
|
BtShared *pBt = p->pBt;
|
|
+ Pager *pPager = pBt->pPager;
|
|
int rc = SQLITE_OK;
|
|
|
|
sqlite3BtreeEnter(p);
|
|
@@ -67488,8 +71930,8 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVers
|
|
}
|
|
assert( pBt->inTransaction==TRANS_WRITE || IfNotOmitAV(pBt->bDoTruncate)==0 );
|
|
|
|
- if( (p->db->flags & SQLITE_ResetDatabase)
|
|
- && sqlite3PagerIsreadonly(pBt->pPager)==0
|
|
+ if( (p->db->flags & SQLITE_ResetDatabase)
|
|
+ && sqlite3PagerIsreadonly(pPager)==0
|
|
){
|
|
pBt->btsFlags &= ~BTS_READ_ONLY;
|
|
}
|
|
@@ -67503,7 +71945,7 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVers
|
|
#ifndef SQLITE_OMIT_SHARED_CACHE
|
|
{
|
|
sqlite3 *pBlock = 0;
|
|
- /* If another database handle has already opened a write transaction
|
|
+ /* If another database handle has already opened a write transaction
|
|
** on this shared-btree structure and a second write transaction is
|
|
** requested, return SQLITE_LOCKED.
|
|
*/
|
|
@@ -67528,19 +71970,31 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVers
|
|
}
|
|
#endif
|
|
|
|
- /* Any read-only or read-write transaction implies a read-lock on
|
|
- ** page 1. So if some other shared-cache client already has a write-lock
|
|
+ /* Any read-only or read-write transaction implies a read-lock on
|
|
+ ** page 1. So if some other shared-cache client already has a write-lock
|
|
** on page 1, the transaction cannot be opened. */
|
|
- rc = querySharedCacheTableLock(p, MASTER_ROOT, READ_LOCK);
|
|
+ rc = querySharedCacheTableLock(p, SCHEMA_ROOT, READ_LOCK);
|
|
if( SQLITE_OK!=rc ) goto trans_begun;
|
|
|
|
pBt->btsFlags &= ~BTS_INITIALLY_EMPTY;
|
|
if( pBt->nPage==0 ) pBt->btsFlags |= BTS_INITIALLY_EMPTY;
|
|
do {
|
|
+ sqlite3PagerWalDb(pPager, p->db);
|
|
+
|
|
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
|
+ /* If transitioning from no transaction directly to a write transaction,
|
|
+ ** block for the WRITER lock first if possible. */
|
|
+ if( pBt->pPage1==0 && wrflag ){
|
|
+ assert( pBt->inTransaction==TRANS_NONE );
|
|
+ rc = sqlite3PagerWalWriteLock(pPager, 1);
|
|
+ if( rc!=SQLITE_BUSY && rc!=SQLITE_OK ) break;
|
|
+ }
|
|
+#endif
|
|
+
|
|
/* Call lockBtree() until either pBt->pPage1 is populated or
|
|
** lockBtree() returns something other than SQLITE_OK. lockBtree()
|
|
** may return SQLITE_OK but leave pBt->pPage1 set to 0 if after
|
|
- ** reading page 1 it discovers that the page-size of the database
|
|
+ ** reading page 1 it discovers that the page-size of the database
|
|
** file is not pBt->pageSize. In this case lockBtree() will update
|
|
** pBt->pageSize to the page-size of the file on disk.
|
|
*/
|
|
@@ -67550,7 +72004,7 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVers
|
|
if( (pBt->btsFlags & BTS_READ_ONLY)!=0 ){
|
|
rc = SQLITE_READONLY;
|
|
}else{
|
|
- rc = sqlite3PagerBegin(pBt->pPager,wrflag>1,sqlite3TempInMemory(p->db));
|
|
+ rc = sqlite3PagerBegin(pPager, wrflag>1, sqlite3TempInMemory(p->db));
|
|
if( rc==SQLITE_OK ){
|
|
rc = newDatabase(pBt);
|
|
}else if( rc==SQLITE_BUSY_SNAPSHOT && pBt->inTransaction==TRANS_NONE ){
|
|
@@ -67561,13 +72015,17 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVers
|
|
}
|
|
}
|
|
}
|
|
-
|
|
+
|
|
if( rc!=SQLITE_OK ){
|
|
+ (void)sqlite3PagerWalWriteLock(pPager, 0);
|
|
unlockBtreeIfUnused(pBt);
|
|
}
|
|
}while( (rc&0xFF)==SQLITE_BUSY && pBt->inTransaction==TRANS_NONE &&
|
|
btreeInvokeBusyHandler(pBt) );
|
|
- sqlite3PagerResetLockTimeout(pBt->pPager);
|
|
+ sqlite3PagerWalDb(pPager, 0);
|
|
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
|
+ if( rc==SQLITE_BUSY_TIMEOUT ) rc = SQLITE_BUSY;
|
|
+#endif
|
|
|
|
if( rc==SQLITE_OK ){
|
|
if( p->inTrans==TRANS_NONE ){
|
|
@@ -67596,7 +72054,7 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVers
|
|
|
|
/* If the db-size header field is incorrect (as it may be if an old
|
|
** client has been writing the database file), update it now. Doing
|
|
- ** this sooner rather than later means the database size can safely
|
|
+ ** this sooner rather than later means the database size can safely
|
|
** re-read the database size from page 1 if a savepoint or transaction
|
|
** rollback occurs within the transaction.
|
|
*/
|
|
@@ -67619,7 +72077,7 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVers
|
|
** open savepoints. If the second parameter is greater than 0 and
|
|
** the sub-journal is not already open, then it will be opened here.
|
|
*/
|
|
- rc = sqlite3PagerOpenSavepoint(pBt->pPager, p->db->nSavepoint);
|
|
+ rc = sqlite3PagerOpenSavepoint(pPager, p->db->nSavepoint);
|
|
}
|
|
}
|
|
|
|
@@ -67671,7 +72129,7 @@ static int setChildPtrmaps(MemPage *pPage){
|
|
** that it points to iTo. Parameter eType describes the type of pointer to
|
|
** be modified, as follows:
|
|
**
|
|
-** PTRMAP_BTREE: pPage is a btree-page. The pointer points at a child
|
|
+** PTRMAP_BTREE: pPage is a btree-page. The pointer points at a child
|
|
** page of pPage.
|
|
**
|
|
** PTRMAP_OVERFLOW1: pPage is a btree-page. The pointer points at an overflow
|
|
@@ -67713,15 +72171,18 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){
|
|
}
|
|
}
|
|
}else{
|
|
+ if( pCell+4 > pPage->aData+pPage->pBt->usableSize ){
|
|
+ return SQLITE_CORRUPT_PAGE(pPage);
|
|
+ }
|
|
if( get4byte(pCell)==iFrom ){
|
|
put4byte(pCell, iTo);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
-
|
|
+
|
|
if( i==nCell ){
|
|
- if( eType!=PTRMAP_BTREE ||
|
|
+ if( eType!=PTRMAP_BTREE ||
|
|
get4byte(&pPage->aData[pPage->hdrOffset+8])!=iFrom ){
|
|
return SQLITE_CORRUPT_PAGE(pPage);
|
|
}
|
|
@@ -67733,11 +72194,11 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){
|
|
|
|
|
|
/*
|
|
-** Move the open database page pDbPage to location iFreePage in the
|
|
+** Move the open database page pDbPage to location iFreePage in the
|
|
** database. The pDbPage reference remains valid.
|
|
**
|
|
** The isCommit flag indicates that there is no need to remember that
|
|
-** the journal needs to be sync()ed before database page pDbPage->pgno
|
|
+** the journal needs to be sync()ed before database page pDbPage->pgno
|
|
** can be written to. The caller has already promised not to write to that
|
|
** page.
|
|
*/
|
|
@@ -67754,14 +72215,14 @@ static int relocatePage(
|
|
Pager *pPager = pBt->pPager;
|
|
int rc;
|
|
|
|
- assert( eType==PTRMAP_OVERFLOW2 || eType==PTRMAP_OVERFLOW1 ||
|
|
+ assert( eType==PTRMAP_OVERFLOW2 || eType==PTRMAP_OVERFLOW1 ||
|
|
eType==PTRMAP_BTREE || eType==PTRMAP_ROOTPAGE );
|
|
assert( sqlite3_mutex_held(pBt->mutex) );
|
|
assert( pDbPage->pBt==pBt );
|
|
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 %d to free page %d (ptr page %d type %d)\n",
|
|
iDbPage, iFreePage, iPtrPage, eType));
|
|
rc = sqlite3PagerMovepage(pPager, pDbPage->pDbPage, iFreePage, isCommit);
|
|
if( rc!=SQLITE_OK ){
|
|
@@ -67820,19 +72281,19 @@ static int allocateBtreePage(BtShared *, MemPage **, Pgno *, Pgno, u8);
|
|
|
|
/*
|
|
** Perform a single step of an incremental-vacuum. If successful, return
|
|
-** SQLITE_OK. If there is no work to do (and therefore no point in
|
|
-** calling this function again), return SQLITE_DONE. Or, if an error
|
|
+** SQLITE_OK. If there is no work to do (and therefore no point in
|
|
+** calling this function again), return SQLITE_DONE. Or, if an error
|
|
** occurs, return some other error code.
|
|
**
|
|
-** More specifically, this function attempts to re-organize the database so
|
|
+** More specifically, this function attempts to re-organize the database so
|
|
** that the last page of the file currently in use is no longer in use.
|
|
**
|
|
** Parameter nFin is the number of pages that this database would contain
|
|
** were this function called until it returns SQLITE_DONE.
|
|
**
|
|
-** If the bCommit parameter is non-zero, this function assumes that the
|
|
-** caller will keep calling incrVacuumStep() until it returns SQLITE_DONE
|
|
-** or an error. bCommit is passed true for an auto-vacuum-on-commit
|
|
+** If the bCommit parameter is non-zero, this function assumes that the
|
|
+** caller will keep calling incrVacuumStep() until it returns SQLITE_DONE
|
|
+** or an error. bCommit is passed true for an auto-vacuum-on-commit
|
|
** operation, or false for an incremental vacuum.
|
|
*/
|
|
static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg, int bCommit){
|
|
@@ -67863,7 +72324,7 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg, int bCommit){
|
|
if( bCommit==0 ){
|
|
/* Remove the page from the files free-list. This is not required
|
|
** if bCommit is non-zero. In that case, the free-list will be
|
|
- ** truncated to zero after this function returns, so it doesn't
|
|
+ ** truncated to zero after this function returns, so it doesn't
|
|
** matter if it still contains some garbage entries.
|
|
*/
|
|
Pgno iFreePg;
|
|
@@ -67899,15 +72360,20 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg, int bCommit){
|
|
}
|
|
do {
|
|
MemPage *pFreePg;
|
|
+ Pgno dbSize = btreePagecount(pBt);
|
|
rc = allocateBtreePage(pBt, &pFreePg, &iFreePg, iNear, eMode);
|
|
if( rc!=SQLITE_OK ){
|
|
releasePage(pLastPg);
|
|
return rc;
|
|
}
|
|
releasePage(pFreePg);
|
|
+ if( iFreePg>dbSize ){
|
|
+ releasePage(pLastPg);
|
|
+ return SQLITE_CORRUPT_BKPT;
|
|
+ }
|
|
}while( bCommit && iFreePg>nFin );
|
|
assert( iFreePg<iLastPg );
|
|
-
|
|
+
|
|
rc = relocatePage(pBt, pLastPg, eType, iPtrPage, iFreePg, bCommit);
|
|
releasePage(pLastPg);
|
|
if( rc!=SQLITE_OK ){
|
|
@@ -67928,7 +72394,7 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg, int bCommit){
|
|
|
|
/*
|
|
** The database opened by the first argument is an auto-vacuum database
|
|
-** nOrig pages in size containing nFree free pages. Return the expected
|
|
+** nOrig pages in size containing nFree free pages. Return the expected
|
|
** size of the database in pages following an auto-vacuum operation.
|
|
*/
|
|
static Pgno finalDbSize(BtShared *pBt, Pgno nOrig, Pgno nFree){
|
|
@@ -67955,7 +72421,7 @@ static Pgno finalDbSize(BtShared *pBt, Pgno nOrig, Pgno nFree){
|
|
**
|
|
** If the incremental vacuum is finished after this function has run,
|
|
** SQLITE_DONE is returned. If it is not finished, but no error occurred,
|
|
-** SQLITE_OK is returned. Otherwise an SQLite error code.
|
|
+** SQLITE_OK is returned. Otherwise an SQLite error code.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3BtreeIncrVacuum(Btree *p){
|
|
int rc;
|
|
@@ -67970,7 +72436,7 @@ SQLITE_PRIVATE int sqlite3BtreeIncrVacuum(Btree *p){
|
|
Pgno nFree = get4byte(&pBt->pPage1->aData[36]);
|
|
Pgno nFin = finalDbSize(pBt, nOrig, nFree);
|
|
|
|
- if( nOrig<nFin ){
|
|
+ if( nOrig<nFin || nFree>=nOrig ){
|
|
rc = SQLITE_CORRUPT_BKPT;
|
|
}else if( nFree>0 ){
|
|
rc = saveAllCursors(pBt, 0, 0);
|
|
@@ -67993,16 +72459,18 @@ SQLITE_PRIVATE int sqlite3BtreeIncrVacuum(Btree *p){
|
|
/*
|
|
** This routine is called prior to sqlite3PagerCommit when a transaction
|
|
** is committed for an auto-vacuum database.
|
|
-**
|
|
-** If SQLITE_OK is returned, then *pnTrunc is set to the number of pages
|
|
-** the database file should be truncated to during the commit process.
|
|
-** i.e. the database has been reorganized so that only the first *pnTrunc
|
|
-** pages are in use.
|
|
*/
|
|
-static int autoVacuumCommit(BtShared *pBt){
|
|
+static int autoVacuumCommit(Btree *p){
|
|
int rc = SQLITE_OK;
|
|
- Pager *pPager = pBt->pPager;
|
|
- VVA_ONLY( int nRef = sqlite3PagerRefcount(pPager); )
|
|
+ Pager *pPager;
|
|
+ BtShared *pBt;
|
|
+ sqlite3 *db;
|
|
+ VVA_ONLY( int nRef );
|
|
+
|
|
+ assert( p!=0 );
|
|
+ pBt = p->pBt;
|
|
+ pPager = pBt->pPager;
|
|
+ VVA_ONLY( nRef = sqlite3PagerRefcount(pPager); )
|
|
|
|
assert( sqlite3_mutex_held(pBt->mutex) );
|
|
invalidateAllOverflowCache(pBt);
|
|
@@ -68010,6 +72478,7 @@ static int autoVacuumCommit(BtShared *pBt){
|
|
if( !pBt->incrVacuum ){
|
|
Pgno nFin; /* Number of pages in database after autovacuuming */
|
|
Pgno nFree; /* Number of pages on the freelist initially */
|
|
+ Pgno nVac; /* Number of pages to vacuum */
|
|
Pgno iFree; /* The next page to be freed */
|
|
Pgno nOrig; /* Database size before freeing */
|
|
|
|
@@ -68023,18 +72492,42 @@ static int autoVacuumCommit(BtShared *pBt){
|
|
}
|
|
|
|
nFree = get4byte(&pBt->pPage1->aData[36]);
|
|
- nFin = finalDbSize(pBt, nOrig, nFree);
|
|
+ db = p->db;
|
|
+ if( db->xAutovacPages ){
|
|
+ int iDb;
|
|
+ for(iDb=0; ALWAYS(iDb<db->nDb); iDb++){
|
|
+ if( db->aDb[iDb].pBt==p ) break;
|
|
+ }
|
|
+ nVac = db->xAutovacPages(
|
|
+ db->pAutovacPagesArg,
|
|
+ db->aDb[iDb].zDbSName,
|
|
+ nOrig,
|
|
+ nFree,
|
|
+ pBt->pageSize
|
|
+ );
|
|
+ if( nVac>nFree ){
|
|
+ nVac = nFree;
|
|
+ }
|
|
+ if( nVac==0 ){
|
|
+ return SQLITE_OK;
|
|
+ }
|
|
+ }else{
|
|
+ nVac = nFree;
|
|
+ }
|
|
+ nFin = finalDbSize(pBt, nOrig, nVac);
|
|
if( nFin>nOrig ) return SQLITE_CORRUPT_BKPT;
|
|
if( nFin<nOrig ){
|
|
rc = saveAllCursors(pBt, 0, 0);
|
|
}
|
|
for(iFree=nOrig; iFree>nFin && rc==SQLITE_OK; iFree--){
|
|
- rc = incrVacuumStep(pBt, nFin, iFree, 1);
|
|
+ rc = incrVacuumStep(pBt, nFin, iFree, nVac==nFree);
|
|
}
|
|
if( (rc==SQLITE_DONE || rc==SQLITE_OK) && nFree>0 ){
|
|
rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
|
|
- put4byte(&pBt->pPage1->aData[32], 0);
|
|
- put4byte(&pBt->pPage1->aData[36], 0);
|
|
+ if( nVac==nFree ){
|
|
+ put4byte(&pBt->pPage1->aData[32], 0);
|
|
+ put4byte(&pBt->pPage1->aData[36], 0);
|
|
+ }
|
|
put4byte(&pBt->pPage1->aData[28], nFin);
|
|
pBt->bDoTruncate = 1;
|
|
pBt->nPage = nFin;
|
|
@@ -68067,25 +72560,25 @@ static int autoVacuumCommit(BtShared *pBt){
|
|
**
|
|
** This call is a no-op if no write-transaction is currently active on pBt.
|
|
**
|
|
-** Otherwise, sync the database file for the btree pBt. zMaster points to
|
|
-** the name of a master journal file that should be written into the
|
|
-** individual journal file, or is NULL, indicating no master journal file
|
|
+** Otherwise, sync the database file for the btree pBt. zSuperJrnl points to
|
|
+** the name of a super-journal file that should be written into the
|
|
+** individual journal file, or is NULL, indicating no super-journal file
|
|
** (single database transaction).
|
|
**
|
|
-** When this is called, the master journal should already have been
|
|
+** When this is called, the super-journal should already have been
|
|
** created, populated with this journal pointer and synced to disk.
|
|
**
|
|
** Once this is routine has returned, the only thing required to commit
|
|
** the write-transaction for this database file is to delete the journal.
|
|
*/
|
|
-SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree *p, const char *zMaster){
|
|
+SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree *p, const char *zSuperJrnl){
|
|
int rc = SQLITE_OK;
|
|
if( p->inTrans==TRANS_WRITE ){
|
|
BtShared *pBt = p->pBt;
|
|
sqlite3BtreeEnter(p);
|
|
#ifndef SQLITE_OMIT_AUTOVACUUM
|
|
if( pBt->autoVacuum ){
|
|
- rc = autoVacuumCommit(pBt);
|
|
+ rc = autoVacuumCommit(p);
|
|
if( rc!=SQLITE_OK ){
|
|
sqlite3BtreeLeave(p);
|
|
return rc;
|
|
@@ -68095,7 +72588,7 @@ SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree *p, const char *zMaster){
|
|
sqlite3PagerTruncateImage(pBt->pPager, pBt->nPage);
|
|
}
|
|
#endif
|
|
- rc = sqlite3PagerCommitPhaseOne(pBt->pPager, zMaster, 0);
|
|
+ rc = sqlite3PagerCommitPhaseOne(pBt->pPager, zSuperJrnl, 0);
|
|
sqlite3BtreeLeave(p);
|
|
}
|
|
return rc;
|
|
@@ -68120,8 +72613,8 @@ static void btreeEndTransaction(Btree *p){
|
|
downgradeAllSharedCacheTableLocks(p);
|
|
p->inTrans = TRANS_READ;
|
|
}else{
|
|
- /* If the handle had any kind of transaction open, decrement the
|
|
- ** transaction count of the shared btree. If the transaction count
|
|
+ /* If the handle had any kind of transaction open, decrement the
|
|
+ ** transaction count of the shared btree. If the transaction count
|
|
** reaches 0, set the shared state to TRANS_NONE. The unlockBtreeIfUnused()
|
|
** call below will unlock the pager. */
|
|
if( p->inTrans!=TRANS_NONE ){
|
|
@@ -68132,7 +72625,7 @@ static void btreeEndTransaction(Btree *p){
|
|
}
|
|
}
|
|
|
|
- /* Set the current transaction state to TRANS_NONE and unlock the
|
|
+ /* Set the current transaction state to TRANS_NONE and unlock the
|
|
** pager if this call closed the only read or write transaction. */
|
|
p->inTrans = TRANS_NONE;
|
|
unlockBtreeIfUnused(pBt);
|
|
@@ -68153,12 +72646,12 @@ static void btreeEndTransaction(Btree *p){
|
|
** the rollback journal (which causes the transaction to commit) and
|
|
** drop locks.
|
|
**
|
|
-** Normally, if an error occurs while the pager layer is attempting to
|
|
+** Normally, if an error occurs while the pager layer is attempting to
|
|
** finalize the underlying journal file, this function returns an error and
|
|
** the upper layer will attempt a rollback. However, if the second argument
|
|
-** is non-zero then this b-tree transaction is part of a multi-file
|
|
-** transaction. In this case, the transaction has already been committed
|
|
-** (by deleting a master journal file) and the caller will ignore this
|
|
+** is non-zero then this b-tree transaction is part of a multi-file
|
|
+** transaction. In this case, the transaction has already been committed
|
|
+** (by deleting a super-journal file) and the caller will ignore this
|
|
** functions return code. So, even if an error occurs in the pager layer,
|
|
** reset the b-tree objects internal state to indicate that the write
|
|
** transaction has been closed. This is quite safe, as the pager will have
|
|
@@ -68173,7 +72666,7 @@ SQLITE_PRIVATE int sqlite3BtreeCommitPhaseTwo(Btree *p, int bCleanup){
|
|
sqlite3BtreeEnter(p);
|
|
btreeIntegrity(p);
|
|
|
|
- /* If the handle has a write-transaction open, commit the shared-btrees
|
|
+ /* If the handle has a write-transaction open, commit the shared-btrees
|
|
** transaction and set the shared state to TRANS_READ.
|
|
*/
|
|
if( p->inTrans==TRANS_WRITE ){
|
|
@@ -68186,7 +72679,7 @@ SQLITE_PRIVATE int sqlite3BtreeCommitPhaseTwo(Btree *p, int bCleanup){
|
|
sqlite3BtreeLeave(p);
|
|
return rc;
|
|
}
|
|
- p->iDataVersion--; /* Compensate for pPager->iDataVersion++; */
|
|
+ p->iBDataVersion--; /* Compensate for pPager->iDataVersion++; */
|
|
pBt->inTransaction = TRANS_READ;
|
|
btreeClearHasContent(pBt);
|
|
}
|
|
@@ -68222,15 +72715,15 @@ SQLITE_PRIVATE int sqlite3BtreeCommit(Btree *p){
|
|
**
|
|
** This routine gets called when a rollback occurs. If the writeOnly
|
|
** flag is true, then only write-cursors need be tripped - read-only
|
|
-** cursors save their current positions so that they may continue
|
|
-** following the rollback. Or, if writeOnly is false, all cursors are
|
|
+** cursors save their current positions so that they may continue
|
|
+** following the rollback. Or, if writeOnly is false, all cursors are
|
|
** tripped. In general, writeOnly is false if the transaction being
|
|
** rolled back modified the database schema. In this case b-tree root
|
|
** pages may be moved or deleted from the database altogether, making
|
|
** it unsafe for read cursors to continue.
|
|
**
|
|
-** If the writeOnly flag is true and an error is encountered while
|
|
-** saving the current position of a read-only cursor, all cursors,
|
|
+** If the writeOnly flag is true and an error is encountered while
|
|
+** saving the current position of a read-only cursor, all cursors,
|
|
** including all read-cursors are tripped.
|
|
**
|
|
** SQLITE_OK is returned if successful, or if an error occurs while
|
|
@@ -68272,7 +72765,7 @@ static void btreeSetNPage(BtShared *pBt, MemPage *pPage1){
|
|
int nPage = get4byte(&pPage1->aData[28]);
|
|
testcase( nPage==0 );
|
|
if( nPage==0 ) sqlite3PagerPagecount(pBt->pPager, &nPage);
|
|
- testcase( pBt->nPage!=nPage );
|
|
+ testcase( pBt->nPage!=(u32)nPage );
|
|
pBt->nPage = nPage;
|
|
}
|
|
|
|
@@ -68336,8 +72829,8 @@ SQLITE_PRIVATE int sqlite3BtreeRollback(Btree *p, int tripCode, int writeOnly){
|
|
|
|
/*
|
|
** Start a statement subtransaction. The subtransaction can be rolled
|
|
-** back independently of the main transaction. You must start a transaction
|
|
-** before starting a subtransaction. The subtransaction is ended automatically
|
|
+** back independently of the main transaction. You must start a transaction
|
|
+** before starting a subtransaction. The subtransaction is ended automatically
|
|
** if the main transaction commits or rolls back.
|
|
**
|
|
** Statement subtransactions are used around individual SQL statements
|
|
@@ -68374,11 +72867,11 @@ SQLITE_PRIVATE int sqlite3BtreeBeginStmt(Btree *p, int iStatement){
|
|
/*
|
|
** The second argument to this function, op, is always SAVEPOINT_ROLLBACK
|
|
** or SAVEPOINT_RELEASE. This function either releases or rolls back the
|
|
-** savepoint identified by parameter iSavepoint, depending on the value
|
|
+** savepoint identified by parameter iSavepoint, depending on the value
|
|
** of op.
|
|
**
|
|
** Normally, iSavepoint is greater than or equal to zero. However, if op is
|
|
-** SAVEPOINT_ROLLBACK, then iSavepoint may also be -1. In this case the
|
|
+** SAVEPOINT_ROLLBACK, then iSavepoint may also be -1. In this case the
|
|
** contents of the entire transaction are rolled back. This is different
|
|
** from a normal transaction rollback, as no locks are released and the
|
|
** transaction remains open.
|
|
@@ -68403,7 +72896,7 @@ SQLITE_PRIVATE int sqlite3BtreeSavepoint(Btree *p, int op, int iSavepoint){
|
|
rc = newDatabase(pBt);
|
|
btreeSetNPage(pBt, pBt->pPage1);
|
|
|
|
- /* pBt->nPage might be zero if the database was corrupt when
|
|
+ /* pBt->nPage might be zero if the database was corrupt when
|
|
** the transaction was started. Otherwise, it must be at least 1. */
|
|
assert( CORRUPT_DB || pBt->nPage>0 );
|
|
}
|
|
@@ -68441,10 +72934,10 @@ SQLITE_PRIVATE int sqlite3BtreeSavepoint(Btree *p, int op, int iSavepoint){
|
|
** is set. If FORDELETE is set, that is a hint to the implementation that
|
|
** this cursor will only be used to seek to and delete entries of an index
|
|
** as part of a larger DELETE statement. The FORDELETE hint is not used by
|
|
-** this implementation. But in a hypothetical alternative storage engine
|
|
+** this implementation. But in a hypothetical alternative storage engine
|
|
** in which index entries are automatically deleted when corresponding table
|
|
** rows are deleted, the FORDELETE flag is a hint that all SEEK and DELETE
|
|
-** operations on this cursor can be no-ops and all READ operations can
|
|
+** operations on this cursor can be no-ops and all READ operations can
|
|
** return a null row (2-bytes: 0x01 0x00).
|
|
**
|
|
** No checking is done to make sure that page iTable really is the
|
|
@@ -68456,7 +72949,7 @@ SQLITE_PRIVATE int sqlite3BtreeSavepoint(Btree *p, int op, int iSavepoint){
|
|
*/
|
|
static int btreeCursor(
|
|
Btree *p, /* The btree */
|
|
- int iTable, /* Root page of table to open */
|
|
+ Pgno iTable, /* Root page of table to open */
|
|
int wrFlag, /* 1 to write. 0 read-only */
|
|
struct KeyInfo *pKeyInfo, /* First arg to comparison function */
|
|
BtCursor *pCur /* Space for new cursor */
|
|
@@ -68465,14 +72958,14 @@ static int btreeCursor(
|
|
BtCursor *pX; /* Looping over other all cursors */
|
|
|
|
assert( sqlite3BtreeHoldsMutex(p) );
|
|
- assert( wrFlag==0
|
|
- || wrFlag==BTREE_WRCSR
|
|
- || wrFlag==(BTREE_WRCSR|BTREE_FORDELETE)
|
|
+ assert( wrFlag==0
|
|
+ || wrFlag==BTREE_WRCSR
|
|
+ || wrFlag==(BTREE_WRCSR|BTREE_FORDELETE)
|
|
);
|
|
|
|
- /* The following assert statements verify that if this is a sharable
|
|
- ** b-tree database, the connection is holding the required table locks,
|
|
- ** and that no other connection has any open cursor that conflicts with
|
|
+ /* The following assert statements verify that if this is a sharable
|
|
+ ** b-tree database, the connection is holding the required table locks,
|
|
+ ** and that no other connection has any open cursor that conflicts with
|
|
** this lock. The iTable<1 term disables the check for corrupt schemas. */
|
|
assert( hasSharedCacheTableLock(p, iTable, pKeyInfo!=0, (wrFlag?2:1))
|
|
|| iTable<1 );
|
|
@@ -68484,10 +72977,6 @@ static int btreeCursor(
|
|
assert( pBt->pPage1 && pBt->pPage1->aData );
|
|
assert( wrFlag==0 || (pBt->btsFlags & BTS_READ_ONLY)==0 );
|
|
|
|
- if( wrFlag ){
|
|
- allocateTempSpace(pBt);
|
|
- if( pBt->pTmpSpace==0 ) return SQLITE_NOMEM_BKPT;
|
|
- }
|
|
if( iTable<=1 ){
|
|
if( iTable<1 ){
|
|
return SQLITE_CORRUPT_BKPT;
|
|
@@ -68499,29 +72988,35 @@ static int btreeCursor(
|
|
|
|
/* Now that no other errors can occur, finish filling in the BtCursor
|
|
** variables and link the cursor into the BtShared list. */
|
|
- pCur->pgnoRoot = (Pgno)iTable;
|
|
+ pCur->pgnoRoot = iTable;
|
|
pCur->iPage = -1;
|
|
pCur->pKeyInfo = pKeyInfo;
|
|
pCur->pBtree = p;
|
|
pCur->pBt = pBt;
|
|
- pCur->curFlags = wrFlag ? BTCF_WriteFlag : 0;
|
|
- pCur->curPagerFlags = wrFlag ? 0 : PAGER_GET_READONLY;
|
|
+ pCur->curFlags = 0;
|
|
/* If there are two or more cursors on the same btree, then all such
|
|
** cursors *must* have the BTCF_Multiple flag set. */
|
|
for(pX=pBt->pCursor; pX; pX=pX->pNext){
|
|
- if( pX->pgnoRoot==(Pgno)iTable ){
|
|
+ if( pX->pgnoRoot==iTable ){
|
|
pX->curFlags |= BTCF_Multiple;
|
|
- pCur->curFlags |= BTCF_Multiple;
|
|
+ pCur->curFlags = BTCF_Multiple;
|
|
}
|
|
}
|
|
+ pCur->eState = CURSOR_INVALID;
|
|
pCur->pNext = pBt->pCursor;
|
|
pBt->pCursor = pCur;
|
|
- pCur->eState = CURSOR_INVALID;
|
|
+ if( wrFlag ){
|
|
+ pCur->curFlags |= BTCF_WriteFlag;
|
|
+ pCur->curPagerFlags = 0;
|
|
+ if( pBt->pTmpSpace==0 ) return allocateTempSpace(pBt);
|
|
+ }else{
|
|
+ pCur->curPagerFlags = PAGER_GET_READONLY;
|
|
+ }
|
|
return SQLITE_OK;
|
|
}
|
|
static int btreeCursorWithLock(
|
|
Btree *p, /* The btree */
|
|
- int iTable, /* Root page of table to open */
|
|
+ Pgno iTable, /* Root page of table to open */
|
|
int wrFlag, /* 1 to write. 0 read-only */
|
|
struct KeyInfo *pKeyInfo, /* First arg to comparison function */
|
|
BtCursor *pCur /* Space for new cursor */
|
|
@@ -68534,7 +73029,7 @@ static int btreeCursorWithLock(
|
|
}
|
|
SQLITE_PRIVATE int sqlite3BtreeCursor(
|
|
Btree *p, /* The btree */
|
|
- int iTable, /* Root page of table to open */
|
|
+ Pgno iTable, /* Root page of table to open */
|
|
int wrFlag, /* 1 to write. 0 read-only */
|
|
struct KeyInfo *pKeyInfo, /* First arg to xCompare() */
|
|
BtCursor *pCur /* Write new cursor here */
|
|
@@ -68596,7 +73091,14 @@ SQLITE_PRIVATE int sqlite3BtreeCloseCursor(BtCursor *pCur){
|
|
unlockBtreeIfUnused(pBt);
|
|
sqlite3_free(pCur->aOverflow);
|
|
sqlite3_free(pCur->pKey);
|
|
- sqlite3BtreeLeave(pBtree);
|
|
+ if( (pBt->openFlags & BTREE_SINGLE) && pBt->pCursor==0 ){
|
|
+ /* Since the BtShared is not sharable, there is no need to
|
|
+ ** worry about the missing sqlite3BtreeLeave() call here. */
|
|
+ assert( pBtree->sharable==0 );
|
|
+ sqlite3BtreeClose(pBtree);
|
|
+ }else{
|
|
+ sqlite3BtreeLeave(pBtree);
|
|
+ }
|
|
pCur->pBtree = 0;
|
|
}
|
|
return SQLITE_OK;
|
|
@@ -68729,15 +73231,15 @@ SQLITE_PRIVATE sqlite3_int64 sqlite3BtreeMaxRecordSize(BtCursor *pCur){
|
|
|
|
/*
|
|
** Given the page number of an overflow page in the database (parameter
|
|
-** ovfl), this function finds the page number of the next page in the
|
|
+** ovfl), this function finds the page number of the next page in the
|
|
** linked list of overflow pages. If possible, it uses the auto-vacuum
|
|
-** pointer-map data instead of reading the content of page ovfl to do so.
|
|
+** pointer-map data instead of reading the content of page ovfl to do so.
|
|
**
|
|
** If an error occurs an SQLite error code is returned. Otherwise:
|
|
**
|
|
-** The page number of the next overflow page in the linked list is
|
|
-** written to *pPgnoNext. If page ovfl is the last page in its linked
|
|
-** list, *pPgnoNext is set to zero.
|
|
+** The page number of the next overflow page in the linked list is
|
|
+** written to *pPgnoNext. If page ovfl is the last page in its linked
|
|
+** list, *pPgnoNext is set to zero.
|
|
**
|
|
** If ppPage is not NULL, and a reference to the MemPage object corresponding
|
|
** to page number pOvfl was obtained, then *ppPage is set to point to that
|
|
@@ -68761,9 +73263,9 @@ static int getOverflowPage(
|
|
|
|
#ifndef SQLITE_OMIT_AUTOVACUUM
|
|
/* Try to find the next page in the overflow list using the
|
|
- ** autovacuum pointer-map pages. Guess that the next page in
|
|
- ** the overflow list is page number (ovfl+1). If that guess turns
|
|
- ** out to be wrong, fall back to loading the data of page
|
|
+ ** autovacuum pointer-map pages. Guess that the next page in
|
|
+ ** the overflow list is page number (ovfl+1). If that guess turns
|
|
+ ** out to be wrong, fall back to loading the data of page
|
|
** number ovfl to determine the next page number.
|
|
*/
|
|
if( pBt->autoVacuum ){
|
|
@@ -68851,8 +73353,8 @@ static int copyPayload(
|
|
**
|
|
** If the current cursor entry uses one or more overflow pages
|
|
** this function may allocate space for and lazily populate
|
|
-** the overflow page-list cache array (BtCursor.aOverflow).
|
|
-** Subsequent calls use this cache to make seeking to the supplied offset
|
|
+** the overflow page-list cache array (BtCursor.aOverflow).
|
|
+** Subsequent calls use this cache to make seeking to the supplied offset
|
|
** more efficient.
|
|
**
|
|
** Once an overflow page-list cache has been allocated, it must be
|
|
@@ -68868,7 +73370,7 @@ static int accessPayload(
|
|
BtCursor *pCur, /* Cursor pointing to entry to read from */
|
|
u32 offset, /* Begin reading this far into payload */
|
|
u32 amt, /* Read this many bytes */
|
|
- unsigned char *pBuf, /* Write the bytes into this buffer */
|
|
+ unsigned char *pBuf, /* Write the bytes into this buffer */
|
|
int eOp /* zero to read. non-zero to write. */
|
|
){
|
|
unsigned char *aPayload;
|
|
@@ -68883,7 +73385,9 @@ static int accessPayload(
|
|
assert( pPage );
|
|
assert( eOp==0 || eOp==1 );
|
|
assert( pCur->eState==CURSOR_VALID );
|
|
- assert( pCur->ix<pPage->nCell );
|
|
+ if( pCur->ix>=pPage->nCell ){
|
|
+ return SQLITE_CORRUPT_PAGE(pPage);
|
|
+ }
|
|
assert( cursorHoldsMutex(pCur) );
|
|
|
|
getCellInfo(pCur);
|
|
@@ -68959,6 +73463,7 @@ static int accessPayload(
|
|
assert( rc==SQLITE_OK && amt>0 );
|
|
while( nextPage ){
|
|
/* If required, populate the overflow page-list cache. */
|
|
+ if( nextPage > pBt->nPage ) return SQLITE_CORRUPT_BKPT;
|
|
assert( pCur->aOverflow[iIdx]==0
|
|
|| pCur->aOverflow[iIdx]==nextPage
|
|
|| CORRUPT_DB );
|
|
@@ -68991,12 +73496,12 @@ static int accessPayload(
|
|
#ifdef SQLITE_DIRECT_OVERFLOW_READ
|
|
/* If all the following are true:
|
|
**
|
|
- ** 1) this is a read operation, and
|
|
+ ** 1) this is a read operation, and
|
|
** 2) data is required from the start of this overflow page, and
|
|
** 3) there are no dirty pages in the page-cache
|
|
** 4) the database is file-backed, and
|
|
** 5) the page is not in the WAL file
|
|
- ** 6) at least 4 bytes have already been read into the output buffer
|
|
+ ** 6) at least 4 bytes have already been read into the output buffer
|
|
**
|
|
** then data can be read directly from the database file into the
|
|
** output buffer, bypassing the page-cache altogether. This speeds
|
|
@@ -69069,7 +73574,6 @@ SQLITE_PRIVATE int sqlite3BtreePayload(BtCursor *pCur, u32 offset, u32 amt, void
|
|
assert( cursorHoldsMutex(pCur) );
|
|
assert( pCur->eState==CURSOR_VALID );
|
|
assert( pCur->iPage>=0 && pCur->pPage );
|
|
- assert( pCur->ix<pCur->pPage->nCell );
|
|
return accessPayload(pCur, offset, amt, (unsigned char*)pBuf, 0);
|
|
}
|
|
|
|
@@ -69104,7 +73608,7 @@ SQLITE_PRIVATE int sqlite3BtreePayloadChecked(BtCursor *pCur, u32 offset, u32 am
|
|
#endif /* SQLITE_OMIT_INCRBLOB */
|
|
|
|
/*
|
|
-** Return a pointer to payload information from the entry that the
|
|
+** Return a pointer to payload information from the entry that the
|
|
** pCur cursor is pointing to. The pointer is to the beginning of
|
|
** the key if index btrees (pPage->intKey==0) and is the data for
|
|
** table btrees (pPage->intKey==1). The number of bytes of available
|
|
@@ -69131,7 +73635,7 @@ static const void *fetchPayload(
|
|
assert( pCur->eState==CURSOR_VALID );
|
|
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
|
|
assert( cursorOwnsBtShared(pCur) );
|
|
- assert( pCur->ix<pCur->pPage->nCell );
|
|
+ assert( pCur->ix<pCur->pPage->nCell || CORRUPT_DB );
|
|
assert( pCur->info.nSize>0 );
|
|
assert( pCur->info.pPayload>pCur->pPage->aData || CORRUPT_DB );
|
|
assert( pCur->info.pPayload<pCur->pPage->aDataEnd ||CORRUPT_DB);
|
|
@@ -69176,8 +73680,6 @@ SQLITE_PRIVATE const void *sqlite3BtreePayloadFetch(BtCursor *pCur, u32 *pAmt){
|
|
** vice-versa).
|
|
*/
|
|
static int moveToChild(BtCursor *pCur, u32 newPgno){
|
|
- BtShared *pBt = pCur->pBt;
|
|
-
|
|
assert( cursorOwnsBtShared(pCur) );
|
|
assert( pCur->eState==CURSOR_VALID );
|
|
assert( pCur->iPage<BTCURSOR_MAX_DEPTH );
|
|
@@ -69191,12 +73693,13 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
|
|
pCur->apPage[pCur->iPage] = pCur->pPage;
|
|
pCur->ix = 0;
|
|
pCur->iPage++;
|
|
- return getAndInitPage(pBt, newPgno, &pCur->pPage, pCur, pCur->curPagerFlags);
|
|
+ return getAndInitPage(pCur->pBt, newPgno, &pCur->pPage, pCur,
|
|
+ pCur->curPagerFlags);
|
|
}
|
|
|
|
#ifdef SQLITE_DEBUG
|
|
/*
|
|
-** Page pParent is an internal (non-leaf) tree page. This function
|
|
+** Page pParent is an internal (non-leaf) tree page. This function
|
|
** asserts that page number iChild is the left-child if the iIdx'th
|
|
** cell in page pParent. Or, if iIdx is equal to the total number of
|
|
** cells in pParent, that page number iChild is the right-child of
|
|
@@ -69213,7 +73716,7 @@ static void assertParentIndex(MemPage *pParent, int iIdx, Pgno iChild){
|
|
}
|
|
}
|
|
#else
|
|
-# define assertParentIndex(x,y,z)
|
|
+# define assertParentIndex(x,y,z)
|
|
#endif
|
|
|
|
/*
|
|
@@ -69231,8 +73734,8 @@ static void moveToParent(BtCursor *pCur){
|
|
assert( pCur->iPage>0 );
|
|
assert( pCur->pPage );
|
|
assertParentIndex(
|
|
- pCur->apPage[pCur->iPage-1],
|
|
- pCur->aiIdx[pCur->iPage-1],
|
|
+ pCur->apPage[pCur->iPage-1],
|
|
+ pCur->aiIdx[pCur->iPage-1],
|
|
pCur->pPage->pgno
|
|
);
|
|
testcase( pCur->aiIdx[pCur->iPage-1] > pCur->apPage[pCur->iPage-1]->nCell );
|
|
@@ -69249,19 +73752,19 @@ static void moveToParent(BtCursor *pCur){
|
|
**
|
|
** If the table has a virtual root page, then the cursor is moved to point
|
|
** to the virtual root page instead of the actual root page. A table has a
|
|
-** virtual root page when the actual root page contains no cells and a
|
|
+** virtual root page when the actual root page contains no cells and a
|
|
** single child page. This can only happen with the table rooted at page 1.
|
|
**
|
|
-** If the b-tree structure is empty, the cursor state is set to
|
|
+** If the b-tree structure is empty, the cursor state is set to
|
|
** CURSOR_INVALID and this routine returns SQLITE_EMPTY. Otherwise,
|
|
** the cursor is set to point to the first cell located on the root
|
|
** (or virtual root) page and the cursor state is set to CURSOR_VALID.
|
|
**
|
|
** If this function returns successfully, it may be assumed that the
|
|
-** page-header flags indicate that the [virtual] root-page is the expected
|
|
+** page-header flags indicate that the [virtual] root-page is the expected
|
|
** kind of b-tree page (i.e. if when opening the cursor the caller did not
|
|
** specify a KeyInfo structure the flags byte is set to 0x05 or 0x0D,
|
|
-** indicating a table b-tree, or if the caller did specify a KeyInfo
|
|
+** indicating a table b-tree, or if the caller did specify a KeyInfo
|
|
** structure the flags byte is set to 0x02 or 0x0A, indicating an index
|
|
** b-tree).
|
|
*/
|
|
@@ -69282,7 +73785,7 @@ static int moveToRoot(BtCursor *pCur){
|
|
while( --pCur->iPage ){
|
|
releasePageNotNull(pCur->apPage[pCur->iPage]);
|
|
}
|
|
- pCur->pPage = pCur->apPage[0];
|
|
+ pRoot = pCur->pPage = pCur->apPage[0];
|
|
goto skip_init;
|
|
}
|
|
}else if( pCur->pgnoRoot==0 ){
|
|
@@ -69297,7 +73800,7 @@ static int moveToRoot(BtCursor *pCur){
|
|
}
|
|
sqlite3BtreeClearCursor(pCur);
|
|
}
|
|
- rc = getAndInitPage(pCur->pBtree->pBt, pCur->pgnoRoot, &pCur->pPage,
|
|
+ rc = getAndInitPage(pCur->pBt, pCur->pgnoRoot, &pCur->pPage,
|
|
0, pCur->curPagerFlags);
|
|
if( rc!=SQLITE_OK ){
|
|
pCur->eState = CURSOR_INVALID;
|
|
@@ -69307,29 +73810,28 @@ static int moveToRoot(BtCursor *pCur){
|
|
pCur->curIntKey = pCur->pPage->intKey;
|
|
}
|
|
pRoot = pCur->pPage;
|
|
- assert( pRoot->pgno==pCur->pgnoRoot );
|
|
+ assert( pRoot->pgno==pCur->pgnoRoot || CORRUPT_DB );
|
|
|
|
/* If pCur->pKeyInfo is not NULL, then the caller that opened this cursor
|
|
** expected to open it on an index b-tree. Otherwise, if pKeyInfo is
|
|
** NULL, the caller expects a table b-tree. If this is not the case,
|
|
- ** return an SQLITE_CORRUPT error.
|
|
+ ** return an SQLITE_CORRUPT error.
|
|
**
|
|
** Earlier versions of SQLite assumed that this test could not fail
|
|
** if the root page was already loaded when this function was called (i.e.
|
|
- ** if pCur->iPage>=0). But this is not so if the database is corrupted
|
|
- ** in such a way that page pRoot is linked into a second b-tree table
|
|
+ ** if pCur->iPage>=0). But this is not so if the database is corrupted
|
|
+ ** in such a way that page pRoot is linked into a second b-tree table
|
|
** (or the freelist). */
|
|
assert( pRoot->intKey==1 || pRoot->intKey==0 );
|
|
if( pRoot->isInit==0 || (pCur->pKeyInfo==0)!=pRoot->intKey ){
|
|
return SQLITE_CORRUPT_PAGE(pCur->pPage);
|
|
}
|
|
|
|
-skip_init:
|
|
+skip_init:
|
|
pCur->ix = 0;
|
|
pCur->info.nSize = 0;
|
|
pCur->curFlags &= ~(BTCF_AtLast|BTCF_ValidNKey|BTCF_ValidOvfl);
|
|
|
|
- pRoot = pCur->pPage;
|
|
if( pRoot->nCell>0 ){
|
|
pCur->eState = CURSOR_VALID;
|
|
}else if( !pRoot->leaf ){
|
|
@@ -69422,52 +73924,50 @@ SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){
|
|
** on success. Set *pRes to 0 if the cursor actually points to something
|
|
** or set *pRes to 1 if the table is empty.
|
|
*/
|
|
+static SQLITE_NOINLINE int btreeLast(BtCursor *pCur, int *pRes){
|
|
+ int rc = moveToRoot(pCur);
|
|
+ if( rc==SQLITE_OK ){
|
|
+ assert( pCur->eState==CURSOR_VALID );
|
|
+ *pRes = 0;
|
|
+ rc = moveToRightmost(pCur);
|
|
+ if( rc==SQLITE_OK ){
|
|
+ pCur->curFlags |= BTCF_AtLast;
|
|
+ }else{
|
|
+ pCur->curFlags &= ~BTCF_AtLast;
|
|
+ }
|
|
+ }else if( rc==SQLITE_EMPTY ){
|
|
+ assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 );
|
|
+ *pRes = 1;
|
|
+ rc = SQLITE_OK;
|
|
+ }
|
|
+ return rc;
|
|
+}
|
|
SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
|
|
- int rc;
|
|
-
|
|
assert( cursorOwnsBtShared(pCur) );
|
|
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
|
|
|
|
/* If the cursor already points to the last entry, this is a no-op. */
|
|
if( CURSOR_VALID==pCur->eState && (pCur->curFlags & BTCF_AtLast)!=0 ){
|
|
#ifdef SQLITE_DEBUG
|
|
- /* This block serves to assert() that the cursor really does point
|
|
+ /* This block serves to assert() that the cursor really does point
|
|
** to the last entry in the b-tree. */
|
|
int ii;
|
|
for(ii=0; ii<pCur->iPage; ii++){
|
|
assert( pCur->aiIdx[ii]==pCur->apPage[ii]->nCell );
|
|
}
|
|
- assert( pCur->ix==pCur->pPage->nCell-1 );
|
|
+ assert( pCur->ix==pCur->pPage->nCell-1 || CORRUPT_DB );
|
|
+ testcase( pCur->ix!=pCur->pPage->nCell-1 );
|
|
+ /* ^-- dbsqlfuzz b92b72e4de80b5140c30ab71372ca719b8feb618 */
|
|
assert( pCur->pPage->leaf );
|
|
#endif
|
|
*pRes = 0;
|
|
return SQLITE_OK;
|
|
}
|
|
-
|
|
- rc = moveToRoot(pCur);
|
|
- if( rc==SQLITE_OK ){
|
|
- assert( pCur->eState==CURSOR_VALID );
|
|
- *pRes = 0;
|
|
- rc = moveToRightmost(pCur);
|
|
- if( rc==SQLITE_OK ){
|
|
- pCur->curFlags |= BTCF_AtLast;
|
|
- }else{
|
|
- pCur->curFlags &= ~BTCF_AtLast;
|
|
- }
|
|
- }else if( rc==SQLITE_EMPTY ){
|
|
- assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 );
|
|
- *pRes = 1;
|
|
- rc = SQLITE_OK;
|
|
- }
|
|
- return rc;
|
|
+ return btreeLast(pCur, pRes);
|
|
}
|
|
|
|
-/* Move the cursor so that it points to an entry near the key
|
|
-** specified by pIdxKey or intKey. Return a success code.
|
|
-**
|
|
-** For INTKEY tables, the intKey parameter is used. pIdxKey
|
|
-** must be NULL. For index tables, pIdxKey is used and intKey
|
|
-** is ignored.
|
|
+/* Move the cursor so that it points to an entry in a table (a.k.a INTKEY)
|
|
+** table near the key intKey. Return a success code.
|
|
**
|
|
** If an exact match is not found, then the cursor is always
|
|
** left pointing at a leaf page which would hold the entry if it
|
|
@@ -69475,44 +73975,37 @@ SQLITE_PRIVATE int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
|
|
** before or after the key.
|
|
**
|
|
** An integer is written into *pRes which is the result of
|
|
-** comparing the key with the entry to which the cursor is
|
|
+** comparing the key with the entry to which the cursor is
|
|
** pointing. The meaning of the integer written into
|
|
** *pRes is as follows:
|
|
**
|
|
** *pRes<0 The cursor is left pointing at an entry that
|
|
-** is smaller than intKey/pIdxKey or if the table is empty
|
|
+** is smaller than intKey or if the table is empty
|
|
** and the cursor is therefore left point to nothing.
|
|
**
|
|
** *pRes==0 The cursor is left pointing at an entry that
|
|
-** exactly matches intKey/pIdxKey.
|
|
+** exactly matches intKey.
|
|
**
|
|
** *pRes>0 The cursor is left pointing at an entry that
|
|
-** is larger than intKey/pIdxKey.
|
|
-**
|
|
-** For index tables, the pIdxKey->eqSeen field is set to 1 if there
|
|
-** exists an entry in the table that exactly matches pIdxKey.
|
|
+** is larger than intKey.
|
|
*/
|
|
-SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
|
|
+SQLITE_PRIVATE int sqlite3BtreeTableMoveto(
|
|
BtCursor *pCur, /* The cursor to be moved */
|
|
- UnpackedRecord *pIdxKey, /* Unpacked index key */
|
|
i64 intKey, /* The table key */
|
|
int biasRight, /* If true, bias the search to the high end */
|
|
int *pRes /* Write search results here */
|
|
){
|
|
int rc;
|
|
- RecordCompare xRecordCompare;
|
|
|
|
assert( cursorOwnsBtShared(pCur) );
|
|
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
|
|
assert( pRes );
|
|
- assert( (pIdxKey==0)==(pCur->pKeyInfo==0) );
|
|
- assert( pCur->eState!=CURSOR_VALID || (pIdxKey==0)==(pCur->curIntKey!=0) );
|
|
+ assert( pCur->pKeyInfo==0 );
|
|
+ assert( pCur->eState!=CURSOR_VALID || pCur->curIntKey!=0 );
|
|
|
|
/* If the cursor is already positioned at the point we are trying
|
|
** to move to, then just return without doing any work */
|
|
- if( pIdxKey==0
|
|
- && pCur->eState==CURSOR_VALID && (pCur->curFlags & BTCF_ValidNKey)!=0
|
|
- ){
|
|
+ if( pCur->eState==CURSOR_VALID && (pCur->curFlags & BTCF_ValidNKey)!=0 ){
|
|
if( pCur->info.nKey==intKey ){
|
|
*pRes = 0;
|
|
return SQLITE_OK;
|
|
@@ -69534,25 +74027,16 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
|
|
if( pCur->info.nKey==intKey ){
|
|
return SQLITE_OK;
|
|
}
|
|
- }else if( rc==SQLITE_DONE ){
|
|
- rc = SQLITE_OK;
|
|
- }else{
|
|
+ }else if( rc!=SQLITE_DONE ){
|
|
return rc;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
- if( pIdxKey ){
|
|
- xRecordCompare = sqlite3VdbeFindCompare(pIdxKey);
|
|
- pIdxKey->errCode = 0;
|
|
- assert( pIdxKey->default_rc==1
|
|
- || pIdxKey->default_rc==0
|
|
- || pIdxKey->default_rc==-1
|
|
- );
|
|
- }else{
|
|
- xRecordCompare = 0; /* All keys are integers */
|
|
- }
|
|
+#ifdef SQLITE_DEBUG
|
|
+ pCur->pBtree->nSeek++; /* Performance measurement during testing */
|
|
+#endif
|
|
|
|
rc = moveToRoot(pCur);
|
|
if( rc ){
|
|
@@ -69568,7 +74052,8 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
|
|
assert( pCur->eState==CURSOR_VALID );
|
|
assert( pCur->pPage->nCell > 0 );
|
|
assert( pCur->iPage==0 || pCur->apPage[0]->intKey==pCur->curIntKey );
|
|
- assert( pCur->curIntKey || pIdxKey );
|
|
+ assert( pCur->curIntKey );
|
|
+
|
|
for(;;){
|
|
int lwr, upr, idx, c;
|
|
Pgno chldPg;
|
|
@@ -69582,144 +74067,348 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
|
|
** be the right kind (index or table) of b-tree page. Otherwise
|
|
** a moveToChild() or moveToRoot() call would have detected corruption. */
|
|
assert( pPage->nCell>0 );
|
|
- assert( pPage->intKey==(pIdxKey==0) );
|
|
+ assert( pPage->intKey );
|
|
lwr = 0;
|
|
upr = pPage->nCell-1;
|
|
assert( biasRight==0 || biasRight==1 );
|
|
idx = upr>>(1-biasRight); /* idx = biasRight ? upr : (lwr+upr)/2; */
|
|
- pCur->ix = (u16)idx;
|
|
- if( xRecordCompare==0 ){
|
|
- for(;;){
|
|
- i64 nCellKey;
|
|
- pCell = findCellPastPtr(pPage, idx);
|
|
- if( pPage->intKeyLeaf ){
|
|
- while( 0x80 <= *(pCell++) ){
|
|
- if( pCell>=pPage->aDataEnd ){
|
|
- return SQLITE_CORRUPT_PAGE(pPage);
|
|
- }
|
|
+ for(;;){
|
|
+ i64 nCellKey;
|
|
+ pCell = findCellPastPtr(pPage, idx);
|
|
+ if( pPage->intKeyLeaf ){
|
|
+ while( 0x80 <= *(pCell++) ){
|
|
+ if( pCell>=pPage->aDataEnd ){
|
|
+ return SQLITE_CORRUPT_PAGE(pPage);
|
|
}
|
|
}
|
|
- getVarint(pCell, (u64*)&nCellKey);
|
|
- if( nCellKey<intKey ){
|
|
- lwr = idx+1;
|
|
- if( lwr>upr ){ c = -1; break; }
|
|
- }else if( nCellKey>intKey ){
|
|
- upr = idx-1;
|
|
- if( lwr>upr ){ c = +1; break; }
|
|
+ }
|
|
+ getVarint(pCell, (u64*)&nCellKey);
|
|
+ if( nCellKey<intKey ){
|
|
+ lwr = idx+1;
|
|
+ if( lwr>upr ){ c = -1; break; }
|
|
+ }else if( nCellKey>intKey ){
|
|
+ upr = idx-1;
|
|
+ if( lwr>upr ){ c = +1; break; }
|
|
+ }else{
|
|
+ assert( nCellKey==intKey );
|
|
+ pCur->ix = (u16)idx;
|
|
+ if( !pPage->leaf ){
|
|
+ lwr = idx;
|
|
+ goto moveto_table_next_layer;
|
|
}else{
|
|
- assert( nCellKey==intKey );
|
|
- pCur->ix = (u16)idx;
|
|
- if( !pPage->leaf ){
|
|
- lwr = idx;
|
|
- goto moveto_next_layer;
|
|
- }else{
|
|
- pCur->curFlags |= BTCF_ValidNKey;
|
|
- pCur->info.nKey = nCellKey;
|
|
- pCur->info.nSize = 0;
|
|
- *pRes = 0;
|
|
- return SQLITE_OK;
|
|
- }
|
|
+ pCur->curFlags |= BTCF_ValidNKey;
|
|
+ pCur->info.nKey = nCellKey;
|
|
+ pCur->info.nSize = 0;
|
|
+ *pRes = 0;
|
|
+ return SQLITE_OK;
|
|
}
|
|
- assert( lwr+upr>=0 );
|
|
- idx = (lwr+upr)>>1; /* idx = (lwr+upr)/2; */
|
|
}
|
|
+ assert( lwr+upr>=0 );
|
|
+ idx = (lwr+upr)>>1; /* idx = (lwr+upr)/2; */
|
|
+ }
|
|
+ assert( lwr==upr+1 || !pPage->leaf );
|
|
+ assert( pPage->isInit );
|
|
+ if( pPage->leaf ){
|
|
+ assert( pCur->ix<pCur->pPage->nCell );
|
|
+ pCur->ix = (u16)idx;
|
|
+ *pRes = c;
|
|
+ rc = SQLITE_OK;
|
|
+ goto moveto_table_finish;
|
|
+ }
|
|
+moveto_table_next_layer:
|
|
+ if( lwr>=pPage->nCell ){
|
|
+ chldPg = get4byte(&pPage->aData[pPage->hdrOffset+8]);
|
|
}else{
|
|
- for(;;){
|
|
- int nCell; /* Size of the pCell cell in bytes */
|
|
- pCell = findCellPastPtr(pPage, idx);
|
|
-
|
|
- /* The maximum supported page-size is 65536 bytes. This means that
|
|
- ** the maximum number of record bytes stored on an index B-Tree
|
|
- ** page is less than 16384 bytes and may be stored as a 2-byte
|
|
- ** varint. This information is used to attempt to avoid parsing
|
|
- ** the entire cell by checking for the cases where the record is
|
|
- ** stored entirely within the b-tree page by inspecting the first
|
|
- ** 2 bytes of the cell.
|
|
- */
|
|
- nCell = pCell[0];
|
|
- if( nCell<=pPage->max1bytePayload ){
|
|
- /* This branch runs if the record-size field of the cell is a
|
|
- ** single byte varint and the record fits entirely on the main
|
|
- ** b-tree page. */
|
|
- testcase( pCell+nCell+1==pPage->aDataEnd );
|
|
- c = xRecordCompare(nCell, (void*)&pCell[1], pIdxKey);
|
|
- }else if( !(pCell[1] & 0x80)
|
|
- && (nCell = ((nCell&0x7f)<<7) + pCell[1])<=pPage->maxLocal
|
|
- ){
|
|
- /* The record-size field is a 2 byte varint and the record
|
|
- ** fits entirely on the main b-tree page. */
|
|
- testcase( pCell+nCell+2==pPage->aDataEnd );
|
|
- c = xRecordCompare(nCell, (void*)&pCell[2], pIdxKey);
|
|
- }else{
|
|
- /* The record flows over onto one or more overflow pages. In
|
|
- ** this case the whole cell needs to be parsed, a buffer allocated
|
|
- ** and accessPayload() used to retrieve the record into the
|
|
- ** buffer before VdbeRecordCompare() can be called.
|
|
- **
|
|
- ** If the record is corrupt, the xRecordCompare routine may read
|
|
- ** up to two varints past the end of the buffer. An extra 18
|
|
- ** bytes of padding is allocated at the end of the buffer in
|
|
- ** case this happens. */
|
|
- void *pCellKey;
|
|
- u8 * const pCellBody = pCell - pPage->childPtrSize;
|
|
- const int nOverrun = 18; /* Size of the overrun padding */
|
|
- pPage->xParseCell(pPage, pCellBody, &pCur->info);
|
|
- nCell = (int)pCur->info.nKey;
|
|
- testcase( nCell<0 ); /* True if key size is 2^32 or more */
|
|
- testcase( nCell==0 ); /* Invalid key size: 0x80 0x80 0x00 */
|
|
- testcase( nCell==1 ); /* Invalid key size: 0x80 0x80 0x01 */
|
|
- testcase( nCell==2 ); /* Minimum legal index key size */
|
|
- if( nCell<2 || nCell/pCur->pBt->usableSize>pCur->pBt->nPage ){
|
|
- rc = SQLITE_CORRUPT_PAGE(pPage);
|
|
- goto moveto_finish;
|
|
- }
|
|
- pCellKey = sqlite3Malloc( nCell+nOverrun );
|
|
- if( pCellKey==0 ){
|
|
- rc = SQLITE_NOMEM_BKPT;
|
|
- goto moveto_finish;
|
|
- }
|
|
- pCur->ix = (u16)idx;
|
|
- rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 0);
|
|
- memset(((u8*)pCellKey)+nCell,0,nOverrun); /* Fix uninit warnings */
|
|
- pCur->curFlags &= ~BTCF_ValidOvfl;
|
|
- if( rc ){
|
|
- sqlite3_free(pCellKey);
|
|
- goto moveto_finish;
|
|
- }
|
|
- c = sqlite3VdbeRecordCompare(nCell, pCellKey, pIdxKey);
|
|
- sqlite3_free(pCellKey);
|
|
+ chldPg = get4byte(findCell(pPage, lwr));
|
|
+ }
|
|
+ pCur->ix = (u16)lwr;
|
|
+ rc = moveToChild(pCur, chldPg);
|
|
+ if( rc ) break;
|
|
+ }
|
|
+moveto_table_finish:
|
|
+ pCur->info.nSize = 0;
|
|
+ assert( (pCur->curFlags & BTCF_ValidOvfl)==0 );
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Compare the "idx"-th cell on the page the cursor pCur is currently
|
|
+** pointing to to pIdxKey using xRecordCompare. Return negative or
|
|
+** zero if the cell is less than or equal pIdxKey. Return positive
|
|
+** if unknown.
|
|
+**
|
|
+** Return value negative: Cell at pCur[idx] less than pIdxKey
|
|
+**
|
|
+** Return value is zero: Cell at pCur[idx] equals pIdxKey
|
|
+**
|
|
+** Return value positive: Nothing is known about the relationship
|
|
+** of the cell at pCur[idx] and pIdxKey.
|
|
+**
|
|
+** This routine is part of an optimization. It is always safe to return
|
|
+** a positive value as that will cause the optimization to be skipped.
|
|
+*/
|
|
+static int indexCellCompare(
|
|
+ BtCursor *pCur,
|
|
+ int idx,
|
|
+ UnpackedRecord *pIdxKey,
|
|
+ RecordCompare xRecordCompare
|
|
+){
|
|
+ MemPage *pPage = pCur->pPage;
|
|
+ int c;
|
|
+ int nCell; /* Size of the pCell cell in bytes */
|
|
+ u8 *pCell = findCellPastPtr(pPage, idx);
|
|
+
|
|
+ nCell = pCell[0];
|
|
+ if( nCell<=pPage->max1bytePayload ){
|
|
+ /* This branch runs if the record-size field of the cell is a
|
|
+ ** single byte varint and the record fits entirely on the main
|
|
+ ** b-tree page. */
|
|
+ testcase( pCell+nCell+1==pPage->aDataEnd );
|
|
+ c = xRecordCompare(nCell, (void*)&pCell[1], pIdxKey);
|
|
+ }else if( !(pCell[1] & 0x80)
|
|
+ && (nCell = ((nCell&0x7f)<<7) + pCell[1])<=pPage->maxLocal
|
|
+ ){
|
|
+ /* The record-size field is a 2 byte varint and the record
|
|
+ ** fits entirely on the main b-tree page. */
|
|
+ testcase( pCell+nCell+2==pPage->aDataEnd );
|
|
+ c = xRecordCompare(nCell, (void*)&pCell[2], pIdxKey);
|
|
+ }else{
|
|
+ /* If the record extends into overflow pages, do not attempt
|
|
+ ** the optimization. */
|
|
+ c = 99;
|
|
+ }
|
|
+ return c;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Return true (non-zero) if pCur is current pointing to the last
|
|
+** page of a table.
|
|
+*/
|
|
+static int cursorOnLastPage(BtCursor *pCur){
|
|
+ int i;
|
|
+ assert( pCur->eState==CURSOR_VALID );
|
|
+ for(i=0; i<pCur->iPage; i++){
|
|
+ MemPage *pPage = pCur->apPage[i];
|
|
+ if( pCur->aiIdx[i]<pPage->nCell ) return 0;
|
|
+ }
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+/* Move the cursor so that it points to an entry in an index table
|
|
+** near the key pIdxKey. Return a success code.
|
|
+**
|
|
+** If an exact match is not found, then the cursor is always
|
|
+** left pointing at a leaf page which would hold the entry if it
|
|
+** were present. The cursor might point to an entry that comes
|
|
+** before or after the key.
|
|
+**
|
|
+** An integer is written into *pRes which is the result of
|
|
+** comparing the key with the entry to which the cursor is
|
|
+** pointing. The meaning of the integer written into
|
|
+** *pRes is as follows:
|
|
+**
|
|
+** *pRes<0 The cursor is left pointing at an entry that
|
|
+** is smaller than pIdxKey or if the table is empty
|
|
+** and the cursor is therefore left point to nothing.
|
|
+**
|
|
+** *pRes==0 The cursor is left pointing at an entry that
|
|
+** exactly matches pIdxKey.
|
|
+**
|
|
+** *pRes>0 The cursor is left pointing at an entry that
|
|
+** is larger than pIdxKey.
|
|
+**
|
|
+** The pIdxKey->eqSeen field is set to 1 if there
|
|
+** exists an entry in the table that exactly matches pIdxKey.
|
|
+*/
|
|
+SQLITE_PRIVATE int sqlite3BtreeIndexMoveto(
|
|
+ BtCursor *pCur, /* The cursor to be moved */
|
|
+ UnpackedRecord *pIdxKey, /* Unpacked index key */
|
|
+ int *pRes /* Write search results here */
|
|
+){
|
|
+ int rc;
|
|
+ RecordCompare xRecordCompare;
|
|
+
|
|
+ assert( cursorOwnsBtShared(pCur) );
|
|
+ assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
|
|
+ assert( pRes );
|
|
+ assert( pCur->pKeyInfo!=0 );
|
|
+
|
|
+#ifdef SQLITE_DEBUG
|
|
+ pCur->pBtree->nSeek++; /* Performance measurement during testing */
|
|
+#endif
|
|
+
|
|
+ xRecordCompare = sqlite3VdbeFindCompare(pIdxKey);
|
|
+ pIdxKey->errCode = 0;
|
|
+ assert( pIdxKey->default_rc==1
|
|
+ || pIdxKey->default_rc==0
|
|
+ || pIdxKey->default_rc==-1
|
|
+ );
|
|
+
|
|
+
|
|
+ /* Check to see if we can skip a lot of work. Two cases:
|
|
+ **
|
|
+ ** (1) If the cursor is already pointing to the very last cell
|
|
+ ** in the table and the pIdxKey search key is greater than or
|
|
+ ** equal to that last cell, then no movement is required.
|
|
+ **
|
|
+ ** (2) If the cursor is on the last page of the table and the first
|
|
+ ** cell on that last page is less than or equal to the pIdxKey
|
|
+ ** search key, then we can start the search on the current page
|
|
+ ** without needing to go back to root.
|
|
+ */
|
|
+ if( pCur->eState==CURSOR_VALID
|
|
+ && pCur->pPage->leaf
|
|
+ && cursorOnLastPage(pCur)
|
|
+ ){
|
|
+ int c;
|
|
+ if( pCur->ix==pCur->pPage->nCell-1
|
|
+ && (c = indexCellCompare(pCur, pCur->ix, pIdxKey, xRecordCompare))<=0
|
|
+ && pIdxKey->errCode==SQLITE_OK
|
|
+ ){
|
|
+ *pRes = c;
|
|
+ return SQLITE_OK; /* Cursor already pointing at the correct spot */
|
|
+ }
|
|
+ if( pCur->iPage>0
|
|
+ && indexCellCompare(pCur, 0, pIdxKey, xRecordCompare)<=0
|
|
+ && pIdxKey->errCode==SQLITE_OK
|
|
+ ){
|
|
+ pCur->curFlags &= ~BTCF_ValidOvfl;
|
|
+ if( !pCur->pPage->isInit ){
|
|
+ return SQLITE_CORRUPT_BKPT;
|
|
+ }
|
|
+ goto bypass_moveto_root; /* Start search on the current page */
|
|
+ }
|
|
+ pIdxKey->errCode = SQLITE_OK;
|
|
+ }
|
|
+
|
|
+ rc = moveToRoot(pCur);
|
|
+ if( rc ){
|
|
+ if( rc==SQLITE_EMPTY ){
|
|
+ assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 );
|
|
+ *pRes = -1;
|
|
+ return SQLITE_OK;
|
|
+ }
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+bypass_moveto_root:
|
|
+ assert( pCur->pPage );
|
|
+ assert( pCur->pPage->isInit );
|
|
+ assert( pCur->eState==CURSOR_VALID );
|
|
+ assert( pCur->pPage->nCell > 0 );
|
|
+ assert( pCur->curIntKey==0 );
|
|
+ assert( pIdxKey!=0 );
|
|
+ for(;;){
|
|
+ int lwr, upr, idx, c;
|
|
+ Pgno chldPg;
|
|
+ MemPage *pPage = pCur->pPage;
|
|
+ u8 *pCell; /* Pointer to current cell in pPage */
|
|
+
|
|
+ /* pPage->nCell must be greater than zero. If this is the root-page
|
|
+ ** the cursor would have been INVALID above and this for(;;) loop
|
|
+ ** not run. If this is not the root-page, then the moveToChild() routine
|
|
+ ** would have already detected db corruption. Similarly, pPage must
|
|
+ ** be the right kind (index or table) of b-tree page. Otherwise
|
|
+ ** a moveToChild() or moveToRoot() call would have detected corruption. */
|
|
+ assert( pPage->nCell>0 );
|
|
+ assert( pPage->intKey==0 );
|
|
+ lwr = 0;
|
|
+ upr = pPage->nCell-1;
|
|
+ idx = upr>>1; /* idx = (lwr+upr)/2; */
|
|
+ for(;;){
|
|
+ int nCell; /* Size of the pCell cell in bytes */
|
|
+ pCell = findCellPastPtr(pPage, idx);
|
|
+
|
|
+ /* The maximum supported page-size is 65536 bytes. This means that
|
|
+ ** the maximum number of record bytes stored on an index B-Tree
|
|
+ ** page is less than 16384 bytes and may be stored as a 2-byte
|
|
+ ** varint. This information is used to attempt to avoid parsing
|
|
+ ** the entire cell by checking for the cases where the record is
|
|
+ ** stored entirely within the b-tree page by inspecting the first
|
|
+ ** 2 bytes of the cell.
|
|
+ */
|
|
+ nCell = pCell[0];
|
|
+ if( nCell<=pPage->max1bytePayload ){
|
|
+ /* This branch runs if the record-size field of the cell is a
|
|
+ ** single byte varint and the record fits entirely on the main
|
|
+ ** b-tree page. */
|
|
+ testcase( pCell+nCell+1==pPage->aDataEnd );
|
|
+ c = xRecordCompare(nCell, (void*)&pCell[1], pIdxKey);
|
|
+ }else if( !(pCell[1] & 0x80)
|
|
+ && (nCell = ((nCell&0x7f)<<7) + pCell[1])<=pPage->maxLocal
|
|
+ ){
|
|
+ /* The record-size field is a 2 byte varint and the record
|
|
+ ** fits entirely on the main b-tree page. */
|
|
+ testcase( pCell+nCell+2==pPage->aDataEnd );
|
|
+ c = xRecordCompare(nCell, (void*)&pCell[2], pIdxKey);
|
|
+ }else{
|
|
+ /* The record flows over onto one or more overflow pages. In
|
|
+ ** this case the whole cell needs to be parsed, a buffer allocated
|
|
+ ** and accessPayload() used to retrieve the record into the
|
|
+ ** buffer before VdbeRecordCompare() can be called.
|
|
+ **
|
|
+ ** If the record is corrupt, the xRecordCompare routine may read
|
|
+ ** up to two varints past the end of the buffer. An extra 18
|
|
+ ** bytes of padding is allocated at the end of the buffer in
|
|
+ ** case this happens. */
|
|
+ void *pCellKey;
|
|
+ u8 * const pCellBody = pCell - pPage->childPtrSize;
|
|
+ const int nOverrun = 18; /* Size of the overrun padding */
|
|
+ pPage->xParseCell(pPage, pCellBody, &pCur->info);
|
|
+ nCell = (int)pCur->info.nKey;
|
|
+ testcase( nCell<0 ); /* True if key size is 2^32 or more */
|
|
+ testcase( nCell==0 ); /* Invalid key size: 0x80 0x80 0x00 */
|
|
+ testcase( nCell==1 ); /* Invalid key size: 0x80 0x80 0x01 */
|
|
+ testcase( nCell==2 ); /* Minimum legal index key size */
|
|
+ if( nCell<2 || nCell/pCur->pBt->usableSize>pCur->pBt->nPage ){
|
|
+ rc = SQLITE_CORRUPT_PAGE(pPage);
|
|
+ goto moveto_index_finish;
|
|
+ }
|
|
+ pCellKey = sqlite3Malloc( nCell+nOverrun );
|
|
+ if( pCellKey==0 ){
|
|
+ rc = SQLITE_NOMEM_BKPT;
|
|
+ goto moveto_index_finish;
|
|
}
|
|
- assert(
|
|
- (pIdxKey->errCode!=SQLITE_CORRUPT || c==0)
|
|
- && (pIdxKey->errCode!=SQLITE_NOMEM || pCur->pBtree->db->mallocFailed)
|
|
- );
|
|
- if( c<0 ){
|
|
- lwr = idx+1;
|
|
- }else if( c>0 ){
|
|
- upr = idx-1;
|
|
- }else{
|
|
- assert( c==0 );
|
|
- *pRes = 0;
|
|
- rc = SQLITE_OK;
|
|
- pCur->ix = (u16)idx;
|
|
- if( pIdxKey->errCode ) rc = SQLITE_CORRUPT_BKPT;
|
|
- goto moveto_finish;
|
|
+ pCur->ix = (u16)idx;
|
|
+ rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 0);
|
|
+ memset(((u8*)pCellKey)+nCell,0,nOverrun); /* Fix uninit warnings */
|
|
+ pCur->curFlags &= ~BTCF_ValidOvfl;
|
|
+ if( rc ){
|
|
+ sqlite3_free(pCellKey);
|
|
+ goto moveto_index_finish;
|
|
}
|
|
- if( lwr>upr ) break;
|
|
- assert( lwr+upr>=0 );
|
|
- idx = (lwr+upr)>>1; /* idx = (lwr+upr)/2 */
|
|
+ c = sqlite3VdbeRecordCompare(nCell, pCellKey, pIdxKey);
|
|
+ sqlite3_free(pCellKey);
|
|
+ }
|
|
+ assert(
|
|
+ (pIdxKey->errCode!=SQLITE_CORRUPT || c==0)
|
|
+ && (pIdxKey->errCode!=SQLITE_NOMEM || pCur->pBtree->db->mallocFailed)
|
|
+ );
|
|
+ if( c<0 ){
|
|
+ lwr = idx+1;
|
|
+ }else if( c>0 ){
|
|
+ upr = idx-1;
|
|
+ }else{
|
|
+ assert( c==0 );
|
|
+ *pRes = 0;
|
|
+ rc = SQLITE_OK;
|
|
+ pCur->ix = (u16)idx;
|
|
+ if( pIdxKey->errCode ) rc = SQLITE_CORRUPT_BKPT;
|
|
+ goto moveto_index_finish;
|
|
}
|
|
+ if( lwr>upr ) break;
|
|
+ assert( lwr+upr>=0 );
|
|
+ idx = (lwr+upr)>>1; /* idx = (lwr+upr)/2 */
|
|
}
|
|
assert( lwr==upr+1 || (pPage->intKey && !pPage->leaf) );
|
|
assert( pPage->isInit );
|
|
if( pPage->leaf ){
|
|
- assert( pCur->ix<pCur->pPage->nCell );
|
|
+ assert( pCur->ix<pCur->pPage->nCell || CORRUPT_DB );
|
|
pCur->ix = (u16)idx;
|
|
*pRes = c;
|
|
rc = SQLITE_OK;
|
|
- goto moveto_finish;
|
|
+ goto moveto_index_finish;
|
|
}
|
|
-moveto_next_layer:
|
|
if( lwr>=pPage->nCell ){
|
|
chldPg = get4byte(&pPage->aData[pPage->hdrOffset+8]);
|
|
}else{
|
|
@@ -69729,7 +74418,7 @@ SQLITE_PRIVATE int sqlite3BtreeMovetoUnpacked(
|
|
rc = moveToChild(pCur, chldPg);
|
|
if( rc ) break;
|
|
}
|
|
-moveto_finish:
|
|
+moveto_index_finish:
|
|
pCur->info.nSize = 0;
|
|
assert( (pCur->curFlags & BTCF_ValidOvfl)==0 );
|
|
return rc;
|
|
@@ -69753,7 +74442,7 @@ SQLITE_PRIVATE int sqlite3BtreeEof(BtCursor *pCur){
|
|
|
|
/*
|
|
** Return an estimate for the number of rows in the table that pCur is
|
|
-** pointing to. Return a negative number if no estimate is currently
|
|
+** pointing to. Return a negative number if no estimate is currently
|
|
** available.
|
|
*/
|
|
SQLITE_PRIVATE i64 sqlite3BtreeRowCountEst(BtCursor *pCur){
|
|
@@ -69777,7 +74466,7 @@ SQLITE_PRIVATE i64 sqlite3BtreeRowCountEst(BtCursor *pCur){
|
|
}
|
|
|
|
/*
|
|
-** Advance the cursor to the next entry in the database.
|
|
+** Advance the cursor to the next entry in the database.
|
|
** Return value:
|
|
**
|
|
** SQLITE_OK success
|
|
@@ -69819,27 +74508,10 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur){
|
|
|
|
pPage = pCur->pPage;
|
|
idx = ++pCur->ix;
|
|
- if( !pPage->isInit ){
|
|
- /* The only known way for this to happen is for there to be a
|
|
- ** recursive SQL function that does a DELETE operation as part of a
|
|
- ** SELECT which deletes content out from under an active cursor
|
|
- ** in a corrupt database file where the table being DELETE-ed from
|
|
- ** has pages in common with the table being queried. See TH3
|
|
- ** module cov1/btree78.test testcase 220 (2018-06-08) for an
|
|
- ** example. */
|
|
+ if( !pPage->isInit || sqlite3FaultSim(412) ){
|
|
return SQLITE_CORRUPT_BKPT;
|
|
}
|
|
|
|
- /* If the database file is corrupt, it is possible for the value of idx
|
|
- ** to be invalid here. This can only occur if a second cursor modifies
|
|
- ** the page while cursor pCur is holding a reference to it. Which can
|
|
- ** only happen if the database is corrupt in such a way as to link the
|
|
- ** page into more than one b-tree structure.
|
|
- **
|
|
- ** Update 2019-12-23: appears to long longer be possible after the
|
|
- ** addition of anotherValidCursor() condition on balance_deeper(). */
|
|
- harmless( idx>pPage->nCell );
|
|
-
|
|
if( idx>=pPage->nCell ){
|
|
if( !pPage->leaf ){
|
|
rc = moveToChild(pCur, get4byte(&pPage->aData[pPage->hdrOffset+8]));
|
|
@@ -69982,7 +74654,7 @@ SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor *pCur, int flags){
|
|
** SQLITE_OK is returned on success. Any other return value indicates
|
|
** an error. *ppPage is set to NULL in the event of an error.
|
|
**
|
|
-** If the "nearby" parameter is not 0, then an effort is made to
|
|
+** If the "nearby" parameter is not 0, then an effort is made to
|
|
** locate a page close to the page number "nearby". This can be used in an
|
|
** attempt to keep related pages close to each other in the database file,
|
|
** which in turn can make database access faster.
|
|
@@ -70012,8 +74684,8 @@ static int allocateBtreePage(
|
|
assert( eMode==BTALLOC_ANY || (nearby>0 && IfNotOmitAV(pBt->autoVacuum)) );
|
|
pPage1 = pBt->pPage1;
|
|
mxPage = btreePagecount(pBt);
|
|
- /* EVIDENCE-OF: R-05119-02637 The 4-byte big-endian integer at offset 36
|
|
- ** stores stores the total number of pages on the freelist. */
|
|
+ /* EVIDENCE-OF: R-21003-45125 The 4-byte big-endian integer at offset 36
|
|
+ ** stores the total number of pages on the freelist. */
|
|
n = get4byte(&pPage1->aData[36]);
|
|
testcase( n==mxPage-1 );
|
|
if( n>=mxPage ){
|
|
@@ -70024,7 +74696,7 @@ static int allocateBtreePage(
|
|
Pgno iTrunk;
|
|
u8 searchList = 0; /* If the free-list must be searched for 'nearby' */
|
|
u32 nSearch = 0; /* Count of the number of search attempts */
|
|
-
|
|
+
|
|
/* If eMode==BTALLOC_EXACT and a query of the pointer-map
|
|
** shows that the page 'nearby' is somewhere on the free-list, then
|
|
** the entire-list will be searched for that page.
|
|
@@ -70087,8 +74759,8 @@ static int allocateBtreePage(
|
|
** is the number of leaf page pointers to follow. */
|
|
k = get4byte(&pTrunk->aData[4]);
|
|
if( k==0 && !searchList ){
|
|
- /* The trunk has no leaves and the list is not being searched.
|
|
- ** So extract the trunk page itself and use it as the newly
|
|
+ /* The trunk has no leaves and the list is not being searched.
|
|
+ ** So extract the trunk page itself and use it as the newly
|
|
** allocated page */
|
|
assert( pPrevTrunk==0 );
|
|
rc = sqlite3PagerWrite(pTrunk->pDbPage);
|
|
@@ -70105,8 +74777,8 @@ static int allocateBtreePage(
|
|
rc = SQLITE_CORRUPT_PGNO(iTrunk);
|
|
goto end_allocate_page;
|
|
#ifndef SQLITE_OMIT_AUTOVACUUM
|
|
- }else if( searchList
|
|
- && (nearby==iTrunk || (iTrunk<nearby && eMode==BTALLOC_LE))
|
|
+ }else if( searchList
|
|
+ && (nearby==iTrunk || (iTrunk<nearby && eMode==BTALLOC_LE))
|
|
){
|
|
/* The list is being searched and this trunk page is the page
|
|
** to allocate, regardless of whether it has leaves.
|
|
@@ -70129,13 +74801,13 @@ static int allocateBtreePage(
|
|
memcpy(&pPrevTrunk->aData[0], &pTrunk->aData[0], 4);
|
|
}
|
|
}else{
|
|
- /* The trunk page is required by the caller but it contains
|
|
+ /* The trunk page is required by the caller but it contains
|
|
** pointers to free-list leaves. The first leaf becomes a trunk
|
|
** page in this case.
|
|
*/
|
|
MemPage *pNewTrunk;
|
|
Pgno iNewTrunk = get4byte(&pTrunk->aData[8]);
|
|
- if( iNewTrunk>mxPage ){
|
|
+ if( iNewTrunk>mxPage ){
|
|
rc = SQLITE_CORRUPT_PGNO(iTrunk);
|
|
goto end_allocate_page;
|
|
}
|
|
@@ -70200,13 +74872,13 @@ static int allocateBtreePage(
|
|
|
|
iPage = get4byte(&aData[8+closest*4]);
|
|
testcase( iPage==mxPage );
|
|
- if( iPage>mxPage ){
|
|
+ if( iPage>mxPage || iPage<2 ){
|
|
rc = SQLITE_CORRUPT_PGNO(iTrunk);
|
|
goto end_allocate_page;
|
|
}
|
|
testcase( iPage==mxPage );
|
|
- if( !searchList
|
|
- || (iPage==nearby || (iPage<nearby && eMode==BTALLOC_LE))
|
|
+ if( !searchList
|
|
+ || (iPage==nearby || (iPage<nearby && eMode==BTALLOC_LE))
|
|
){
|
|
int noContent;
|
|
*pPgno = iPage;
|
|
@@ -70247,7 +74919,7 @@ static int allocateBtreePage(
|
|
** not set the no-content flag. This causes the pager to load and journal
|
|
** the current page content before overwriting it.
|
|
**
|
|
- ** Note that the pager will not actually attempt to load or journal
|
|
+ ** Note that the pager will not actually attempt to load or journal
|
|
** content for any page that really does lie past the end of the database
|
|
** file on disk. So the effects of disabling the no-content optimization
|
|
** here are confined to those pages that lie between the end of the
|
|
@@ -70304,12 +74976,12 @@ static int allocateBtreePage(
|
|
}
|
|
|
|
/*
|
|
-** This function is used to add page iPage to the database file free-list.
|
|
+** This function is used to add page iPage to the database file free-list.
|
|
** It is assumed that the page is not already a part of the free-list.
|
|
**
|
|
** The value passed as the second argument to this function is optional.
|
|
-** If the caller happens to have a pointer to the MemPage object
|
|
-** corresponding to page iPage handy, it may pass it as the second value.
|
|
+** If the caller happens to have a pointer to the MemPage object
|
|
+** corresponding to page iPage handy, it may pass it as the second value.
|
|
** Otherwise, it may pass NULL.
|
|
**
|
|
** If a pointer to a MemPage object is passed as the second argument,
|
|
@@ -70317,7 +74989,7 @@ static int allocateBtreePage(
|
|
*/
|
|
static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
|
|
MemPage *pTrunk = 0; /* Free-list trunk page */
|
|
- Pgno iTrunk = 0; /* Page number of free-list trunk page */
|
|
+ Pgno iTrunk = 0; /* Page number of free-list trunk page */
|
|
MemPage *pPage1 = pBt->pPage1; /* Local reference to page 1 */
|
|
MemPage *pPage; /* Page being freed. May be NULL. */
|
|
int rc; /* Return Code */
|
|
@@ -70358,7 +75030,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
|
|
/* If the database supports auto-vacuum, write an entry in the pointer-map
|
|
** to indicate that the page is free.
|
|
*/
|
|
- if( ISAUTOVACUUM ){
|
|
+ if( ISAUTOVACUUM(pBt) ){
|
|
ptrmapPut(pBt, iPage, PTRMAP_FREEPAGE, 0, &rc);
|
|
if( rc ) goto freepage_out;
|
|
}
|
|
@@ -70374,6 +75046,10 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
|
|
u32 nLeaf; /* Initial number of leaf cells on trunk page */
|
|
|
|
iTrunk = get4byte(&pPage1->aData[32]);
|
|
+ if( iTrunk>btreePagecount(pBt) ){
|
|
+ rc = SQLITE_CORRUPT_BKPT;
|
|
+ goto freepage_out;
|
|
+ }
|
|
rc = btreeGetPage(pBt, iTrunk, &pTrunk, 0);
|
|
if( rc!=SQLITE_OK ){
|
|
goto freepage_out;
|
|
@@ -70421,7 +75097,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
|
|
|
|
/* If control flows to this point, then it was not possible to add the
|
|
** the page being freed as a leaf page of the first trunk in the free-list.
|
|
- ** Possibly because the free-list is empty, or possibly because the
|
|
+ ** Possibly because the free-list is empty, or possibly because the
|
|
** first trunk in the free-list is full. Either way, the page being freed
|
|
** will become the new first trunk page in the free-list.
|
|
*/
|
|
@@ -70452,10 +75128,9 @@ static void freePage(MemPage *pPage, int *pRC){
|
|
}
|
|
|
|
/*
|
|
-** Free any overflow pages associated with the given Cell. Store
|
|
-** size information about the cell in pInfo.
|
|
+** Free the overflow pages associated with the given Cell.
|
|
*/
|
|
-static int clearCell(
|
|
+static SQLITE_NOINLINE int clearCellOverflow(
|
|
MemPage *pPage, /* The page that contains the Cell */
|
|
unsigned char *pCell, /* First byte of the Cell */
|
|
CellInfo *pInfo /* Size information about the cell */
|
|
@@ -70467,10 +75142,7 @@ static int clearCell(
|
|
u32 ovflPageSize;
|
|
|
|
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
|
|
- pPage->xParseCell(pPage, pCell, pInfo);
|
|
- if( pInfo->nLocal==pInfo->nPayload ){
|
|
- return SQLITE_OK; /* No overflow pages. Return without doing anything */
|
|
- }
|
|
+ assert( pInfo->nLocal!=pInfo->nPayload );
|
|
testcase( pCell + pInfo->nSize == pPage->aDataEnd );
|
|
testcase( pCell + (pInfo->nSize-1) == pPage->aDataEnd );
|
|
if( pCell + pInfo->nSize > pPage->aDataEnd ){
|
|
@@ -70482,15 +75154,15 @@ static int clearCell(
|
|
assert( pBt->usableSize > 4 );
|
|
ovflPageSize = pBt->usableSize - 4;
|
|
nOvfl = (pInfo->nPayload - pInfo->nLocal + ovflPageSize - 1)/ovflPageSize;
|
|
- assert( nOvfl>0 ||
|
|
+ assert( nOvfl>0 ||
|
|
(CORRUPT_DB && (pInfo->nPayload + ovflPageSize)<ovflPageSize)
|
|
);
|
|
while( nOvfl-- ){
|
|
Pgno iNext = 0;
|
|
MemPage *pOvfl = 0;
|
|
if( ovflPgno<2 || ovflPgno>btreePagecount(pBt) ){
|
|
- /* 0 is not a legal page number and page 1 cannot be an
|
|
- ** overflow page. Therefore if ovflPgno<2 or past the end of the
|
|
+ /* 0 is not a legal page number and page 1 cannot be an
|
|
+ ** overflow page. Therefore if ovflPgno<2 or past the end of the
|
|
** file the database must be corrupt. */
|
|
return SQLITE_CORRUPT_BKPT;
|
|
}
|
|
@@ -70502,11 +75174,11 @@ static int clearCell(
|
|
if( ( pOvfl || ((pOvfl = btreePageLookup(pBt, ovflPgno))!=0) )
|
|
&& sqlite3PagerPageRefcount(pOvfl->pDbPage)!=1
|
|
){
|
|
- /* There is no reason any cursor should have an outstanding reference
|
|
+ /* There is no reason any cursor should have an outstanding reference
|
|
** to an overflow page belonging to a cell that is being deleted/updated.
|
|
- ** So if there exists more than one reference to this page, then it
|
|
- ** must not really be an overflow page and the database must be corrupt.
|
|
- ** It is helpful to detect this before calling freePage2(), as
|
|
+ ** So if there exists more than one reference to this page, then it
|
|
+ ** must not really be an overflow page and the database must be corrupt.
|
|
+ ** It is helpful to detect this before calling freePage2(), as
|
|
** freePage2() may zero the page contents if secure-delete mode is
|
|
** enabled. If this 'overflow' page happens to be a page that the
|
|
** caller is iterating through or using in some other way, this
|
|
@@ -70526,6 +75198,21 @@ static int clearCell(
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
+/* 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.
|
|
+**
|
|
+** Implemented as macro to force inlining for performance.
|
|
+*/
|
|
+#define BTREE_CLEAR_CELL(rc, pPage, pCell, sInfo) \
|
|
+ pPage->xParseCell(pPage, pCell, &sInfo); \
|
|
+ if( sInfo.nLocal!=sInfo.nPayload ){ \
|
|
+ rc = clearCellOverflow(pPage, pCell, &sInfo); \
|
|
+ }else{ \
|
|
+ rc = SQLITE_OK; \
|
|
+ }
|
|
+
|
|
+
|
|
/*
|
|
** Create the byte sequence used to represent a cell on page pPage
|
|
** and write that byte sequence into pCell[]. Overflow pages are
|
|
@@ -70577,7 +75264,7 @@ static int fillInCell(
|
|
pSrc = pX->pKey;
|
|
nHeader += putVarint32(&pCell[nHeader], nPayload);
|
|
}
|
|
-
|
|
+
|
|
/* Fill in the payload */
|
|
pPayload = &pCell[nHeader];
|
|
if( nPayload<=pPage->maxLocal ){
|
|
@@ -70668,8 +75355,8 @@ static int fillInCell(
|
|
if( pBt->autoVacuum ){
|
|
do{
|
|
pgnoOvfl++;
|
|
- } while(
|
|
- PTRMAP_ISPAGE(pBt, pgnoOvfl) || pgnoOvfl==PENDING_BYTE_PAGE(pBt)
|
|
+ } while(
|
|
+ PTRMAP_ISPAGE(pBt, pgnoOvfl) || pgnoOvfl==PENDING_BYTE_PAGE(pBt)
|
|
);
|
|
}
|
|
#endif
|
|
@@ -70677,9 +75364,9 @@ static int fillInCell(
|
|
#ifndef SQLITE_OMIT_AUTOVACUUM
|
|
/* If the database supports auto-vacuum, and the second or subsequent
|
|
** overflow page is being allocated, add an entry to the pointer-map
|
|
- ** for that page now.
|
|
+ ** for that page now.
|
|
**
|
|
- ** If this is the first overflow page, then write a partial entry
|
|
+ ** If this is the first overflow page, then write a partial entry
|
|
** to the pointer-map. If we write nothing to this pointer-map slot,
|
|
** then the optimistic overflow chain processing in clearCell()
|
|
** may misinterpret the uninitialized values and delete the
|
|
@@ -70736,16 +75423,18 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
|
|
int hdr; /* Beginning of the header. 0 most pages. 100 page 1 */
|
|
|
|
if( *pRC ) return;
|
|
- assert( idx>=0 && idx<pPage->nCell );
|
|
+ assert( idx>=0 );
|
|
+ assert( idx<pPage->nCell );
|
|
assert( CORRUPT_DB || sz==cellSize(pPage, idx) );
|
|
assert( sqlite3PagerIswriteable(pPage->pDbPage) );
|
|
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
|
|
assert( pPage->nFree>=0 );
|
|
data = pPage->aData;
|
|
ptr = &pPage->aCellIdx[2*idx];
|
|
+ assert( pPage->pBt->usableSize > (u32)(ptr-data) );
|
|
pc = get2byte(ptr);
|
|
hdr = pPage->hdrOffset;
|
|
- testcase( pc==get2byte(&data[hdr+5]) );
|
|
+ testcase( pc==(u32)get2byte(&data[hdr+5]) );
|
|
testcase( pc+sz==pPage->pBt->usableSize );
|
|
if( pc+sz > pPage->pBt->usableSize ){
|
|
*pRC = SQLITE_CORRUPT_BKPT;
|
|
@@ -70778,27 +75467,23 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
|
|
** will not fit, then make a copy of the cell content into pTemp if
|
|
** pTemp is not null. Regardless of pTemp, allocate a new entry
|
|
** in pPage->apOvfl[] and make it point to the cell content (either
|
|
-** in pTemp or the original pCell) and also record its index.
|
|
-** Allocating a new entry in pPage->aCell[] implies that
|
|
+** in pTemp or the original pCell) and also record its index.
|
|
+** Allocating a new entry in pPage->aCell[] implies that
|
|
** pPage->nOverflow is incremented.
|
|
-**
|
|
-** *pRC must be SQLITE_OK when this routine is called.
|
|
*/
|
|
-static void insertCell(
|
|
+static int insertCell(
|
|
MemPage *pPage, /* Page into which we are copying */
|
|
int i, /* New cell becomes the i-th cell of the page */
|
|
u8 *pCell, /* Content of the new cell */
|
|
int sz, /* Bytes of content in pCell */
|
|
u8 *pTemp, /* Temp storage space for pCell, if needed */
|
|
- Pgno iChild, /* If non-zero, replace first 4 bytes with this value */
|
|
- int *pRC /* Read and write return code from here */
|
|
+ Pgno iChild /* If non-zero, replace first 4 bytes with this value */
|
|
){
|
|
int idx = 0; /* Where to write new cell content in data[] */
|
|
int j; /* Loop counter */
|
|
u8 *data; /* The content of the whole page */
|
|
u8 *pIns; /* The point in pPage->aCellIdx[] where no cell inserted */
|
|
|
|
- assert( *pRC==SQLITE_OK );
|
|
assert( i>=0 && i<=pPage->nCell+pPage->nOverflow );
|
|
assert( MX_CELL(pPage->pBt)<=10921 );
|
|
assert( pPage->nCell<=MX_CELL(pPage->pBt) || CORRUPT_DB );
|
|
@@ -70833,14 +75518,13 @@ static void insertCell(
|
|
}else{
|
|
int rc = sqlite3PagerWrite(pPage->pDbPage);
|
|
if( rc!=SQLITE_OK ){
|
|
- *pRC = rc;
|
|
- return;
|
|
+ return rc;
|
|
}
|
|
assert( sqlite3PagerIswriteable(pPage->pDbPage) );
|
|
data = pPage->aData;
|
|
assert( &data[pPage->cellOffset]==pPage->aCellIdx );
|
|
rc = allocateSpace(pPage, sz, &idx);
|
|
- if( rc ){ *pRC = rc; return; }
|
|
+ if( rc ){ return rc; }
|
|
/* The allocateSpace() routine guarantees the following properties
|
|
** if it returns successfully */
|
|
assert( idx >= 0 );
|
|
@@ -70867,13 +75551,16 @@ static void insertCell(
|
|
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, pRC);
|
|
+ ptrmapPutOvflPtr(pPage, pPage, pCell, &rc2);
|
|
+ if( rc2 ) return rc2;
|
|
}
|
|
#endif
|
|
}
|
|
+ return SQLITE_OK;
|
|
}
|
|
|
|
/*
|
|
@@ -70974,14 +75661,16 @@ struct CellArray {
|
|
** computed.
|
|
*/
|
|
static void populateCellCache(CellArray *p, int idx, int N){
|
|
+ MemPage *pRef = p->pRef;
|
|
+ u16 *szCell = p->szCell;
|
|
assert( idx>=0 && idx+N<=p->nCell );
|
|
while( N>0 ){
|
|
assert( p->apCell[idx]!=0 );
|
|
- if( p->szCell[idx]==0 ){
|
|
- p->szCell[idx] = p->pRef->xCellSize(p->pRef, p->apCell[idx]);
|
|
+ if( szCell[idx]==0 ){
|
|
+ szCell[idx] = pRef->xCellSize(pRef, p->apCell[idx]);
|
|
}else{
|
|
assert( CORRUPT_DB ||
|
|
- p->szCell[idx]==p->pRef->xCellSize(p->pRef, p->apCell[idx]) );
|
|
+ szCell[idx]==pRef->xCellSize(pRef, p->apCell[idx]) );
|
|
}
|
|
idx++;
|
|
N--;
|
|
@@ -71004,16 +75693,16 @@ static u16 cachedCellSize(CellArray *p, int N){
|
|
}
|
|
|
|
/*
|
|
-** Array apCell[] contains pointers to nCell b-tree page cells. The
|
|
+** Array apCell[] contains pointers to nCell b-tree page cells. The
|
|
** szCell[] array contains the size in bytes of each cell. This function
|
|
** replaces the current contents of page pPg with the contents of the cell
|
|
** array.
|
|
**
|
|
** Some of the cells in apCell[] may currently be stored in pPg. This
|
|
-** function works around problems caused by this by making a copy of any
|
|
+** function works around problems caused by this by making a copy of any
|
|
** such cells before overwriting the page data.
|
|
**
|
|
-** The MemPage.nFree field is invalidated by this function. It is the
|
|
+** The MemPage.nFree field is invalidated by this function. It is the
|
|
** responsibility of the caller to set it correctly.
|
|
*/
|
|
static int rebuildPage(
|
|
@@ -71037,7 +75726,7 @@ static int rebuildPage(
|
|
|
|
assert( i<iEnd );
|
|
j = get2byte(&aData[hdr+5]);
|
|
- if( NEVER(j>(u32)usableSize) ){ j = 0; }
|
|
+ if( j>(u32)usableSize ){ j = 0; }
|
|
memcpy(&pTmp[j], &aData[j], usableSize - j);
|
|
|
|
for(k=0; pCArray->ixNx[k]<=i && ALWAYS(k<NB*2); k++){}
|
|
@@ -71048,7 +75737,7 @@ static int rebuildPage(
|
|
u8 *pCell = pCArray->apCell[i];
|
|
u16 sz = pCArray->szCell[i];
|
|
assert( sz>0 );
|
|
- if( SQLITE_WITHIN(pCell,aData,pEnd) ){
|
|
+ if( SQLITE_WITHIN(pCell,aData+j,pEnd) ){
|
|
if( ((uptr)(pCell+sz))>(uptr)pEnd ) return SQLITE_CORRUPT_BKPT;
|
|
pCell = &pTmp[pCell - aData];
|
|
}else if( (uptr)(pCell+sz)>(uptr)pSrcEnd
|
|
@@ -71061,9 +75750,8 @@ static int rebuildPage(
|
|
put2byte(pCellptr, (pData - aData));
|
|
pCellptr += 2;
|
|
if( pData < pCellptr ) return SQLITE_CORRUPT_BKPT;
|
|
- memcpy(pData, pCell, sz);
|
|
+ memmove(pData, pCell, sz);
|
|
assert( sz==pPg->xCellSize(pPg, pCell) || CORRUPT_DB );
|
|
- testcase( sz!=pPg->xCellSize(pPg,pCell) )
|
|
i++;
|
|
if( i>=iEnd ) break;
|
|
if( pCArray->ixNx[k]<=i ){
|
|
@@ -71096,7 +75784,7 @@ static int rebuildPage(
|
|
** cell in the array. It is the responsibility of the caller to ensure
|
|
** that it is safe to overwrite this part of the cell-pointer array.
|
|
**
|
|
-** When this function is called, *ppData points to the start of the
|
|
+** When this function is called, *ppData points to the start of the
|
|
** content area on page pPg. If the size of the content area is extended,
|
|
** *ppData is updated to point to the new start of the content area
|
|
** before returning.
|
|
@@ -71184,8 +75872,8 @@ static int pageFreeArray(
|
|
int nRet = 0;
|
|
int i;
|
|
int iEnd = iFirst + nCell;
|
|
- u8 *pFree = 0;
|
|
- int szFree = 0;
|
|
+ u8 *pFree = 0; /* \__ Parameters for pending call to */
|
|
+ int szFree = 0; /* / freeSpace() */
|
|
|
|
for(i=iFirst; i<iEnd; i++){
|
|
u8 *pCell = pCArray->apCell[i];
|
|
@@ -71202,8 +75890,13 @@ static int pageFreeArray(
|
|
}
|
|
pFree = pCell;
|
|
szFree = sz;
|
|
- if( pFree+sz>pEnd ) return 0;
|
|
+ if( pFree+sz>pEnd ){
|
|
+ return 0;
|
|
+ }
|
|
}else{
|
|
+ /* The current cell is adjacent to and before the pFree cell.
|
|
+ ** Combine the two regions into one to reduce the number of calls
|
|
+ ** to freeSpace(). */
|
|
pFree = pCell;
|
|
szFree += sz;
|
|
}
|
|
@@ -71255,7 +75948,7 @@ static int editPage(
|
|
assert( nCell>=0 );
|
|
if( iOld<iNew ){
|
|
int nShift = pageFreeArray(pPg, iOld, iNew-iOld, pCArray);
|
|
- if( nShift>nCell ) return SQLITE_CORRUPT_BKPT;
|
|
+ if( NEVER(nShift>nCell) ) return SQLITE_CORRUPT_BKPT;
|
|
memmove(pPg->aCellIdx, &pPg->aCellIdx[nShift*2], nCell*2);
|
|
nCell -= nShift;
|
|
}
|
|
@@ -71267,6 +75960,7 @@ static int editPage(
|
|
|
|
pData = &aData[get2byteNotZero(&aData[hdr+5])];
|
|
if( pData<pBegin ) goto editpage_fail;
|
|
+ if( pData>pPg->aDataEnd ) goto editpage_fail;
|
|
|
|
/* Add cells to the start of the page */
|
|
if( iNew<iOld ){
|
|
@@ -71366,12 +76060,12 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){
|
|
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
|
|
assert( sqlite3PagerIswriteable(pParent->pDbPage) );
|
|
assert( pPage->nOverflow==1 );
|
|
-
|
|
+
|
|
if( pPage->nCell==0 ) return SQLITE_CORRUPT_BKPT; /* dbfuzz001.test */
|
|
assert( pPage->nFree>=0 );
|
|
assert( pParent->nFree>=0 );
|
|
|
|
- /* Allocate a new page. This page will become the right-sibling of
|
|
+ /* Allocate a new page. This page will become the right-sibling of
|
|
** pPage. Make the parent page writable, so that the new divider cell
|
|
** may be inserted. If both these operations are successful, proceed.
|
|
*/
|
|
@@ -71402,7 +76096,7 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){
|
|
pNew->nFree = pBt->usableSize - pNew->cellOffset - 2 - szCell;
|
|
|
|
/* If this is an auto-vacuum database, update the pointer map
|
|
- ** with entries for the new page, and any pointer from the
|
|
+ ** with entries for the new page, and any pointer from the
|
|
** cell on the page to an overflow page. If either of these
|
|
** operations fails, the return code is set, but the contents
|
|
** of the parent page are still manipulated by thh code below.
|
|
@@ -71410,20 +76104,20 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){
|
|
** be marked as dirty. Returning an error code will cause a
|
|
** rollback, undoing any changes made to the parent page.
|
|
*/
|
|
- if( ISAUTOVACUUM ){
|
|
+ if( ISAUTOVACUUM(pBt) ){
|
|
ptrmapPut(pBt, pgnoNew, PTRMAP_BTREE, pParent->pgno, &rc);
|
|
if( szCell>pNew->minLocal ){
|
|
ptrmapPutOvflPtr(pNew, pNew, pCell, &rc);
|
|
}
|
|
}
|
|
-
|
|
+
|
|
/* Create a divider cell to insert into pParent. The divider cell
|
|
** consists of a 4-byte page number (the page number of pPage) and
|
|
** a variable length key value (which must be the same value as the
|
|
** largest key on pPage).
|
|
**
|
|
- ** To find the largest key value on pPage, first find the right-most
|
|
- ** cell on pPage. The first two fields of this cell are the
|
|
+ ** To find the largest key value on pPage, first find the right-most
|
|
+ ** cell on pPage. The first two fields of this cell are the
|
|
** record-length (a variable length integer at most 32-bits in size)
|
|
** and the key value (a variable length integer, may have any value).
|
|
** The first of the while(...) loops below skips over the record-length
|
|
@@ -71438,13 +76132,13 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){
|
|
|
|
/* Insert the new divider cell into pParent. */
|
|
if( rc==SQLITE_OK ){
|
|
- insertCell(pParent, pParent->nCell, pSpace, (int)(pOut-pSpace),
|
|
- 0, pPage->pgno, &rc);
|
|
+ rc = insertCell(pParent, pParent->nCell, pSpace, (int)(pOut-pSpace),
|
|
+ 0, pPage->pgno);
|
|
}
|
|
|
|
/* Set the right-child pointer of pParent to point to the new page. */
|
|
put4byte(&pParent->aData[pParent->hdrOffset+8], pgnoNew);
|
|
-
|
|
+
|
|
/* Release the reference to the new page. */
|
|
releasePage(pNew);
|
|
}
|
|
@@ -71456,7 +76150,7 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){
|
|
#if 0
|
|
/*
|
|
** This function does not contribute anything to the operation of SQLite.
|
|
-** it is sometimes activated temporarily while debugging code responsible
|
|
+** it is sometimes activated temporarily while debugging code responsible
|
|
** for setting pointer-map entries.
|
|
*/
|
|
static int ptrmapCheckPages(MemPage **apPage, int nPage){
|
|
@@ -71471,7 +76165,7 @@ static int ptrmapCheckPages(MemPage **apPage, int nPage){
|
|
for(j=0; j<pPage->nCell; j++){
|
|
CellInfo info;
|
|
u8 *z;
|
|
-
|
|
+
|
|
z = findCell(pPage, j);
|
|
pPage->xParseCell(pPage, z, &info);
|
|
if( info.nLocal<info.nPayload ){
|
|
@@ -71496,7 +76190,7 @@ static int ptrmapCheckPages(MemPage **apPage, int nPage){
|
|
#endif
|
|
|
|
/*
|
|
-** This function is used to copy the contents of the b-tree node stored
|
|
+** This function is used to copy the contents of the b-tree node stored
|
|
** on page pFrom to page pTo. If page pFrom was not a leaf page, then
|
|
** the pointer-map entries for each child page are updated so that the
|
|
** parent page stored in the pointer map is page pTo. If pFrom contained
|
|
@@ -71504,11 +76198,11 @@ static int ptrmapCheckPages(MemPage **apPage, int nPage){
|
|
** map entries are also updated so that the parent page is page pTo.
|
|
**
|
|
** If pFrom is currently carrying any overflow cells (entries in the
|
|
-** MemPage.apOvfl[] array), they are not copied to pTo.
|
|
+** MemPage.apOvfl[] array), they are not copied to pTo.
|
|
**
|
|
** Before returning, page pTo is reinitialized using btreeInitPage().
|
|
**
|
|
-** The performance of this function is not critical. It is only used by
|
|
+** The performance of this function is not critical. It is only used by
|
|
** the balance_shallower() and balance_deeper() procedures, neither of
|
|
** which are called often under normal circumstances.
|
|
*/
|
|
@@ -71521,20 +76215,20 @@ static void copyNodeContent(MemPage *pFrom, MemPage *pTo, int *pRC){
|
|
int const iToHdr = ((pTo->pgno==1) ? 100 : 0);
|
|
int rc;
|
|
int iData;
|
|
-
|
|
-
|
|
+
|
|
+
|
|
assert( pFrom->isInit );
|
|
assert( pFrom->nFree>=iToHdr );
|
|
assert( get2byte(&aFrom[iFromHdr+5]) <= (int)pBt->usableSize );
|
|
-
|
|
+
|
|
/* Copy the b-tree node content from page pFrom to page pTo. */
|
|
iData = get2byte(&aFrom[iFromHdr+5]);
|
|
memcpy(&aTo[iData], &aFrom[iData], pBt->usableSize-iData);
|
|
memcpy(&aTo[iToHdr], &aFrom[iFromHdr], pFrom->cellOffset + 2*pFrom->nCell);
|
|
-
|
|
+
|
|
/* Reinitialize page pTo so that the contents of the MemPage structure
|
|
** match the new data. The initialization of pTo can actually fail under
|
|
- ** fairly obscure circumstances, even though it is a copy of initialized
|
|
+ ** fairly obscure circumstances, even though it is a copy of initialized
|
|
** page pFrom.
|
|
*/
|
|
pTo->isInit = 0;
|
|
@@ -71544,11 +76238,11 @@ static void copyNodeContent(MemPage *pFrom, MemPage *pTo, int *pRC){
|
|
*pRC = rc;
|
|
return;
|
|
}
|
|
-
|
|
+
|
|
/* If this is an auto-vacuum database, update the pointer-map entries
|
|
** for any b-tree or overflow pages that pTo now contains the pointers to.
|
|
*/
|
|
- if( ISAUTOVACUUM ){
|
|
+ if( ISAUTOVACUUM(pBt) ){
|
|
*pRC = setChildPtrmaps(pTo);
|
|
}
|
|
}
|
|
@@ -71559,13 +76253,13 @@ static void copyNodeContent(MemPage *pFrom, MemPage *pTo, int *pRC){
|
|
** (hereafter "the page") and up to 2 siblings so that all pages have about the
|
|
** same amount of free space. Usually a single sibling on either side of the
|
|
** page are used in the balancing, though both siblings might come from one
|
|
-** side if the page is the first or last child of its parent. If the page
|
|
+** side if the page is the first or last child of its parent. If the page
|
|
** has fewer than 2 siblings (something which can only happen if the page
|
|
** is a root page or a child of a root page) then all available siblings
|
|
** participate in the balancing.
|
|
**
|
|
-** The number of siblings of the page might be increased or decreased by
|
|
-** one or two in an effort to keep pages nearly full but not over full.
|
|
+** The number of siblings of the page might be increased or decreased by
|
|
+** one or two in an effort to keep pages nearly full but not over full.
|
|
**
|
|
** Note that when this routine is called, some of the cells on the page
|
|
** might not actually be stored in MemPage.aData[]. This can happen
|
|
@@ -71576,7 +76270,7 @@ static void copyNodeContent(MemPage *pFrom, MemPage *pTo, int *pRC){
|
|
** inserted into or removed from the parent page (pParent). Doing so
|
|
** may cause the parent page to become overfull or underfull. If this
|
|
** happens, it is the responsibility of the caller to invoke the correct
|
|
-** balancing routine to fix this problem (see the balance() routine).
|
|
+** balancing routine to fix this problem (see the balance() routine).
|
|
**
|
|
** If this routine fails for any reason, it might leave the database
|
|
** in a corrupted state. So if this routine fails, the database should
|
|
@@ -71591,7 +76285,7 @@ static void copyNodeContent(MemPage *pFrom, MemPage *pTo, int *pRC){
|
|
** of the page-size, the aOvflSpace[] buffer is guaranteed to be large
|
|
** enough for all overflow cells.
|
|
**
|
|
-** If aOvflSpace is set to a null pointer, this function returns
|
|
+** If aOvflSpace is set to a null pointer, this function returns
|
|
** SQLITE_NOMEM.
|
|
*/
|
|
static int balance_nonroot(
|
|
@@ -71626,19 +76320,16 @@ static int balance_nonroot(
|
|
Pgno pgno; /* Temp var to store a page number in */
|
|
u8 abDone[NB+2]; /* True after i'th new page is populated */
|
|
Pgno aPgno[NB+2]; /* Page numbers of new pages before shuffling */
|
|
- Pgno aPgOrder[NB+2]; /* Copy of aPgno[] used for sorting pages */
|
|
- u16 aPgFlags[NB+2]; /* flags field of new pages before shuffling */
|
|
- CellArray b; /* Parsed information on cells being balanced */
|
|
+ CellArray b; /* Parsed information on cells being balanced */
|
|
|
|
memset(abDone, 0, sizeof(abDone));
|
|
- b.nCell = 0;
|
|
- b.apCell = 0;
|
|
+ memset(&b, 0, sizeof(b));
|
|
pBt = pParent->pBt;
|
|
assert( sqlite3_mutex_held(pBt->mutex) );
|
|
assert( sqlite3PagerIswriteable(pParent->pDbPage) );
|
|
|
|
/* At this point pParent may have at most one overflow cell. And if
|
|
- ** this overflow cell is present, it must be the cell with
|
|
+ ** this overflow cell is present, it must be the cell with
|
|
** index iParentIdx. This scenario comes about when this function
|
|
** is called (indirectly) from sqlite3BtreeDelete().
|
|
*/
|
|
@@ -71650,11 +76341,11 @@ static int balance_nonroot(
|
|
}
|
|
assert( pParent->nFree>=0 );
|
|
|
|
- /* Find the sibling pages to balance. Also locate the cells in pParent
|
|
- ** that divide the siblings. An attempt is made to find NN siblings on
|
|
- ** either side of pPage. More siblings are taken from one side, however,
|
|
+ /* Find the sibling pages to balance. Also locate the cells in pParent
|
|
+ ** that divide the siblings. An attempt is made to find NN siblings on
|
|
+ ** either side of pPage. More siblings are taken from one side, however,
|
|
** if there are fewer than NN siblings on the other side. If pParent
|
|
- ** has NB or fewer children then all children of pParent are taken.
|
|
+ ** has NB or fewer children then all children of pParent are taken.
|
|
**
|
|
** This loop also drops the divider cells from the parent page. This
|
|
** way, the remainder of the function does not have to deal with any
|
|
@@ -71666,7 +76357,7 @@ static int balance_nonroot(
|
|
nxDiv = 0;
|
|
}else{
|
|
assert( bBulk==0 || bBulk==1 );
|
|
- if( iParentIdx==0 ){
|
|
+ if( iParentIdx==0 ){
|
|
nxDiv = 0;
|
|
}else if( iParentIdx==i ){
|
|
nxDiv = i-2+bBulk;
|
|
@@ -71683,7 +76374,9 @@ static int balance_nonroot(
|
|
}
|
|
pgno = get4byte(pRight);
|
|
while( 1 ){
|
|
- rc = getAndInitPage(pBt, pgno, &apOld[i], 0, 0);
|
|
+ if( rc==SQLITE_OK ){
|
|
+ rc = getAndInitPage(pBt, pgno, &apOld[i], 0, 0);
|
|
+ }
|
|
if( rc ){
|
|
memset(apOld, 0, (i+1)*sizeof(MemPage*));
|
|
goto balance_cleanup;
|
|
@@ -71695,6 +76388,7 @@ static int balance_nonroot(
|
|
goto balance_cleanup;
|
|
}
|
|
}
|
|
+ nMaxCells += apOld[i]->nCell + ArraySize(pParent->apOvfl);
|
|
if( (i--)==0 ) break;
|
|
|
|
if( pParent->nOverflow && i+nxDiv==pParent->aiOvfl[0] ){
|
|
@@ -71712,7 +76406,7 @@ static int balance_nonroot(
|
|
** This is safe because dropping a cell only overwrites the first
|
|
** four bytes of it, and this function does not need the first
|
|
** four bytes of the divider cell. So the pointer is safe to use
|
|
- ** later on.
|
|
+ ** later on.
|
|
**
|
|
** But not if we are in secure-delete mode. In secure-delete mode,
|
|
** the dropCell() routine will overwrite the entire cell with zeroes.
|
|
@@ -71722,12 +76416,10 @@ static int balance_nonroot(
|
|
if( pBt->btsFlags & BTS_FAST_SECURE ){
|
|
int iOff;
|
|
|
|
+ /* If the following if() condition is not true, the db is corrupted.
|
|
+ ** The call to dropCell() below will detect this. */
|
|
iOff = SQLITE_PTR_TO_INT(apDiv[i]) - SQLITE_PTR_TO_INT(pParent->aData);
|
|
- if( (iOff+szNew[i])>(int)pBt->usableSize ){
|
|
- rc = SQLITE_CORRUPT_BKPT;
|
|
- memset(apOld, 0, (i+1)*sizeof(MemPage*));
|
|
- goto balance_cleanup;
|
|
- }else{
|
|
+ if( (iOff+szNew[i])<=(int)pBt->usableSize ){
|
|
memcpy(&aOvflSpace[iOff], apDiv[i], szNew[i]);
|
|
apDiv[i] = &aOvflSpace[apDiv[i]-pParent->aData];
|
|
}
|
|
@@ -71738,7 +76430,6 @@ static int balance_nonroot(
|
|
|
|
/* Make nMaxCells a multiple of 4 in order to preserve 8-byte
|
|
** alignment */
|
|
- nMaxCells = nOld*(MX_CELL(pBt) + ArraySize(pParent->apOvfl));
|
|
nMaxCells = (nMaxCells + 3)&~3;
|
|
|
|
/*
|
|
@@ -71855,7 +76546,7 @@ static int balance_nonroot(
|
|
b.szCell[b.nCell] = b.szCell[b.nCell] - leafCorrection;
|
|
if( !pOld->leaf ){
|
|
assert( leafCorrection==0 );
|
|
- assert( pOld->hdrOffset==0 );
|
|
+ assert( pOld->hdrOffset==0 || CORRUPT_DB );
|
|
/* The right pointer of the child page pOld becomes the left
|
|
** pointer of the divider cell */
|
|
memcpy(b.apCell[b.nCell], &pOld->aData[8], 4);
|
|
@@ -71878,7 +76569,7 @@ static int balance_nonroot(
|
|
** Figure out the number of pages needed to hold all b.nCell cells.
|
|
** Store this number in "k". Also compute szNew[] which is the total
|
|
** size of all cells on the i-th page and cntNew[] which is the index
|
|
- ** in b.apCell[] of the cell that divides page i from page i+1.
|
|
+ ** in b.apCell[] of the cell that divides page i from page i+1.
|
|
** cntNew[k] should equal b.nCell.
|
|
**
|
|
** Values computed by this block:
|
|
@@ -71888,7 +76579,7 @@ static int balance_nonroot(
|
|
** cntNew[i]: Index in b.apCell[] and b.szCell[] for the first cell to
|
|
** the right of the i-th sibling page.
|
|
** usableSpace: Number of bytes of space available on each sibling.
|
|
- **
|
|
+ **
|
|
*/
|
|
usableSpace = pBt->usableSize - 12 + leafCorrection;
|
|
for(i=k=0; i<nOld; i++, k++){
|
|
@@ -71975,15 +76666,17 @@ static int balance_nonroot(
|
|
d = r + 1 - leafData;
|
|
(void)cachedCellSize(&b, d);
|
|
do{
|
|
+ int szR, szD;
|
|
assert( d<nMaxCells );
|
|
assert( r<nMaxCells );
|
|
- (void)cachedCellSize(&b, r);
|
|
+ szR = cachedCellSize(&b, r);
|
|
+ szD = b.szCell[d];
|
|
if( szRight!=0
|
|
- && (bBulk || szRight+b.szCell[d]+2 > szLeft-(b.szCell[r]+(i==k-1?0:2)))){
|
|
+ && (bBulk || szRight+szD+2 > szLeft-(szR+(i==k-1?0:2)))){
|
|
break;
|
|
}
|
|
- szRight += b.szCell[d] + 2;
|
|
- szLeft -= b.szCell[r] + 2;
|
|
+ szRight += szD + 2;
|
|
+ szLeft -= szR + 2;
|
|
cntNew[i-1] = r;
|
|
r--;
|
|
d--;
|
|
@@ -72021,6 +76714,11 @@ static int balance_nonroot(
|
|
apOld[i] = 0;
|
|
rc = sqlite3PagerWrite(pNew->pDbPage);
|
|
nNew++;
|
|
+ if( sqlite3PagerPageRefcount(pNew->pDbPage)!=1+(i==(iParentIdx-nxDiv))
|
|
+ && rc==SQLITE_OK
|
|
+ ){
|
|
+ rc = SQLITE_CORRUPT_BKPT;
|
|
+ }
|
|
if( rc ) goto balance_cleanup;
|
|
}else{
|
|
assert( i>0 );
|
|
@@ -72032,7 +76730,7 @@ static int balance_nonroot(
|
|
cntOld[i] = b.nCell;
|
|
|
|
/* Set the pointer-map entry for the new sibling page. */
|
|
- if( ISAUTOVACUUM ){
|
|
+ if( ISAUTOVACUUM(pBt) ){
|
|
ptrmapPut(pBt, pNew->pgno, PTRMAP_BTREE, pParent->pgno, &rc);
|
|
if( rc!=SQLITE_OK ){
|
|
goto balance_cleanup;
|
|
@@ -72042,47 +76740,44 @@ static int balance_nonroot(
|
|
}
|
|
|
|
/*
|
|
- ** Reassign page numbers so that the new pages are in ascending order.
|
|
+ ** Reassign page numbers so that the new pages are in ascending order.
|
|
** This helps to keep entries in the disk file in order so that a scan
|
|
- ** of the table is closer to a linear scan through the file. That in turn
|
|
+ ** of the table is closer to a linear scan through the file. That in turn
|
|
** helps the operating system to deliver pages from the disk more rapidly.
|
|
**
|
|
- ** An O(n^2) insertion sort algorithm is used, but since n is never more
|
|
- ** than (NB+2) (a small constant), that should not be a problem.
|
|
+ ** An O(N*N) sort algorithm is used, but since N is never more than NB+2
|
|
+ ** (5), that is not a performance concern.
|
|
**
|
|
- ** When NB==3, this one optimization makes the database about 25% faster
|
|
+ ** When NB==3, this one optimization makes the database about 25% faster
|
|
** for large insertions and deletions.
|
|
*/
|
|
for(i=0; i<nNew; i++){
|
|
- aPgOrder[i] = aPgno[i] = apNew[i]->pgno;
|
|
- aPgFlags[i] = apNew[i]->pDbPage->flags;
|
|
- for(j=0; j<i; j++){
|
|
- if( aPgno[j]==aPgno[i] ){
|
|
- /* This branch is taken if the set of sibling pages somehow contains
|
|
- ** duplicate entries. This can happen if the database is corrupt.
|
|
- ** It would be simpler to detect this as part of the loop below, but
|
|
- ** we do the detection here in order to avoid populating the pager
|
|
- ** cache with two separate objects associated with the same
|
|
- ** page number. */
|
|
- assert( CORRUPT_DB );
|
|
- rc = SQLITE_CORRUPT_BKPT;
|
|
- goto balance_cleanup;
|
|
- }
|
|
- }
|
|
+ aPgno[i] = apNew[i]->pgno;
|
|
+ assert( apNew[i]->pDbPage->flags & PGHDR_WRITEABLE );
|
|
+ assert( apNew[i]->pDbPage->flags & PGHDR_DIRTY );
|
|
}
|
|
- for(i=0; i<nNew; i++){
|
|
- int iBest = 0; /* aPgno[] index of page number to use */
|
|
- for(j=1; j<nNew; j++){
|
|
- if( aPgOrder[j]<aPgOrder[iBest] ) iBest = j;
|
|
+ for(i=0; i<nNew-1; i++){
|
|
+ int iB = i;
|
|
+ for(j=i+1; j<nNew; j++){
|
|
+ if( apNew[j]->pgno < apNew[iB]->pgno ) iB = j;
|
|
}
|
|
- pgno = aPgOrder[iBest];
|
|
- aPgOrder[iBest] = 0xffffffff;
|
|
- if( iBest!=i ){
|
|
- if( iBest>i ){
|
|
- sqlite3PagerRekey(apNew[iBest]->pDbPage, pBt->nPage+iBest+1, 0);
|
|
- }
|
|
- sqlite3PagerRekey(apNew[i]->pDbPage, pgno, aPgFlags[iBest]);
|
|
- apNew[i]->pgno = pgno;
|
|
+
|
|
+ /* If apNew[i] has a page number that is bigger than any of the
|
|
+ ** subsequence apNew[i] entries, then swap apNew[i] with the subsequent
|
|
+ ** entry that has the smallest page number (which we know to be
|
|
+ ** entry apNew[iB]).
|
|
+ */
|
|
+ if( iB!=i ){
|
|
+ Pgno pgnoA = apNew[i]->pgno;
|
|
+ Pgno pgnoB = apNew[iB]->pgno;
|
|
+ Pgno pgnoTemp = (PENDING_BYTE/pBt->pageSize)+1;
|
|
+ u16 fgA = apNew[i]->pDbPage->flags;
|
|
+ u16 fgB = apNew[iB]->pDbPage->flags;
|
|
+ sqlite3PagerRekey(apNew[i]->pDbPage, pgnoTemp, fgB);
|
|
+ sqlite3PagerRekey(apNew[iB]->pDbPage, pgnoA, fgA);
|
|
+ sqlite3PagerRekey(apNew[i]->pDbPage, pgnoB, fgB);
|
|
+ apNew[i]->pgno = pgnoB;
|
|
+ apNew[iB]->pgno = pgnoA;
|
|
}
|
|
}
|
|
|
|
@@ -72105,14 +76800,14 @@ static int balance_nonroot(
|
|
put4byte(pRight, apNew[nNew-1]->pgno);
|
|
|
|
/* If the sibling pages are not leaves, ensure that the right-child pointer
|
|
- ** of the right-most new sibling page is set to the value that was
|
|
+ ** of the right-most new sibling page is set to the value that was
|
|
** originally in the same field of the right-most old sibling page. */
|
|
if( (pageFlags & PTF_LEAF)==0 && nOld!=nNew ){
|
|
MemPage *pOld = (nNew>nOld ? apNew : apOld)[nOld-1];
|
|
memcpy(&apNew[nNew-1]->aData[8], &pOld->aData[8], 4);
|
|
}
|
|
|
|
- /* Make any required updates to pointer map entries associated with
|
|
+ /* Make any required updates to pointer map entries associated with
|
|
** cells stored on sibling pages following the balance operation. Pointer
|
|
** map entries associated with divider cells are set by the insertCell()
|
|
** routine. The associated pointer map entries are:
|
|
@@ -72123,12 +76818,12 @@ static int balance_nonroot(
|
|
** b) if the sibling pages are not leaves, the child page associated
|
|
** with the cell.
|
|
**
|
|
- ** If the sibling pages are not leaves, then the pointer map entry
|
|
- ** associated with the right-child of each sibling may also need to be
|
|
- ** updated. This happens below, after the sibling pages have been
|
|
+ ** If the sibling pages are not leaves, then the pointer map entry
|
|
+ ** associated with the right-child of each sibling may also need to be
|
|
+ ** updated. This happens below, after the sibling pages have been
|
|
** populated, not here.
|
|
*/
|
|
- if( ISAUTOVACUUM ){
|
|
+ if( ISAUTOVACUUM(pBt) ){
|
|
MemPage *pOld;
|
|
MemPage *pNew = pOld = apNew[0];
|
|
int cntOldNext = pNew->nCell + pNew->nOverflow;
|
|
@@ -72150,7 +76845,7 @@ static int balance_nonroot(
|
|
}
|
|
|
|
/* Cell pCell is destined for new sibling page pNew. Originally, it
|
|
- ** was either part of sibling page iOld (possibly an overflow cell),
|
|
+ ** was either part of sibling page iOld (possibly an overflow cell),
|
|
** or else the divider cell to the left of sibling page iOld. So,
|
|
** if sibling page iOld had the same page number as pNew, and if
|
|
** pCell really was a part of sibling page iOld (not a divider or
|
|
@@ -72175,6 +76870,7 @@ static int balance_nonroot(
|
|
u8 *pCell;
|
|
u8 *pTemp;
|
|
int sz;
|
|
+ u8 *pSrcEnd;
|
|
MemPage *pNew = apNew[i];
|
|
j = cntNew[i];
|
|
|
|
@@ -72186,9 +76882,9 @@ static int balance_nonroot(
|
|
if( !pNew->leaf ){
|
|
memcpy(&pNew->aData[8], pCell, 4);
|
|
}else if( leafData ){
|
|
- /* If the tree is a leaf-data tree, and the siblings are leaves,
|
|
- ** then there is no divider cell in b.apCell[]. Instead, the divider
|
|
- ** cell consists of the integer key for the right-most cell of
|
|
+ /* If the tree is a leaf-data tree, and the siblings are leaves,
|
|
+ ** then there is no divider cell in b.apCell[]. Instead, the divider
|
|
+ ** cell consists of the integer key for the right-most cell of
|
|
** the sibling-page assembled above only.
|
|
*/
|
|
CellInfo info;
|
|
@@ -72201,9 +76897,9 @@ static int balance_nonroot(
|
|
pCell -= 4;
|
|
/* Obscure case for non-leaf-data trees: If the cell at pCell was
|
|
** previously stored on a leaf node, and its reported size was 4
|
|
- ** bytes, then it may actually be smaller than this
|
|
+ ** bytes, then it may actually be smaller than this
|
|
** (see btreeParseCellPtr(), 4 bytes is the minimum size of
|
|
- ** any cell). But it is important to pass the correct size to
|
|
+ ** any cell). But it is important to pass the correct size to
|
|
** insertCell(), so reparse the cell now.
|
|
**
|
|
** This can only happen for b-trees used to evaluate "IN (SELECT ...)"
|
|
@@ -72218,7 +76914,13 @@ static int balance_nonroot(
|
|
iOvflSpace += sz;
|
|
assert( sz<=pBt->maxLocal+23 );
|
|
assert( iOvflSpace <= (int)pBt->pageSize );
|
|
- insertCell(pParent, nxDiv+i, pCell, sz, pTemp, pNew->pgno, &rc);
|
|
+ for(k=0; b.ixNx[k]<=j && ALWAYS(k<NB*2); k++){}
|
|
+ pSrcEnd = b.apEnd[k];
|
|
+ if( SQLITE_WITHIN(pSrcEnd, pCell, pCell+sz) ){
|
|
+ rc = SQLITE_CORRUPT_BKPT;
|
|
+ goto balance_cleanup;
|
|
+ }
|
|
+ rc = insertCell(pParent, nxDiv+i, pCell, sz, pTemp, pNew->pgno);
|
|
if( rc!=SQLITE_OK ) goto balance_cleanup;
|
|
assert( sqlite3PagerIswriteable(pParent->pDbPage) );
|
|
}
|
|
@@ -72295,8 +76997,8 @@ static int balance_nonroot(
|
|
** b-tree structure by one. This is described as the "balance-shallower"
|
|
** sub-algorithm in some documentation.
|
|
**
|
|
- ** If this is an auto-vacuum database, the call to copyNodeContent()
|
|
- ** sets all pointer-map entries corresponding to database image pages
|
|
+ ** If this is an auto-vacuum database, the call to copyNodeContent()
|
|
+ ** sets all pointer-map entries corresponding to database image pages
|
|
** for which the pointer is stored within the content being copied.
|
|
**
|
|
** It is critical that the child page be defragmented before being
|
|
@@ -72307,14 +77009,14 @@ static int balance_nonroot(
|
|
assert( nNew==1 || CORRUPT_DB );
|
|
rc = defragmentPage(apNew[0], -1);
|
|
testcase( rc!=SQLITE_OK );
|
|
- assert( apNew[0]->nFree ==
|
|
+ assert( apNew[0]->nFree ==
|
|
(get2byteNotZero(&apNew[0]->aData[5]) - apNew[0]->cellOffset
|
|
- apNew[0]->nCell*2)
|
|
|| rc!=SQLITE_OK
|
|
);
|
|
copyNodeContent(apNew[0], pParent, &rc);
|
|
freePage(apNew[0], &rc);
|
|
- }else if( ISAUTOVACUUM && !leafCorrection ){
|
|
+ }else if( ISAUTOVACUUM(pBt) && !leafCorrection ){
|
|
/* Fix the pointer map entries associated with the right-child of each
|
|
** sibling page. All other pointer map entries have already been taken
|
|
** care of. */
|
|
@@ -72335,9 +77037,9 @@ static int balance_nonroot(
|
|
}
|
|
|
|
#if 0
|
|
- if( ISAUTOVACUUM && rc==SQLITE_OK && apNew[0]->isInit ){
|
|
+ if( ISAUTOVACUUM(pBt) && rc==SQLITE_OK && apNew[0]->isInit ){
|
|
/* The ptrmapCheckPages() contains assert() statements that verify that
|
|
- ** all pointer map pages are set correctly. This is helpful while
|
|
+ ** all pointer map pages are set correctly. This is helpful while
|
|
** debugging. This is usually disabled because a corrupt database may
|
|
** cause an assert() statement to fail. */
|
|
ptrmapCheckPages(apNew, nNew);
|
|
@@ -72367,15 +77069,15 @@ static int balance_nonroot(
|
|
**
|
|
** A new child page is allocated and the contents of the current root
|
|
** page, including overflow cells, are copied into the child. The root
|
|
-** page is then overwritten to make it an empty page with the right-child
|
|
+** page is then overwritten to make it an empty page with the right-child
|
|
** pointer pointing to the new page.
|
|
**
|
|
-** Before returning, all pointer-map entries corresponding to pages
|
|
+** Before returning, all pointer-map entries corresponding to pages
|
|
** that the new child-page now contains pointers to are updated. The
|
|
** entry corresponding to the new right-child pointer of the root
|
|
** page is also updated.
|
|
**
|
|
-** If successful, *ppChild is set to contain a reference to the child
|
|
+** If successful, *ppChild is set to contain a reference to the child
|
|
** page and SQLITE_OK is returned. In this case the caller is required
|
|
** to call releasePage() on *ppChild exactly once. If an error occurs,
|
|
** an error code is returned and *ppChild is set to 0.
|
|
@@ -72389,7 +77091,7 @@ static int balance_deeper(MemPage *pRoot, MemPage **ppChild){
|
|
assert( pRoot->nOverflow>0 );
|
|
assert( sqlite3_mutex_held(pBt->mutex) );
|
|
|
|
- /* Make pRoot, the root page of the b-tree, writable. Allocate a new
|
|
+ /* Make pRoot, the root page of the b-tree, writable. Allocate a new
|
|
** page that will become the new right-child of pPage. Copy the contents
|
|
** of the node stored on pRoot into the new child page.
|
|
*/
|
|
@@ -72397,7 +77099,7 @@ static int balance_deeper(MemPage *pRoot, MemPage **ppChild){
|
|
if( rc==SQLITE_OK ){
|
|
rc = allocateBtreePage(pBt,&pChild,&pgnoChild,pRoot->pgno,0);
|
|
copyNodeContent(pRoot, pChild, &rc);
|
|
- if( ISAUTOVACUUM ){
|
|
+ if( ISAUTOVACUUM(pBt) ){
|
|
ptrmapPut(pBt, pgnoChild, PTRMAP_BTREE, pRoot->pgno, &rc);
|
|
}
|
|
}
|
|
@@ -72431,7 +77133,7 @@ static int balance_deeper(MemPage *pRoot, MemPage **ppChild){
|
|
** Return SQLITE_CORRUPT if any cursor other than pCur is currently valid
|
|
** on the same B-tree as pCur.
|
|
**
|
|
-** This can if a database is corrupt with two or more SQL tables
|
|
+** This can occur if a database is corrupt with two or more SQL tables
|
|
** pointing to the same b-tree. If an insert occurs on one SQL table
|
|
** and causes a BEFORE TRIGGER to do a secondary insert on the other SQL
|
|
** table linked to the same b-tree. If the secondary insert causes a
|
|
@@ -72454,7 +77156,7 @@ static int anotherValidCursor(BtCursor *pCur){
|
|
/*
|
|
** The page that pCur currently points to has just been modified in
|
|
** some way. This function figures out if this modification means the
|
|
-** tree needs to be balanced, and if so calls the appropriate balancing
|
|
+** tree needs to be balanced, and if so calls the appropriate balancing
|
|
** routine. Balancing routines are:
|
|
**
|
|
** balance_quick()
|
|
@@ -72463,7 +77165,6 @@ static int anotherValidCursor(BtCursor *pCur){
|
|
*/
|
|
static int balance(BtCursor *pCur){
|
|
int rc = SQLITE_OK;
|
|
- const int nMin = pCur->pBt->usableSize * 2 / 3;
|
|
u8 aBalanceQuickSpace[13];
|
|
u8 *pFree = 0;
|
|
|
|
@@ -72475,7 +77176,11 @@ static int balance(BtCursor *pCur){
|
|
MemPage *pPage = pCur->pPage;
|
|
|
|
if( NEVER(pPage->nFree<0) && btreeComputeFreeSpace(pPage) ) break;
|
|
- if( pPage->nOverflow==0 && pPage->nFree<=nMin ){
|
|
+ if( pPage->nOverflow==0 && pPage->nFree*3<=(int)pCur->pBt->usableSize*2 ){
|
|
+ /* No rebalance required as long as:
|
|
+ ** (1) There are no overflow cells
|
|
+ ** (2) The amount of free space on the page is less than 2/3rds of
|
|
+ ** the total usable space on the page. */
|
|
break;
|
|
}else if( (iPage = pCur->iPage)==0 ){
|
|
if( pPage->nOverflow && (rc = anotherValidCursor(pCur))==SQLITE_OK ){
|
|
@@ -72483,7 +77188,7 @@ static int balance(BtCursor *pCur){
|
|
** balance_deeper() function to create a new child for the root-page
|
|
** and copy the current contents of the root-page to it. The
|
|
** next iteration of the do-loop will balance the child page.
|
|
- */
|
|
+ */
|
|
assert( balance_deeper_called==0 );
|
|
VVA_ONLY( balance_deeper_called++ );
|
|
rc = balance_deeper(pPage, &pCur->apPage[1]);
|
|
@@ -72498,6 +77203,11 @@ static int balance(BtCursor *pCur){
|
|
}else{
|
|
break;
|
|
}
|
|
+ }else if( sqlite3PagerPageRefcount(pPage->pDbPage)>1 ){
|
|
+ /* The page being written is not a root page, and there is currently
|
|
+ ** more than one reference to it. This only happens if the page is one
|
|
+ ** of its own ancestor pages. Corruption. */
|
|
+ rc = SQLITE_CORRUPT_BKPT;
|
|
}else{
|
|
MemPage * const pParent = pCur->apPage[iPage-1];
|
|
int const iIdx = pCur->aiIdx[iPage-1];
|
|
@@ -72517,17 +77227,17 @@ static int balance(BtCursor *pCur){
|
|
/* Call balance_quick() to create a new sibling of pPage on which
|
|
** to store the overflow cell. balance_quick() inserts a new cell
|
|
** into pParent, which may cause pParent overflow. If this
|
|
- ** happens, the next iteration of the do-loop will balance pParent
|
|
+ ** happens, the next iteration of the do-loop will balance pParent
|
|
** use either balance_nonroot() or balance_deeper(). Until this
|
|
** happens, the overflow cell is stored in the aBalanceQuickSpace[]
|
|
- ** buffer.
|
|
+ ** buffer.
|
|
**
|
|
** The purpose of the following assert() is to check that only a
|
|
** single call to balance_quick() is made for each call to this
|
|
** function. If this were not verified, a subtle bug involving reuse
|
|
** of the aBalanceQuickSpace[] might sneak in.
|
|
*/
|
|
- assert( balance_quick_called==0 );
|
|
+ assert( balance_quick_called==0 );
|
|
VVA_ONLY( balance_quick_called++ );
|
|
rc = balance_quick(pParent, pPage, aBalanceQuickSpace);
|
|
}else
|
|
@@ -72538,15 +77248,15 @@ static int balance(BtCursor *pCur){
|
|
** modifying the contents of pParent, which may cause pParent to
|
|
** become overfull or underfull. The next iteration of the do-loop
|
|
** will balance the parent page to correct this.
|
|
- **
|
|
+ **
|
|
** If the parent page becomes overfull, the overflow cell or cells
|
|
- ** are stored in the pSpace buffer allocated immediately below.
|
|
+ ** are stored in the pSpace buffer allocated immediately below.
|
|
** A subsequent iteration of the do-loop will deal with this by
|
|
** calling balance_nonroot() (balance_deeper() may be called first,
|
|
** but it doesn't deal with overflow cells - just moves them to a
|
|
- ** different page). Once this subsequent call to balance_nonroot()
|
|
+ ** different page). Once this subsequent call to balance_nonroot()
|
|
** has completed, it is safe to release the pSpace buffer used by
|
|
- ** the previous call, as the overflow cell data will have been
|
|
+ ** the previous call, as the overflow cell data will have been
|
|
** copied either into the body of a database page or into the new
|
|
** pSpace buffer passed to the latter call to balance_nonroot().
|
|
*/
|
|
@@ -72554,9 +77264,9 @@ static int balance(BtCursor *pCur){
|
|
rc = balance_nonroot(pParent, iIdx, pSpace, iPage==1,
|
|
pCur->hints&BTREE_BULKLOAD);
|
|
if( pFree ){
|
|
- /* If pFree is not NULL, it points to the pSpace buffer used
|
|
+ /* If pFree is not NULL, it points to the pSpace buffer used
|
|
** by a previous call to balance_nonroot(). Its contents are
|
|
- ** now stored either on real database pages or within the
|
|
+ ** now stored either on real database pages or within the
|
|
** new pSpace buffer, so it may be safely freed here. */
|
|
sqlite3PageFree(pFree);
|
|
}
|
|
@@ -72628,9 +77338,13 @@ static int btreeOverwriteContent(
|
|
|
|
/*
|
|
** Overwrite the cell that cursor pCur is pointing to with fresh content
|
|
-** contained in pX.
|
|
+** contained in pX. In this variant, pCur is pointing to an overflow
|
|
+** cell.
|
|
*/
|
|
-static int btreeOverwriteCell(BtCursor *pCur, const BtreePayload *pX){
|
|
+static SQLITE_NOINLINE int btreeOverwriteOverflowCell(
|
|
+ BtCursor *pCur, /* Cursor pointing to cell to ovewrite */
|
|
+ const BtreePayload *pX /* Content to write into the cell */
|
|
+){
|
|
int iOffset; /* Next byte of pX->pData to write */
|
|
int nTotal = pX->nData + pX->nZero; /* Total bytes of to write */
|
|
int rc; /* Return code */
|
|
@@ -72639,16 +77353,12 @@ static int btreeOverwriteCell(BtCursor *pCur, const BtreePayload *pX){
|
|
Pgno ovflPgno; /* Next overflow page to write */
|
|
u32 ovflPageSize; /* Size to write on overflow page */
|
|
|
|
- if( pCur->info.pPayload + pCur->info.nLocal > pPage->aDataEnd
|
|
- || pCur->info.pPayload < pPage->aData + pPage->cellOffset
|
|
- ){
|
|
- return SQLITE_CORRUPT_BKPT;
|
|
- }
|
|
+ assert( pCur->info.nLocal<nTotal ); /* pCur is an overflow cell */
|
|
+
|
|
/* Overwrite the local portion first */
|
|
rc = btreeOverwriteContent(pPage, pCur->info.pPayload, pX,
|
|
0, pCur->info.nLocal);
|
|
if( rc ) return rc;
|
|
- if( pCur->info.nLocal==nTotal ) return SQLITE_OK;
|
|
|
|
/* Now overwrite the overflow pages */
|
|
iOffset = pCur->info.nLocal;
|
|
@@ -72660,7 +77370,7 @@ static int btreeOverwriteCell(BtCursor *pCur, const BtreePayload *pX){
|
|
do{
|
|
rc = btreeGetPage(pBt, ovflPgno, &pPage, 0);
|
|
if( rc ) return rc;
|
|
- if( sqlite3PagerPageRefcount(pPage->pDbPage)!=1 ){
|
|
+ if( sqlite3PagerPageRefcount(pPage->pDbPage)!=1 || pPage->isInit ){
|
|
rc = SQLITE_CORRUPT_BKPT;
|
|
}else{
|
|
if( iOffset+ovflPageSize<(u32)nTotal ){
|
|
@@ -72675,7 +77385,30 @@ static int btreeOverwriteCell(BtCursor *pCur, const BtreePayload *pX){
|
|
if( rc ) return rc;
|
|
iOffset += ovflPageSize;
|
|
}while( iOffset<nTotal );
|
|
- return SQLITE_OK;
|
|
+ return SQLITE_OK;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Overwrite the cell that cursor pCur is pointing to with fresh content
|
|
+** contained in pX.
|
|
+*/
|
|
+static int btreeOverwriteCell(BtCursor *pCur, const BtreePayload *pX){
|
|
+ int nTotal = pX->nData + pX->nZero; /* Total bytes of to write */
|
|
+ MemPage *pPage = pCur->pPage; /* Page being written */
|
|
+
|
|
+ if( pCur->info.pPayload + pCur->info.nLocal > pPage->aDataEnd
|
|
+ || pCur->info.pPayload < pPage->aData + pPage->cellOffset
|
|
+ ){
|
|
+ return SQLITE_CORRUPT_BKPT;
|
|
+ }
|
|
+ if( pCur->info.nLocal==nTotal ){
|
|
+ /* The entire cell is local */
|
|
+ return btreeOverwriteContent(pPage, pCur->info.pPayload, pX,
|
|
+ 0, pCur->info.nLocal);
|
|
+ }else{
|
|
+ /* The cell contains overflow content */
|
|
+ return btreeOverwriteOverflowCell(pCur, pX);
|
|
+ }
|
|
}
|
|
|
|
|
|
@@ -72691,11 +77424,11 @@ static int btreeOverwriteCell(BtCursor *pCur, const BtreePayload *pX){
|
|
** hold the content of the row.
|
|
**
|
|
** For an index btree (used for indexes and WITHOUT ROWID tables), the
|
|
-** key is an arbitrary byte sequence stored in pX.pKey,nKey. The
|
|
+** key is an arbitrary byte sequence stored in pX.pKey,nKey. The
|
|
** pX.pData,nData,nZero fields must be zero.
|
|
**
|
|
** If the seekResult parameter is non-zero, then a successful call to
|
|
-** MovetoUnpacked() to seek cursor pCur to (pKey,nKey) has already
|
|
+** sqlite3BtreeIndexMoveto() to seek cursor pCur to (pKey,nKey) has already
|
|
** been performed. In other words, if seekResult!=0 then the cursor
|
|
** is currently pointing to a cell that will be adjacent to the cell
|
|
** to be inserted. If seekResult<0 then pCur points to a cell that is
|
|
@@ -72713,7 +77446,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
|
|
BtCursor *pCur, /* Insert data into the table of this cursor */
|
|
const BtreePayload *pX, /* Content of the row to be inserted */
|
|
int flags, /* True if this is likely an append */
|
|
- int seekResult /* Result of prior MovetoUnpacked() call */
|
|
+ int seekResult /* Result of prior IndexMoveto() call */
|
|
){
|
|
int rc;
|
|
int loc = seekResult; /* -1: before desired location +1: after */
|
|
@@ -72721,53 +77454,68 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
|
|
int idx;
|
|
MemPage *pPage;
|
|
Btree *p = pCur->pBtree;
|
|
- BtShared *pBt = p->pBt;
|
|
unsigned char *oldCell;
|
|
unsigned char *newCell = 0;
|
|
|
|
- assert( (flags & (BTREE_SAVEPOSITION|BTREE_APPEND))==flags );
|
|
-
|
|
- if( pCur->eState==CURSOR_FAULT ){
|
|
- assert( pCur->skipNext!=SQLITE_OK );
|
|
- return pCur->skipNext;
|
|
- }
|
|
-
|
|
- assert( cursorOwnsBtShared(pCur) );
|
|
- assert( (pCur->curFlags & BTCF_WriteFlag)!=0
|
|
- && pBt->inTransaction==TRANS_WRITE
|
|
- && (pBt->btsFlags & BTS_READ_ONLY)==0 );
|
|
- assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
|
|
-
|
|
- /* Assert that the caller has been consistent. If this cursor was opened
|
|
- ** expecting an index b-tree, then the caller should be inserting blob
|
|
- ** keys with no associated data. If the cursor was opened expecting an
|
|
- ** intkey table, the caller should be inserting integer keys with a
|
|
- ** blob of associated data. */
|
|
- assert( (pX->pKey==0)==(pCur->pKeyInfo==0) );
|
|
+ assert( (flags & (BTREE_SAVEPOSITION|BTREE_APPEND|BTREE_PREFORMAT))==flags );
|
|
+ assert( (flags & BTREE_PREFORMAT)==0 || seekResult || pCur->pKeyInfo==0 );
|
|
|
|
/* Save the positions of any other cursors open on this table.
|
|
**
|
|
** In some cases, the call to btreeMoveto() below is a no-op. For
|
|
** example, when inserting data into a table with auto-generated integer
|
|
- ** keys, the VDBE layer invokes sqlite3BtreeLast() to figure out the
|
|
- ** integer key to use. It then calls this function to actually insert the
|
|
+ ** keys, the VDBE layer invokes sqlite3BtreeLast() to figure out the
|
|
+ ** integer key to use. It then calls this function to actually insert the
|
|
** data into the intkey B-Tree. In this case btreeMoveto() recognizes
|
|
** that the cursor is already where it needs to be and returns without
|
|
** doing any work. To avoid thwarting these optimizations, it is important
|
|
** not to clear the cursor here.
|
|
*/
|
|
if( pCur->curFlags & BTCF_Multiple ){
|
|
- rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur);
|
|
+ rc = saveAllCursors(p->pBt, pCur->pgnoRoot, pCur);
|
|
if( rc ) return rc;
|
|
+ if( loc && pCur->iPage<0 ){
|
|
+ /* This can only happen if the schema is corrupt such that there is more
|
|
+ ** than one table or index with the same root page as used by the cursor.
|
|
+ ** Which can only happen if the SQLITE_NoSchemaError flag was set when
|
|
+ ** the schema was loaded. This cannot be asserted though, as a user might
|
|
+ ** set the flag, load the schema, and then unset the flag. */
|
|
+ return SQLITE_CORRUPT_BKPT;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Ensure that the cursor is not in the CURSOR_FAULT state and that it
|
|
+ ** points to a valid cell.
|
|
+ */
|
|
+ if( pCur->eState>=CURSOR_REQUIRESEEK ){
|
|
+ testcase( pCur->eState==CURSOR_REQUIRESEEK );
|
|
+ testcase( pCur->eState==CURSOR_FAULT );
|
|
+ rc = moveToRoot(pCur);
|
|
+ if( rc && rc!=SQLITE_EMPTY ) return rc;
|
|
}
|
|
|
|
+ assert( cursorOwnsBtShared(pCur) );
|
|
+ assert( (pCur->curFlags & BTCF_WriteFlag)!=0
|
|
+ && p->pBt->inTransaction==TRANS_WRITE
|
|
+ && (p->pBt->btsFlags & BTS_READ_ONLY)==0 );
|
|
+ assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
|
|
+
|
|
+ /* Assert that the caller has been consistent. If this cursor was opened
|
|
+ ** expecting an index b-tree, then the caller should be inserting blob
|
|
+ ** keys with no associated data. If the cursor was opened expecting an
|
|
+ ** intkey table, the caller should be inserting integer keys with a
|
|
+ ** blob of associated data. */
|
|
+ assert( (flags & BTREE_PREFORMAT) || (pX->pKey==0)==(pCur->pKeyInfo==0) );
|
|
+
|
|
if( pCur->pKeyInfo==0 ){
|
|
assert( pX->pKey==0 );
|
|
- /* If this is an insert into a table b-tree, invalidate any incrblob
|
|
+ /* If this is an insert into a table b-tree, invalidate any incrblob
|
|
** cursors open on the row being replaced */
|
|
- invalidateIncrblobCursors(p, pCur->pgnoRoot, pX->nKey, 0);
|
|
+ if( p->hasIncrblobCur ){
|
|
+ invalidateIncrblobCursors(p, pCur->pgnoRoot, pX->nKey, 0);
|
|
+ }
|
|
|
|
- /* If BTREE_SAVEPOSITION is set, the cursor must already be pointing
|
|
+ /* If BTREE_SAVEPOSITION is set, the cursor must already be pointing
|
|
** to a row with the same key as the new entry being inserted.
|
|
*/
|
|
#ifdef SQLITE_DEBUG
|
|
@@ -72798,13 +77546,14 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
|
|
** to an adjacent cell. Move the cursor so that it is pointing either
|
|
** to the cell to be overwritten or an adjacent cell.
|
|
*/
|
|
- rc = sqlite3BtreeMovetoUnpacked(pCur, 0, pX->nKey, flags!=0, &loc);
|
|
+ rc = sqlite3BtreeTableMoveto(pCur, pX->nKey,
|
|
+ (flags & BTREE_APPEND)!=0, &loc);
|
|
if( rc ) return rc;
|
|
}
|
|
}else{
|
|
/* This is an index or a WITHOUT ROWID table */
|
|
|
|
- /* If BTREE_SAVEPOSITION is set, the cursor must already be pointing
|
|
+ /* If BTREE_SAVEPOSITION is set, the cursor must already be pointing
|
|
** to a row with the same key as the new entry being inserted.
|
|
*/
|
|
assert( (flags & BTREE_SAVEPOSITION)==0 || loc==0 );
|
|
@@ -72821,13 +77570,11 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
|
|
r.aMem = pX->aMem;
|
|
r.nField = pX->nMem;
|
|
r.default_rc = 0;
|
|
- r.errCode = 0;
|
|
- r.r1 = 0;
|
|
- r.r2 = 0;
|
|
r.eqSeen = 0;
|
|
- rc = sqlite3BtreeMovetoUnpacked(pCur, &r, 0, flags!=0, &loc);
|
|
+ rc = sqlite3BtreeIndexMoveto(pCur, &r, &loc);
|
|
}else{
|
|
- rc = btreeMoveto(pCur, pX->pKey, pX->nKey, flags!=0, &loc);
|
|
+ rc = btreeMoveto(pCur, pX->pKey, pX->nKey,
|
|
+ (flags & BTREE_APPEND)!=0, &loc);
|
|
}
|
|
if( rc ) return rc;
|
|
}
|
|
@@ -72846,34 +77593,57 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
|
|
return btreeOverwriteCell(pCur, &x2);
|
|
}
|
|
}
|
|
-
|
|
}
|
|
- assert( pCur->eState==CURSOR_VALID
|
|
- || (pCur->eState==CURSOR_INVALID && loc)
|
|
- || CORRUPT_DB );
|
|
+ assert( pCur->eState==CURSOR_VALID
|
|
+ || (pCur->eState==CURSOR_INVALID && loc) );
|
|
|
|
pPage = pCur->pPage;
|
|
- assert( pPage->intKey || pX->nKey>=0 );
|
|
+ assert( pPage->intKey || pX->nKey>=0 || (flags & BTREE_PREFORMAT) );
|
|
assert( pPage->leaf || !pPage->intKey );
|
|
if( pPage->nFree<0 ){
|
|
- rc = btreeComputeFreeSpace(pPage);
|
|
+ if( NEVER(pCur->eState>CURSOR_INVALID) ){
|
|
+ /* ^^^^^--- due to the moveToRoot() call above */
|
|
+ rc = SQLITE_CORRUPT_BKPT;
|
|
+ }else{
|
|
+ rc = btreeComputeFreeSpace(pPage);
|
|
+ }
|
|
if( rc ) return rc;
|
|
}
|
|
|
|
TRACE(("INSERT: table=%d nkey=%lld ndata=%d page=%d %s\n",
|
|
pCur->pgnoRoot, pX->nKey, pX->nData, pPage->pgno,
|
|
loc==0 ? "overwrite" : "new entry"));
|
|
- assert( pPage->isInit );
|
|
- newCell = pBt->pTmpSpace;
|
|
+ assert( pPage->isInit || CORRUPT_DB );
|
|
+ newCell = p->pBt->pTmpSpace;
|
|
assert( newCell!=0 );
|
|
- rc = fillInCell(pPage, newCell, pX, &szNew);
|
|
- if( rc ) goto end_insert;
|
|
+ assert( BTREE_PREFORMAT==OPFLAG_PREFORMAT );
|
|
+ if( flags & BTREE_PREFORMAT ){
|
|
+ rc = SQLITE_OK;
|
|
+ szNew = p->pBt->nPreformatSize;
|
|
+ if( szNew<4 ) szNew = 4;
|
|
+ if( ISAUTOVACUUM(p->pBt) && szNew>pPage->maxLocal ){
|
|
+ CellInfo info;
|
|
+ pPage->xParseCell(pPage, newCell, &info);
|
|
+ if( info.nPayload!=info.nLocal ){
|
|
+ Pgno ovfl = get4byte(&newCell[szNew-4]);
|
|
+ ptrmapPut(p->pBt, ovfl, PTRMAP_OVERFLOW1, pPage->pgno, &rc);
|
|
+ if( NEVER(rc) ) goto end_insert;
|
|
+ }
|
|
+ }
|
|
+ }else{
|
|
+ rc = fillInCell(pPage, newCell, pX, &szNew);
|
|
+ if( rc ) goto end_insert;
|
|
+ }
|
|
assert( szNew==pPage->xCellSize(pPage, newCell) );
|
|
- assert( szNew <= MX_CELL_SIZE(pBt) );
|
|
+ assert( szNew <= MX_CELL_SIZE(p->pBt) );
|
|
idx = pCur->ix;
|
|
+ pCur->info.nSize = 0;
|
|
if( loc==0 ){
|
|
CellInfo info;
|
|
- assert( idx<pPage->nCell );
|
|
+ assert( idx>=0 );
|
|
+ if( idx>=pPage->nCell ){
|
|
+ return SQLITE_CORRUPT_BKPT;
|
|
+ }
|
|
rc = sqlite3PagerWrite(pPage->pDbPage);
|
|
if( rc ){
|
|
goto end_insert;
|
|
@@ -72882,17 +77652,17 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
|
|
if( !pPage->leaf ){
|
|
memcpy(newCell, oldCell, 4);
|
|
}
|
|
- rc = clearCell(pPage, oldCell, &info);
|
|
+ BTREE_CLEAR_CELL(rc, pPage, oldCell, info);
|
|
testcase( pCur->curFlags & BTCF_ValidOvfl );
|
|
invalidateOverflowCache(pCur);
|
|
- if( info.nSize==szNew && info.nLocal==info.nPayload
|
|
- && (!ISAUTOVACUUM || szNew<pPage->minLocal)
|
|
+ if( info.nSize==szNew && info.nLocal==info.nPayload
|
|
+ && (!ISAUTOVACUUM(p->pBt) || szNew<pPage->minLocal)
|
|
){
|
|
/* Overwrite the old cell with the new if they are the same size.
|
|
** We could also try to do this if the old cell is smaller, then add
|
|
** the leftover space to the free list. But experiments show that
|
|
** doing that is no faster then skipping this optimization and just
|
|
- ** calling dropCell() and insertCell().
|
|
+ ** calling dropCell() and insertCell().
|
|
**
|
|
** This optimization cannot be used on an autovacuum database if the
|
|
** new entry uses overflow pages, as the insertCell() call below is
|
|
@@ -72916,11 +77686,11 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
|
|
}else{
|
|
assert( pPage->leaf );
|
|
}
|
|
- insertCell(pPage, idx, newCell, szNew, 0, 0, &rc);
|
|
+ rc = insertCell(pPage, idx, newCell, szNew, 0, 0);
|
|
assert( pPage->nOverflow==0 || rc==SQLITE_OK );
|
|
assert( rc!=SQLITE_OK || pPage->nCell>0 || pPage->nOverflow>0 );
|
|
|
|
- /* If no error has occurred and pPage has an overflow cell, call balance()
|
|
+ /* If no error has occurred and pPage has an overflow cell, call balance()
|
|
** to redistribute the cells within the tree. Since balance() may move
|
|
** the cursor, zero the BtCursor.info.nSize and BTCF_ValidNKey
|
|
** variables.
|
|
@@ -72940,14 +77710,13 @@ 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);
|
|
rc = balance(pCur);
|
|
|
|
/* Must make sure nOverflow is reset to zero even if the balance()
|
|
- ** fails. Internal data structure corruption will result otherwise.
|
|
+ ** fails. Internal data structure corruption will result otherwise.
|
|
** Also, set the cursor state to invalid. This stops saveCursorPosition()
|
|
** from trying to save the current position of the cursor. */
|
|
pCur->pPage->nOverflow = 0;
|
|
@@ -72974,7 +77743,119 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
|
|
}
|
|
|
|
/*
|
|
-** Delete the entry that the cursor is pointing to.
|
|
+** This function is used as part of copying the current row from cursor
|
|
+** pSrc into cursor pDest. If the cursors are open on intkey tables, then
|
|
+** parameter iKey is used as the rowid value when the record is copied
|
|
+** into pDest. Otherwise, the record is copied verbatim.
|
|
+**
|
|
+** This function does not actually write the new value to cursor pDest.
|
|
+** Instead, it creates and populates any required overflow pages and
|
|
+** writes the data for the new cell into the BtShared.pTmpSpace buffer
|
|
+** for the destination database. The size of the cell, in bytes, is left
|
|
+** in BtShared.nPreformatSize. The caller completes the insertion by
|
|
+** calling sqlite3BtreeInsert() with the BTREE_PREFORMAT flag specified.
|
|
+**
|
|
+** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
|
|
+*/
|
|
+SQLITE_PRIVATE int sqlite3BtreeTransferRow(BtCursor *pDest, BtCursor *pSrc, i64 iKey){
|
|
+ BtShared *pBt = pDest->pBt;
|
|
+ u8 *aOut = pBt->pTmpSpace; /* Pointer to next output buffer */
|
|
+ const u8 *aIn; /* Pointer to next input buffer */
|
|
+ u32 nIn; /* Size of input buffer aIn[] */
|
|
+ u32 nRem; /* Bytes of data still to copy */
|
|
+
|
|
+ getCellInfo(pSrc);
|
|
+ if( pSrc->info.nPayload<0x80 ){
|
|
+ *(aOut++) = pSrc->info.nPayload;
|
|
+ }else{
|
|
+ aOut += sqlite3PutVarint(aOut, pSrc->info.nPayload);
|
|
+ }
|
|
+ if( pDest->pKeyInfo==0 ) aOut += putVarint(aOut, iKey);
|
|
+ nIn = pSrc->info.nLocal;
|
|
+ aIn = pSrc->info.pPayload;
|
|
+ if( aIn+nIn>pSrc->pPage->aDataEnd ){
|
|
+ return SQLITE_CORRUPT_BKPT;
|
|
+ }
|
|
+ nRem = pSrc->info.nPayload;
|
|
+ if( nIn==nRem && nIn<pDest->pPage->maxLocal ){
|
|
+ memcpy(aOut, aIn, nIn);
|
|
+ pBt->nPreformatSize = nIn + (aOut - pBt->pTmpSpace);
|
|
+ return SQLITE_OK;
|
|
+ }else{
|
|
+ int rc = SQLITE_OK;
|
|
+ Pager *pSrcPager = pSrc->pBt->pPager;
|
|
+ u8 *pPgnoOut = 0;
|
|
+ Pgno ovflIn = 0;
|
|
+ DbPage *pPageIn = 0;
|
|
+ MemPage *pPageOut = 0;
|
|
+ u32 nOut; /* Size of output buffer aOut[] */
|
|
+
|
|
+ nOut = btreePayloadToLocal(pDest->pPage, pSrc->info.nPayload);
|
|
+ pBt->nPreformatSize = nOut + (aOut - pBt->pTmpSpace);
|
|
+ if( nOut<pSrc->info.nPayload ){
|
|
+ pPgnoOut = &aOut[nOut];
|
|
+ pBt->nPreformatSize += 4;
|
|
+ }
|
|
+
|
|
+ if( nRem>nIn ){
|
|
+ if( aIn+nIn+4>pSrc->pPage->aDataEnd ){
|
|
+ return SQLITE_CORRUPT_BKPT;
|
|
+ }
|
|
+ ovflIn = get4byte(&pSrc->info.pPayload[nIn]);
|
|
+ }
|
|
+
|
|
+ do {
|
|
+ nRem -= nOut;
|
|
+ do{
|
|
+ assert( nOut>0 );
|
|
+ if( nIn>0 ){
|
|
+ int nCopy = MIN(nOut, nIn);
|
|
+ memcpy(aOut, aIn, nCopy);
|
|
+ nOut -= nCopy;
|
|
+ nIn -= nCopy;
|
|
+ aOut += nCopy;
|
|
+ aIn += nCopy;
|
|
+ }
|
|
+ if( nOut>0 ){
|
|
+ sqlite3PagerUnref(pPageIn);
|
|
+ pPageIn = 0;
|
|
+ rc = sqlite3PagerGet(pSrcPager, ovflIn, &pPageIn, PAGER_GET_READONLY);
|
|
+ if( rc==SQLITE_OK ){
|
|
+ aIn = (const u8*)sqlite3PagerGetData(pPageIn);
|
|
+ ovflIn = get4byte(aIn);
|
|
+ aIn += 4;
|
|
+ nIn = pSrc->pBt->usableSize - 4;
|
|
+ }
|
|
+ }
|
|
+ }while( rc==SQLITE_OK && nOut>0 );
|
|
+
|
|
+ if( rc==SQLITE_OK && nRem>0 && ALWAYS(pPgnoOut) ){
|
|
+ Pgno pgnoNew;
|
|
+ MemPage *pNew = 0;
|
|
+ rc = allocateBtreePage(pBt, &pNew, &pgnoNew, 0, 0);
|
|
+ put4byte(pPgnoOut, pgnoNew);
|
|
+ if( ISAUTOVACUUM(pBt) && pPageOut ){
|
|
+ ptrmapPut(pBt, pgnoNew, PTRMAP_OVERFLOW2, pPageOut->pgno, &rc);
|
|
+ }
|
|
+ releasePage(pPageOut);
|
|
+ pPageOut = pNew;
|
|
+ if( pPageOut ){
|
|
+ pPgnoOut = pPageOut->aData;
|
|
+ put4byte(pPgnoOut, 0);
|
|
+ aOut = &pPgnoOut[4];
|
|
+ nOut = MIN(pBt->usableSize - 4, nRem);
|
|
+ }
|
|
+ }
|
|
+ }while( nRem>0 && rc==SQLITE_OK );
|
|
+
|
|
+ releasePage(pPageOut);
|
|
+ sqlite3PagerUnref(pPageIn);
|
|
+ return rc;
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+** Delete the entry that the cursor is pointing to.
|
|
**
|
|
** If the BTREE_SAVEPOSITION bit of the flags parameter is zero, then
|
|
** the cursor is left pointing at an arbitrary location after the delete.
|
|
@@ -72992,15 +77873,14 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
|
|
Btree *p = pCur->pBtree;
|
|
- BtShared *pBt = p->pBt;
|
|
- int rc; /* Return code */
|
|
- MemPage *pPage; /* Page to delete cell from */
|
|
- unsigned char *pCell; /* Pointer to cell to delete */
|
|
- int iCellIdx; /* Index of cell to delete */
|
|
- int iCellDepth; /* Depth of node containing pCell */
|
|
- CellInfo info; /* Size of the cell being deleted */
|
|
- int bSkipnext = 0; /* Leaf cursor in SKIPNEXT state */
|
|
- u8 bPreserve = flags & BTREE_SAVEPOSITION; /* Keep cursor valid */
|
|
+ BtShared *pBt = p->pBt;
|
|
+ int rc; /* Return code */
|
|
+ MemPage *pPage; /* Page to delete cell from */
|
|
+ unsigned char *pCell; /* Pointer to cell to delete */
|
|
+ int iCellIdx; /* Index of cell to delete */
|
|
+ int iCellDepth; /* Depth of node containing pCell */
|
|
+ CellInfo info; /* Size of the cell being deleted */
|
|
+ u8 bPreserve; /* Keep cursor valid. 2 for CURSOR_SKIPNEXT */
|
|
|
|
assert( cursorOwnsBtShared(pCur) );
|
|
assert( pBt->inTransaction==TRANS_WRITE );
|
|
@@ -73009,30 +77889,49 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
|
|
assert( hasSharedCacheTableLock(p, pCur->pgnoRoot, pCur->pKeyInfo!=0, 2) );
|
|
assert( !hasReadConflicts(p, pCur->pgnoRoot) );
|
|
assert( (flags & ~(BTREE_SAVEPOSITION | BTREE_AUXDELETE))==0 );
|
|
- if( pCur->eState==CURSOR_REQUIRESEEK ){
|
|
- rc = btreeRestoreCursorPosition(pCur);
|
|
- if( rc ) return rc;
|
|
+ if( pCur->eState!=CURSOR_VALID ){
|
|
+ if( pCur->eState>=CURSOR_REQUIRESEEK ){
|
|
+ rc = btreeRestoreCursorPosition(pCur);
|
|
+ assert( rc!=SQLITE_OK || CORRUPT_DB || pCur->eState==CURSOR_VALID );
|
|
+ if( rc || pCur->eState!=CURSOR_VALID ) return rc;
|
|
+ }else{
|
|
+ return SQLITE_CORRUPT_BKPT;
|
|
+ }
|
|
}
|
|
assert( pCur->eState==CURSOR_VALID );
|
|
|
|
iCellDepth = pCur->iPage;
|
|
iCellIdx = pCur->ix;
|
|
pPage = pCur->pPage;
|
|
+ if( pPage->nCell<=iCellIdx ){
|
|
+ return SQLITE_CORRUPT_BKPT;
|
|
+ }
|
|
pCell = findCell(pPage, iCellIdx);
|
|
- if( pPage->nFree<0 && btreeComputeFreeSpace(pPage) ) return SQLITE_CORRUPT;
|
|
+ if( pPage->nFree<0 && btreeComputeFreeSpace(pPage) ){
|
|
+ return SQLITE_CORRUPT_BKPT;
|
|
+ }
|
|
|
|
- /* If the bPreserve flag is set to true, then the cursor position must
|
|
+ /* If the BTREE_SAVEPOSITION bit is on, then the cursor position must
|
|
** be preserved following this delete operation. If the current delete
|
|
** will cause a b-tree rebalance, then this is done by saving the cursor
|
|
- ** key and leaving the cursor in CURSOR_REQUIRESEEK state before
|
|
- ** returning.
|
|
+ ** key and leaving the cursor in CURSOR_REQUIRESEEK state before
|
|
+ ** returning.
|
|
**
|
|
- ** Or, if the current delete will not cause a rebalance, then the cursor
|
|
+ ** If the current delete will not cause a rebalance, then the cursor
|
|
** will be left in CURSOR_SKIPNEXT state pointing to the entry immediately
|
|
- ** before or after the deleted entry. In this case set bSkipnext to true. */
|
|
+ ** before or after the deleted entry.
|
|
+ **
|
|
+ ** The bPreserve value records which path is required:
|
|
+ **
|
|
+ ** bPreserve==0 Not necessary to save the cursor position
|
|
+ ** bPreserve==1 Use CURSOR_REQUIRESEEK to save the cursor position
|
|
+ ** bPreserve==2 Cursor won't move. Set CURSOR_SKIPNEXT.
|
|
+ */
|
|
+ bPreserve = (flags & BTREE_SAVEPOSITION)!=0;
|
|
if( bPreserve ){
|
|
- if( !pPage->leaf
|
|
- || (pPage->nFree+cellSizePtr(pPage,pCell)+2)>(int)(pBt->usableSize*2/3)
|
|
+ if( !pPage->leaf
|
|
+ || (pPage->nFree+pPage->xCellSize(pPage,pCell)+2) >
|
|
+ (int)(pBt->usableSize*2/3)
|
|
|| pPage->nCell==1 /* See dbfuzz001.test for a test case */
|
|
){
|
|
/* A b-tree rebalance will be required after deleting this entry.
|
|
@@ -73040,7 +77939,7 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
|
|
rc = saveCursorKey(pCur);
|
|
if( rc ) return rc;
|
|
}else{
|
|
- bSkipnext = 1;
|
|
+ bPreserve = 2;
|
|
}
|
|
}
|
|
|
|
@@ -73066,7 +77965,7 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
|
|
|
|
/* If this is a delete operation to remove a row from a table b-tree,
|
|
** invalidate any incrblob cursors open on the row being deleted. */
|
|
- if( pCur->pKeyInfo==0 ){
|
|
+ if( pCur->pKeyInfo==0 && p->hasIncrblobCur ){
|
|
invalidateIncrblobCursors(p, pCur->pgnoRoot, pCur->info.nKey, 0);
|
|
}
|
|
|
|
@@ -73075,7 +77974,7 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
|
|
** itself from within the page. */
|
|
rc = sqlite3PagerWrite(pPage->pDbPage);
|
|
if( rc ) return rc;
|
|
- rc = clearCell(pPage, pCell, &info);
|
|
+ BTREE_CLEAR_CELL(rc, pPage, pCell, info);
|
|
dropCell(pPage, iCellIdx, info.nSize, &rc);
|
|
if( rc ) return rc;
|
|
|
|
@@ -73107,7 +78006,7 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
|
|
assert( pTmp!=0 );
|
|
rc = sqlite3PagerWrite(pLeaf->pDbPage);
|
|
if( rc==SQLITE_OK ){
|
|
- insertCell(pPage, iCellIdx, pCell-4, nCell+4, pTmp, n, &rc);
|
|
+ rc = insertCell(pPage, iCellIdx, pCell-4, nCell+4, pTmp, n);
|
|
}
|
|
dropCell(pLeaf, pLeaf->nCell-1, nCell, &rc);
|
|
if( rc ) return rc;
|
|
@@ -73126,9 +78025,17 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
|
|
** on the leaf node first. If the balance proceeds far enough up the
|
|
** tree that we can be sure that any problem in the internal node has
|
|
** been corrected, so be it. Otherwise, after balancing the leaf node,
|
|
- ** walk the cursor up the tree to the internal node and balance it as
|
|
+ ** walk the cursor up the tree to the internal node and balance it as
|
|
** well. */
|
|
- rc = balance(pCur);
|
|
+ assert( pCur->pPage->nOverflow==0 );
|
|
+ assert( pCur->pPage->nFree>=0 );
|
|
+ if( pCur->pPage->nFree*3<=(int)pCur->pBt->usableSize*2 ){
|
|
+ /* Optimization: If the free space is less than 2/3rds of the page,
|
|
+ ** then balance() will always be a no-op. No need to invoke it. */
|
|
+ rc = SQLITE_OK;
|
|
+ }else{
|
|
+ rc = balance(pCur);
|
|
+ }
|
|
if( rc==SQLITE_OK && pCur->iPage>iCellDepth ){
|
|
releasePageNotNull(pCur->pPage);
|
|
pCur->iPage--;
|
|
@@ -73140,8 +78047,8 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
|
|
}
|
|
|
|
if( rc==SQLITE_OK ){
|
|
- if( bSkipnext ){
|
|
- assert( bPreserve && (pCur->iPage==iCellDepth || CORRUPT_DB) );
|
|
+ if( bPreserve>1 ){
|
|
+ assert( (pCur->iPage==iCellDepth || CORRUPT_DB) );
|
|
assert( pPage==pCur->pPage || CORRUPT_DB );
|
|
assert( (pPage->nCell>0 || CORRUPT_DB) && iCellIdx<=pPage->nCell );
|
|
pCur->eState = CURSOR_SKIPNEXT;
|
|
@@ -73174,7 +78081,7 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
|
|
** BTREE_INTKEY|BTREE_LEAFDATA Used for SQL tables with rowid keys
|
|
** BTREE_ZERODATA Used for SQL indices
|
|
*/
|
|
-static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){
|
|
+static int btreeCreateTable(Btree *p, Pgno *piTable, int createTabFlags){
|
|
BtShared *pBt = p->pBt;
|
|
MemPage *pRoot;
|
|
Pgno pgnoRoot;
|
|
@@ -73207,6 +78114,9 @@ static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){
|
|
** created so far, so the new root-page is (meta[3]+1).
|
|
*/
|
|
sqlite3BtreeGetMeta(p, BTREE_LARGEST_ROOT_PAGE, &pgnoRoot);
|
|
+ if( pgnoRoot>btreePagecount(pBt) ){
|
|
+ return SQLITE_CORRUPT_BKPT;
|
|
+ }
|
|
pgnoRoot++;
|
|
|
|
/* The new root-page may not be allocated on a pointer-map page, or the
|
|
@@ -73216,8 +78126,7 @@ static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){
|
|
pgnoRoot==PENDING_BYTE_PAGE(pBt) ){
|
|
pgnoRoot++;
|
|
}
|
|
- assert( pgnoRoot>=3 || CORRUPT_DB );
|
|
- testcase( pgnoRoot<3 );
|
|
+ assert( pgnoRoot>=3 );
|
|
|
|
/* Allocate a page. The page that currently resides at pgnoRoot will
|
|
** be moved to the allocated page (unless the allocated page happens
|
|
@@ -73280,7 +78189,7 @@ static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){
|
|
}
|
|
}else{
|
|
pRoot = pPageMove;
|
|
- }
|
|
+ }
|
|
|
|
/* Update the pointer-map and meta-data with the new root-page number. */
|
|
ptrmapPut(pBt, pgnoRoot, PTRMAP_ROOTPAGE, 0, &rc);
|
|
@@ -73314,10 +78223,10 @@ static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){
|
|
zeroPage(pRoot, ptfFlags);
|
|
sqlite3PagerUnref(pRoot->pDbPage);
|
|
assert( (pBt->openFlags & BTREE_SINGLE)==0 || pgnoRoot==2 );
|
|
- *piTable = (int)pgnoRoot;
|
|
+ *piTable = pgnoRoot;
|
|
return SQLITE_OK;
|
|
}
|
|
-SQLITE_PRIVATE int sqlite3BtreeCreateTable(Btree *p, int *piTable, int flags){
|
|
+SQLITE_PRIVATE int sqlite3BtreeCreateTable(Btree *p, Pgno *piTable, int flags){
|
|
int rc;
|
|
sqlite3BtreeEnter(p);
|
|
rc = btreeCreateTable(p, piTable, flags);
|
|
@@ -73333,7 +78242,7 @@ static int clearDatabasePage(
|
|
BtShared *pBt, /* The BTree that contains the table */
|
|
Pgno pgno, /* Page number to clear */
|
|
int freePageFlag, /* Deallocate page if true */
|
|
- int *pnChange /* Add number of Cells freed to this counter */
|
|
+ i64 *pnChange /* Add number of Cells freed to this counter */
|
|
){
|
|
MemPage *pPage;
|
|
int rc;
|
|
@@ -73348,11 +78257,12 @@ static int clearDatabasePage(
|
|
}
|
|
rc = getAndInitPage(pBt, pgno, &pPage, 0, 0);
|
|
if( rc ) return rc;
|
|
- if( pPage->bBusy ){
|
|
+ if( (pBt->openFlags & BTREE_SINGLE)==0
|
|
+ && sqlite3PagerPageRefcount(pPage->pDbPage) != (1 + (pgno==1))
|
|
+ ){
|
|
rc = SQLITE_CORRUPT_BKPT;
|
|
goto cleardatabasepage_out;
|
|
}
|
|
- pPage->bBusy = 1;
|
|
hdr = pPage->hdrOffset;
|
|
for(i=0; i<pPage->nCell; i++){
|
|
pCell = findCell(pPage, i);
|
|
@@ -73360,14 +78270,15 @@ static int clearDatabasePage(
|
|
rc = clearDatabasePage(pBt, get4byte(pCell), 1, pnChange);
|
|
if( rc ) goto cleardatabasepage_out;
|
|
}
|
|
- rc = clearCell(pPage, pCell, &info);
|
|
+ BTREE_CLEAR_CELL(rc, pPage, pCell, info);
|
|
if( rc ) goto cleardatabasepage_out;
|
|
}
|
|
if( !pPage->leaf ){
|
|
rc = clearDatabasePage(pBt, get4byte(&pPage->aData[hdr+8]), 1, pnChange);
|
|
if( rc ) goto cleardatabasepage_out;
|
|
- }else if( pnChange ){
|
|
- assert( pPage->intKey || CORRUPT_DB );
|
|
+ if( pPage->intKey ) pnChange = 0;
|
|
+ }
|
|
+ if( pnChange ){
|
|
testcase( !pPage->intKey );
|
|
*pnChange += pPage->nCell;
|
|
}
|
|
@@ -73378,7 +78289,6 @@ static int clearDatabasePage(
|
|
}
|
|
|
|
cleardatabasepage_out:
|
|
- pPage->bBusy = 0;
|
|
releasePage(pPage);
|
|
return rc;
|
|
}
|
|
@@ -73392,11 +78302,10 @@ static int clearDatabasePage(
|
|
** read cursors on the table. Open write cursors are moved to the
|
|
** root of the table.
|
|
**
|
|
-** If pnChange is not NULL, then table iTable must be an intkey table. The
|
|
-** integer value pointed to by pnChange is incremented by the number of
|
|
-** entries in the table.
|
|
+** If pnChange is not NULL, then the integer value pointed to by pnChange
|
|
+** is incremented by the number of entries in the table.
|
|
*/
|
|
-SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree *p, int iTable, int *pnChange){
|
|
+SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree *p, int iTable, i64 *pnChange){
|
|
int rc;
|
|
BtShared *pBt = p->pBt;
|
|
sqlite3BtreeEnter(p);
|
|
@@ -73408,7 +78317,9 @@ SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree *p, int iTable, int *pnChange){
|
|
/* Invalidate all incrblob cursors open on table iTable (assuming iTable
|
|
** is the root of a table b-tree - if it is not, the following call is
|
|
** a no-op). */
|
|
- invalidateIncrblobCursors(p, (Pgno)iTable, 0, 1);
|
|
+ if( p->hasIncrblobCur ){
|
|
+ invalidateIncrblobCursors(p, (Pgno)iTable, 0, 1);
|
|
+ }
|
|
rc = clearDatabasePage(pBt, (Pgno)iTable, 0, pnChange);
|
|
}
|
|
sqlite3BtreeLeave(p);
|
|
@@ -73433,12 +78344,12 @@ SQLITE_PRIVATE int sqlite3BtreeClearTableOfCursor(BtCursor *pCur){
|
|
** cursors on the table.
|
|
**
|
|
** If AUTOVACUUM is enabled and the page at iTable is not the last
|
|
-** root page in the database file, then the last root page
|
|
+** root page in the database file, then the last root page
|
|
** in the database file is moved into the slot formerly occupied by
|
|
** iTable and that last slot formerly occupied by the last root page
|
|
** is added to the freelist instead of iTable. In this say, all
|
|
** root pages are kept at the beginning of the database file, which
|
|
-** is necessary for AUTOVACUUM to work right. *piMoved is set to the
|
|
+** is necessary for AUTOVACUUM to work right. *piMoved is set to the
|
|
** page number that used to be the last root page in the file before
|
|
** the move. If no page gets moved, *piMoved is set to 0.
|
|
** The last root page is recorded in meta[3] and the value of
|
|
@@ -73456,10 +78367,10 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){
|
|
return SQLITE_CORRUPT_BKPT;
|
|
}
|
|
|
|
- rc = btreeGetPage(pBt, (Pgno)iTable, &pPage, 0);
|
|
- if( rc ) return rc;
|
|
rc = sqlite3BtreeClearTable(p, iTable, 0);
|
|
- if( rc ){
|
|
+ if( rc ) return rc;
|
|
+ rc = btreeGetPage(pBt, (Pgno)iTable, &pPage, 0);
|
|
+ if( NEVER(rc) ){
|
|
releasePage(pPage);
|
|
return rc;
|
|
}
|
|
@@ -73476,7 +78387,7 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){
|
|
|
|
if( iTable==maxRootPgno ){
|
|
/* If the table being dropped is the table with the largest root-page
|
|
- ** number in the database, put the root page on the free list.
|
|
+ ** number in the database, put the root page on the free list.
|
|
*/
|
|
freePage(pPage, &rc);
|
|
releasePage(pPage);
|
|
@@ -73485,7 +78396,7 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){
|
|
}
|
|
}else{
|
|
/* The table being dropped does not have the largest root-page
|
|
- ** number in the database. So move the page that does into the
|
|
+ ** number in the database. So move the page that does into the
|
|
** gap left by the deleted root-page.
|
|
*/
|
|
MemPage *pMove;
|
|
@@ -73527,7 +78438,7 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){
|
|
releasePage(pPage);
|
|
}
|
|
#endif
|
|
- return rc;
|
|
+ return rc;
|
|
}
|
|
SQLITE_PRIVATE int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){
|
|
int rc;
|
|
@@ -73546,7 +78457,7 @@ SQLITE_PRIVATE int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){
|
|
** is the number of free pages currently in the database. Meta[1]
|
|
** through meta[15] are available for use by higher layers. Meta[0]
|
|
** is read-only, the others are read/write.
|
|
-**
|
|
+**
|
|
** The schema layer numbers meta values differently. At the schema
|
|
** layer (and the SetCookie and ReadCookie opcodes) the number of
|
|
** free pages is not visible. So Cookie[0] is the same as Meta[1].
|
|
@@ -73563,12 +78474,12 @@ SQLITE_PRIVATE void sqlite3BtreeGetMeta(Btree *p, int idx, u32 *pMeta){
|
|
|
|
sqlite3BtreeEnter(p);
|
|
assert( p->inTrans>TRANS_NONE );
|
|
- assert( SQLITE_OK==querySharedCacheTableLock(p, MASTER_ROOT, READ_LOCK) );
|
|
+ assert( SQLITE_OK==querySharedCacheTableLock(p, SCHEMA_ROOT, READ_LOCK) );
|
|
assert( pBt->pPage1 );
|
|
assert( idx>=0 && idx<=15 );
|
|
|
|
if( idx==BTREE_DATA_VERSION ){
|
|
- *pMeta = sqlite3PagerDataVersion(pBt->pPager) + p->iDataVersion;
|
|
+ *pMeta = sqlite3PagerDataVersion(pBt->pPager) + p->iBDataVersion;
|
|
}else{
|
|
*pMeta = get4byte(&pBt->pPage1->aData[36 + idx*4]);
|
|
}
|
|
@@ -73612,12 +78523,11 @@ SQLITE_PRIVATE int sqlite3BtreeUpdateMeta(Btree *p, int idx, u32 iMeta){
|
|
return rc;
|
|
}
|
|
|
|
-#ifndef SQLITE_OMIT_BTREECOUNT
|
|
/*
|
|
** The first argument, pCur, is a cursor opened on some b-tree. Count the
|
|
** number of entries in the b-tree and write the result to *pnEntry.
|
|
**
|
|
-** SQLITE_OK is returned if the operation is successfully executed.
|
|
+** SQLITE_OK is returned if the operation is successfully executed.
|
|
** Otherwise, if an error is encountered (i.e. an IO error or database
|
|
** corruption) an SQLite error code is returned.
|
|
*/
|
|
@@ -73632,13 +78542,13 @@ SQLITE_PRIVATE int sqlite3BtreeCount(sqlite3 *db, BtCursor *pCur, i64 *pnEntry){
|
|
}
|
|
|
|
/* Unless an error occurs, the following loop runs one iteration for each
|
|
- ** page in the B-Tree structure (not including overflow pages).
|
|
+ ** page in the B-Tree structure (not including overflow pages).
|
|
*/
|
|
- while( rc==SQLITE_OK && !db->u1.isInterrupted ){
|
|
+ while( rc==SQLITE_OK && !AtomicLoad(&db->u1.isInterrupted) ){
|
|
int iIdx; /* Index of child node in parent */
|
|
MemPage *pPage; /* Current page of the b-tree */
|
|
|
|
- /* If this is a leaf page or the tree is not an int-key tree, then
|
|
+ /* If this is a leaf page or the tree is not an int-key tree, then
|
|
** this page contains countable entries. Increment the entry counter
|
|
** accordingly.
|
|
*/
|
|
@@ -73647,7 +78557,7 @@ SQLITE_PRIVATE int sqlite3BtreeCount(sqlite3 *db, BtCursor *pCur, i64 *pnEntry){
|
|
nEntry += pPage->nCell;
|
|
}
|
|
|
|
- /* pPage is a leaf node. This loop navigates the cursor so that it
|
|
+ /* pPage is a leaf node. This loop navigates the cursor so that it
|
|
** points to the first interior cell that it points to the parent of
|
|
** the next page in the tree that has not yet been visited. The
|
|
** pCur->aiIdx[pCur->iPage] value is set to the index of the parent cell
|
|
@@ -73671,7 +78581,7 @@ SQLITE_PRIVATE int sqlite3BtreeCount(sqlite3 *db, BtCursor *pCur, i64 *pnEntry){
|
|
pPage = pCur->pPage;
|
|
}
|
|
|
|
- /* Descend to the child node of the cell that the cursor currently
|
|
+ /* Descend to the child node of the cell that the cursor currently
|
|
** points at. This is the right-child if (iIdx==pPage->nCell).
|
|
*/
|
|
iIdx = pCur->ix;
|
|
@@ -73685,7 +78595,6 @@ SQLITE_PRIVATE int sqlite3BtreeCount(sqlite3 *db, BtCursor *pCur, i64 *pnEntry){
|
|
/* An error has occurred. Return an error code. */
|
|
return rc;
|
|
}
|
|
-#endif
|
|
|
|
/*
|
|
** Return the pager associated with a BTree. This routine is used for
|
|
@@ -73696,6 +78605,41 @@ SQLITE_PRIVATE Pager *sqlite3BtreePager(Btree *p){
|
|
}
|
|
|
|
#ifndef SQLITE_OMIT_INTEGRITY_CHECK
|
|
+/*
|
|
+** Record an OOM error during integrity_check
|
|
+*/
|
|
+static void checkOom(IntegrityCk *pCheck){
|
|
+ pCheck->rc = SQLITE_NOMEM;
|
|
+ pCheck->mxErr = 0; /* Causes integrity_check processing to stop */
|
|
+ if( pCheck->nErr==0 ) pCheck->nErr++;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Invoke the progress handler, if appropriate. Also check for an
|
|
+** interrupt.
|
|
+*/
|
|
+static void checkProgress(IntegrityCk *pCheck){
|
|
+ sqlite3 *db = pCheck->db;
|
|
+ if( AtomicLoad(&db->u1.isInterrupted) ){
|
|
+ pCheck->rc = SQLITE_INTERRUPT;
|
|
+ pCheck->nErr++;
|
|
+ pCheck->mxErr = 0;
|
|
+ }
|
|
+#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
|
|
+ if( db->xProgress ){
|
|
+ assert( db->nProgressOps>0 );
|
|
+ pCheck->nStep++;
|
|
+ if( (pCheck->nStep % db->nProgressOps)==0
|
|
+ && db->xProgress(db->pProgressArg)
|
|
+ ){
|
|
+ pCheck->rc = SQLITE_INTERRUPT;
|
|
+ pCheck->nErr++;
|
|
+ pCheck->mxErr = 0;
|
|
+ }
|
|
+ }
|
|
+#endif
|
|
+}
|
|
+
|
|
/*
|
|
** Append a message to the error message string.
|
|
*/
|
|
@@ -73705,6 +78649,7 @@ static void checkAppendMsg(
|
|
...
|
|
){
|
|
va_list ap;
|
|
+ checkProgress(pCheck);
|
|
if( !pCheck->mxErr ) return;
|
|
pCheck->mxErr--;
|
|
pCheck->nErr++;
|
|
@@ -73718,7 +78663,7 @@ static void checkAppendMsg(
|
|
sqlite3_str_vappendf(&pCheck->errMsg, zFormat, ap);
|
|
va_end(ap);
|
|
if( pCheck->errMsg.accError==SQLITE_NOMEM ){
|
|
- pCheck->mallocFailed = 1;
|
|
+ checkOom(pCheck);
|
|
}
|
|
}
|
|
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
|
|
@@ -73760,14 +78705,13 @@ static int checkRef(IntegrityCk *pCheck, Pgno iPage){
|
|
checkAppendMsg(pCheck, "2nd reference to page %d", iPage);
|
|
return 1;
|
|
}
|
|
- if( pCheck->db->u1.isInterrupted ) return 1;
|
|
setPageReferenced(pCheck, iPage);
|
|
return 0;
|
|
}
|
|
|
|
#ifndef SQLITE_OMIT_AUTOVACUUM
|
|
/*
|
|
-** Check that the entry in the pointer-map for page iChild maps to
|
|
+** Check that the entry in the pointer-map for page iChild maps to
|
|
** page iParent, pointer type ptrType. If not, append an error message
|
|
** to pCheck.
|
|
*/
|
|
@@ -73783,14 +78727,14 @@ static void checkPtrmap(
|
|
|
|
rc = ptrmapGet(pCheck->pBt, iChild, &ePtrmapType, &iPtrmapParent);
|
|
if( rc!=SQLITE_OK ){
|
|
- if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ) pCheck->mallocFailed = 1;
|
|
+ if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ) checkOom(pCheck);
|
|
checkAppendMsg(pCheck, "Failed to read ptrmap key=%d", 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=%d expected=(%d,%d) got=(%d,%d)",
|
|
iChild, eType, iParent, ePtrmapType, iPtrmapParent);
|
|
}
|
|
}
|
|
@@ -73803,7 +78747,7 @@ static void checkPtrmap(
|
|
static void checkList(
|
|
IntegrityCk *pCheck, /* Integrity checking context */
|
|
int isFreeList, /* True for a freelist. False for overflow page list */
|
|
- int iPage, /* Page number for first page in the list */
|
|
+ Pgno iPage, /* Page number for first page in the list */
|
|
u32 N /* Expected number of pages in the list */
|
|
){
|
|
int i;
|
|
@@ -73885,12 +78829,14 @@ static void checkList(
|
|
** property.
|
|
**
|
|
** This heap is used for cell overlap and coverage testing. Each u32
|
|
-** entry represents the span of a cell or freeblock on a btree page.
|
|
+** entry represents the span of a cell or freeblock on a btree page.
|
|
** The upper 16 bits are the index of the first byte of a range and the
|
|
** lower 16 bits are the index of the last byte of that range.
|
|
*/
|
|
static void btreeHeapInsert(u32 *aHeap, u32 x){
|
|
- u32 j, i = ++aHeap[0];
|
|
+ u32 j, i;
|
|
+ assert( aHeap!=0 );
|
|
+ i = ++aHeap[0];
|
|
aHeap[i] = x;
|
|
while( (j = i/2)>0 && aHeap[j]>aHeap[i] ){
|
|
x = aHeap[j];
|
|
@@ -73915,7 +78861,7 @@ static int btreeHeapPull(u32 *aHeap, u32 *pOut){
|
|
aHeap[j] = x;
|
|
i = j;
|
|
}
|
|
- return 1;
|
|
+ return 1;
|
|
}
|
|
|
|
#ifndef SQLITE_OMIT_INTEGRITY_CHECK
|
|
@@ -73923,7 +78869,7 @@ static int btreeHeapPull(u32 *aHeap, u32 *pOut){
|
|
** Do various sanity checks on a single page of a tree. Return
|
|
** the tree depth. Root pages return 0. Parents of root pages
|
|
** return 1, and so forth.
|
|
-**
|
|
+**
|
|
** These checks are done:
|
|
**
|
|
** 1. Make sure that cells and freeblocks do not overlap
|
|
@@ -73935,7 +78881,7 @@ static int btreeHeapPull(u32 *aHeap, u32 *pOut){
|
|
*/
|
|
static int checkTreePage(
|
|
IntegrityCk *pCheck, /* Context for the sanity check */
|
|
- int iPage, /* Page number of the page to check */
|
|
+ Pgno iPage, /* Page number of the page to check */
|
|
i64 *piMinKey, /* Write minimum integer primary key here */
|
|
i64 maxKey /* Error if integer primary key greater than this */
|
|
){
|
|
@@ -73967,13 +78913,15 @@ static int checkTreePage(
|
|
|
|
/* Check that the page exists
|
|
*/
|
|
+ checkProgress(pCheck);
|
|
+ if( pCheck->mxErr==0 ) goto end_of_check;
|
|
pBt = pCheck->pBt;
|
|
usableSize = pBt->usableSize;
|
|
if( iPage==0 ) return 0;
|
|
if( checkRef(pCheck, iPage) ) return 0;
|
|
- pCheck->zPfx = "Page %d: ";
|
|
+ pCheck->zPfx = "Page %u: ";
|
|
pCheck->v1 = iPage;
|
|
- if( (rc = btreeGetPage(pBt, (Pgno)iPage, &pPage, 0))!=0 ){
|
|
+ if( (rc = btreeGetPage(pBt, iPage, &pPage, 0))!=0 ){
|
|
checkAppendMsg(pCheck,
|
|
"unable to get the page. error code=%d", rc);
|
|
goto end_of_check;
|
|
@@ -73998,7 +78946,7 @@ static int checkTreePage(
|
|
hdr = pPage->hdrOffset;
|
|
|
|
/* Set up for cell analysis */
|
|
- pCheck->zPfx = "On tree page %d cell %d: ";
|
|
+ pCheck->zPfx = "On tree page %u cell %d: ";
|
|
contentOffset = get2byteNotZero(&data[hdr+5]);
|
|
assert( contentOffset<=usableSize ); /* Enforced by btreeInitPage() */
|
|
|
|
@@ -74018,7 +78966,7 @@ static int checkTreePage(
|
|
pgno = get4byte(&data[hdr+8]);
|
|
#ifndef SQLITE_OMIT_AUTOVACUUM
|
|
if( pBt->autoVacuum ){
|
|
- pCheck->zPfx = "On page %d at right child: ";
|
|
+ pCheck->zPfx = "On page %u at right child: ";
|
|
checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage);
|
|
}
|
|
#endif
|
|
@@ -74121,7 +79069,7 @@ static int checkTreePage(
|
|
**
|
|
** EVIDENCE-OF: R-20690-50594 The second field of the b-tree page header
|
|
** is the offset of the first freeblock, or zero if there are no
|
|
- ** freeblocks on the page.
|
|
+ ** freeblocks on the page.
|
|
*/
|
|
i = get2byte(&data[hdr+1]);
|
|
while( i>0 ){
|
|
@@ -74141,13 +79089,13 @@ static int checkTreePage(
|
|
assert( (u32)j<=usableSize-4 ); /* Enforced by btreeComputeFreeSpace() */
|
|
i = j;
|
|
}
|
|
- /* Analyze the min-heap looking for overlap between cells and/or
|
|
+ /* Analyze the min-heap looking for overlap between cells and/or
|
|
** freeblocks, and counting the number of untracked bytes in nFrag.
|
|
- **
|
|
+ **
|
|
** Each min-heap entry is of the form: (start_address<<16)|end_address.
|
|
** There is an implied first entry the covers the page header, the cell
|
|
** pointer index, and the gap between the cell pointer index and the start
|
|
- ** of cell content.
|
|
+ ** of cell content.
|
|
**
|
|
** The loop below pulls entries from the min-heap in order and compares
|
|
** the start_address against the previous end_address. If there is an
|
|
@@ -74159,7 +79107,7 @@ static int checkTreePage(
|
|
while( btreeHeapPull(heap,&x) ){
|
|
if( (prev&0xffff)>=(x>>16) ){
|
|
checkAppendMsg(pCheck,
|
|
- "Multiple uses for byte %u of page %d", x>>16, iPage);
|
|
+ "Multiple uses for byte %u of page %u", x>>16, iPage);
|
|
break;
|
|
}else{
|
|
nFrag += (x>>16) - (prev&0xffff) - 1;
|
|
@@ -74174,7 +79122,7 @@ static int checkTreePage(
|
|
*/
|
|
if( heap[0]==0 && nFrag!=data[hdr+7] ){
|
|
checkAppendMsg(pCheck,
|
|
- "Fragmentation of %d bytes reported as %d on page %d",
|
|
+ "Fragmentation of %d bytes reported as %d on page %u",
|
|
nFrag, data[hdr+7], iPage);
|
|
}
|
|
}
|
|
@@ -74202,38 +79150,52 @@ static int checkTreePage(
|
|
** allocation errors, an error message held in memory obtained from
|
|
** malloc is returned if *pnErr is non-zero. If *pnErr==0 then NULL is
|
|
** returned. If a memory allocation error occurs, NULL is returned.
|
|
+**
|
|
+** If the first entry in aRoot[] is 0, that indicates that the list of
|
|
+** root pages is incomplete. This is a "partial integrity-check". This
|
|
+** happens when performing an integrity check on a single table. The
|
|
+** zero is skipped, of course. But in addition, the freelist checks
|
|
+** and the checks to make sure every page is referenced are also skipped,
|
|
+** since obviously it is not possible to know which pages are covered by
|
|
+** the unverified btrees. Except, if aRoot[1] is 1, then the freelist
|
|
+** checks are still performed.
|
|
*/
|
|
-SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(
|
|
+SQLITE_PRIVATE int sqlite3BtreeIntegrityCheck(
|
|
sqlite3 *db, /* Database connection that is running the check */
|
|
Btree *p, /* The btree to be checked */
|
|
- int *aRoot, /* An array of root pages numbers for individual trees */
|
|
+ Pgno *aRoot, /* An array of root pages numbers for individual trees */
|
|
int nRoot, /* Number of entries in aRoot[] */
|
|
int mxErr, /* Stop reporting errors after this many */
|
|
- int *pnErr /* Write number of errors seen to this variable */
|
|
+ int *pnErr, /* OUT: Write number of errors seen to this variable */
|
|
+ char **pzOut /* OUT: Write the error message string here */
|
|
){
|
|
Pgno i;
|
|
IntegrityCk sCheck;
|
|
BtShared *pBt = p->pBt;
|
|
u64 savedDbFlags = pBt->db->flags;
|
|
char zErr[100];
|
|
+ int bPartial = 0; /* True if not checking all btrees */
|
|
+ int bCkFreelist = 1; /* True to scan the freelist */
|
|
VVA_ONLY( int nRef );
|
|
+ assert( nRoot>0 );
|
|
+
|
|
+ /* aRoot[0]==0 means this is a partial check */
|
|
+ if( aRoot[0]==0 ){
|
|
+ assert( nRoot>1 );
|
|
+ bPartial = 1;
|
|
+ if( aRoot[1]!=1 ) bCkFreelist = 0;
|
|
+ }
|
|
|
|
sqlite3BtreeEnter(p);
|
|
assert( p->inTrans>TRANS_NONE && pBt->inTransaction>TRANS_NONE );
|
|
VVA_ONLY( nRef = sqlite3PagerRefcount(pBt->pPager) );
|
|
assert( nRef>=0 );
|
|
+ memset(&sCheck, 0, sizeof(sCheck));
|
|
sCheck.db = db;
|
|
sCheck.pBt = pBt;
|
|
sCheck.pPager = pBt->pPager;
|
|
sCheck.nPage = btreePagecount(sCheck.pBt);
|
|
sCheck.mxErr = mxErr;
|
|
- sCheck.nErr = 0;
|
|
- sCheck.mallocFailed = 0;
|
|
- sCheck.zPfx = 0;
|
|
- sCheck.v1 = 0;
|
|
- sCheck.v2 = 0;
|
|
- sCheck.aPgRef = 0;
|
|
- sCheck.heap = 0;
|
|
sqlite3StrAccumInit(&sCheck.errMsg, 0, zErr, sizeof(zErr), SQLITE_MAX_LENGTH);
|
|
sCheck.errMsg.printfFlags = SQLITE_PRINTF_INTERNAL;
|
|
if( sCheck.nPage==0 ){
|
|
@@ -74242,12 +79204,12 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(
|
|
|
|
sCheck.aPgRef = sqlite3MallocZero((sCheck.nPage / 8)+ 1);
|
|
if( !sCheck.aPgRef ){
|
|
- sCheck.mallocFailed = 1;
|
|
+ checkOom(&sCheck);
|
|
goto integrity_ck_cleanup;
|
|
}
|
|
sCheck.heap = (u32*)sqlite3PageMalloc( pBt->pageSize );
|
|
if( sCheck.heap==0 ){
|
|
- sCheck.mallocFailed = 1;
|
|
+ checkOom(&sCheck);
|
|
goto integrity_ck_cleanup;
|
|
}
|
|
|
|
@@ -74256,29 +79218,33 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(
|
|
|
|
/* Check the integrity of the freelist
|
|
*/
|
|
- sCheck.zPfx = "Main freelist: ";
|
|
- checkList(&sCheck, 1, get4byte(&pBt->pPage1->aData[32]),
|
|
- get4byte(&pBt->pPage1->aData[36]));
|
|
- sCheck.zPfx = 0;
|
|
+ if( bCkFreelist ){
|
|
+ sCheck.zPfx = "Main freelist: ";
|
|
+ checkList(&sCheck, 1, get4byte(&pBt->pPage1->aData[32]),
|
|
+ get4byte(&pBt->pPage1->aData[36]));
|
|
+ sCheck.zPfx = 0;
|
|
+ }
|
|
|
|
/* Check all the tables.
|
|
*/
|
|
#ifndef SQLITE_OMIT_AUTOVACUUM
|
|
- if( pBt->autoVacuum ){
|
|
- int mx = 0;
|
|
- int mxInHdr;
|
|
- for(i=0; (int)i<nRoot; i++) if( mx<aRoot[i] ) mx = aRoot[i];
|
|
- mxInHdr = get4byte(&pBt->pPage1->aData[52]);
|
|
- if( mx!=mxInHdr ){
|
|
+ if( !bPartial ){
|
|
+ if( pBt->autoVacuum ){
|
|
+ Pgno mx = 0;
|
|
+ Pgno mxInHdr;
|
|
+ for(i=0; (int)i<nRoot; i++) if( mx<aRoot[i] ) mx = aRoot[i];
|
|
+ mxInHdr = get4byte(&pBt->pPage1->aData[52]);
|
|
+ if( mx!=mxInHdr ){
|
|
+ checkAppendMsg(&sCheck,
|
|
+ "max rootpage (%d) disagrees with header (%d)",
|
|
+ mx, mxInHdr
|
|
+ );
|
|
+ }
|
|
+ }else if( get4byte(&pBt->pPage1->aData[64])!=0 ){
|
|
checkAppendMsg(&sCheck,
|
|
- "max rootpage (%d) disagrees with header (%d)",
|
|
- mx, mxInHdr
|
|
+ "incremental_vacuum enabled with a max rootpage of zero"
|
|
);
|
|
}
|
|
- }else if( get4byte(&pBt->pPage1->aData[64])!=0 ){
|
|
- checkAppendMsg(&sCheck,
|
|
- "incremental_vacuum enabled with a max rootpage of zero"
|
|
- );
|
|
}
|
|
#endif
|
|
testcase( pBt->db->flags & SQLITE_CellSizeCk );
|
|
@@ -74287,7 +79253,7 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(
|
|
i64 notUsed;
|
|
if( aRoot[i]==0 ) continue;
|
|
#ifndef SQLITE_OMIT_AUTOVACUUM
|
|
- if( pBt->autoVacuum && aRoot[i]>1 ){
|
|
+ if( pBt->autoVacuum && aRoot[i]>1 && !bPartial ){
|
|
checkPtrmap(&sCheck, aRoot[i], PTRMAP_ROOTPAGE, 0);
|
|
}
|
|
#endif
|
|
@@ -74297,24 +79263,26 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(
|
|
|
|
/* Make sure every page in the file is referenced
|
|
*/
|
|
- for(i=1; i<=sCheck.nPage && sCheck.mxErr; i++){
|
|
+ if( !bPartial ){
|
|
+ for(i=1; i<=sCheck.nPage && sCheck.mxErr; i++){
|
|
#ifdef SQLITE_OMIT_AUTOVACUUM
|
|
- if( getPageReferenced(&sCheck, i)==0 ){
|
|
- checkAppendMsg(&sCheck, "Page %d is never used", i);
|
|
- }
|
|
+ if( getPageReferenced(&sCheck, i)==0 ){
|
|
+ checkAppendMsg(&sCheck, "Page %d is never used", i);
|
|
+ }
|
|
#else
|
|
- /* If the database supports auto-vacuum, make sure no tables contain
|
|
- ** references to pointer-map pages.
|
|
- */
|
|
- if( getPageReferenced(&sCheck, i)==0 &&
|
|
- (PTRMAP_PAGENO(pBt, i)!=i || !pBt->autoVacuum) ){
|
|
- checkAppendMsg(&sCheck, "Page %d is never used", i);
|
|
- }
|
|
- if( getPageReferenced(&sCheck, i)!=0 &&
|
|
- (PTRMAP_PAGENO(pBt, i)==i && pBt->autoVacuum) ){
|
|
- checkAppendMsg(&sCheck, "Pointer map page %d is referenced", i);
|
|
- }
|
|
+ /* If the database supports auto-vacuum, make sure no tables contain
|
|
+ ** references to pointer-map pages.
|
|
+ */
|
|
+ if( getPageReferenced(&sCheck, i)==0 &&
|
|
+ (PTRMAP_PAGENO(pBt, i)!=i || !pBt->autoVacuum) ){
|
|
+ checkAppendMsg(&sCheck, "Page %d is never used", i);
|
|
+ }
|
|
+ if( getPageReferenced(&sCheck, i)!=0 &&
|
|
+ (PTRMAP_PAGENO(pBt, i)==i && pBt->autoVacuum) ){
|
|
+ checkAppendMsg(&sCheck, "Pointer map page %d is referenced", i);
|
|
+ }
|
|
#endif
|
|
+ }
|
|
}
|
|
|
|
/* Clean up and report errors.
|
|
@@ -74322,16 +79290,17 @@ SQLITE_PRIVATE char *sqlite3BtreeIntegrityCheck(
|
|
integrity_ck_cleanup:
|
|
sqlite3PageFree(sCheck.heap);
|
|
sqlite3_free(sCheck.aPgRef);
|
|
- if( sCheck.mallocFailed ){
|
|
+ *pnErr = sCheck.nErr;
|
|
+ if( sCheck.nErr==0 ){
|
|
sqlite3_str_reset(&sCheck.errMsg);
|
|
- sCheck.nErr++;
|
|
+ *pzOut = 0;
|
|
+ }else{
|
|
+ *pzOut = sqlite3StrAccumFinish(&sCheck.errMsg);
|
|
}
|
|
- *pnErr = sCheck.nErr;
|
|
- if( sCheck.nErr==0 ) sqlite3_str_reset(&sCheck.errMsg);
|
|
/* Make sure this analysis did not leave any unref() pages. */
|
|
assert( nRef==sqlite3PagerRefcount(pBt->pPager) );
|
|
sqlite3BtreeLeave(p);
|
|
- return sqlite3StrAccumFinish(&sCheck.errMsg);
|
|
+ return sCheck.rc;
|
|
}
|
|
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
|
|
|
|
@@ -74361,18 +79330,19 @@ SQLITE_PRIVATE const char *sqlite3BtreeGetJournalname(Btree *p){
|
|
}
|
|
|
|
/*
|
|
-** Return non-zero if a transaction is active.
|
|
+** Return one of SQLITE_TXN_NONE, SQLITE_TXN_READ, or SQLITE_TXN_WRITE
|
|
+** to describe the current transaction state of Btree p.
|
|
*/
|
|
-SQLITE_PRIVATE int sqlite3BtreeIsInTrans(Btree *p){
|
|
+SQLITE_PRIVATE int sqlite3BtreeTxnState(Btree *p){
|
|
assert( p==0 || sqlite3_mutex_held(p->db->mutex) );
|
|
- return (p && (p->inTrans==TRANS_WRITE));
|
|
+ return p ? p->inTrans : 0;
|
|
}
|
|
|
|
#ifndef SQLITE_OMIT_WAL
|
|
/*
|
|
** Run a checkpoint on the Btree passed as the first argument.
|
|
**
|
|
-** Return SQLITE_LOCKED if this or any other connection has an open
|
|
+** Return SQLITE_LOCKED if this or any other connection has an open
|
|
** transaction on the shared-cache the argument Btree is connected to.
|
|
**
|
|
** Parameter eMode is one of SQLITE_CHECKPOINT_PASSIVE, FULL or RESTART.
|
|
@@ -74394,14 +79364,8 @@ SQLITE_PRIVATE int sqlite3BtreeCheckpoint(Btree *p, int eMode, int *pnLog, int *
|
|
#endif
|
|
|
|
/*
|
|
-** Return non-zero if a read (or write) transaction is active.
|
|
+** Return true if there is currently a backup running on Btree p.
|
|
*/
|
|
-SQLITE_PRIVATE int sqlite3BtreeIsInReadTrans(Btree *p){
|
|
- assert( p );
|
|
- assert( sqlite3_mutex_held(p->db->mutex) );
|
|
- return p->inTrans!=TRANS_NONE;
|
|
-}
|
|
-
|
|
SQLITE_PRIVATE int sqlite3BtreeIsInBackup(Btree *p){
|
|
assert( p );
|
|
assert( sqlite3_mutex_held(p->db->mutex) );
|
|
@@ -74411,20 +79375,20 @@ SQLITE_PRIVATE int sqlite3BtreeIsInBackup(Btree *p){
|
|
/*
|
|
** This function returns a pointer to a blob of memory associated with
|
|
** a single shared-btree. The memory is used by client code for its own
|
|
-** purposes (for example, to store a high-level schema associated with
|
|
+** purposes (for example, to store a high-level schema associated with
|
|
** the shared-btree). The btree layer manages reference counting issues.
|
|
**
|
|
** The first time this is called on a shared-btree, nBytes bytes of memory
|
|
-** are allocated, zeroed, and returned to the caller. For each subsequent
|
|
+** are allocated, zeroed, and returned to the caller. For each subsequent
|
|
** call the nBytes parameter is ignored and a pointer to the same blob
|
|
-** of memory returned.
|
|
+** of memory returned.
|
|
**
|
|
** If the nBytes parameter is 0 and the blob of memory has not yet been
|
|
** allocated, a null pointer is returned. If the blob has already been
|
|
** allocated, it is returned as normal.
|
|
**
|
|
-** Just before the shared-btree is closed, the function passed as the
|
|
-** xFree argument when the memory allocation was made is invoked on the
|
|
+** Just before the shared-btree is closed, the function passed as the
|
|
+** xFree argument when the memory allocation was made is invoked on the
|
|
** blob of allocated memory. The xFree function should not call sqlite3_free()
|
|
** on the memory, the btree layer does that.
|
|
*/
|
|
@@ -74440,15 +79404,15 @@ SQLITE_PRIVATE void *sqlite3BtreeSchema(Btree *p, int nBytes, void(*xFree)(void
|
|
}
|
|
|
|
/*
|
|
-** Return SQLITE_LOCKED_SHAREDCACHE if another user of the same shared
|
|
-** btree as the argument handle holds an exclusive lock on the
|
|
-** sqlite_master table. Otherwise SQLITE_OK.
|
|
+** Return SQLITE_LOCKED_SHAREDCACHE if another user of the same shared
|
|
+** btree as the argument handle holds an exclusive lock on the
|
|
+** sqlite_schema table. Otherwise SQLITE_OK.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3BtreeSchemaLocked(Btree *p){
|
|
int rc;
|
|
assert( sqlite3_mutex_held(p->db->mutex) );
|
|
sqlite3BtreeEnter(p);
|
|
- rc = querySharedCacheTableLock(p, MASTER_ROOT, READ_LOCK);
|
|
+ rc = querySharedCacheTableLock(p, SCHEMA_ROOT, READ_LOCK);
|
|
assert( rc==SQLITE_OK || rc==SQLITE_LOCKED_SHAREDCACHE );
|
|
sqlite3BtreeLeave(p);
|
|
return rc;
|
|
@@ -74482,11 +79446,11 @@ SQLITE_PRIVATE int sqlite3BtreeLockTable(Btree *p, int iTab, u8 isWriteLock){
|
|
|
|
#ifndef SQLITE_OMIT_INCRBLOB
|
|
/*
|
|
-** Argument pCsr must be a cursor opened for writing on an
|
|
-** INTKEY table currently pointing at a valid table entry.
|
|
+** Argument pCsr must be a cursor opened for writing on an
|
|
+** INTKEY table currently pointing at a valid table entry.
|
|
** This function modifies the data stored as part of that entry.
|
|
**
|
|
-** Only the data content may only be modified, it is not possible to
|
|
+** Only the data content may only be modified, it is not possible to
|
|
** change the length of the data stored. If this function is called with
|
|
** parameters that attempt to write past the end of the existing data,
|
|
** no modifications are made and SQLITE_CORRUPT is returned.
|
|
@@ -74517,7 +79481,7 @@ SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void
|
|
VVA_ONLY(rc =) saveAllCursors(pCsr->pBt, pCsr->pgnoRoot, pCsr);
|
|
assert( rc==SQLITE_OK );
|
|
|
|
- /* Check some assumptions:
|
|
+ /* Check some assumptions:
|
|
** (a) the cursor is open for writing,
|
|
** (b) there is a read/write transaction open,
|
|
** (c) the connection holds a write-lock on the table (if required),
|
|
@@ -74536,7 +79500,7 @@ SQLITE_PRIVATE int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void
|
|
return accessPayload(pCsr, offset, amt, (unsigned char *)z, 1);
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** Mark this cursor as an incremental blob cursor.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3BtreeIncrblobCursor(BtCursor *pCur){
|
|
@@ -74546,14 +79510,14 @@ SQLITE_PRIVATE void sqlite3BtreeIncrblobCursor(BtCursor *pCur){
|
|
#endif
|
|
|
|
/*
|
|
-** Set both the "read version" (single byte at byte offset 18) and
|
|
+** Set both the "read version" (single byte at byte offset 18) and
|
|
** "write version" (single byte at byte offset 19) fields in the database
|
|
** header to iVersion.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3BtreeSetVersion(Btree *pBtree, int iVersion){
|
|
BtShared *pBt = pBtree->pBt;
|
|
int rc; /* Return code */
|
|
-
|
|
+
|
|
assert( iVersion==1 || iVersion==2 );
|
|
|
|
/* If setting the version fields to 1, do not automatically open the
|
|
@@ -74601,6 +79565,17 @@ SQLITE_PRIVATE int sqlite3BtreeIsReadonly(Btree *p){
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3HeaderSizeBtree(void){ return ROUND8(sizeof(MemPage)); }
|
|
|
|
+/*
|
|
+** If no transaction is active and the database is not a temp-db, clear
|
|
+** the in-memory pager cache.
|
|
+*/
|
|
+SQLITE_PRIVATE void sqlite3BtreeClearCache(Btree *p){
|
|
+ BtShared *pBt = p->pBt;
|
|
+ if( pBt->inTransaction==TRANS_NONE ){
|
|
+ sqlite3PagerClearCache(pBt->pPager);
|
|
+ }
|
|
+}
|
|
+
|
|
#if !defined(SQLITE_OMIT_SHARED_CACHE)
|
|
/*
|
|
** Return true if the Btree passed as the only argument is sharable.
|
|
@@ -74611,7 +79586,7 @@ SQLITE_PRIVATE int sqlite3BtreeSharable(Btree *p){
|
|
|
|
/*
|
|
** Return the number of connections to the BtShared object accessed by
|
|
-** the Btree handle passed as the only argument. For private caches
|
|
+** the Btree handle passed as the only argument. For private caches
|
|
** this is always 1. For shared caches it may be 1 or greater.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3BtreeConnectionCount(Btree *p){
|
|
@@ -74633,7 +79608,7 @@ SQLITE_PRIVATE int sqlite3BtreeConnectionCount(Btree *p){
|
|
** May you share freely, never taking more than you give.
|
|
**
|
|
*************************************************************************
|
|
-** This file contains the implementation of the sqlite3_backup_XXX()
|
|
+** This file contains the implementation of the sqlite3_backup_XXX()
|
|
** API functions and the related features.
|
|
*/
|
|
/* #include "sqliteInt.h" */
|
|
@@ -74670,15 +79645,15 @@ struct sqlite3_backup {
|
|
** Once it has been created using backup_init(), a single sqlite3_backup
|
|
** structure may be accessed via two groups of thread-safe entry points:
|
|
**
|
|
-** * Via the sqlite3_backup_XXX() API function backup_step() and
|
|
+** * Via the sqlite3_backup_XXX() API function backup_step() and
|
|
** backup_finish(). Both these functions obtain the source database
|
|
-** handle mutex and the mutex associated with the source BtShared
|
|
+** handle mutex and the mutex associated with the source BtShared
|
|
** structure, in that order.
|
|
**
|
|
** * Via the BackupUpdate() and BackupRestart() functions, which are
|
|
** invoked by the pager layer to report various state changes in
|
|
** the page cache associated with the source database. The mutex
|
|
-** associated with the source database BtShared structure will always
|
|
+** associated with the source database BtShared structure will always
|
|
** be held when either of these functions are invoked.
|
|
**
|
|
** The other sqlite3_backup_XXX() API functions, backup_remaining() and
|
|
@@ -74699,8 +79674,8 @@ struct sqlite3_backup {
|
|
** in connection handle pDb. If such a database cannot be found, return
|
|
** a NULL pointer and write an error message to pErrorDb.
|
|
**
|
|
-** If the "temp" database is requested, it may need to be opened by this
|
|
-** function. If an error occurs while doing so, return 0 and write an
|
|
+** If the "temp" database is requested, it may need to be opened by this
|
|
+** function. If an error occurs while doing so, return 0 and write an
|
|
** error message to pErrorDb.
|
|
*/
|
|
static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){
|
|
@@ -74709,14 +79684,13 @@ static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){
|
|
if( i==1 ){
|
|
Parse sParse;
|
|
int rc = 0;
|
|
- memset(&sParse, 0, sizeof(sParse));
|
|
- sParse.db = pDb;
|
|
+ sqlite3ParseObjectInit(&sParse,pDb);
|
|
if( sqlite3OpenTempDatabase(&sParse) ){
|
|
sqlite3ErrorWithMsg(pErrorDb, sParse.rc, "%s", sParse.zErrMsg);
|
|
rc = SQLITE_ERROR;
|
|
}
|
|
sqlite3DbFree(pErrorDb, sParse.zErrMsg);
|
|
- sqlite3ParserReset(&sParse);
|
|
+ sqlite3ParseObjectReset(&sParse);
|
|
if( rc ){
|
|
return 0;
|
|
}
|
|
@@ -74736,18 +79710,18 @@ static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){
|
|
*/
|
|
static int setDestPgsz(sqlite3_backup *p){
|
|
int rc;
|
|
- rc = sqlite3BtreeSetPageSize(p->pDest,sqlite3BtreeGetPageSize(p->pSrc),-1,0);
|
|
+ rc = sqlite3BtreeSetPageSize(p->pDest,sqlite3BtreeGetPageSize(p->pSrc),0,0);
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
** Check that there is no open read-transaction on the b-tree passed as the
|
|
** second argument. If there is not, return SQLITE_OK. Otherwise, if there
|
|
-** is an open read-transaction, return SQLITE_ERROR and leave an error
|
|
+** is an open read-transaction, return SQLITE_ERROR and leave an error
|
|
** message in database handle db.
|
|
*/
|
|
static int checkReadTransaction(sqlite3 *db, Btree *p){
|
|
- if( sqlite3BtreeIsInReadTrans(p) ){
|
|
+ if( sqlite3BtreeTxnState(p)!=SQLITE_TXN_NONE ){
|
|
sqlite3ErrorWithMsg(db, SQLITE_ERROR, "destination database is in use");
|
|
return SQLITE_ERROR;
|
|
}
|
|
@@ -74813,13 +79787,13 @@ SQLITE_API sqlite3_backup *sqlite3_backup_init(
|
|
p->iNext = 1;
|
|
p->isAttached = 0;
|
|
|
|
- if( 0==p->pSrc || 0==p->pDest
|
|
- || checkReadTransaction(pDestDb, p->pDest)!=SQLITE_OK
|
|
+ if( 0==p->pSrc || 0==p->pDest
|
|
+ || checkReadTransaction(pDestDb, p->pDest)!=SQLITE_OK
|
|
){
|
|
/* One (or both) of the named databases did not exist or an OOM
|
|
** error was hit. Or there is a transaction open on the destination
|
|
- ** database. The error has already been written into the pDestDb
|
|
- ** handle. All that is left to do here is free the sqlite3_backup
|
|
+ ** database. The error has already been written into the pDestDb
|
|
+ ** handle. All that is left to do here is free the sqlite3_backup
|
|
** structure. */
|
|
sqlite3_free(p);
|
|
p = 0;
|
|
@@ -74835,7 +79809,7 @@ SQLITE_API sqlite3_backup *sqlite3_backup_init(
|
|
}
|
|
|
|
/*
|
|
-** Argument rc is an SQLite error code. Return true if this error is
|
|
+** Argument rc is an SQLite error code. Return true if this error is
|
|
** considered fatal if encountered during a backup operation. All errors
|
|
** are considered fatal except for SQLITE_BUSY and SQLITE_LOCKED.
|
|
*/
|
|
@@ -74844,8 +79818,8 @@ static int isFatalError(int rc){
|
|
}
|
|
|
|
/*
|
|
-** Parameter zSrcData points to a buffer containing the data for
|
|
-** page iSrcPg from the source database. Copy this data into the
|
|
+** Parameter zSrcData points to a buffer containing the data for
|
|
+** page iSrcPg from the source database. Copy this data into the
|
|
** destination database.
|
|
*/
|
|
static int backupOnePage(
|
|
@@ -74859,13 +79833,6 @@ static int backupOnePage(
|
|
int nDestPgsz = sqlite3BtreeGetPageSize(p->pDest);
|
|
const int nCopy = MIN(nSrcPgsz, nDestPgsz);
|
|
const i64 iEnd = (i64)iSrcPg*(i64)nSrcPgsz;
|
|
-#ifdef SQLITE_HAS_CODEC
|
|
- /* Use BtreeGetReserveNoMutex() for the source b-tree, as although it is
|
|
- ** guaranteed that the shared-mutex is held by this thread, handle
|
|
- ** p->pSrc may not actually be the owner. */
|
|
- int nSrcReserve = sqlite3BtreeGetReserveNoMutex(p->pSrc);
|
|
- int nDestReserve = sqlite3BtreeGetOptimalReserve(p->pDest);
|
|
-#endif
|
|
int rc = SQLITE_OK;
|
|
i64 iOff;
|
|
|
|
@@ -74876,33 +79843,13 @@ static int backupOnePage(
|
|
assert( zSrcData );
|
|
|
|
/* Catch the case where the destination is an in-memory database and the
|
|
- ** page sizes of the source and destination differ.
|
|
+ ** page sizes of the source and destination differ.
|
|
*/
|
|
if( nSrcPgsz!=nDestPgsz && sqlite3PagerIsMemdb(pDestPager) ){
|
|
rc = SQLITE_READONLY;
|
|
}
|
|
|
|
-#ifdef SQLITE_HAS_CODEC
|
|
- /* Backup is not possible if the page size of the destination is changing
|
|
- ** and a codec is in use.
|
|
- */
|
|
- if( nSrcPgsz!=nDestPgsz && sqlite3PagerGetCodec(pDestPager)!=0 ){
|
|
- rc = SQLITE_READONLY;
|
|
- }
|
|
-
|
|
- /* Backup is not possible if the number of bytes of reserve space differ
|
|
- ** between source and destination. If there is a difference, try to
|
|
- ** fix the destination to agree with the source. If that is not possible,
|
|
- ** then the backup cannot proceed.
|
|
- */
|
|
- if( nSrcReserve!=nDestReserve ){
|
|
- u32 newPgsz = nSrcPgsz;
|
|
- rc = sqlite3PagerSetPagesize(pDestPager, &newPgsz, nSrcReserve);
|
|
- if( rc==SQLITE_OK && newPgsz!=(u32)nSrcPgsz ) rc = SQLITE_READONLY;
|
|
- }
|
|
-#endif
|
|
-
|
|
- /* This loop runs once for each destination page spanned by the source
|
|
+ /* This loop runs once for each destination page spanned by the source
|
|
** page. For each iteration, variable iOff is set to the byte offset
|
|
** of the destination page.
|
|
*/
|
|
@@ -74921,7 +79868,7 @@ static int backupOnePage(
|
|
** Then clear the Btree layer MemPage.isInit flag. Both this module
|
|
** and the pager code use this trick (clearing the first byte
|
|
** of the page 'extra' space to invalidate the Btree layers
|
|
- ** cached parse of the page). MemPage.isInit is marked
|
|
+ ** cached parse of the page). MemPage.isInit is marked
|
|
** "MUST BE FIRST" for this purpose.
|
|
*/
|
|
memcpy(zOut, zIn, nCopy);
|
|
@@ -74941,7 +79888,7 @@ static int backupOnePage(
|
|
** exactly iSize bytes. If pFile is not larger than iSize bytes, then
|
|
** this function is a no-op.
|
|
**
|
|
-** Return SQLITE_OK if everything is successful, or an SQLite error
|
|
+** Return SQLITE_OK if everything is successful, or an SQLite error
|
|
** code if an error occurs.
|
|
*/
|
|
static int backupTruncateFile(sqlite3_file *pFile, i64 iSize){
|
|
@@ -75005,7 +79952,7 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
|
|
** one now. If a transaction is opened here, then it will be closed
|
|
** before this function exits.
|
|
*/
|
|
- if( rc==SQLITE_OK && 0==sqlite3BtreeIsInReadTrans(p->pSrc) ){
|
|
+ if( rc==SQLITE_OK && SQLITE_TXN_NONE==sqlite3BtreeTxnState(p->pSrc) ){
|
|
rc = sqlite3BtreeBeginTrans(p->pSrc, 0, 0);
|
|
bCloseTrans = 1;
|
|
}
|
|
@@ -75023,7 +79970,7 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
|
|
/* Lock the destination database, if it is not locked already. */
|
|
if( SQLITE_OK==rc && p->bDestLocked==0
|
|
&& SQLITE_OK==(rc = sqlite3BtreeBeginTrans(p->pDest, 2,
|
|
- (int*)&p->iDestSchema))
|
|
+ (int*)&p->iDestSchema))
|
|
){
|
|
p->bDestLocked = 1;
|
|
}
|
|
@@ -75036,7 +79983,7 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
|
|
if( SQLITE_OK==rc && destMode==PAGER_JOURNALMODE_WAL && pgszSrc!=pgszDest ){
|
|
rc = SQLITE_READONLY;
|
|
}
|
|
-
|
|
+
|
|
/* Now that there is a read-lock on the source database, query the
|
|
** source pager for the number of pages in the database.
|
|
*/
|
|
@@ -75063,7 +80010,7 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
|
|
attachBackupObject(p);
|
|
}
|
|
}
|
|
-
|
|
+
|
|
/* Update the schema version field in the destination database. This
|
|
** is to make sure that the schema-version really does change in
|
|
** the case where the source and destination databases have the
|
|
@@ -75089,12 +80036,12 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
|
|
int nDestTruncate;
|
|
/* Set nDestTruncate to the final number of pages in the destination
|
|
** database. The complication here is that the destination page
|
|
- ** size may be different to the source page size.
|
|
+ ** size may be different to the source page size.
|
|
**
|
|
- ** If the source page size is smaller than the destination page size,
|
|
+ ** If the source page size is smaller than the destination page size,
|
|
** round up. In this case the call to sqlite3OsTruncate() below will
|
|
** fix the size of the file. However it is important to call
|
|
- ** sqlite3PagerTruncateImage() here so that any pages in the
|
|
+ ** sqlite3PagerTruncateImage() here so that any pages in the
|
|
** destination file that lie beyond the nDestTruncate page mark are
|
|
** journalled by PagerCommitPhaseOne() before they are destroyed
|
|
** by the file truncation.
|
|
@@ -75118,7 +80065,7 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
|
|
**
|
|
** * The destination may need to be truncated, and
|
|
**
|
|
- ** * Data stored on the pages immediately following the
|
|
+ ** * Data stored on the pages immediately following the
|
|
** pending-byte page in the source database may need to be
|
|
** copied into the destination database.
|
|
*/
|
|
@@ -75130,7 +80077,7 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
|
|
i64 iEnd;
|
|
|
|
assert( pFile );
|
|
- assert( nDestTruncate==0
|
|
+ assert( nDestTruncate==0
|
|
|| (i64)nDestTruncate*(i64)pgszDest >= iSize || (
|
|
nDestTruncate==(int)(PENDING_BYTE_PAGE(p->pDest->pBt)-1)
|
|
&& iSize>=PENDING_BYTE && iSize<=PENDING_BYTE+pgszDest
|
|
@@ -75140,7 +80087,7 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
|
|
** database has been stored in the journal for pDestPager and the
|
|
** journal synced to disk. So at this point we may safely modify
|
|
** the database file in any way, knowing that if a power failure
|
|
- ** occurs, the original database will be reconstructed from the
|
|
+ ** occurs, the original database will be reconstructed from the
|
|
** journal file. */
|
|
sqlite3PagerPagecount(pDestPager, &nDstPage);
|
|
for(iPg=nDestTruncate; rc==SQLITE_OK && iPg<=(Pgno)nDstPage; iPg++){
|
|
@@ -75160,8 +80107,8 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
|
|
/* Write the extra pages and truncate the database file as required */
|
|
iEnd = MIN(PENDING_BYTE + pgszDest, iSize);
|
|
for(
|
|
- iOff=PENDING_BYTE+pgszSrc;
|
|
- rc==SQLITE_OK && iOff<iEnd;
|
|
+ iOff=PENDING_BYTE+pgszSrc;
|
|
+ rc==SQLITE_OK && iOff<iEnd;
|
|
iOff+=pgszSrc
|
|
){
|
|
PgHdr *pSrcPg = 0;
|
|
@@ -75185,7 +80132,7 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
|
|
sqlite3PagerTruncateImage(pDestPager, nDestTruncate);
|
|
rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 0);
|
|
}
|
|
-
|
|
+
|
|
/* Finish committing the transaction to the destination database. */
|
|
if( SQLITE_OK==rc
|
|
&& SQLITE_OK==(rc = sqlite3BtreeCommitPhaseTwo(p->pDest, 0))
|
|
@@ -75194,7 +80141,7 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
|
|
}
|
|
}
|
|
}
|
|
-
|
|
+
|
|
/* If bCloseTrans is true, then this function opened a read transaction
|
|
** on the source database. Close the read transaction here. There is
|
|
** no need to check the return values of the btree methods here, as
|
|
@@ -75206,7 +80153,7 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
|
|
TESTONLY( rc2 |= ) sqlite3BtreeCommitPhaseTwo(p->pSrc, 0);
|
|
assert( rc2==SQLITE_OK );
|
|
}
|
|
-
|
|
+
|
|
if( rc==SQLITE_IOERR_NOMEM ){
|
|
rc = SQLITE_NOMEM_BKPT;
|
|
}
|
|
@@ -75288,7 +80235,7 @@ SQLITE_API int sqlite3_backup_remaining(sqlite3_backup *p){
|
|
}
|
|
|
|
/*
|
|
-** Return the total number of pages in the source database as of the most
|
|
+** Return the total number of pages in the source database as of the most
|
|
** recent call to sqlite3_backup_step().
|
|
*/
|
|
SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p){
|
|
@@ -75303,7 +80250,7 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p){
|
|
|
|
/*
|
|
** This function is called after the contents of page iPage of the
|
|
-** source database have been modified. If page iPage has already been
|
|
+** source database have been modified. If page iPage has already been
|
|
** copied into the destination database, then the data written to the
|
|
** destination is now invalidated. The destination copy of iPage needs
|
|
** to be updated with the new data before the backup operation is
|
|
@@ -75346,7 +80293,7 @@ SQLITE_PRIVATE void sqlite3BackupUpdate(sqlite3_backup *pBackup, Pgno iPage, con
|
|
** Restart the backup process. This is called when the pager layer
|
|
** detects that the database has been modified by an external database
|
|
** connection. In this case there is no way of knowing which of the
|
|
-** pages that have been copied into the destination database are still
|
|
+** pages that have been copied into the destination database are still
|
|
** valid and which are not, so the entire process needs to be restarted.
|
|
**
|
|
** It is assumed that the mutex associated with the BtShared object
|
|
@@ -75366,8 +80313,8 @@ SQLITE_PRIVATE void sqlite3BackupRestart(sqlite3_backup *pBackup){
|
|
** Copy the complete content of pBtFrom into pBtTo. A transaction
|
|
** must be active for both files.
|
|
**
|
|
-** The size of file pTo may be reduced by this operation. If anything
|
|
-** goes wrong, the transaction on pTo is rolled back. If successful, the
|
|
+** The size of file pTo may be reduced by this operation. If anything
|
|
+** goes wrong, the transaction on pTo is rolled back. If successful, the
|
|
** transaction is committed before returning.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){
|
|
@@ -75377,7 +80324,7 @@ SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){
|
|
sqlite3BtreeEnter(pTo);
|
|
sqlite3BtreeEnter(pFrom);
|
|
|
|
- assert( sqlite3BtreeIsInTrans(pTo) );
|
|
+ assert( sqlite3BtreeTxnState(pTo)==SQLITE_TXN_WRITE );
|
|
pFd = sqlite3PagerFile(sqlite3BtreePager(pTo));
|
|
if( pFd->pMethods ){
|
|
i64 nByte = sqlite3BtreeGetPageSize(pFrom)*(i64)sqlite3BtreeLastPage(pFrom);
|
|
@@ -75397,15 +80344,11 @@ SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){
|
|
b.pDest = pTo;
|
|
b.iNext = 1;
|
|
|
|
-#ifdef SQLITE_HAS_CODEC
|
|
- sqlite3PagerAlignReserve(sqlite3BtreePager(pTo), sqlite3BtreePager(pFrom));
|
|
-#endif
|
|
-
|
|
/* 0x7FFFFFFF is the hard limit for the number of pages in a database
|
|
** file. By passing this as the number of pages to copy to
|
|
- ** sqlite3_backup_step(), we can guarantee that the copy finishes
|
|
+ ** sqlite3_backup_step(), we can guarantee that the copy finishes
|
|
** within a single call (unless an error occurs). The assert() statement
|
|
- ** checks this assumption - (p->rc) should be set to either SQLITE_DONE
|
|
+ ** checks this assumption - (p->rc) should be set to either SQLITE_DONE
|
|
** or an error code. */
|
|
sqlite3_backup_step(&b, 0x7FFFFFFF);
|
|
assert( b.rc!=SQLITE_OK );
|
|
@@ -75417,7 +80360,7 @@ SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){
|
|
sqlite3PagerClearCache(sqlite3BtreePager(b.pDest));
|
|
}
|
|
|
|
- assert( sqlite3BtreeIsInTrans(pTo)==0 );
|
|
+ assert( sqlite3BtreeTxnState(pTo)!=SQLITE_TXN_WRITE );
|
|
copy_finished:
|
|
sqlite3BtreeLeave(pFrom);
|
|
sqlite3BtreeLeave(pTo);
|
|
@@ -75460,7 +80403,7 @@ SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){
|
|
** this: assert( sqlite3VdbeCheckMemInvariants(pMem) );
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3VdbeCheckMemInvariants(Mem *p){
|
|
- /* If MEM_Dyn is set then Mem.xDel!=0.
|
|
+ /* If MEM_Dyn is set then Mem.xDel!=0.
|
|
** Mem.xDel might not be initialized if MEM_Dyn is clear.
|
|
*/
|
|
assert( (p->flags & MEM_Dyn)==0 || p->xDel!=0 );
|
|
@@ -75504,7 +80447,9 @@ SQLITE_PRIVATE int sqlite3VdbeCheckMemInvariants(Mem *p){
|
|
|
|
/* The szMalloc field holds the correct memory allocation size */
|
|
assert( p->szMalloc==0
|
|
- || p->szMalloc==sqlite3DbMallocSize(p->db,p->zMalloc) );
|
|
+ || (p->flags==MEM_Undefined
|
|
+ && p->szMalloc<=sqlite3DbMallocSize(p->db,p->zMalloc))
|
|
+ || p->szMalloc==sqlite3DbMallocSize(p->db,p->zMalloc));
|
|
|
|
/* If p holds a string or blob, the Mem.z must point to exactly
|
|
** one of the following:
|
|
@@ -75515,7 +80460,7 @@ SQLITE_PRIVATE int sqlite3VdbeCheckMemInvariants(Mem *p){
|
|
** (4) A static string or blob
|
|
*/
|
|
if( (p->flags & (MEM_Str|MEM_Blob)) && p->n>0 ){
|
|
- assert(
|
|
+ assert(
|
|
((p->szMalloc>0 && p->z==p->zMalloc)? 1 : 0) +
|
|
((p->flags&MEM_Dyn)!=0 ? 1 : 0) +
|
|
((p->flags&MEM_Ephem)!=0 ? 1 : 0) +
|
|
@@ -75533,16 +80478,26 @@ SQLITE_PRIVATE int sqlite3VdbeCheckMemInvariants(Mem *p){
|
|
static void vdbeMemRenderNum(int sz, char *zBuf, Mem *p){
|
|
StrAccum acc;
|
|
assert( p->flags & (MEM_Int|MEM_Real|MEM_IntReal) );
|
|
- sqlite3StrAccumInit(&acc, 0, zBuf, sz, 0);
|
|
+ assert( sz>22 );
|
|
if( p->flags & MEM_Int ){
|
|
- sqlite3_str_appendf(&acc, "%lld", p->u.i);
|
|
- }else if( p->flags & MEM_IntReal ){
|
|
- sqlite3_str_appendf(&acc, "%!.15g", (double)p->u.i);
|
|
+#if GCC_VERSION>=7000000
|
|
+ /* Work-around for GCC bug
|
|
+ ** https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96270 */
|
|
+ i64 x;
|
|
+ assert( (p->flags&MEM_Int)*2==sizeof(x) );
|
|
+ memcpy(&x, (char*)&p->u, (p->flags&MEM_Int)*2);
|
|
+ p->n = sqlite3Int64ToText(x, zBuf);
|
|
+#else
|
|
+ p->n = sqlite3Int64ToText(p->u.i, zBuf);
|
|
+#endif
|
|
}else{
|
|
- sqlite3_str_appendf(&acc, "%!.15g", p->u.r);
|
|
+ sqlite3StrAccumInit(&acc, 0, zBuf, sz, 0);
|
|
+ sqlite3_str_appendf(&acc, "%!.15g",
|
|
+ (p->flags & MEM_IntReal)!=0 ? (double)p->u.i : p->u.r);
|
|
+ assert( acc.zText==zBuf && acc.mxAlloc<=0 );
|
|
+ zBuf[acc.nChar] = 0; /* Fast version of sqlite3StrAccumFinish(&acc) */
|
|
+ p->n = acc.nChar;
|
|
}
|
|
- assert( acc.zText==zBuf && acc.mxAlloc<=0 );
|
|
- zBuf[acc.nChar] = 0; /* Fast version of sqlite3StrAccumFinish(&acc) */
|
|
}
|
|
|
|
#ifdef SQLITE_DEBUG
|
|
@@ -75569,6 +80524,7 @@ static void vdbeMemRenderNum(int sz, char *zBuf, Mem *p){
|
|
** This routine is for use inside of assert() statements only.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3VdbeMemValidStrRep(Mem *p){
|
|
+ Mem tmp;
|
|
char zBuf[100];
|
|
char *z;
|
|
int i, j, incr;
|
|
@@ -75585,7 +80541,8 @@ SQLITE_PRIVATE int sqlite3VdbeMemValidStrRep(Mem *p){
|
|
assert( p->enc==SQLITE_UTF8 || p->z[((p->n+1)&~1)+1]==0 );
|
|
}
|
|
if( (p->flags & (MEM_Int|MEM_Real|MEM_IntReal))==0 ) return 1;
|
|
- vdbeMemRenderNum(sizeof(zBuf), zBuf, p);
|
|
+ memcpy(&tmp, p, sizeof(tmp));
|
|
+ vdbeMemRenderNum(sizeof(zBuf), zBuf, &tmp);
|
|
z = p->z;
|
|
i = j = 0;
|
|
incr = 1;
|
|
@@ -75618,10 +80575,15 @@ SQLITE_PRIVATE int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
|
|
#ifndef SQLITE_OMIT_UTF16
|
|
int rc;
|
|
#endif
|
|
+ assert( pMem!=0 );
|
|
assert( !sqlite3VdbeMemIsRowSet(pMem) );
|
|
assert( desiredEnc==SQLITE_UTF8 || desiredEnc==SQLITE_UTF16LE
|
|
|| desiredEnc==SQLITE_UTF16BE );
|
|
- if( !(pMem->flags&MEM_Str) || pMem->enc==desiredEnc ){
|
|
+ if( !(pMem->flags&MEM_Str) ){
|
|
+ pMem->enc = desiredEnc;
|
|
+ return SQLITE_OK;
|
|
+ }
|
|
+ if( pMem->enc==desiredEnc ){
|
|
return SQLITE_OK;
|
|
}
|
|
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
|
|
@@ -75659,7 +80621,9 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPre
|
|
testcase( bPreserve && pMem->z==0 );
|
|
|
|
assert( pMem->szMalloc==0
|
|
- || pMem->szMalloc==sqlite3DbMallocSize(pMem->db, pMem->zMalloc) );
|
|
+ || (pMem->flags==MEM_Undefined
|
|
+ && pMem->szMalloc<=sqlite3DbMallocSize(pMem->db,pMem->zMalloc))
|
|
+ || pMem->szMalloc==sqlite3DbMallocSize(pMem->db,pMem->zMalloc));
|
|
if( pMem->szMalloc>0 && bPreserve && pMem->z==pMem->zMalloc ){
|
|
if( pMem->db ){
|
|
pMem->z = pMem->zMalloc = sqlite3DbReallocOrFree(pMem->db, pMem->z, n);
|
|
@@ -75748,6 +80712,7 @@ static SQLITE_NOINLINE int vdbeMemAddTerminator(Mem *pMem){
|
|
** Return SQLITE_OK on success or SQLITE_NOMEM if malloc fails.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem *pMem){
|
|
+ assert( pMem!=0 );
|
|
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
|
|
assert( !sqlite3VdbeMemIsRowSet(pMem) );
|
|
if( (pMem->flags & (MEM_Str|MEM_Blob))!=0 ){
|
|
@@ -75772,6 +80737,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem *pMem){
|
|
#ifndef SQLITE_OMIT_INCRBLOB
|
|
SQLITE_PRIVATE int sqlite3VdbeMemExpandBlob(Mem *pMem){
|
|
int nByte;
|
|
+ assert( pMem!=0 );
|
|
assert( pMem->flags & MEM_Zero );
|
|
assert( (pMem->flags&MEM_Blob)!=0 || MemNullNochng(pMem) );
|
|
testcase( sqlite3_value_nochange(pMem) );
|
|
@@ -75787,6 +80753,8 @@ SQLITE_PRIVATE int sqlite3VdbeMemExpandBlob(Mem *pMem){
|
|
if( sqlite3VdbeMemGrow(pMem, nByte, 1) ){
|
|
return SQLITE_NOMEM_BKPT;
|
|
}
|
|
+ assert( pMem->z!=0 );
|
|
+ assert( sqlite3DbMallocSize(pMem->db,pMem->z) >= nByte );
|
|
|
|
memset(&pMem->z[pMem->n], 0, pMem->u.nZero);
|
|
pMem->n += pMem->u.nZero;
|
|
@@ -75799,6 +80767,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemExpandBlob(Mem *pMem){
|
|
** Make sure the given Mem is \u0000 terminated.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3VdbeMemNulTerminate(Mem *pMem){
|
|
+ assert( pMem!=0 );
|
|
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
|
|
testcase( (pMem->flags & (MEM_Term|MEM_Str))==(MEM_Term|MEM_Str) );
|
|
testcase( (pMem->flags & (MEM_Term|MEM_Str))==0 );
|
|
@@ -75826,6 +80795,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemNulTerminate(Mem *pMem){
|
|
SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){
|
|
const int nByte = 32;
|
|
|
|
+ assert( pMem!=0 );
|
|
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
|
|
assert( !(pMem->flags&MEM_Zero) );
|
|
assert( !(pMem->flags&(MEM_Str|MEM_Blob)) );
|
|
@@ -75841,7 +80811,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){
|
|
|
|
vdbeMemRenderNum(nByte, pMem->z, pMem);
|
|
assert( pMem->z!=0 );
|
|
- pMem->n = sqlite3Strlen30NN(pMem->z);
|
|
+ assert( pMem->n==sqlite3Strlen30NN(pMem->z) );
|
|
pMem->enc = SQLITE_UTF8;
|
|
pMem->flags |= MEM_Str|MEM_Term;
|
|
if( bForce ) pMem->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal);
|
|
@@ -75861,9 +80831,11 @@ SQLITE_PRIVATE int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
|
|
sqlite3_context ctx;
|
|
Mem t;
|
|
assert( pFunc!=0 );
|
|
+ assert( pMem!=0 );
|
|
+ assert( pMem->db!=0 );
|
|
assert( pFunc->xFinalize!=0 );
|
|
assert( (pMem->flags & MEM_Null)!=0 || pFunc==pMem->u.pDef );
|
|
- assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
|
|
+ assert( sqlite3_mutex_held(pMem->db->mutex) );
|
|
memset(&ctx, 0, sizeof(ctx));
|
|
memset(&t, 0, sizeof(t));
|
|
t.flags = MEM_Null;
|
|
@@ -75871,6 +80843,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
|
|
ctx.pOut = &t;
|
|
ctx.pMem = pMem;
|
|
ctx.pFunc = pFunc;
|
|
+ ctx.enc = ENC(t.db);
|
|
pFunc->xFinalize(&ctx); /* IMP: R-24505-23230 */
|
|
assert( (pMem->flags & MEM_Dyn)==0 );
|
|
if( pMem->szMalloc>0 ) sqlite3DbFreeNN(pMem->db, pMem->zMalloc);
|
|
@@ -75883,7 +80856,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
|
|
** This routine calls the xValue method for that function and stores
|
|
** the results in memory cell pMem.
|
|
**
|
|
-** SQLITE_ERROR is returned if xValue() reports an error. SQLITE_OK
|
|
+** SQLITE_ERROR is returned if xValue() reports an error. SQLITE_OK
|
|
** otherwise.
|
|
*/
|
|
#ifndef SQLITE_OMIT_WINDOWFUNC
|
|
@@ -75892,12 +80865,14 @@ SQLITE_PRIVATE int sqlite3VdbeMemAggValue(Mem *pAccum, Mem *pOut, FuncDef *pFunc
|
|
assert( pFunc!=0 );
|
|
assert( pFunc->xValue!=0 );
|
|
assert( (pAccum->flags & MEM_Null)!=0 || pFunc==pAccum->u.pDef );
|
|
- assert( pAccum->db==0 || sqlite3_mutex_held(pAccum->db->mutex) );
|
|
+ assert( pAccum->db!=0 );
|
|
+ assert( sqlite3_mutex_held(pAccum->db->mutex) );
|
|
memset(&ctx, 0, sizeof(ctx));
|
|
sqlite3VdbeMemSetNull(pOut);
|
|
ctx.pOut = pOut;
|
|
ctx.pMem = pAccum;
|
|
ctx.pFunc = pFunc;
|
|
+ ctx.enc = ENC(pAccum->db);
|
|
pFunc->xValue(&ctx);
|
|
return ctx.isError;
|
|
}
|
|
@@ -75963,6 +80938,14 @@ SQLITE_PRIVATE void sqlite3VdbeMemRelease(Mem *p){
|
|
}
|
|
}
|
|
|
|
+/* Like sqlite3VdbeMemRelease() but faster for cases where we
|
|
+** know in advance that the Mem is not MEM_Dyn or MEM_Agg.
|
|
+*/
|
|
+SQLITE_PRIVATE void sqlite3VdbeMemReleaseMalloc(Mem *p){
|
|
+ assert( !VdbeMemDynamic(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
|
|
@@ -76004,13 +80987,14 @@ static SQLITE_NOINLINE i64 doubleToInt64(double r){
|
|
**
|
|
** If pMem represents a string value, its encoding might be changed.
|
|
*/
|
|
-static SQLITE_NOINLINE i64 memIntValue(Mem *pMem){
|
|
+static SQLITE_NOINLINE i64 memIntValue(const Mem *pMem){
|
|
i64 value = 0;
|
|
sqlite3Atoi64(pMem->z, &value, pMem->n, pMem->enc);
|
|
return value;
|
|
}
|
|
-SQLITE_PRIVATE i64 sqlite3VdbeIntValue(Mem *pMem){
|
|
+SQLITE_PRIVATE i64 sqlite3VdbeIntValue(const Mem *pMem){
|
|
int flags;
|
|
+ assert( pMem!=0 );
|
|
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
|
|
assert( EIGHT_BYTE_ALIGNMENT(pMem) );
|
|
flags = pMem->flags;
|
|
@@ -76039,6 +81023,7 @@ static SQLITE_NOINLINE double memRealValue(Mem *pMem){
|
|
return val;
|
|
}
|
|
SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem *pMem){
|
|
+ assert( pMem!=0 );
|
|
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
|
|
assert( EIGHT_BYTE_ALIGNMENT(pMem) );
|
|
if( pMem->flags & MEM_Real ){
|
|
@@ -76056,7 +81041,7 @@ SQLITE_PRIVATE double sqlite3VdbeRealValue(Mem *pMem){
|
|
|
|
/*
|
|
** Return 1 if pMem represents true, and return 0 if pMem represents false.
|
|
-** Return the value ifNull if pMem is NULL.
|
|
+** Return the value ifNull if pMem is NULL.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3VdbeBooleanValue(Mem *pMem, int ifNull){
|
|
testcase( pMem->flags & MEM_IntReal );
|
|
@@ -76066,31 +81051,35 @@ SQLITE_PRIVATE int sqlite3VdbeBooleanValue(Mem *pMem, int ifNull){
|
|
}
|
|
|
|
/*
|
|
-** The MEM structure is already a MEM_Real. Try to also make it a
|
|
-** MEM_Int if we can.
|
|
+** The MEM structure is already a MEM_Real or MEM_IntReal. Try to
|
|
+** make it a MEM_Int if we can.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3VdbeIntegerAffinity(Mem *pMem){
|
|
- i64 ix;
|
|
- assert( pMem->flags & MEM_Real );
|
|
+ assert( pMem!=0 );
|
|
+ assert( pMem->flags & (MEM_Real|MEM_IntReal) );
|
|
assert( !sqlite3VdbeMemIsRowSet(pMem) );
|
|
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
|
|
assert( EIGHT_BYTE_ALIGNMENT(pMem) );
|
|
|
|
- ix = doubleToInt64(pMem->u.r);
|
|
-
|
|
- /* Only mark the value as an integer if
|
|
- **
|
|
- ** (1) the round-trip conversion real->int->real is a no-op, and
|
|
- ** (2) The integer is neither the largest nor the smallest
|
|
- ** possible integer (ticket #3922)
|
|
- **
|
|
- ** The second and third terms in the following conditional enforces
|
|
- ** the second condition under the assumption that addition overflow causes
|
|
- ** values to wrap around.
|
|
- */
|
|
- if( pMem->u.r==ix && ix>SMALLEST_INT64 && ix<LARGEST_INT64 ){
|
|
- pMem->u.i = ix;
|
|
+ if( pMem->flags & MEM_IntReal ){
|
|
MemSetTypeFlag(pMem, MEM_Int);
|
|
+ }else{
|
|
+ i64 ix = doubleToInt64(pMem->u.r);
|
|
+
|
|
+ /* Only mark the value as an integer if
|
|
+ **
|
|
+ ** (1) the round-trip conversion real->int->real is a no-op, and
|
|
+ ** (2) The integer is neither the largest nor the smallest
|
|
+ ** possible integer (ticket #3922)
|
|
+ **
|
|
+ ** The second and third terms in the following conditional enforces
|
|
+ ** the second condition under the assumption that addition overflow causes
|
|
+ ** values to wrap around.
|
|
+ */
|
|
+ if( pMem->u.r==ix && ix>SMALLEST_INT64 && ix<LARGEST_INT64 ){
|
|
+ pMem->u.i = ix;
|
|
+ MemSetTypeFlag(pMem, MEM_Int);
|
|
+ }
|
|
}
|
|
}
|
|
|
|
@@ -76098,6 +81087,7 @@ SQLITE_PRIVATE void sqlite3VdbeIntegerAffinity(Mem *pMem){
|
|
** Convert pMem to type integer. Invalidate any prior representations.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3VdbeMemIntegerify(Mem *pMem){
|
|
+ assert( pMem!=0 );
|
|
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
|
|
assert( !sqlite3VdbeMemIsRowSet(pMem) );
|
|
assert( EIGHT_BYTE_ALIGNMENT(pMem) );
|
|
@@ -76112,6 +81102,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemIntegerify(Mem *pMem){
|
|
** Invalidate any prior representations.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3VdbeMemRealify(Mem *pMem){
|
|
+ assert( pMem!=0 );
|
|
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
|
|
assert( EIGHT_BYTE_ALIGNMENT(pMem) );
|
|
|
|
@@ -76136,6 +81127,16 @@ SQLITE_PRIVATE int sqlite3RealSameAsInt(double r1, sqlite3_int64 i){
|
|
&& i >= -2251799813685248LL && i < 2251799813685248LL);
|
|
}
|
|
|
|
+/* Convert a floating point value to its closest integer. Do so in
|
|
+** a way that avoids 'outside the range of representable values' warnings
|
|
+** from UBSAN.
|
|
+*/
|
|
+SQLITE_PRIVATE i64 sqlite3RealToI64(double r){
|
|
+ if( r<=(double)SMALLEST_INT64 ) return SMALLEST_INT64;
|
|
+ if( r>=(double)LARGEST_INT64) return LARGEST_INT64;
|
|
+ return (i64)r;
|
|
+}
|
|
+
|
|
/*
|
|
** Convert pMem so that it has type MEM_Real or MEM_Int.
|
|
** Invalidate any prior representations.
|
|
@@ -76145,6 +81146,7 @@ SQLITE_PRIVATE int sqlite3RealSameAsInt(double r1, sqlite3_int64 i){
|
|
** as much of the string as we can and ignore the rest.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem *pMem){
|
|
+ assert( pMem!=0 );
|
|
testcase( pMem->flags & MEM_Int );
|
|
testcase( pMem->flags & MEM_Real );
|
|
testcase( pMem->flags & MEM_IntReal );
|
|
@@ -76156,7 +81158,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem *pMem){
|
|
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
|
|
rc = sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc);
|
|
if( ((rc==0 || rc==1) && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)<=1)
|
|
- || sqlite3RealSameAsInt(pMem->u.r, (ix = (i64)pMem->u.r))
|
|
+ || sqlite3RealSameAsInt(pMem->u.r, (ix = sqlite3RealToI64(pMem->u.r)))
|
|
){
|
|
pMem->u.i = ix;
|
|
MemSetTypeFlag(pMem, MEM_Int);
|
|
@@ -76208,6 +81210,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemCast(Mem *pMem, u8 aff, u8 encoding){
|
|
sqlite3ValueApplyAffinity(pMem, SQLITE_AFF_TEXT, 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);
|
|
}
|
|
}
|
|
@@ -76247,13 +81250,14 @@ SQLITE_PRIVATE void sqlite3VdbeMemSetNull(Mem *pMem){
|
|
}
|
|
}
|
|
SQLITE_PRIVATE void sqlite3ValueSetNull(sqlite3_value *p){
|
|
- sqlite3VdbeMemSetNull((Mem*)p);
|
|
+ sqlite3VdbeMemSetNull((Mem*)p);
|
|
}
|
|
|
|
/*
|
|
** Delete any previous value and set the value to be a BLOB of length
|
|
** n containing all zeros.
|
|
*/
|
|
+#ifndef SQLITE_OMIT_INCRBLOB
|
|
SQLITE_PRIVATE void sqlite3VdbeMemSetZeroBlob(Mem *pMem, int n){
|
|
sqlite3VdbeMemRelease(pMem);
|
|
pMem->flags = MEM_Blob|MEM_Zero;
|
|
@@ -76263,6 +81267,21 @@ SQLITE_PRIVATE void sqlite3VdbeMemSetZeroBlob(Mem *pMem, int n){
|
|
pMem->enc = SQLITE_UTF8;
|
|
pMem->z = 0;
|
|
}
|
|
+#else
|
|
+SQLITE_PRIVATE int sqlite3VdbeMemSetZeroBlob(Mem *pMem, int n){
|
|
+ int nByte = n>0?n:1;
|
|
+ if( sqlite3VdbeMemGrow(pMem, nByte, 0) ){
|
|
+ return SQLITE_NOMEM_BKPT;
|
|
+ }
|
|
+ assert( pMem->z!=0 );
|
|
+ assert( sqlite3DbMallocSize(pMem->db, pMem->z)>=nByte );
|
|
+ memset(pMem->z, 0, nByte);
|
|
+ pMem->n = n>0?n:0;
|
|
+ pMem->flags = MEM_Blob;
|
|
+ pMem->enc = SQLITE_UTF8;
|
|
+ return SQLITE_OK;
|
|
+}
|
|
+#endif
|
|
|
|
/*
|
|
** The pMem is known to contain content that needs to be destroyed prior
|
|
@@ -76302,6 +81321,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemSetPointer(
|
|
void (*xDestructor)(void*)
|
|
){
|
|
assert( pMem->flags==MEM_Null );
|
|
+ vdbeMemClear(pMem);
|
|
pMem->u.zPType = zPType ? zPType : "";
|
|
pMem->z = pPtr;
|
|
pMem->flags = MEM_Null|MEM_Dyn|MEM_Subtype|MEM_Term;
|
|
@@ -76368,7 +81388,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemTooBig(Mem *p){
|
|
}
|
|
return n>p->db->aLimit[SQLITE_LIMIT_LENGTH];
|
|
}
|
|
- return 0;
|
|
+ return 0;
|
|
}
|
|
|
|
#ifdef SQLITE_DEBUG
|
|
@@ -76390,7 +81410,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){
|
|
sqlite3DebugPrintf("Invalidate R[%d] due to change in R[%d]\n",
|
|
(int)(pX - pVdbe->aMem), (int)(pMem - pVdbe->aMem));
|
|
}
|
|
- /* If pX is marked as a shallow copy of pMem, then verify that
|
|
+ /* If pX is marked as a shallow copy of pMem, then try to verify that
|
|
** no significant changes have been made to pX since the OP_SCopy.
|
|
** A significant change would indicated a missed call to this
|
|
** function for pX. Minor changes, such as adding or removing a
|
|
@@ -76398,12 +81418,7 @@ SQLITE_PRIVATE void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){
|
|
** same. */
|
|
mFlags = pMem->flags & pX->flags & pX->mScopyFlags;
|
|
assert( (mFlags&(MEM_Int|MEM_IntReal))==0 || pMem->u.i==pX->u.i );
|
|
- /* assert( (mFlags&MEM_Real)==0 || pMem->u.r==pX->u.r ); */
|
|
- /* ^^ */
|
|
- /* Cannot reliably compare doubles for equality */
|
|
- assert( (mFlags&MEM_Str)==0 || (pMem->n==pX->n && pMem->z==pX->z) );
|
|
- assert( (mFlags&MEM_Blob)==0 || sqlite3BlobCompare(pMem,pX)==0 );
|
|
-
|
|
+
|
|
/* pMem is the register that is changing. But also mark pX as
|
|
** undefined so that we can quickly detect the shallow-copy error */
|
|
pX->flags = MEM_Undefined;
|
|
@@ -76479,8 +81494,8 @@ SQLITE_PRIVATE void sqlite3VdbeMemMove(Mem *pTo, Mem *pFrom){
|
|
** Change the value of a Mem to be a string or a BLOB.
|
|
**
|
|
** The memory management strategy depends on the value of the xDel
|
|
-** parameter. If the value passed is SQLITE_TRANSIENT, then the
|
|
-** string is copied into a (possibly existing) buffer managed by the
|
|
+** parameter. If the value passed is SQLITE_TRANSIENT, then the
|
|
+** string is copied into a (possibly existing) buffer managed by the
|
|
** Mem structure. Otherwise, any existing buffer is freed and the
|
|
** pointer copied.
|
|
**
|
|
@@ -76489,20 +81504,29 @@ SQLITE_PRIVATE void sqlite3VdbeMemMove(Mem *pTo, Mem *pFrom){
|
|
** stored without allocating memory, then it is. If a memory allocation
|
|
** is required to store the string, then value of pMem is unchanged. In
|
|
** either case, SQLITE_TOOBIG is returned.
|
|
+**
|
|
+** The "enc" parameter is the text encoding for the string, or zero
|
|
+** to store a blob.
|
|
+**
|
|
+** If n is negative, then the string consists of all bytes up to but
|
|
+** excluding the first zero character. The n parameter must be
|
|
+** non-negative for blobs.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3VdbeMemSetStr(
|
|
Mem *pMem, /* Memory cell to set to string value */
|
|
const char *z, /* String pointer */
|
|
- int n, /* Bytes in string, or negative */
|
|
+ i64 n, /* Bytes in string, or negative */
|
|
u8 enc, /* Encoding of z. 0 for BLOBs */
|
|
void (*xDel)(void*) /* Destructor function */
|
|
){
|
|
- int nByte = n; /* New value for pMem->n */
|
|
+ i64 nByte = n; /* New value for pMem->n */
|
|
int iLimit; /* Maximum allowed string or blob size */
|
|
- u16 flags = 0; /* New value for pMem->flags */
|
|
+ u16 flags; /* New value for pMem->flags */
|
|
|
|
+ assert( pMem!=0 );
|
|
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
|
|
assert( !sqlite3VdbeMemIsRowSet(pMem) );
|
|
+ assert( enc!=0 || n>=0 );
|
|
|
|
/* If z is a NULL pointer, set pMem to contain an SQL NULL. */
|
|
if( !z ){
|
|
@@ -76515,15 +81539,30 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetStr(
|
|
}else{
|
|
iLimit = SQLITE_MAX_LENGTH;
|
|
}
|
|
- flags = (enc==0?MEM_Blob:MEM_Str);
|
|
if( nByte<0 ){
|
|
assert( enc!=0 );
|
|
if( enc==SQLITE_UTF8 ){
|
|
- nByte = 0x7fffffff & (int)strlen(z);
|
|
+ nByte = strlen(z);
|
|
}else{
|
|
for(nByte=0; nByte<=iLimit && (z[nByte] | z[nByte+1]); nByte+=2){}
|
|
}
|
|
- flags |= MEM_Term;
|
|
+ flags= MEM_Str|MEM_Term;
|
|
+ }else if( enc==0 ){
|
|
+ flags = MEM_Blob;
|
|
+ enc = SQLITE_UTF8;
|
|
+ }else{
|
|
+ flags = MEM_Str;
|
|
+ }
|
|
+ if( nByte>iLimit ){
|
|
+ if( xDel && xDel!=SQLITE_TRANSIENT ){
|
|
+ if( xDel==SQLITE_DYNAMIC ){
|
|
+ sqlite3DbFree(pMem->db, (void*)z);
|
|
+ }else{
|
|
+ xDel((void*)z);
|
|
+ }
|
|
+ }
|
|
+ sqlite3VdbeMemSetNull(pMem);
|
|
+ return sqlite3ErrorToParser(pMem->db, SQLITE_TOOBIG);
|
|
}
|
|
|
|
/* The following block sets the new values of Mem.z and Mem.xDel. It
|
|
@@ -76531,13 +81570,10 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetStr(
|
|
** management (one of MEM_Dyn or MEM_Static).
|
|
*/
|
|
if( xDel==SQLITE_TRANSIENT ){
|
|
- u32 nAlloc = nByte;
|
|
+ i64 nAlloc = nByte;
|
|
if( flags&MEM_Term ){
|
|
nAlloc += (enc==SQLITE_UTF8?1:2);
|
|
}
|
|
- if( nByte>iLimit ){
|
|
- return sqlite3ErrorToParser(pMem->db, SQLITE_TOOBIG);
|
|
- }
|
|
testcase( nAlloc==0 );
|
|
testcase( nAlloc==31 );
|
|
testcase( nAlloc==32 );
|
|
@@ -76557,18 +81593,9 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetStr(
|
|
}
|
|
}
|
|
|
|
- pMem->n = nByte;
|
|
+ pMem->n = (int)(nByte & 0x7fffffff);
|
|
pMem->flags = flags;
|
|
- if( enc ){
|
|
- pMem->enc = enc;
|
|
-#ifdef SQLITE_ENABLE_SESSION
|
|
- }else if( pMem->db==0 ){
|
|
- pMem->enc = SQLITE_UTF8;
|
|
-#endif
|
|
- }else{
|
|
- assert( pMem->db!=0 );
|
|
- pMem->enc = ENC(pMem->db);
|
|
- }
|
|
+ pMem->enc = enc;
|
|
|
|
#ifndef SQLITE_OMIT_UTF16
|
|
if( enc>SQLITE_UTF8 && sqlite3VdbeMemHandleBom(pMem) ){
|
|
@@ -76576,9 +81603,6 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetStr(
|
|
}
|
|
#endif
|
|
|
|
- if( nByte>iLimit ){
|
|
- return SQLITE_TOOBIG;
|
|
- }
|
|
|
|
return SQLITE_OK;
|
|
}
|
|
@@ -76598,7 +81622,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetStr(
|
|
** If this routine fails for any reason (malloc returns NULL or unable
|
|
** to read from the disk) then the pMem is left in an inconsistent state.
|
|
*/
|
|
-static SQLITE_NOINLINE int vdbeMemFromBtreeResize(
|
|
+SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(
|
|
BtCursor *pCur, /* Cursor pointing at record to retrieve. */
|
|
u32 offset, /* Offset from the start of data to return bytes from. */
|
|
u32 amt, /* Number of bytes to return. */
|
|
@@ -76621,31 +81645,28 @@ static SQLITE_NOINLINE int vdbeMemFromBtreeResize(
|
|
}
|
|
return rc;
|
|
}
|
|
-SQLITE_PRIVATE int sqlite3VdbeMemFromBtree(
|
|
+SQLITE_PRIVATE int sqlite3VdbeMemFromBtreeZeroOffset(
|
|
BtCursor *pCur, /* Cursor pointing at record to retrieve. */
|
|
- u32 offset, /* Offset from the start of data to return bytes from. */
|
|
u32 amt, /* Number of bytes to return. */
|
|
Mem *pMem /* OUT: Return data in this Mem structure. */
|
|
){
|
|
- char *zData; /* Data from the btree layer */
|
|
u32 available = 0; /* Number of bytes available on the local btree page */
|
|
int rc = SQLITE_OK; /* Return code */
|
|
|
|
assert( sqlite3BtreeCursorIsValid(pCur) );
|
|
assert( !VdbeMemDynamic(pMem) );
|
|
|
|
- /* Note: the calls to BtreeKeyFetch() and DataFetch() below assert()
|
|
+ /* Note: the calls to BtreeKeyFetch() and DataFetch() below assert()
|
|
** that both the BtShared and database handle mutexes are held. */
|
|
assert( !sqlite3VdbeMemIsRowSet(pMem) );
|
|
- zData = (char *)sqlite3BtreePayloadFetch(pCur, &available);
|
|
- assert( zData!=0 );
|
|
+ pMem->z = (char *)sqlite3BtreePayloadFetch(pCur, &available);
|
|
+ assert( pMem->z!=0 );
|
|
|
|
- if( offset+amt<=available ){
|
|
- pMem->z = &zData[offset];
|
|
+ if( amt<=available ){
|
|
pMem->flags = MEM_Blob|MEM_Ephem;
|
|
pMem->n = (int)amt;
|
|
}else{
|
|
- rc = vdbeMemFromBtreeResize(pCur, offset, amt, pMem);
|
|
+ rc = sqlite3VdbeMemFromBtree(pCur, 0, amt, pMem);
|
|
}
|
|
|
|
return rc;
|
|
@@ -76727,7 +81748,7 @@ SQLITE_PRIVATE sqlite3_value *sqlite3ValueNew(sqlite3 *db){
|
|
}
|
|
|
|
/*
|
|
-** Context object passed by sqlite3Stat4ProbeSetValue() through to
|
|
+** Context object passed by sqlite3Stat4ProbeSetValue() through to
|
|
** valueNew(). See comments above valueNew() for details.
|
|
*/
|
|
struct ValueNewStat4Ctx {
|
|
@@ -76742,9 +81763,9 @@ struct ValueNewStat4Ctx {
|
|
** the second argument to this function is NULL, the object is allocated
|
|
** by calling sqlite3ValueNew().
|
|
**
|
|
-** Otherwise, if the second argument is non-zero, then this function is
|
|
+** Otherwise, if the second argument is non-zero, then this function is
|
|
** being called indirectly by sqlite3Stat4ProbeSetValue(). If it has not
|
|
-** already been allocated, allocate the UnpackedRecord structure that
|
|
+** already been allocated, allocate the UnpackedRecord structure that
|
|
** that function will return to its caller here. Then return a pointer to
|
|
** an sqlite3_value within the UnpackedRecord.a[] array.
|
|
*/
|
|
@@ -76758,7 +81779,7 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){
|
|
int nByte; /* Bytes of space to allocate */
|
|
int i; /* Counter variable */
|
|
int nCol = pIdx->nColumn; /* Number of index columns including rowid */
|
|
-
|
|
+
|
|
nByte = sizeof(Mem) * nCol + ROUND8(sizeof(UnpackedRecord));
|
|
pRec = (UnpackedRecord*)sqlite3DbMallocZero(db, nByte);
|
|
if( pRec ){
|
|
@@ -76779,7 +81800,7 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){
|
|
if( pRec==0 ) return 0;
|
|
p->ppRec[0] = pRec;
|
|
}
|
|
-
|
|
+
|
|
pRec->nField = p->iVal+1;
|
|
return &pRec->aMem[p->iVal];
|
|
}
|
|
@@ -76798,11 +81819,11 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){
|
|
** * the SQLITE_FUNC_NEEDCOLL function flag is not set,
|
|
**
|
|
** then this routine attempts to invoke the SQL function. Assuming no
|
|
-** error occurs, output parameter (*ppVal) is set to point to a value
|
|
+** error occurs, output parameter (*ppVal) is set to point to a value
|
|
** object containing the result before returning SQLITE_OK.
|
|
**
|
|
** Affinity aff is applied to the result of the function before returning.
|
|
-** If the result is a text value, the sqlite3_value object uses encoding
|
|
+** If the result is a text value, the sqlite3_value object uses encoding
|
|
** enc.
|
|
**
|
|
** If the conditions above are not met, this function returns SQLITE_OK
|
|
@@ -76812,7 +81833,7 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){
|
|
#ifdef SQLITE_ENABLE_STAT4
|
|
static int valueFromFunction(
|
|
sqlite3 *db, /* The database connection */
|
|
- Expr *p, /* The expression to evaluate */
|
|
+ const Expr *p, /* The expression to evaluate */
|
|
u8 enc, /* Encoding to use */
|
|
u8 aff, /* Affinity to use */
|
|
sqlite3_value **ppVal, /* Write the new value here */
|
|
@@ -76829,11 +81850,13 @@ static int valueFromFunction(
|
|
|
|
assert( pCtx!=0 );
|
|
assert( (p->flags & EP_TokenOnly)==0 );
|
|
+ assert( ExprUseXList(p) );
|
|
pList = p->x.pList;
|
|
if( pList ) nVal = pList->nExpr;
|
|
+ assert( !ExprHasProperty(p, EP_IntValue) );
|
|
pFunc = sqlite3FindFunction(db, p->u.zToken, nVal, enc, 0);
|
|
assert( pFunc );
|
|
- if( (pFunc->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG))==0
|
|
+ if( (pFunc->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG))==0
|
|
|| (pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL)
|
|
){
|
|
return SQLITE_OK;
|
|
@@ -76857,10 +81880,10 @@ static int valueFromFunction(
|
|
goto value_from_function_out;
|
|
}
|
|
|
|
- assert( pCtx->pParse->rc==SQLITE_OK );
|
|
memset(&ctx, 0, sizeof(ctx));
|
|
ctx.pOut = pVal;
|
|
ctx.pFunc = pFunc;
|
|
+ ctx.enc = ENC(db);
|
|
pFunc->xSFunc(&ctx, nVal, apVal);
|
|
if( ctx.isError ){
|
|
rc = ctx.isError;
|
|
@@ -76868,17 +81891,22 @@ 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) ){
|
|
rc = SQLITE_TOOBIG;
|
|
pCtx->pParse->nErr++;
|
|
}
|
|
+#endif
|
|
}
|
|
- pCtx->pParse->rc = rc;
|
|
|
|
value_from_function_out:
|
|
if( rc!=SQLITE_OK ){
|
|
pVal = 0;
|
|
+ pCtx->pParse->rc = rc;
|
|
}
|
|
if( apVal ){
|
|
for(i=0; i<nVal; i++){
|
|
@@ -76906,7 +81934,7 @@ static int valueFromFunction(
|
|
*/
|
|
static int valueFromExpr(
|
|
sqlite3 *db, /* The database connection */
|
|
- Expr *pExpr, /* The expression to evaluate */
|
|
+ const Expr *pExpr, /* The expression to evaluate */
|
|
u8 enc, /* Encoding to use */
|
|
u8 affinity, /* Affinity to use */
|
|
sqlite3_value **ppVal, /* Write the new value here */
|
|
@@ -76921,11 +81949,7 @@ static int valueFromExpr(
|
|
|
|
assert( pExpr!=0 );
|
|
while( (op = pExpr->op)==TK_UPLUS || op==TK_SPAN ) pExpr = pExpr->pLeft;
|
|
-#if defined(SQLITE_ENABLE_STAT4)
|
|
if( op==TK_REGISTER ) op = pExpr->op2;
|
|
-#else
|
|
- if( NEVER(op==TK_REGISTER) ) op = pExpr->op2;
|
|
-#endif
|
|
|
|
/* Compressed expressions only appear when parsing the DEFAULT clause
|
|
** on a table column definition, and hence only when pCtx==0. This
|
|
@@ -76934,12 +81958,14 @@ static int valueFromExpr(
|
|
assert( (pExpr->flags & EP_TokenOnly)==0 || pCtx==0 );
|
|
|
|
if( op==TK_CAST ){
|
|
- u8 aff = sqlite3AffinityType(pExpr->u.zToken,0);
|
|
+ u8 aff;
|
|
+ assert( !ExprHasProperty(pExpr, EP_IntValue) );
|
|
+ aff = sqlite3AffinityType(pExpr->u.zToken,0);
|
|
rc = valueFromExpr(db, pExpr->pLeft, enc, aff, ppVal, pCtx);
|
|
testcase( rc!=SQLITE_OK );
|
|
if( *ppVal ){
|
|
- sqlite3VdbeMemCast(*ppVal, aff, SQLITE_UTF8);
|
|
- sqlite3ValueApplyAffinity(*ppVal, affinity, SQLITE_UTF8);
|
|
+ sqlite3VdbeMemCast(*ppVal, aff, enc);
|
|
+ sqlite3ValueApplyAffinity(*ppVal, affinity, enc);
|
|
}
|
|
return rc;
|
|
}
|
|
@@ -76981,7 +82007,7 @@ static int valueFromExpr(
|
|
}
|
|
}else if( op==TK_UMINUS ) {
|
|
/* This branch happens for multiple negative signs. Ex: -(-5) */
|
|
- if( SQLITE_OK==valueFromExpr(db,pExpr->pLeft,enc,affinity,&pVal,pCtx)
|
|
+ if( SQLITE_OK==valueFromExpr(db,pExpr->pLeft,enc,affinity,&pVal,pCtx)
|
|
&& pVal!=0
|
|
){
|
|
sqlite3VdbeMemNumerify(pVal);
|
|
@@ -77007,6 +82033,7 @@ static int valueFromExpr(
|
|
#ifndef SQLITE_OMIT_BLOB_LITERAL
|
|
else if( op==TK_BLOB ){
|
|
int nVal;
|
|
+ assert( !ExprHasProperty(pExpr, EP_IntValue) );
|
|
assert( pExpr->u.zToken[0]=='x' || pExpr->u.zToken[0]=='X' );
|
|
assert( pExpr->u.zToken[1]=='\'' );
|
|
pVal = valueNew(db, pCtx);
|
|
@@ -77024,6 +82051,7 @@ static int valueFromExpr(
|
|
}
|
|
#endif
|
|
else if( op==TK_TRUEFALSE ){
|
|
+ assert( !ExprHasProperty(pExpr, EP_IntValue) );
|
|
pVal = valueNew(db, pCtx);
|
|
if( pVal ){
|
|
pVal->flags = MEM_Int;
|
|
@@ -77036,7 +82064,7 @@ static int valueFromExpr(
|
|
|
|
no_mem:
|
|
#ifdef SQLITE_ENABLE_STAT4
|
|
- if( pCtx==0 || pCtx->pParse->nErr==0 )
|
|
+ if( pCtx==0 || NEVER(pCtx->pParse->nErr==0) )
|
|
#endif
|
|
sqlite3OomFault(db);
|
|
sqlite3DbFree(db, zVal);
|
|
@@ -77061,7 +82089,7 @@ static int valueFromExpr(
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3ValueFromExpr(
|
|
sqlite3 *db, /* The database connection */
|
|
- Expr *pExpr, /* The expression to evaluate */
|
|
+ const Expr *pExpr, /* The expression to evaluate */
|
|
u8 enc, /* Encoding to use */
|
|
u8 affinity, /* Affinity to use */
|
|
sqlite3_value **ppVal /* Write the new value here */
|
|
@@ -77130,8 +82158,8 @@ static int stat4ValueFromExpr(
|
|
}
|
|
|
|
/*
|
|
-** This function is used to allocate and populate UnpackedRecord
|
|
-** structures intended to be compared against sample index keys stored
|
|
+** This function is used to allocate and populate UnpackedRecord
|
|
+** structures intended to be compared against sample index keys stored
|
|
** in the sqlite_stat4 table.
|
|
**
|
|
** A single call to this function populates zero or more fields of the
|
|
@@ -77142,14 +82170,14 @@ static int stat4ValueFromExpr(
|
|
**
|
|
** * The expression is a bound variable, and this is a reprepare, or
|
|
**
|
|
-** * The sqlite3ValueFromExpr() function is able to extract a value
|
|
+** * The sqlite3ValueFromExpr() function is able to extract a value
|
|
** from the expression (i.e. the expression is a literal value).
|
|
**
|
|
** Or, if pExpr is a TK_VECTOR, one field is populated for each of the
|
|
** vector components that match either of the two latter criteria listed
|
|
** above.
|
|
**
|
|
-** Before any value is appended to the record, the affinity of the
|
|
+** Before any value is appended to the record, the affinity of the
|
|
** corresponding column within index pIdx is applied to it. Before
|
|
** this function returns, output parameter *pnExtract is set to the
|
|
** number of values appended to the record.
|
|
@@ -77200,9 +82228,9 @@ SQLITE_PRIVATE int sqlite3Stat4ProbeSetValue(
|
|
|
|
/*
|
|
** Attempt to extract a value from expression pExpr using the methods
|
|
-** as described for sqlite3Stat4ProbeSetValue() above.
|
|
+** as described for sqlite3Stat4ProbeSetValue() above.
|
|
**
|
|
-** If successful, set *ppVal to point to a new value object and return
|
|
+** If successful, set *ppVal to point to a new value object and return
|
|
** SQLITE_OK. If no value can be extracted, but no other error occurs
|
|
** (e.g. OOM), return SQLITE_OK and set *ppVal to NULL. Or, if an error
|
|
** does occur, return an SQLite error code. The final value of *ppVal
|
|
@@ -77222,7 +82250,7 @@ SQLITE_PRIVATE int sqlite3Stat4ValueFromExpr(
|
|
** the column value into *ppVal. If *ppVal is initially NULL then a new
|
|
** sqlite3_value object is allocated.
|
|
**
|
|
-** If *ppVal is initially NULL then the caller is responsible for
|
|
+** If *ppVal is initially NULL then the caller is responsible for
|
|
** ensuring that the value written into *ppVal is eventually freed.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3Stat4Column(
|
|
@@ -77321,6 +82349,9 @@ SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value *pVal, u8 enc){
|
|
if( (p->flags & MEM_Str)!=0 && pVal->enc==enc ){
|
|
return p->n;
|
|
}
|
|
+ if( (p->flags & MEM_Str)!=0 && enc!=SQLITE_UTF8 && pVal->enc!=SQLITE_UTF8 ){
|
|
+ return p->n;
|
|
+ }
|
|
if( (p->flags & MEM_Blob)!=0 ){
|
|
if( p->flags & MEM_Zero ){
|
|
return p->n + p->u.nZero;
|
|
@@ -77346,7 +82377,7 @@ SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value *pVal, u8 enc){
|
|
**
|
|
*************************************************************************
|
|
** This file contains code used for creating, destroying, and populating
|
|
-** a VDBE (or an "sqlite3_stmt" as it is known to the outside world.)
|
|
+** a VDBE (or an "sqlite3_stmt" as it is known to the outside world.)
|
|
*/
|
|
/* #include "sqliteInt.h" */
|
|
/* #include "vdbeInt.h" */
|
|
@@ -77366,12 +82397,12 @@ SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(Parse *pParse){
|
|
memset(&p->aOp, 0, sizeof(Vdbe)-offsetof(Vdbe,aOp));
|
|
p->db = db;
|
|
if( db->pVdbe ){
|
|
- db->pVdbe->pPrev = p;
|
|
+ db->pVdbe->ppVPrev = &p->pVNext;
|
|
}
|
|
- p->pNext = db->pVdbe;
|
|
- p->pPrev = 0;
|
|
+ p->pVNext = db->pVdbe;
|
|
+ p->ppVPrev = &db->pVdbe;
|
|
db->pVdbe = p;
|
|
- p->magic = VDBE_MAGIC_INIT;
|
|
+ assert( p->eVdbeState==VDBE_INIT_STATE );
|
|
p->pParse = pParse;
|
|
pParse->pVdbe = p;
|
|
assert( pParse->aLabel==0 );
|
|
@@ -77451,21 +82482,28 @@ SQLITE_PRIVATE int sqlite3VdbeUsesDoubleQuotedString(
|
|
#endif
|
|
|
|
/*
|
|
-** Swap all content between two VDBE structures.
|
|
+** Swap byte-code between two VDBE structures.
|
|
+**
|
|
+** This happens after pB was previously run and returned
|
|
+** SQLITE_SCHEMA. The statement was then reprepared in pA.
|
|
+** This routine transfers the new bytecode in pA over to pB
|
|
+** so that pB can be run again. The old pB byte code is
|
|
+** moved back to pA so that it will be cleaned up when pA is
|
|
+** finalized.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){
|
|
- Vdbe tmp, *pTmp;
|
|
+ Vdbe tmp, *pTmp, **ppTmp;
|
|
char *zTmp;
|
|
assert( pA->db==pB->db );
|
|
tmp = *pA;
|
|
*pA = *pB;
|
|
*pB = tmp;
|
|
- pTmp = pA->pNext;
|
|
- pA->pNext = pB->pNext;
|
|
- pB->pNext = pTmp;
|
|
- pTmp = pA->pPrev;
|
|
- pA->pPrev = pB->pPrev;
|
|
- pB->pPrev = pTmp;
|
|
+ pTmp = pA->pVNext;
|
|
+ pA->pVNext = pB->pVNext;
|
|
+ pB->pVNext = pTmp;
|
|
+ ppTmp = pA->ppVPrev;
|
|
+ pA->ppVPrev = pB->ppVPrev;
|
|
+ pB->ppVPrev = ppTmp;
|
|
zTmp = pA->zSql;
|
|
pA->zSql = pB->zSql;
|
|
pB->zSql = zTmp;
|
|
@@ -77481,13 +82519,13 @@ SQLITE_PRIVATE void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){
|
|
}
|
|
|
|
/*
|
|
-** Resize the Vdbe.aOp array so that it is at least nOp elements larger
|
|
+** Resize the Vdbe.aOp array so that it is at least nOp elements larger
|
|
** than its current size. nOp is guaranteed to be less than or equal
|
|
** to 1024/sizeof(Op).
|
|
**
|
|
** If an out-of-memory error occurs while resizing the array, return
|
|
-** SQLITE_NOMEM. In this case Vdbe.aOp and Vdbe.nOpAlloc remain
|
|
-** unchanged (this is so that any opcodes already allocated can be
|
|
+** SQLITE_NOMEM. In this case Vdbe.aOp and Vdbe.nOpAlloc remain
|
|
+** unchanged (this is so that any opcodes already allocated can be
|
|
** correctly deallocated along with the rest of the Vdbe).
|
|
*/
|
|
static int growOpArray(Vdbe *v, int nOp){
|
|
@@ -77495,7 +82533,7 @@ static int growOpArray(Vdbe *v, int nOp){
|
|
Parse *p = v->pParse;
|
|
|
|
/* The SQLITE_TEST_REALLOC_STRESS compile-time option is designed to force
|
|
- ** more frequent reallocs and hence provide more opportunities for
|
|
+ ** more frequent reallocs and hence provide more opportunities for
|
|
** simulated OOM faults. SQLITE_TEST_REALLOC_STRESS is generally used
|
|
** during testing only. With SQLITE_TEST_REALLOC_STRESS grow the op array
|
|
** by the minimum* amount required until the size reaches 512. Normal
|
|
@@ -77516,7 +82554,7 @@ static int growOpArray(Vdbe *v, int nOp){
|
|
return SQLITE_NOMEM;
|
|
}
|
|
|
|
- assert( nOp<=(1024/sizeof(Op)) );
|
|
+ assert( nOp<=(int)(1024/sizeof(Op)) );
|
|
assert( nNew>=(v->nOpAlloc+nOp) );
|
|
pNew = sqlite3DbRealloc(p->db, v->aOp, nNew*sizeof(Op));
|
|
if( pNew ){
|
|
@@ -77541,6 +82579,8 @@ static int growOpArray(Vdbe *v, int nOp){
|
|
*/
|
|
static void test_addop_breakpoint(int pc, Op *pOp){
|
|
static int n = 0;
|
|
+ (void)pc;
|
|
+ (void)pOp;
|
|
n++;
|
|
}
|
|
#endif
|
|
@@ -77572,13 +82612,15 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){
|
|
VdbeOp *pOp;
|
|
|
|
i = p->nOp;
|
|
- assert( p->magic==VDBE_MAGIC_INIT );
|
|
+ assert( p->eVdbeState==VDBE_INIT_STATE );
|
|
assert( op>=0 && op<0xff );
|
|
if( p->nOpAlloc<=i ){
|
|
return growOp3(p, op, p1, p2, p3);
|
|
}
|
|
+ assert( p->aOp!=0 );
|
|
p->nOp++;
|
|
pOp = &p->aOp[i];
|
|
+ assert( pOp!=0 );
|
|
pOp->opcode = (u8)op;
|
|
pOp->p5 = 0;
|
|
pOp->p1 = p1;
|
|
@@ -77589,16 +82631,16 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){
|
|
#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 VDBE_PROFILE
|
|
- pOp->cycles = 0;
|
|
- pOp->cnt = 0;
|
|
-#endif
|
|
#ifdef SQLITE_VDBE_COVERAGE
|
|
pOp->iSrcLine = 0;
|
|
#endif
|
|
@@ -77715,6 +82757,7 @@ SQLITE_PRIVATE int sqlite3VdbeAddFunctionCall(
|
|
addr = sqlite3VdbeAddOp4(v, eCallCtx ? OP_PureFunc : OP_Function,
|
|
p1, p2, p3, (char*)pCtx, P4_FUNCCTX);
|
|
sqlite3VdbeChangeP5(v, eCallCtx & NC_SelfRef);
|
|
+ sqlite3MayAbort(pParse);
|
|
return addr;
|
|
}
|
|
|
|
@@ -77760,13 +82803,14 @@ SQLITE_PRIVATE void sqlite3ExplainBreakpoint(const char *z1, const char *z2){
|
|
#endif
|
|
|
|
/*
|
|
-** Add a new OP_ opcode.
|
|
+** Add a new OP_Explain opcode.
|
|
**
|
|
** If the bPush flag is true, then make this opcode the parent for
|
|
** subsequent Explains until sqlite3VdbeExplainPop() is called.
|
|
*/
|
|
-SQLITE_PRIVATE void sqlite3VdbeExplain(Parse *pParse, u8 bPush, const char *zFmt, ...){
|
|
-#ifndef SQLITE_DEBUG
|
|
+SQLITE_PRIVATE int sqlite3VdbeExplain(Parse *pParse, u8 bPush, const char *zFmt, ...){
|
|
+ int addr = 0;
|
|
+#if !defined(SQLITE_DEBUG) && !defined(SQLITE_ENABLE_STMT_SCANSTATUS)
|
|
/* Always include the OP_Explain opcodes if SQLITE_DEBUG is defined.
|
|
** But omit them (for performance) during production builds */
|
|
if( pParse->explain==2 )
|
|
@@ -77781,13 +82825,15 @@ SQLITE_PRIVATE void sqlite3VdbeExplain(Parse *pParse, u8 bPush, const char *zFmt
|
|
va_end(ap);
|
|
v = pParse->pVdbe;
|
|
iThis = v->nOp;
|
|
- sqlite3VdbeAddOp4(v, OP_Explain, iThis, pParse->addrExplain, 0,
|
|
+ addr = sqlite3VdbeAddOp4(v, OP_Explain, iThis, pParse->addrExplain, 0,
|
|
zMsg, P4_DYNAMIC);
|
|
- sqlite3ExplainBreakpoint(bPush?"PUSH":"", sqlite3VdbeGetOp(v,-1)->p4.z);
|
|
+ sqlite3ExplainBreakpoint(bPush?"PUSH":"", sqlite3VdbeGetLastOp(v)->p4.z);
|
|
if( bPush){
|
|
pParse->addrExplain = iThis;
|
|
}
|
|
+ sqlite3VdbeScanStatus(v, iThis, 0, 0, 0, 0);
|
|
}
|
|
+ return addr;
|
|
}
|
|
|
|
/*
|
|
@@ -77807,10 +82853,12 @@ SQLITE_PRIVATE void sqlite3VdbeExplainPop(Parse *pParse){
|
|
** The zWhere string must have been obtained from sqlite3_malloc().
|
|
** This routine will take ownership of the allocated memory.
|
|
*/
|
|
-SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe *p, int iDb, char *zWhere){
|
|
+SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe *p, int iDb, char *zWhere, u16 p5){
|
|
int j;
|
|
sqlite3VdbeAddOp4(p, OP_ParseSchema, iDb, 0, 0, zWhere, P4_DYNAMIC);
|
|
+ sqlite3VdbeChangeP5(p, p5);
|
|
for(j=0; j<p->db->nDb; j++) sqlite3VdbeUsesBtree(p, j);
|
|
+ sqlite3MayAbort(p->pParse);
|
|
}
|
|
|
|
/*
|
|
@@ -77893,6 +82941,9 @@ static SQLITE_NOINLINE void resizeResolveLabel(Parse *p, Vdbe *v, int j){
|
|
int i;
|
|
for(i=p->nLabelAlloc; i<nNewSize; i++) p->aLabel[i] = -1;
|
|
#endif
|
|
+ if( nNewSize>=100 && (nNewSize/100)>(p->nLabelAlloc/100) ){
|
|
+ sqlite3ProgressCheck(p);
|
|
+ }
|
|
p->nLabelAlloc = nNewSize;
|
|
p->aLabel[j] = v->nOp;
|
|
}
|
|
@@ -77900,7 +82951,7 @@ static SQLITE_NOINLINE void resizeResolveLabel(Parse *p, Vdbe *v, int j){
|
|
SQLITE_PRIVATE void sqlite3VdbeResolveLabel(Vdbe *v, int x){
|
|
Parse *p = v->pParse;
|
|
int j = ADDR(x);
|
|
- assert( v->magic==VDBE_MAGIC_INIT );
|
|
+ assert( v->eVdbeState==VDBE_INIT_STATE );
|
|
assert( j<-p->nLabel );
|
|
assert( j>=0 );
|
|
#ifdef SQLITE_DEBUG
|
|
@@ -77920,33 +82971,39 @@ SQLITE_PRIVATE void sqlite3VdbeResolveLabel(Vdbe *v, int x){
|
|
** Mark the VDBE as one that can only be run one time.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3VdbeRunOnlyOnce(Vdbe *p){
|
|
- p->runOnlyOnce = 1;
|
|
+ sqlite3VdbeAddOp2(p, OP_Expire, 1, 1);
|
|
}
|
|
|
|
/*
|
|
-** Mark the VDBE as one that can only be run multiple times.
|
|
+** Mark the VDBE as one that can be run multiple times.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3VdbeReusable(Vdbe *p){
|
|
- p->runOnlyOnce = 0;
|
|
+ int i;
|
|
+ for(i=1; ALWAYS(i<p->nOp); i++){
|
|
+ if( ALWAYS(p->aOp[i].opcode==OP_Expire) ){
|
|
+ p->aOp[1].opcode = OP_Noop;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
}
|
|
|
|
#ifdef SQLITE_DEBUG /* sqlite3AssertMayAbort() logic */
|
|
|
|
/*
|
|
** The following type and function are used to iterate through all opcodes
|
|
-** in a Vdbe main program and each of the sub-programs (triggers) it may
|
|
+** in a Vdbe main program and each of the sub-programs (triggers) it may
|
|
** invoke directly or indirectly. It should be used as follows:
|
|
**
|
|
** Op *pOp;
|
|
** VdbeOpIter sIter;
|
|
**
|
|
** memset(&sIter, 0, sizeof(sIter));
|
|
-** sIter.v = v; // v is of type Vdbe*
|
|
+** sIter.v = v; // v is of type Vdbe*
|
|
** while( (pOp = opIterNext(&sIter)) ){
|
|
** // Do something with pOp
|
|
** }
|
|
** sqlite3DbFree(v->db, sIter.apSub);
|
|
-**
|
|
+**
|
|
*/
|
|
typedef struct VdbeOpIter VdbeOpIter;
|
|
struct VdbeOpIter {
|
|
@@ -77979,7 +83036,7 @@ static Op *opIterNext(VdbeOpIter *p){
|
|
p->iSub++;
|
|
p->iAddr = 0;
|
|
}
|
|
-
|
|
+
|
|
if( pRet->p4type==P4_SUBPROGRAM ){
|
|
int nByte = (p->nSub+1)*sizeof(SubProgram*);
|
|
int j;
|
|
@@ -78013,7 +83070,7 @@ static Op *opIterNext(VdbeOpIter *p){
|
|
** * OP_VCreate
|
|
** * OP_VRename
|
|
** * OP_FkCounter with P2==0 (immediate foreign key constraint)
|
|
-** * OP_CreateBtree/BTREE_INTKEY and OP_InitCoroutine
|
|
+** * OP_CreateBtree/BTREE_INTKEY and OP_InitCoroutine
|
|
** (for CREATE TABLE AS SELECT ...)
|
|
**
|
|
** Then check that the value of Parse.mayAbort is true if an
|
|
@@ -78031,16 +83088,19 @@ SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
|
|
int hasInitCoroutine = 0;
|
|
Op *pOp;
|
|
VdbeOpIter sIter;
|
|
+
|
|
+ if( v==0 ) return 0;
|
|
memset(&sIter, 0, sizeof(sIter));
|
|
sIter.v = v;
|
|
|
|
while( (pOp = opIterNext(&sIter))!=0 ){
|
|
int opcode = pOp->opcode;
|
|
- if( opcode==OP_Destroy || opcode==OP_VUpdate || opcode==OP_VRename
|
|
+ if( opcode==OP_Destroy || opcode==OP_VUpdate || opcode==OP_VRename
|
|
|| opcode==OP_VDestroy
|
|
|| opcode==OP_VCreate
|
|
- || (opcode==OP_ParseSchema && pOp->p4.z==0)
|
|
- || ((opcode==OP_Halt || opcode==OP_HaltIfNull)
|
|
+ || opcode==OP_ParseSchema
|
|
+ || opcode==OP_Function || opcode==OP_PureFunc
|
|
+ || ((opcode==OP_Halt || opcode==OP_HaltIfNull)
|
|
&& ((pOp->p1)!=SQLITE_OK && pOp->p2==OE_Abort))
|
|
){
|
|
hasAbort = 1;
|
|
@@ -78049,7 +83109,7 @@ SQLITE_PRIVATE int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
|
|
if( opcode==OP_CreateBtree && pOp->p3==BTREE_INTKEY ) hasCreateTable = 1;
|
|
if( mayAbort ){
|
|
/* hasCreateIndex may also be set for some DELETE statements that use
|
|
- ** OP_Clear. So this routine may end up returning true in the case
|
|
+ ** OP_Clear. So this routine may end up returning true in the case
|
|
** where a "DELETE FROM tbl" has a statement-journal but does not
|
|
** require one. This is not so bad - it is an inefficiency, not a bug. */
|
|
if( opcode==OP_CreateBtree && pOp->p3==BTREE_BLOBKEY ) hasCreateIndex = 1;
|
|
@@ -78114,7 +83174,7 @@ SQLITE_PRIVATE void sqlite3VdbeAssertAbortable(Vdbe *p){
|
|
** (3) Update the Vdbe.readOnly and Vdbe.bIsReader flags to accurately
|
|
** indicate what the prepared statement actually does.
|
|
**
|
|
-** (4) Initialize the p4.xAdvance pointer on opcodes that use it.
|
|
+** (4) (discontinued)
|
|
**
|
|
** (5) Reclaim the memory allocated for storing labels.
|
|
**
|
|
@@ -78130,8 +83190,8 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
|
|
p->readOnly = 1;
|
|
p->bIsReader = 0;
|
|
pOp = &p->aOp[p->nOp-1];
|
|
- while(1){
|
|
-
|
|
+ assert( p->aOp[0].opcode==OP_Init );
|
|
+ while( 1 /* Loop termates when it reaches the OP_Init opcode */ ){
|
|
/* Only JUMP opcodes and the short list of special opcodes in the switch
|
|
** below need to be considered. The mkopcodeh.tcl generator script groups
|
|
** all these opcodes together near the front of the opcode list. Skip
|
|
@@ -78144,7 +83204,7 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
|
|
switch( pOp->opcode ){
|
|
case OP_Transaction: {
|
|
if( pOp->p2!=0 ) p->readOnly = 0;
|
|
- /* fall thru */
|
|
+ /* no break */ deliberate_fall_through
|
|
}
|
|
case OP_AutoCommit:
|
|
case OP_Savepoint: {
|
|
@@ -78160,24 +83220,9 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
|
|
p->bIsReader = 1;
|
|
break;
|
|
}
|
|
- case OP_Next:
|
|
- case OP_SorterNext: {
|
|
- pOp->p4.xAdvance = sqlite3BtreeNext;
|
|
- pOp->p4type = P4_ADVANCE;
|
|
- /* The code generator never codes any of these opcodes as a jump
|
|
- ** to a label. They are always coded as a jump backwards to a
|
|
- ** known address */
|
|
- assert( pOp->p2>=0 );
|
|
- break;
|
|
- }
|
|
- case OP_Prev: {
|
|
- pOp->p4.xAdvance = sqlite3BtreePrevious;
|
|
- pOp->p4type = P4_ADVANCE;
|
|
- /* The code generator never codes any of these opcodes as a jump
|
|
- ** to a label. They are always coded as a jump backwards to a
|
|
- ** known address */
|
|
+ case OP_Init: {
|
|
assert( pOp->p2>=0 );
|
|
- break;
|
|
+ goto resolve_p2_values_loop_exit;
|
|
}
|
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
|
case OP_VUpdate: {
|
|
@@ -78191,6 +83236,7 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
|
|
n = pOp[-1].p1;
|
|
if( n>nMaxArgs ) nMaxArgs = n;
|
|
/* Fall through into the default case */
|
|
+ /* no break */ deliberate_fall_through
|
|
}
|
|
#endif
|
|
default: {
|
|
@@ -78210,21 +83256,108 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
|
|
** have non-negative values for P2. */
|
|
assert( (sqlite3OpcodeProperty[pOp->opcode]&OPFLG_JUMP)==0 || pOp->p2>=0);
|
|
}
|
|
- if( pOp==p->aOp ) break;
|
|
+ assert( pOp>p->aOp );
|
|
pOp--;
|
|
}
|
|
- sqlite3DbFree(p->db, pParse->aLabel);
|
|
- pParse->aLabel = 0;
|
|
+resolve_p2_values_loop_exit:
|
|
+ if( aLabel ){
|
|
+ sqlite3DbNNFreeNN(p->db, pParse->aLabel);
|
|
+ pParse->aLabel = 0;
|
|
+ }
|
|
pParse->nLabel = 0;
|
|
*pMaxFuncArgs = nMaxArgs;
|
|
assert( p->bIsReader!=0 || DbMaskAllZero(p->btreeMask) );
|
|
}
|
|
|
|
+#ifdef SQLITE_DEBUG
|
|
+/*
|
|
+** Check to see if a subroutine contains a jump to a location outside of
|
|
+** the subroutine. If a jump outside the subroutine is detected, add code
|
|
+** that will cause the program to halt with an error message.
|
|
+**
|
|
+** The subroutine consists of opcodes between iFirst and iLast. Jumps to
|
|
+** locations within the subroutine are acceptable. iRetReg is a register
|
|
+** that contains the return address. Jumps to outside the range of iFirst
|
|
+** through iLast are also acceptable as long as the jump destination is
|
|
+** an OP_Return to iReturnAddr.
|
|
+**
|
|
+** A jump to an unresolved label means that the jump destination will be
|
|
+** beyond the current address. That is normally a jump to an early
|
|
+** termination and is consider acceptable.
|
|
+**
|
|
+** This routine only runs during debug builds. The purpose is (of course)
|
|
+** to detect invalid escapes out of a subroutine. The OP_Halt opcode
|
|
+** is generated rather than an assert() or other error, so that ".eqp full"
|
|
+** will still work to show the original bytecode, to aid in debugging.
|
|
+*/
|
|
+SQLITE_PRIVATE void sqlite3VdbeNoJumpsOutsideSubrtn(
|
|
+ Vdbe *v, /* The byte-code program under construction */
|
|
+ int iFirst, /* First opcode of the subroutine */
|
|
+ int iLast, /* Last opcode of the subroutine */
|
|
+ int iRetReg /* Subroutine return address register */
|
|
+){
|
|
+ VdbeOp *pOp;
|
|
+ Parse *pParse;
|
|
+ int i;
|
|
+ sqlite3_str *pErr = 0;
|
|
+ assert( v!=0 );
|
|
+ pParse = v->pParse;
|
|
+ assert( pParse!=0 );
|
|
+ if( pParse->nErr ) return;
|
|
+ assert( iLast>=iFirst );
|
|
+ assert( iLast<v->nOp );
|
|
+ pOp = &v->aOp[iFirst];
|
|
+ for(i=iFirst; i<=iLast; i++, pOp++){
|
|
+ if( (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_JUMP)!=0 ){
|
|
+ int iDest = pOp->p2; /* Jump destination */
|
|
+ if( iDest==0 ) continue;
|
|
+ if( pOp->opcode==OP_Gosub ) continue;
|
|
+ if( iDest<0 ){
|
|
+ int j = ADDR(iDest);
|
|
+ assert( j>=0 );
|
|
+ if( j>=-pParse->nLabel || pParse->aLabel[j]<0 ){
|
|
+ continue;
|
|
+ }
|
|
+ iDest = pParse->aLabel[j];
|
|
+ }
|
|
+ if( iDest<iFirst || iDest>iLast ){
|
|
+ int j = iDest;
|
|
+ for(; j<v->nOp; j++){
|
|
+ VdbeOp *pX = &v->aOp[j];
|
|
+ if( pX->opcode==OP_Return ){
|
|
+ if( pX->p1==iRetReg ) break;
|
|
+ continue;
|
|
+ }
|
|
+ if( pX->opcode==OP_Noop ) continue;
|
|
+ if( pX->opcode==OP_Explain ) continue;
|
|
+ if( pErr==0 ){
|
|
+ pErr = sqlite3_str_new(0);
|
|
+ }else{
|
|
+ sqlite3_str_appendchar(pErr, 1, '\n');
|
|
+ }
|
|
+ sqlite3_str_appendf(pErr,
|
|
+ "Opcode at %d jumps to %d which is outside the "
|
|
+ "subroutine at %d..%d",
|
|
+ i, iDest, iFirst, iLast);
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ if( pErr ){
|
|
+ char *zErr = sqlite3_str_finish(pErr);
|
|
+ sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_INTERNAL, OE_Abort, 0, zErr, 0);
|
|
+ sqlite3_free(zErr);
|
|
+ sqlite3MayAbort(pParse);
|
|
+ }
|
|
+}
|
|
+#endif /* SQLITE_DEBUG */
|
|
+
|
|
/*
|
|
** Return the address of the next instruction to be inserted.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3VdbeCurrentAddr(Vdbe *p){
|
|
- assert( p->magic==VDBE_MAGIC_INIT );
|
|
+ assert( p->eVdbeState==VDBE_INIT_STATE );
|
|
return p->nOp;
|
|
}
|
|
|
|
@@ -78272,12 +83405,12 @@ SQLITE_PRIVATE void sqlite3VdbeVerifyAbortable(Vdbe *p, int onError){
|
|
/*
|
|
** This function returns a pointer to the array of opcodes associated with
|
|
** the Vdbe passed as the first argument. It is the callers responsibility
|
|
-** to arrange for the returned array to be eventually freed using the
|
|
+** to arrange for the returned array to be eventually freed using the
|
|
** vdbeFreeOpArray() function.
|
|
**
|
|
** Before returning, *pnOp is set to the number of entries in the returned
|
|
-** array. Also, *pnMaxArg is set to the larger of its current value and
|
|
-** the number of entries in the Vdbe.apArg[] array required to execute the
|
|
+** array. Also, *pnMaxArg is set to the larger of its current value and
|
|
+** the number of entries in the Vdbe.apArg[] array required to execute the
|
|
** returned program.
|
|
*/
|
|
SQLITE_PRIVATE VdbeOp *sqlite3VdbeTakeOpArray(Vdbe *p, int *pnOp, int *pnMaxArg){
|
|
@@ -78309,7 +83442,7 @@ SQLITE_PRIVATE VdbeOp *sqlite3VdbeAddOpList(
|
|
int i;
|
|
VdbeOp *pOut, *pFirst;
|
|
assert( nOp>0 );
|
|
- assert( p->magic==VDBE_MAGIC_INIT );
|
|
+ assert( p->eVdbeState==VDBE_INIT_STATE );
|
|
if( p->nOp + nOp > p->nOpAlloc && growOpArray(p, nOp) ){
|
|
return 0;
|
|
}
|
|
@@ -78351,7 +83484,7 @@ SQLITE_PRIVATE VdbeOp *sqlite3VdbeAddOpList(
|
|
SQLITE_PRIVATE void sqlite3VdbeScanStatus(
|
|
Vdbe *p, /* VM to add scanstatus() to */
|
|
int addrExplain, /* Address of OP_Explain (or 0) */
|
|
- int addrLoop, /* Address of loop counter */
|
|
+ int addrLoop, /* Address of loop counter */
|
|
int addrVisit, /* Address of rows visited counter */
|
|
LogEst nEst, /* Estimated number of output rows */
|
|
const char *zName /* Name of table or index being scanned */
|
|
@@ -78361,6 +83494,7 @@ SQLITE_PRIVATE void sqlite3VdbeScanStatus(
|
|
aNew = (ScanStatus*)sqlite3DbRealloc(p->db, p->aScan, nByte);
|
|
if( aNew ){
|
|
ScanStatus *pNew = &aNew[p->nScan++];
|
|
+ memset(pNew, 0, sizeof(ScanStatus));
|
|
pNew->addrExplain = addrExplain;
|
|
pNew->addrLoop = addrLoop;
|
|
pNew->addrVisit = addrVisit;
|
|
@@ -78369,6 +83503,62 @@ SQLITE_PRIVATE void sqlite3VdbeScanStatus(
|
|
p->aScan = aNew;
|
|
}
|
|
}
|
|
+
|
|
+/*
|
|
+** Add the range of instructions from addrStart to addrEnd (inclusive) to
|
|
+** the set of those corresponding to the sqlite3_stmt_scanstatus() counters
|
|
+** associated with the OP_Explain instruction at addrExplain. The
|
|
+** sum of the sqlite3Hwtime() values for each of these instructions
|
|
+** will be returned for SQLITE_SCANSTAT_NCYCLE requests.
|
|
+*/
|
|
+SQLITE_PRIVATE void sqlite3VdbeScanStatusRange(
|
|
+ Vdbe *p,
|
|
+ int addrExplain,
|
|
+ int addrStart,
|
|
+ int addrEnd
|
|
+){
|
|
+ ScanStatus *pScan = 0;
|
|
+ int ii;
|
|
+ for(ii=p->nScan-1; ii>=0; ii--){
|
|
+ pScan = &p->aScan[ii];
|
|
+ if( pScan->addrExplain==addrExplain ) break;
|
|
+ pScan = 0;
|
|
+ }
|
|
+ if( pScan ){
|
|
+ if( addrEnd<0 ) addrEnd = sqlite3VdbeCurrentAddr(p)-1;
|
|
+ for(ii=0; ii<ArraySize(pScan->aAddrRange); ii+=2){
|
|
+ if( pScan->aAddrRange[ii]==0 ){
|
|
+ pScan->aAddrRange[ii] = addrStart;
|
|
+ pScan->aAddrRange[ii+1] = addrEnd;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+** Set the addresses for the SQLITE_SCANSTAT_NLOOP and SQLITE_SCANSTAT_NROW
|
|
+** counters for the query element associated with the OP_Explain at
|
|
+** addrExplain.
|
|
+*/
|
|
+SQLITE_PRIVATE void sqlite3VdbeScanStatusCounters(
|
|
+ Vdbe *p,
|
|
+ int addrExplain,
|
|
+ int addrLoop,
|
|
+ int addrVisit
|
|
+){
|
|
+ ScanStatus *pScan = 0;
|
|
+ int ii;
|
|
+ for(ii=p->nScan-1; ii>=0; ii--){
|
|
+ pScan = &p->aScan[ii];
|
|
+ if( pScan->addrExplain==addrExplain ) break;
|
|
+ pScan = 0;
|
|
+ }
|
|
+ if( pScan ){
|
|
+ pScan->addrLoop = addrLoop;
|
|
+ pScan->addrVisit = addrVisit;
|
|
+ }
|
|
+}
|
|
#endif
|
|
|
|
|
|
@@ -78377,15 +83567,19 @@ SQLITE_PRIVATE void sqlite3VdbeScanStatus(
|
|
** for a specific instruction.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3VdbeChangeOpcode(Vdbe *p, int addr, u8 iNewOpcode){
|
|
+ assert( addr>=0 );
|
|
sqlite3VdbeGetOp(p,addr)->opcode = iNewOpcode;
|
|
}
|
|
SQLITE_PRIVATE void sqlite3VdbeChangeP1(Vdbe *p, int addr, int val){
|
|
+ assert( addr>=0 );
|
|
sqlite3VdbeGetOp(p,addr)->p1 = val;
|
|
}
|
|
SQLITE_PRIVATE void sqlite3VdbeChangeP2(Vdbe *p, int addr, int val){
|
|
+ assert( addr>=0 || p->db->mallocFailed );
|
|
sqlite3VdbeGetOp(p,addr)->p2 = val;
|
|
}
|
|
SQLITE_PRIVATE void sqlite3VdbeChangeP3(Vdbe *p, int addr, int val){
|
|
+ assert( addr>=0 );
|
|
sqlite3VdbeGetOp(p,addr)->p3 = val;
|
|
}
|
|
SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe *p, u16 p5){
|
|
@@ -78393,6 +83587,18 @@ SQLITE_PRIVATE void sqlite3VdbeChangeP5(Vdbe *p, u16 p5){
|
|
if( p->nOp>0 ) p->aOp[p->nOp-1].p5 = p5;
|
|
}
|
|
|
|
+/*
|
|
+** If the previous opcode is an OP_Column that delivers results
|
|
+** into register iDest, then add the OPFLAG_TYPEOFARG flag to that
|
|
+** opcode.
|
|
+*/
|
|
+SQLITE_PRIVATE void sqlite3VdbeTypeofColumn(Vdbe *p, int iDest){
|
|
+ VdbeOp *pOp = sqlite3VdbeGetLastOp(p);
|
|
+ if( pOp->p3==iDest && pOp->opcode==OP_Column ){
|
|
+ pOp->p5 |= OPFLAG_TYPEOFARG;
|
|
+ }
|
|
+}
|
|
+
|
|
/*
|
|
** Change the P2 operand of instruction addr so that it points to
|
|
** the address of the next instruction to be coded.
|
|
@@ -78401,14 +83607,43 @@ SQLITE_PRIVATE void sqlite3VdbeJumpHere(Vdbe *p, int addr){
|
|
sqlite3VdbeChangeP2(p, addr, p->nOp);
|
|
}
|
|
|
|
+/*
|
|
+** Change the P2 operand of the jump instruction at addr so that
|
|
+** the jump lands on the next opcode. Or if the jump instruction was
|
|
+** the previous opcode (and is thus a no-op) then simply back up
|
|
+** the next instruction counter by one slot so that the jump is
|
|
+** overwritten by the next inserted opcode.
|
|
+**
|
|
+** This routine is an optimization of sqlite3VdbeJumpHere() that
|
|
+** strives to omit useless byte-code like this:
|
|
+**
|
|
+** 7 Once 0 8 0
|
|
+** 8 ...
|
|
+*/
|
|
+SQLITE_PRIVATE void sqlite3VdbeJumpHereOrPopInst(Vdbe *p, int addr){
|
|
+ if( addr==p->nOp-1 ){
|
|
+ assert( p->aOp[addr].opcode==OP_Once
|
|
+ || p->aOp[addr].opcode==OP_If
|
|
+ || p->aOp[addr].opcode==OP_FkIfZero );
|
|
+ assert( p->aOp[addr].p4type==0 );
|
|
+#ifdef SQLITE_VDBE_COVERAGE
|
|
+ sqlite3VdbeGetLastOp(p)->iSrcLine = 0; /* Erase VdbeCoverage() macros */
|
|
+#endif
|
|
+ p->nOp--;
|
|
+ }else{
|
|
+ sqlite3VdbeChangeP2(p, addr, p->nOp);
|
|
+ }
|
|
+}
|
|
+
|
|
|
|
/*
|
|
** If the input FuncDef structure is ephemeral, then free it. If
|
|
** the FuncDef is not ephermal, then do nothing.
|
|
*/
|
|
static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef){
|
|
+ assert( db!=0 );
|
|
if( (pDef->funcFlags & SQLITE_FUNC_EPHEM)!=0 ){
|
|
- sqlite3DbFreeNN(db, pDef);
|
|
+ sqlite3DbNNFreeNN(db, pDef);
|
|
}
|
|
}
|
|
|
|
@@ -78417,11 +83652,12 @@ static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef){
|
|
*/
|
|
static SQLITE_NOINLINE void freeP4Mem(sqlite3 *db, Mem *p){
|
|
if( p->szMalloc ) sqlite3DbFree(db, p->zMalloc);
|
|
- sqlite3DbFreeNN(db, p);
|
|
+ sqlite3DbNNFreeNN(db, p);
|
|
}
|
|
static SQLITE_NOINLINE void freeP4FuncCtx(sqlite3 *db, sqlite3_context *p){
|
|
+ assert( db!=0 );
|
|
freeEphemeralFunction(db, p->pFunc);
|
|
- sqlite3DbFreeNN(db, p);
|
|
+ sqlite3DbNNFreeNN(db, p);
|
|
}
|
|
static void freeP4(sqlite3 *db, int p4type, void *p4){
|
|
assert( db );
|
|
@@ -78433,9 +83669,8 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){
|
|
case P4_REAL:
|
|
case P4_INT64:
|
|
case P4_DYNAMIC:
|
|
- case P4_DYNBLOB:
|
|
case P4_INTARRAY: {
|
|
- sqlite3DbFree(db, p4);
|
|
+ if( p4 ) sqlite3DbNNFreeNN(db, p4);
|
|
break;
|
|
}
|
|
case P4_KEYINFO: {
|
|
@@ -78469,19 +83704,23 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){
|
|
|
|
/*
|
|
** Free the space allocated for aOp and any p4 values allocated for the
|
|
-** opcodes contained within. If aOp is not NULL it is assumed to contain
|
|
-** nOp entries.
|
|
+** opcodes contained within. If aOp is not NULL it is assumed to contain
|
|
+** nOp entries.
|
|
*/
|
|
static void vdbeFreeOpArray(sqlite3 *db, Op *aOp, int nOp){
|
|
+ assert( nOp>=0 );
|
|
+ assert( db!=0 );
|
|
if( aOp ){
|
|
- Op *pOp;
|
|
- for(pOp=&aOp[nOp-1]; pOp>=aOp; pOp--){
|
|
+ Op *pOp = &aOp[nOp-1];
|
|
+ while(1){ /* Exit via break */
|
|
if( pOp->p4type <= P4_FREE_IF_LE ) freeP4(db, pOp->p4type, pOp->p4.p);
|
|
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
|
|
sqlite3DbFree(db, pOp->zComment);
|
|
-#endif
|
|
+#endif
|
|
+ if( pOp==aOp ) break;
|
|
+ pOp--;
|
|
}
|
|
- sqlite3DbFreeNN(db, aOp);
|
|
+ sqlite3DbNNFreeNN(db, aOp);
|
|
}
|
|
}
|
|
|
|
@@ -78541,7 +83780,7 @@ SQLITE_PRIVATE void sqlite3VdbeReleaseRegisters(
|
|
u32 mask, /* Mask of registers to NOT release */
|
|
int bUndefine /* If true, mark registers as undefined */
|
|
){
|
|
- if( N==0 ) return;
|
|
+ if( N==0 || OptimizationDisabled(pParse->db, SQLITE_ReleaseReg) ) return;
|
|
assert( pParse->pVdbe );
|
|
assert( iFirst>=1 );
|
|
assert( iFirst+N-1<=pParse->nMem );
|
|
@@ -78574,7 +83813,7 @@ SQLITE_PRIVATE void sqlite3VdbeReleaseRegisters(
|
|
** the string is made into memory obtained from sqlite3_malloc().
|
|
** A value of n==0 means copy bytes of zP4 up to and including the
|
|
** first null byte. If n>0 then copy n+1 bytes of zP4.
|
|
-**
|
|
+**
|
|
** Other values of n (P4_STATIC, P4_COLLSEQ etc.) indicate that zP4 points
|
|
** to a string or structure that is guaranteed to exist for the lifetime of
|
|
** the Vdbe. In these cases we can just copy the pointer.
|
|
@@ -78605,7 +83844,7 @@ SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int
|
|
sqlite3 *db;
|
|
assert( p!=0 );
|
|
db = p->db;
|
|
- assert( p->magic==VDBE_MAGIC_INIT );
|
|
+ assert( p->eVdbeState==VDBE_INIT_STATE );
|
|
assert( p->aOp!=0 || db->mallocFailed );
|
|
if( db->mallocFailed ){
|
|
if( n!=P4_VTAB ) freeP4(db, n, (void*)*(char**)&zP4);
|
|
@@ -78635,7 +83874,7 @@ SQLITE_PRIVATE void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int
|
|
}
|
|
|
|
/*
|
|
-** Change the P4 operand of the most recently coded instruction
|
|
+** Change the P4 operand of the most recently coded instruction
|
|
** to the value defined by the arguments. This is a high-speed
|
|
** version of sqlite3VdbeChangeP4().
|
|
**
|
|
@@ -78650,7 +83889,7 @@ SQLITE_PRIVATE void sqlite3VdbeAppendP4(Vdbe *p, void *pP4, int n){
|
|
if( p->db->mallocFailed ){
|
|
freeP4(p->db, n, pP4);
|
|
}else{
|
|
- assert( pP4!=0 );
|
|
+ assert( pP4!=0 || n==P4_DYNAMIC );
|
|
assert( p->nOp>0 );
|
|
pOp = &p->aOp[p->nOp-1];
|
|
assert( pOp->p4type==P4_NOTUSED );
|
|
@@ -78681,8 +83920,7 @@ SQLITE_PRIVATE void sqlite3VdbeSetP4KeyInfo(Parse *pParse, Index *pIdx){
|
|
*/
|
|
static void vdbeVComment(Vdbe *p, const char *zFormat, va_list ap){
|
|
assert( p->nOp>0 || p->aOp==0 );
|
|
- assert( p->aOp==0 || p->aOp[p->nOp-1].zComment==0 || p->db->mallocFailed
|
|
- || p->pParse->nErr>0 );
|
|
+ assert( p->aOp==0 || p->aOp[p->nOp-1].zComment==0 || p->pParse->nErr>0 );
|
|
if( p->nOp ){
|
|
assert( p->aOp );
|
|
sqlite3DbFree(p->db, p->aOp[p->nOp-1].zComment);
|
|
@@ -78713,19 +83951,19 @@ SQLITE_PRIVATE void sqlite3VdbeNoopComment(Vdbe *p, const char *zFormat, ...){
|
|
** Set the value if the iSrcLine field for the previously coded instruction.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3VdbeSetLineNumber(Vdbe *v, int iLine){
|
|
- sqlite3VdbeGetOp(v,-1)->iSrcLine = iLine;
|
|
+ sqlite3VdbeGetLastOp(v)->iSrcLine = iLine;
|
|
}
|
|
#endif /* SQLITE_VDBE_COVERAGE */
|
|
|
|
/*
|
|
-** Return the opcode for a given address. If the address is -1, then
|
|
-** return the most recently inserted opcode.
|
|
+** Return the opcode for a given address. The address must be non-negative.
|
|
+** See sqlite3VdbeGetLastOp() to get the most recently added opcode.
|
|
**
|
|
** If a memory allocation error has occurred prior to the calling of this
|
|
** routine, then a pointer to a dummy VdbeOp will be returned. That opcode
|
|
** is readable but not writable, though it is cast to a writable value.
|
|
** The return of a dummy opcode allows the call to continue functioning
|
|
-** after an OOM fault without having to check to see if the return from
|
|
+** after an OOM fault without having to check to see if the return from
|
|
** this routine is a valid pointer. But because the dummy.opcode is 0,
|
|
** dummy will never be written to. This is verified by code inspection and
|
|
** by running with Valgrind.
|
|
@@ -78734,10 +83972,7 @@ SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){
|
|
/* C89 specifies that the constant "dummy" will be initialized to all
|
|
** zeros, which is correct. MSVC generates a warning, nevertheless. */
|
|
static VdbeOp dummy; /* Ignore the MSVC warning about no initializer */
|
|
- assert( p->magic==VDBE_MAGIC_INIT );
|
|
- if( addr<0 ){
|
|
- addr = p->nOp - 1;
|
|
- }
|
|
+ assert( p->eVdbeState==VDBE_INIT_STATE );
|
|
assert( (addr>=0 && addr<p->nOp) || p->db->mallocFailed );
|
|
if( p->db->mallocFailed ){
|
|
return (VdbeOp*)&dummy;
|
|
@@ -78746,6 +83981,12 @@ SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){
|
|
}
|
|
}
|
|
|
|
+/* Return the most recently added opcode
|
|
+*/
|
|
+VdbeOp * sqlite3VdbeGetLastOp(Vdbe *p){
|
|
+ return sqlite3VdbeGetOp(p, p->nOp - 1);
|
|
+}
|
|
+
|
|
#if defined(SQLITE_ENABLE_EXPLAIN_COMMENTS)
|
|
/*
|
|
** Return an integer value for one of the parameters to the opcode pOp
|
|
@@ -78772,78 +84013,90 @@ static int translateP(char c, const Op *pOp){
|
|
** "PX@PY+1" -> "r[X..X+Y]" or "r[x]" if y is 0
|
|
** "PY..PY" -> "r[X..Y]" or "r[x]" if y<=x
|
|
*/
|
|
-static int displayComment(
|
|
+SQLITE_PRIVATE char *sqlite3VdbeDisplayComment(
|
|
+ sqlite3 *db, /* Optional - Oom error reporting only */
|
|
const Op *pOp, /* The opcode to be commented */
|
|
- const char *zP4, /* Previously obtained value for P4 */
|
|
- char *zTemp, /* Write result here */
|
|
- int nTemp /* Space available in zTemp[] */
|
|
+ const char *zP4 /* Previously obtained value for P4 */
|
|
){
|
|
const char *zOpName;
|
|
const char *zSynopsis;
|
|
int nOpName;
|
|
- int ii, jj;
|
|
+ int ii;
|
|
char zAlt[50];
|
|
+ StrAccum x;
|
|
+
|
|
+ sqlite3StrAccumInit(&x, 0, 0, 0, SQLITE_MAX_LENGTH);
|
|
zOpName = sqlite3OpcodeName(pOp->opcode);
|
|
nOpName = sqlite3Strlen30(zOpName);
|
|
if( zOpName[nOpName+1] ){
|
|
int seenCom = 0;
|
|
char c;
|
|
- zSynopsis = zOpName += nOpName + 1;
|
|
+ zSynopsis = zOpName + nOpName + 1;
|
|
if( strncmp(zSynopsis,"IF ",3)==0 ){
|
|
- if( pOp->p5 & SQLITE_STOREP2 ){
|
|
- sqlite3_snprintf(sizeof(zAlt), zAlt, "r[P2] = (%s)", zSynopsis+3);
|
|
- }else{
|
|
- sqlite3_snprintf(sizeof(zAlt), zAlt, "if %s goto P2", zSynopsis+3);
|
|
- }
|
|
+ sqlite3_snprintf(sizeof(zAlt), zAlt, "if %s goto P2", zSynopsis+3);
|
|
zSynopsis = zAlt;
|
|
}
|
|
- for(ii=jj=0; jj<nTemp-1 && (c = zSynopsis[ii])!=0; ii++){
|
|
+ for(ii=0; (c = zSynopsis[ii])!=0; ii++){
|
|
if( c=='P' ){
|
|
c = zSynopsis[++ii];
|
|
if( c=='4' ){
|
|
- sqlite3_snprintf(nTemp-jj, zTemp+jj, "%s", zP4);
|
|
+ sqlite3_str_appendall(&x, zP4);
|
|
}else if( c=='X' ){
|
|
- sqlite3_snprintf(nTemp-jj, zTemp+jj, "%s", pOp->zComment);
|
|
- seenCom = 1;
|
|
+ if( pOp->zComment && pOp->zComment[0] ){
|
|
+ sqlite3_str_appendall(&x, pOp->zComment);
|
|
+ seenCom = 1;
|
|
+ break;
|
|
+ }
|
|
}else{
|
|
int v1 = translateP(c, pOp);
|
|
int v2;
|
|
- sqlite3_snprintf(nTemp-jj, zTemp+jj, "%d", v1);
|
|
if( strncmp(zSynopsis+ii+1, "@P", 2)==0 ){
|
|
ii += 3;
|
|
- jj += sqlite3Strlen30(zTemp+jj);
|
|
v2 = translateP(zSynopsis[ii], pOp);
|
|
if( strncmp(zSynopsis+ii+1,"+1",2)==0 ){
|
|
ii += 2;
|
|
v2++;
|
|
}
|
|
- if( v2>1 ){
|
|
- sqlite3_snprintf(nTemp-jj, zTemp+jj, "..%d", v1+v2-1);
|
|
+ if( v2<2 ){
|
|
+ sqlite3_str_appendf(&x, "%d", v1);
|
|
+ }else{
|
|
+ sqlite3_str_appendf(&x, "%d..%d", v1, v1+v2-1);
|
|
+ }
|
|
+ }else if( strncmp(zSynopsis+ii+1, "@NP", 3)==0 ){
|
|
+ sqlite3_context *pCtx = pOp->p4.pCtx;
|
|
+ if( pOp->p4type!=P4_FUNCCTX || pCtx->argc==1 ){
|
|
+ sqlite3_str_appendf(&x, "%d", v1);
|
|
+ }else if( pCtx->argc>1 ){
|
|
+ sqlite3_str_appendf(&x, "%d..%d", v1, v1+pCtx->argc-1);
|
|
+ }else if( x.accError==0 ){
|
|
+ assert( x.nChar>2 );
|
|
+ x.nChar -= 2;
|
|
+ ii++;
|
|
+ }
|
|
+ ii += 3;
|
|
+ }else{
|
|
+ sqlite3_str_appendf(&x, "%d", v1);
|
|
+ if( strncmp(zSynopsis+ii+1, "..P3", 4)==0 && pOp->p3==0 ){
|
|
+ ii += 4;
|
|
}
|
|
- }else if( strncmp(zSynopsis+ii+1, "..P3", 4)==0 && pOp->p3==0 ){
|
|
- ii += 4;
|
|
}
|
|
}
|
|
- jj += sqlite3Strlen30(zTemp+jj);
|
|
}else{
|
|
- zTemp[jj++] = c;
|
|
+ sqlite3_str_appendchar(&x, 1, c);
|
|
}
|
|
}
|
|
- if( !seenCom && jj<nTemp-5 && pOp->zComment ){
|
|
- sqlite3_snprintf(nTemp-jj, zTemp+jj, "; %s", pOp->zComment);
|
|
- jj += sqlite3Strlen30(zTemp+jj);
|
|
+ if( !seenCom && pOp->zComment ){
|
|
+ sqlite3_str_appendf(&x, "; %s", pOp->zComment);
|
|
}
|
|
- if( jj<nTemp ) zTemp[jj] = 0;
|
|
}else if( pOp->zComment ){
|
|
- sqlite3_snprintf(nTemp, zTemp, "%s", pOp->zComment);
|
|
- jj = sqlite3Strlen30(zTemp);
|
|
- }else{
|
|
- zTemp[0] = 0;
|
|
- jj = 0;
|
|
+ sqlite3_str_appendall(&x, pOp->zComment);
|
|
}
|
|
- return jj;
|
|
+ if( (x.accError & SQLITE_NOMEM)!=0 && db!=0 ){
|
|
+ sqlite3OomFault(db);
|
|
+ }
|
|
+ return sqlite3StrAccumFinish(&x);
|
|
}
|
|
-#endif /* SQLITE_DEBUG */
|
|
+#endif /* SQLITE_ENABLE_EXPLAIN_COMMENTS */
|
|
|
|
#if VDBE_DISPLAY_P4 && defined(SQLITE_ENABLE_CURSOR_HINTS)
|
|
/*
|
|
@@ -78854,6 +84107,7 @@ static void displayP4Expr(StrAccum *p, Expr *pExpr){
|
|
const char *zOp = 0;
|
|
switch( pExpr->op ){
|
|
case TK_STRING:
|
|
+ assert( !ExprHasProperty(pExpr, EP_IntValue) );
|
|
sqlite3_str_appendf(p, "%Q", pExpr->u.zToken);
|
|
break;
|
|
case TK_INTEGER:
|
|
@@ -78924,11 +84178,11 @@ static void displayP4Expr(StrAccum *p, Expr *pExpr){
|
|
** Compute a string that describes the P4 parameter for an opcode.
|
|
** Use zTemp for any required temporary buffer space.
|
|
*/
|
|
-static char *displayP4(Op *pOp, char *zTemp, int nTemp){
|
|
- char *zP4 = zTemp;
|
|
+SQLITE_PRIVATE char *sqlite3VdbeDisplayP4(sqlite3 *db, Op *pOp){
|
|
+ char *zP4 = 0;
|
|
StrAccum x;
|
|
- assert( nTemp>=20 );
|
|
- sqlite3StrAccumInit(&x, 0, zTemp, nTemp, 0);
|
|
+
|
|
+ sqlite3StrAccumInit(&x, 0, 0, 0, SQLITE_MAX_LENGTH);
|
|
switch( pOp->p4type ){
|
|
case P4_KEYINFO: {
|
|
int j;
|
|
@@ -78939,9 +84193,9 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
|
|
CollSeq *pColl = pKeyInfo->aColl[j];
|
|
const char *zColl = pColl ? pColl->zName : "";
|
|
if( strcmp(zColl, "BINARY")==0 ) zColl = "B";
|
|
- sqlite3_str_appendf(&x, ",%s%s%s",
|
|
- (pKeyInfo->aSortFlags[j] & KEYINFO_ORDER_DESC) ? "-" : "",
|
|
- (pKeyInfo->aSortFlags[j] & KEYINFO_ORDER_BIGNULL)? "N." : "",
|
|
+ sqlite3_str_appendf(&x, ",%s%s%s",
|
|
+ (pKeyInfo->aSortFlags[j] & KEYINFO_ORDER_DESC) ? "-" : "",
|
|
+ (pKeyInfo->aSortFlags[j] & KEYINFO_ORDER_BIGNULL)? "N." : "",
|
|
zColl);
|
|
}
|
|
sqlite3_str_append(&x, ")", 1);
|
|
@@ -78954,8 +84208,11 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
|
|
}
|
|
#endif
|
|
case P4_COLLSEQ: {
|
|
+ static const char *const encnames[] = {"?", "8", "16LE", "16BE"};
|
|
CollSeq *pColl = pOp->p4.pColl;
|
|
- sqlite3_str_appendf(&x, "(%.20s)", pColl->zName);
|
|
+ assert( pColl->enc<4 );
|
|
+ sqlite3_str_appendf(&x, "%.18s-%s", pColl->zName,
|
|
+ encnames[pColl->enc]);
|
|
break;
|
|
}
|
|
case P4_FUNCDEF: {
|
|
@@ -79004,41 +84261,33 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
|
|
}
|
|
#endif
|
|
case P4_INTARRAY: {
|
|
- int i;
|
|
- int *ai = pOp->p4.ai;
|
|
- int n = ai[0]; /* The first element of an INTARRAY is always the
|
|
+ u32 i;
|
|
+ u32 *ai = pOp->p4.ai;
|
|
+ u32 n = ai[0]; /* The first element of an INTARRAY is always the
|
|
** count of the number of elements to follow */
|
|
for(i=1; i<=n; i++){
|
|
- sqlite3_str_appendf(&x, ",%d", ai[i]);
|
|
+ sqlite3_str_appendf(&x, "%c%u", (i==1 ? '[' : ','), ai[i]);
|
|
}
|
|
- zTemp[0] = '[';
|
|
sqlite3_str_append(&x, "]", 1);
|
|
break;
|
|
}
|
|
case P4_SUBPROGRAM: {
|
|
- sqlite3_str_appendf(&x, "program");
|
|
- break;
|
|
- }
|
|
- case P4_DYNBLOB:
|
|
- case P4_ADVANCE: {
|
|
- zTemp[0] = 0;
|
|
+ zP4 = "program";
|
|
break;
|
|
}
|
|
case P4_TABLE: {
|
|
- sqlite3_str_appendf(&x, "%s", pOp->p4.pTab->zName);
|
|
+ zP4 = pOp->p4.pTab->zName;
|
|
break;
|
|
}
|
|
default: {
|
|
zP4 = pOp->p4.z;
|
|
- if( zP4==0 ){
|
|
- zP4 = zTemp;
|
|
- zTemp[0] = 0;
|
|
- }
|
|
}
|
|
}
|
|
- sqlite3StrAccumFinish(&x);
|
|
- assert( zP4!=0 );
|
|
- return zP4;
|
|
+ if( zP4 ) sqlite3_str_appendall(&x, zP4);
|
|
+ if( (x.accError & SQLITE_NOMEM)!=0 ){
|
|
+ sqlite3OomFault(db);
|
|
+ }
|
|
+ return sqlite3StrAccumFinish(&x);
|
|
}
|
|
#endif /* VDBE_DISPLAY_P4 */
|
|
|
|
@@ -79069,13 +84318,13 @@ SQLITE_PRIVATE void sqlite3VdbeUsesBtree(Vdbe *p, int i){
|
|
**
|
|
** If SQLite is not threadsafe but does support shared-cache mode, then
|
|
** sqlite3BtreeEnter() is invoked to set the BtShared.db variables
|
|
-** of all of BtShared structures accessible via the database handle
|
|
+** of all of BtShared structures accessible via the database handle
|
|
** associated with the VM.
|
|
**
|
|
** If SQLite is not threadsafe and does not support shared-cache mode, this
|
|
** function is a no-op.
|
|
**
|
|
-** The p->btreeMask field is a bitmask of all btrees that the prepared
|
|
+** The p->btreeMask field is a bitmask of all btrees that the prepared
|
|
** statement p will ever use. Let N be the number of bits in p->btreeMask
|
|
** corresponding to btrees that use shared cache. Then the runtime of
|
|
** this routine is N*N. But as N is rarely more than 1, this should not
|
|
@@ -79128,44 +84377,69 @@ SQLITE_PRIVATE void sqlite3VdbeLeave(Vdbe *p){
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE *pOut, int pc, VdbeOp *pOp){
|
|
char *zP4;
|
|
- char zPtr[50];
|
|
- char zCom[100];
|
|
+ char *zCom;
|
|
+ sqlite3 dummyDb;
|
|
static const char *zFormat1 = "%4d %-13s %4d %4d %4d %-13s %.2X %s\n";
|
|
if( pOut==0 ) pOut = stdout;
|
|
- zP4 = displayP4(pOp, zPtr, sizeof(zPtr));
|
|
+ sqlite3BeginBenignMalloc();
|
|
+ dummyDb.mallocFailed = 1;
|
|
+ zP4 = sqlite3VdbeDisplayP4(&dummyDb, pOp);
|
|
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
|
|
- displayComment(pOp, zP4, zCom, sizeof(zCom));
|
|
+ zCom = sqlite3VdbeDisplayComment(0, pOp, zP4);
|
|
#else
|
|
- zCom[0] = 0;
|
|
+ zCom = 0;
|
|
#endif
|
|
/* NB: The sqlite3OpcodeName() function is implemented by code created
|
|
** by the mkopcodeh.awk and mkopcodec.awk scripts which extract the
|
|
** information from the vdbe.c source text */
|
|
- fprintf(pOut, zFormat1, pc,
|
|
- sqlite3OpcodeName(pOp->opcode), pOp->p1, pOp->p2, pOp->p3, zP4, pOp->p5,
|
|
- zCom
|
|
+ fprintf(pOut, zFormat1, pc,
|
|
+ sqlite3OpcodeName(pOp->opcode), pOp->p1, pOp->p2, pOp->p3,
|
|
+ zP4 ? zP4 : "", pOp->p5,
|
|
+ zCom ? zCom : ""
|
|
);
|
|
fflush(pOut);
|
|
+ sqlite3_free(zP4);
|
|
+ sqlite3_free(zCom);
|
|
+ sqlite3EndBenignMalloc();
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
** Initialize an array of N Mem element.
|
|
+**
|
|
+** This is a high-runner, so only those fields that really do need to
|
|
+** be initialized are set. The Mem structure is organized so that
|
|
+** the fields that get initialized are nearby and hopefully on the same
|
|
+** cache line.
|
|
+**
|
|
+** Mem.flags = flags
|
|
+** Mem.db = db
|
|
+** Mem.szMalloc = 0
|
|
+**
|
|
+** All other fields of Mem can safely remain uninitialized for now. They
|
|
+** will be initialized before use.
|
|
*/
|
|
static void initMemArray(Mem *p, int N, sqlite3 *db, u16 flags){
|
|
- while( (N--)>0 ){
|
|
- p->db = db;
|
|
- p->flags = flags;
|
|
- p->szMalloc = 0;
|
|
+ if( N>0 ){
|
|
+ do{
|
|
+ p->flags = flags;
|
|
+ p->db = db;
|
|
+ p->szMalloc = 0;
|
|
#ifdef SQLITE_DEBUG
|
|
- p->pScopyFrom = 0;
|
|
+ p->pScopyFrom = 0;
|
|
#endif
|
|
- p++;
|
|
+ p++;
|
|
+ }while( (--N)>0 );
|
|
}
|
|
}
|
|
|
|
/*
|
|
-** Release an array of N Mem elements
|
|
+** Release auxiliary memory held in an array of N Mem elements.
|
|
+**
|
|
+** After this routine returns, all Mem elements in the array will still
|
|
+** be valid. Those Mem elements that were not holding auxiliary resources
|
|
+** will be unchanged. Mem elements which had something freed will be
|
|
+** set to MEM_Undefined.
|
|
*/
|
|
static void releaseMemArray(Mem *p, int N){
|
|
if( p && N ){
|
|
@@ -79182,28 +84456,33 @@ static void releaseMemArray(Mem *p, int N){
|
|
assert( sqlite3VdbeCheckMemInvariants(p) );
|
|
|
|
/* This block is really an inlined version of sqlite3VdbeMemRelease()
|
|
- ** that takes advantage of the fact that the memory cell value is
|
|
+ ** that takes advantage of the fact that the memory cell value is
|
|
** being set to NULL after releasing any dynamic resources.
|
|
**
|
|
- ** The justification for duplicating code is that according to
|
|
- ** callgrind, this causes a certain test case to hit the CPU 4.7
|
|
- ** percent less (x86 linux, gcc version 4.1.2, -O6) than if
|
|
+ ** The justification for duplicating code is that according to
|
|
+ ** callgrind, this causes a certain test case to hit the CPU 4.7
|
|
+ ** percent less (x86 linux, gcc version 4.1.2, -O6) than if
|
|
** sqlite3MemRelease() were called from here. With -O2, this jumps
|
|
- ** to 6.6 percent. The test case is inserting 1000 rows into a table
|
|
- ** with no indexes using a single prepared INSERT statement, bind()
|
|
+ ** to 6.6 percent. The test case is inserting 1000 rows into a table
|
|
+ ** with no indexes using a single prepared INSERT statement, bind()
|
|
** and reset(). Inserts are grouped into a transaction.
|
|
*/
|
|
testcase( p->flags & MEM_Agg );
|
|
testcase( p->flags & MEM_Dyn );
|
|
- testcase( p->xDel==sqlite3VdbeFrameMemDel );
|
|
if( p->flags&(MEM_Agg|MEM_Dyn) ){
|
|
+ testcase( (p->flags & MEM_Dyn)!=0 && p->xDel==sqlite3VdbeFrameMemDel );
|
|
sqlite3VdbeMemRelease(p);
|
|
+ p->flags = MEM_Undefined;
|
|
}else if( p->szMalloc ){
|
|
- sqlite3DbFreeNN(db, p->zMalloc);
|
|
+ sqlite3DbNNFreeNN(db, p->zMalloc);
|
|
p->szMalloc = 0;
|
|
+ p->flags = MEM_Undefined;
|
|
}
|
|
-
|
|
- p->flags = MEM_Undefined;
|
|
+#ifdef SQLITE_DEBUG
|
|
+ else{
|
|
+ p->flags = MEM_Undefined;
|
|
+ }
|
|
+#endif
|
|
}while( (++p)<pEnd );
|
|
}
|
|
}
|
|
@@ -79236,6 +84515,121 @@ SQLITE_PRIVATE void sqlite3VdbeFrameMemDel(void *pArg){
|
|
pFrame->v->pDelFrame = pFrame;
|
|
}
|
|
|
|
+#if defined(SQLITE_ENABLE_BYTECODE_VTAB) || !defined(SQLITE_OMIT_EXPLAIN)
|
|
+/*
|
|
+** Locate the next opcode to be displayed in EXPLAIN or EXPLAIN
|
|
+** QUERY PLAN output.
|
|
+**
|
|
+** Return SQLITE_ROW on success. Return SQLITE_DONE if there are no
|
|
+** more opcodes to be displayed.
|
|
+*/
|
|
+SQLITE_PRIVATE int sqlite3VdbeNextOpcode(
|
|
+ Vdbe *p, /* The statement being explained */
|
|
+ Mem *pSub, /* Storage for keeping track of subprogram nesting */
|
|
+ int eMode, /* 0: normal. 1: EQP. 2: TablesUsed */
|
|
+ int *piPc, /* IN/OUT: Current rowid. Overwritten with next rowid */
|
|
+ int *piAddr, /* OUT: Write index into (*paOp)[] here */
|
|
+ Op **paOp /* OUT: Write the opcode array here */
|
|
+){
|
|
+ int nRow; /* Stop when row count reaches this */
|
|
+ int nSub = 0; /* Number of sub-vdbes seen so far */
|
|
+ SubProgram **apSub = 0; /* Array of sub-vdbes */
|
|
+ int i; /* Next instruction address */
|
|
+ int rc = SQLITE_OK; /* Result code */
|
|
+ Op *aOp = 0; /* Opcode array */
|
|
+ int iPc; /* Rowid. Copy of value in *piPc */
|
|
+
|
|
+ /* When the number of output rows reaches nRow, that means the
|
|
+ ** listing has finished and sqlite3_step() should return SQLITE_DONE.
|
|
+ ** nRow is the sum of the number of rows in the main program, plus
|
|
+ ** the sum of the number of rows in all trigger subprograms encountered
|
|
+ ** so far. The nRow value will increase as new trigger subprograms are
|
|
+ ** encountered, but p->pc will eventually catch up to nRow.
|
|
+ */
|
|
+ nRow = p->nOp;
|
|
+ if( pSub!=0 ){
|
|
+ if( pSub->flags&MEM_Blob ){
|
|
+ /* pSub is initiallly NULL. It is initialized to a BLOB by
|
|
+ ** the P4_SUBPROGRAM processing logic below */
|
|
+ nSub = pSub->n/sizeof(Vdbe*);
|
|
+ apSub = (SubProgram **)pSub->z;
|
|
+ }
|
|
+ for(i=0; i<nSub; i++){
|
|
+ nRow += apSub[i]->nOp;
|
|
+ }
|
|
+ }
|
|
+ iPc = *piPc;
|
|
+ while(1){ /* Loop exits via break */
|
|
+ i = iPc++;
|
|
+ if( i>=nRow ){
|
|
+ p->rc = SQLITE_OK;
|
|
+ rc = SQLITE_DONE;
|
|
+ break;
|
|
+ }
|
|
+ if( i<p->nOp ){
|
|
+ /* The rowid is small enough that we are still in the
|
|
+ ** main program. */
|
|
+ aOp = p->aOp;
|
|
+ }else{
|
|
+ /* We are currently listing subprograms. Figure out which one and
|
|
+ ** pick up the appropriate opcode. */
|
|
+ int j;
|
|
+ i -= p->nOp;
|
|
+ assert( apSub!=0 );
|
|
+ assert( nSub>0 );
|
|
+ for(j=0; i>=apSub[j]->nOp; j++){
|
|
+ i -= apSub[j]->nOp;
|
|
+ assert( i<apSub[j]->nOp || j+1<nSub );
|
|
+ }
|
|
+ aOp = apSub[j]->aOp;
|
|
+ }
|
|
+
|
|
+ /* When an OP_Program opcode is encounter (the only opcode that has
|
|
+ ** a P4_SUBPROGRAM argument), expand the size of the array of subprograms
|
|
+ ** kept in p->aMem[9].z to hold the new program - assuming this subprogram
|
|
+ ** has not already been seen.
|
|
+ */
|
|
+ if( pSub!=0 && aOp[i].p4type==P4_SUBPROGRAM ){
|
|
+ int nByte = (nSub+1)*sizeof(SubProgram*);
|
|
+ int j;
|
|
+ for(j=0; j<nSub; j++){
|
|
+ if( apSub[j]==aOp[i].p4.pProgram ) break;
|
|
+ }
|
|
+ if( j==nSub ){
|
|
+ p->rc = sqlite3VdbeMemGrow(pSub, nByte, nSub!=0);
|
|
+ if( p->rc!=SQLITE_OK ){
|
|
+ rc = SQLITE_ERROR;
|
|
+ break;
|
|
+ }
|
|
+ apSub = (SubProgram **)pSub->z;
|
|
+ apSub[nSub++] = aOp[i].p4.pProgram;
|
|
+ MemSetTypeFlag(pSub, MEM_Blob);
|
|
+ pSub->n = nSub*sizeof(SubProgram*);
|
|
+ nRow += aOp[i].p4.pProgram->nOp;
|
|
+ }
|
|
+ }
|
|
+ if( eMode==0 ) break;
|
|
+#ifdef SQLITE_ENABLE_BYTECODE_VTAB
|
|
+ if( eMode==2 ){
|
|
+ Op *pOp = aOp + i;
|
|
+ if( pOp->opcode==OP_OpenRead ) break;
|
|
+ if( pOp->opcode==OP_OpenWrite && (pOp->p5 & OPFLAG_P2ISREG)==0 ) break;
|
|
+ if( pOp->opcode==OP_ReopenIdx ) break;
|
|
+ }else
|
|
+#endif
|
|
+ {
|
|
+ assert( eMode==1 );
|
|
+ if( aOp[i].opcode==OP_Explain ) break;
|
|
+ if( aOp[i].opcode==OP_Init && iPc>1 ) break;
|
|
+ }
|
|
+ }
|
|
+ *piPc = iPc;
|
|
+ *piAddr = i;
|
|
+ *paOp = aOp;
|
|
+ return rc;
|
|
+}
|
|
+#endif /* SQLITE_ENABLE_BYTECODE_VTAB || !SQLITE_OMIT_EXPLAIN */
|
|
+
|
|
|
|
/*
|
|
** Delete a VdbeFrame object and its contents. VdbeFrame objects are
|
|
@@ -79247,7 +84641,7 @@ SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame *p){
|
|
VdbeCursor **apCsr = (VdbeCursor **)&aMem[p->nChildMem];
|
|
assert( sqlite3VdbeFrameIsValid(p) );
|
|
for(i=0; i<p->nChildCsr; i++){
|
|
- sqlite3VdbeFreeCursor(p->v, apCsr[i]);
|
|
+ if( apCsr[i] ) sqlite3VdbeFreeCursorNN(p->v, apCsr[i]);
|
|
}
|
|
releaseMemArray(aMem, p->nChildMem);
|
|
sqlite3VdbeDeleteAuxData(p->v->db, &p->pAuxData, -1, 0);
|
|
@@ -79276,19 +84670,17 @@ SQLITE_PRIVATE void sqlite3VdbeFrameDelete(VdbeFrame *p){
|
|
SQLITE_PRIVATE int sqlite3VdbeList(
|
|
Vdbe *p /* The VDBE */
|
|
){
|
|
- int nRow; /* Stop when row count reaches this */
|
|
- int nSub = 0; /* Number of sub-vdbes seen so far */
|
|
- SubProgram **apSub = 0; /* Array of sub-vdbes */
|
|
Mem *pSub = 0; /* Memory cell hold array of subprogs */
|
|
sqlite3 *db = p->db; /* The database connection */
|
|
int i; /* Loop counter */
|
|
int rc = SQLITE_OK; /* Return code */
|
|
Mem *pMem = &p->aMem[1]; /* First Mem of result set */
|
|
int bListSubprogs = (p->explain==1 || (db->flags & SQLITE_TriggerEQP)!=0);
|
|
- Op *pOp = 0;
|
|
+ Op *aOp; /* Array of opcodes */
|
|
+ Op *pOp; /* Current opcode */
|
|
|
|
assert( p->explain );
|
|
- assert( p->magic==VDBE_MAGIC_RUN );
|
|
+ assert( p->eVdbeState==VDBE_RUN_STATE );
|
|
assert( p->rc==SQLITE_OK || p->rc==SQLITE_BUSY || p->rc==SQLITE_NOMEM );
|
|
|
|
/* Even though this opcode does not use dynamic strings for
|
|
@@ -79296,7 +84688,6 @@ SQLITE_PRIVATE int sqlite3VdbeList(
|
|
** sqlite3_column_text16(), causing a translation to UTF-16 encoding.
|
|
*/
|
|
releaseMemArray(pMem, 8);
|
|
- p->pResultSet = 0;
|
|
|
|
if( p->rc==SQLITE_NOMEM ){
|
|
/* This happens if a malloc() inside a call to sqlite3_column_text() or
|
|
@@ -79305,14 +84696,6 @@ SQLITE_PRIVATE int sqlite3VdbeList(
|
|
return SQLITE_ERROR;
|
|
}
|
|
|
|
- /* When the number of output rows reaches nRow, that means the
|
|
- ** listing has finished and sqlite3_step() should return SQLITE_DONE.
|
|
- ** nRow is the sum of the number of rows in the main program, plus
|
|
- ** the sum of the number of rows in all trigger subprograms encountered
|
|
- ** so far. The nRow value will increase as new trigger subprograms are
|
|
- ** encountered, but p->pc will eventually catch up to nRow.
|
|
- */
|
|
- nRow = p->nOp;
|
|
if( bListSubprogs ){
|
|
/* The first 8 memory cells are used for the result set. So we will
|
|
** commandeer the 9th cell to use as storage for an array of pointers
|
|
@@ -79320,147 +84703,55 @@ SQLITE_PRIVATE int sqlite3VdbeList(
|
|
** cells. */
|
|
assert( p->nMem>9 );
|
|
pSub = &p->aMem[9];
|
|
- if( pSub->flags&MEM_Blob ){
|
|
- /* On the first call to sqlite3_step(), pSub will hold a NULL. It is
|
|
- ** initialized to a BLOB by the P4_SUBPROGRAM processing logic below */
|
|
- nSub = pSub->n/sizeof(Vdbe*);
|
|
- apSub = (SubProgram **)pSub->z;
|
|
- }
|
|
- for(i=0; i<nSub; i++){
|
|
- nRow += apSub[i]->nOp;
|
|
- }
|
|
+ }else{
|
|
+ pSub = 0;
|
|
}
|
|
|
|
- while(1){ /* Loop exits via break */
|
|
- i = p->pc++;
|
|
- if( i>=nRow ){
|
|
- p->rc = SQLITE_OK;
|
|
- rc = SQLITE_DONE;
|
|
- break;
|
|
- }
|
|
- if( i<p->nOp ){
|
|
- /* The output line number is small enough that we are still in the
|
|
- ** main program. */
|
|
- pOp = &p->aOp[i];
|
|
- }else{
|
|
- /* We are currently listing subprograms. Figure out which one and
|
|
- ** pick up the appropriate opcode. */
|
|
- int j;
|
|
- i -= p->nOp;
|
|
- assert( apSub!=0 );
|
|
- assert( nSub>0 );
|
|
- for(j=0; i>=apSub[j]->nOp; j++){
|
|
- i -= apSub[j]->nOp;
|
|
- assert( i<apSub[j]->nOp || j+1<nSub );
|
|
- }
|
|
- pOp = &apSub[j]->aOp[i];
|
|
- }
|
|
-
|
|
- /* When an OP_Program opcode is encounter (the only opcode that has
|
|
- ** a P4_SUBPROGRAM argument), expand the size of the array of subprograms
|
|
- ** kept in p->aMem[9].z to hold the new program - assuming this subprogram
|
|
- ** has not already been seen.
|
|
- */
|
|
- if( bListSubprogs && pOp->p4type==P4_SUBPROGRAM ){
|
|
- int nByte = (nSub+1)*sizeof(SubProgram*);
|
|
- int j;
|
|
- for(j=0; j<nSub; j++){
|
|
- if( apSub[j]==pOp->p4.pProgram ) break;
|
|
- }
|
|
- if( j==nSub ){
|
|
- p->rc = sqlite3VdbeMemGrow(pSub, nByte, nSub!=0);
|
|
- if( p->rc!=SQLITE_OK ){
|
|
- rc = SQLITE_ERROR;
|
|
- break;
|
|
- }
|
|
- apSub = (SubProgram **)pSub->z;
|
|
- apSub[nSub++] = pOp->p4.pProgram;
|
|
- pSub->flags |= MEM_Blob;
|
|
- pSub->n = nSub*sizeof(SubProgram*);
|
|
- nRow += pOp->p4.pProgram->nOp;
|
|
- }
|
|
- }
|
|
- if( p->explain<2 ) break;
|
|
- if( pOp->opcode==OP_Explain ) break;
|
|
- if( pOp->opcode==OP_Init && p->pc>1 ) break;
|
|
- }
|
|
+ /* Figure out which opcode is next to display */
|
|
+ rc = sqlite3VdbeNextOpcode(p, pSub, p->explain==2, &p->pc, &i, &aOp);
|
|
|
|
if( rc==SQLITE_OK ){
|
|
- if( db->u1.isInterrupted ){
|
|
+ pOp = aOp + i;
|
|
+ if( AtomicLoad(&db->u1.isInterrupted) ){
|
|
p->rc = SQLITE_INTERRUPT;
|
|
rc = SQLITE_ERROR;
|
|
sqlite3VdbeError(p, sqlite3ErrStr(p->rc));
|
|
}else{
|
|
- char *zP4;
|
|
- if( p->explain==1 ){
|
|
- pMem->flags = MEM_Int;
|
|
- pMem->u.i = i; /* Program counter */
|
|
- pMem++;
|
|
-
|
|
- pMem->flags = MEM_Static|MEM_Str|MEM_Term;
|
|
- pMem->z = (char*)sqlite3OpcodeName(pOp->opcode); /* Opcode */
|
|
- assert( pMem->z!=0 );
|
|
- pMem->n = sqlite3Strlen30(pMem->z);
|
|
- pMem->enc = SQLITE_UTF8;
|
|
- pMem++;
|
|
- }
|
|
-
|
|
- pMem->flags = MEM_Int;
|
|
- pMem->u.i = pOp->p1; /* P1 */
|
|
- pMem++;
|
|
-
|
|
- pMem->flags = MEM_Int;
|
|
- pMem->u.i = pOp->p2; /* P2 */
|
|
- pMem++;
|
|
-
|
|
- pMem->flags = MEM_Int;
|
|
- pMem->u.i = pOp->p3; /* P3 */
|
|
- pMem++;
|
|
-
|
|
- if( sqlite3VdbeMemClearAndResize(pMem, 100) ){ /* P4 */
|
|
- assert( p->db->mallocFailed );
|
|
- return SQLITE_ERROR;
|
|
- }
|
|
- pMem->flags = MEM_Str|MEM_Term;
|
|
- zP4 = displayP4(pOp, pMem->z, pMem->szMalloc);
|
|
- if( zP4!=pMem->z ){
|
|
- pMem->n = 0;
|
|
- sqlite3VdbeMemSetStr(pMem, zP4, -1, SQLITE_UTF8, 0);
|
|
+ char *zP4 = sqlite3VdbeDisplayP4(db, pOp);
|
|
+ if( p->explain==2 ){
|
|
+ sqlite3VdbeMemSetInt64(pMem, pOp->p1);
|
|
+ sqlite3VdbeMemSetInt64(pMem+1, pOp->p2);
|
|
+ sqlite3VdbeMemSetInt64(pMem+2, pOp->p3);
|
|
+ sqlite3VdbeMemSetStr(pMem+3, zP4, -1, SQLITE_UTF8, sqlite3_free);
|
|
+ p->nResColumn = 4;
|
|
}else{
|
|
- assert( pMem->z!=0 );
|
|
- pMem->n = sqlite3Strlen30(pMem->z);
|
|
- pMem->enc = SQLITE_UTF8;
|
|
- }
|
|
- pMem++;
|
|
-
|
|
- if( p->explain==1 ){
|
|
- if( sqlite3VdbeMemClearAndResize(pMem, 4) ){
|
|
- assert( p->db->mallocFailed );
|
|
- return SQLITE_ERROR;
|
|
- }
|
|
- pMem->flags = MEM_Str|MEM_Term;
|
|
- pMem->n = 2;
|
|
- sqlite3_snprintf(3, pMem->z, "%.2x", pOp->p5); /* P5 */
|
|
- pMem->enc = SQLITE_UTF8;
|
|
- pMem++;
|
|
-
|
|
+ sqlite3VdbeMemSetInt64(pMem+0, i);
|
|
+ sqlite3VdbeMemSetStr(pMem+1, (char*)sqlite3OpcodeName(pOp->opcode),
|
|
+ -1, SQLITE_UTF8, SQLITE_STATIC);
|
|
+ sqlite3VdbeMemSetInt64(pMem+2, pOp->p1);
|
|
+ sqlite3VdbeMemSetInt64(pMem+3, pOp->p2);
|
|
+ sqlite3VdbeMemSetInt64(pMem+4, pOp->p3);
|
|
+ /* pMem+5 for p4 is done last */
|
|
+ sqlite3VdbeMemSetInt64(pMem+6, pOp->p5);
|
|
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
|
|
- if( sqlite3VdbeMemClearAndResize(pMem, 500) ){
|
|
- assert( p->db->mallocFailed );
|
|
- return SQLITE_ERROR;
|
|
+ {
|
|
+ char *zCom = sqlite3VdbeDisplayComment(db, pOp, zP4);
|
|
+ sqlite3VdbeMemSetStr(pMem+7, zCom, -1, SQLITE_UTF8, sqlite3_free);
|
|
}
|
|
- pMem->flags = MEM_Str|MEM_Term;
|
|
- pMem->n = displayComment(pOp, zP4, pMem->z, 500);
|
|
- pMem->enc = SQLITE_UTF8;
|
|
#else
|
|
- pMem->flags = MEM_Null; /* Comment */
|
|
+ sqlite3VdbeMemSetNull(pMem+7);
|
|
#endif
|
|
+ sqlite3VdbeMemSetStr(pMem+5, zP4, -1, SQLITE_UTF8, sqlite3_free);
|
|
+ p->nResColumn = 8;
|
|
+ }
|
|
+ p->pResultRow = pMem;
|
|
+ if( db->mallocFailed ){
|
|
+ p->rc = SQLITE_NOMEM;
|
|
+ rc = SQLITE_ERROR;
|
|
+ }else{
|
|
+ p->rc = SQLITE_OK;
|
|
+ rc = SQLITE_ROW;
|
|
}
|
|
-
|
|
- p->nResColumn = 8 - 4*(p->explain-1);
|
|
- p->pResultSet = &p->aMem[1];
|
|
- p->rc = SQLITE_OK;
|
|
- rc = SQLITE_ROW;
|
|
}
|
|
}
|
|
return rc;
|
|
@@ -79543,11 +84834,11 @@ struct ReusableSpace {
|
|
static void *allocSpace(
|
|
struct ReusableSpace *p, /* Bulk memory available for allocation */
|
|
void *pBuf, /* Pointer to a prior allocation */
|
|
- sqlite3_int64 nByte /* Bytes of memory needed */
|
|
+ sqlite3_int64 nByte /* Bytes of memory needed. */
|
|
){
|
|
assert( EIGHT_BYTE_ALIGNMENT(p->pSpace) );
|
|
if( pBuf==0 ){
|
|
- nByte = ROUND8(nByte);
|
|
+ nByte = ROUND8P(nByte);
|
|
if( nByte <= p->nFree ){
|
|
p->nFree -= nByte;
|
|
pBuf = &p->pSpace[p->nFree];
|
|
@@ -79564,18 +84855,19 @@ static void *allocSpace(
|
|
** running it.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3VdbeRewind(Vdbe *p){
|
|
-#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
|
|
+#if defined(SQLITE_DEBUG)
|
|
int i;
|
|
#endif
|
|
assert( p!=0 );
|
|
- assert( p->magic==VDBE_MAGIC_INIT || p->magic==VDBE_MAGIC_RESET );
|
|
+ assert( p->eVdbeState==VDBE_INIT_STATE
|
|
+ || p->eVdbeState==VDBE_READY_STATE
|
|
+ || p->eVdbeState==VDBE_HALT_STATE );
|
|
|
|
/* There should be at least one opcode.
|
|
*/
|
|
assert( p->nOp>0 );
|
|
|
|
- /* Set the magic to VDBE_MAGIC_RUN sooner rather than later. */
|
|
- p->magic = VDBE_MAGIC_RUN;
|
|
+ p->eVdbeState = VDBE_READY_STATE;
|
|
|
|
#ifdef SQLITE_DEBUG
|
|
for(i=0; i<p->nMem; i++){
|
|
@@ -79592,8 +84884,8 @@ SQLITE_PRIVATE void sqlite3VdbeRewind(Vdbe *p){
|
|
p->nFkConstraint = 0;
|
|
#ifdef VDBE_PROFILE
|
|
for(i=0; i<p->nOp; i++){
|
|
- p->aOp[i].cnt = 0;
|
|
- p->aOp[i].cycles = 0;
|
|
+ p->aOp[i].nExec = 0;
|
|
+ p->aOp[i].nCycle = 0;
|
|
}
|
|
#endif
|
|
}
|
|
@@ -79603,11 +84895,11 @@ SQLITE_PRIVATE void sqlite3VdbeRewind(Vdbe *p){
|
|
** creating the virtual machine. This involves things such
|
|
** as allocating registers and initializing the program counter.
|
|
** After the VDBE has be prepped, it can be executed by one or more
|
|
-** calls to sqlite3VdbeExec().
|
|
+** calls to sqlite3VdbeExec().
|
|
**
|
|
** This function may be called exactly once on each virtual machine.
|
|
** After this routine is called the VM has been "packaged" and is ready
|
|
-** to run. After this routine is called, further calls to
|
|
+** to run. After this routine is called, further calls to
|
|
** sqlite3VdbeAddOp() functions are prohibited. This routine disconnects
|
|
** the Vdbe from the Parse object that helped generate it so that the
|
|
** the Vdbe becomes an independent entity and the Parse object can be
|
|
@@ -79631,15 +84923,17 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady(
|
|
assert( p!=0 );
|
|
assert( p->nOp>0 );
|
|
assert( pParse!=0 );
|
|
- assert( p->magic==VDBE_MAGIC_INIT );
|
|
+ assert( p->eVdbeState==VDBE_INIT_STATE );
|
|
assert( pParse==p->pParse );
|
|
+ p->pVList = pParse->pVList;
|
|
+ pParse->pVList = 0;
|
|
db = p->db;
|
|
assert( db->mallocFailed==0 );
|
|
nVar = pParse->nVar;
|
|
nMem = pParse->nMem;
|
|
nCursor = pParse->nTab;
|
|
nArg = pParse->nMaxArg;
|
|
-
|
|
+
|
|
/* Each cursor uses a memory cell. The first cursor (cursor 0) can
|
|
** use aMem[0] which is not otherwise used by the VDBE program. Allocate
|
|
** space at the end of aMem[] for cursors 1 and greater.
|
|
@@ -79652,7 +84946,7 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady(
|
|
** opcode array. This extra memory will be reallocated for other elements
|
|
** of the prepared statement.
|
|
*/
|
|
- n = ROUND8(sizeof(Op)*p->nOp); /* Bytes of opcode memory used */
|
|
+ n = ROUND8P(sizeof(Op)*p->nOp); /* Bytes of opcode memory used */
|
|
x.pSpace = &((u8*)p->aOp)[n]; /* Unused opcode memory */
|
|
assert( EIGHT_BYTE_ALIGNMENT(x.pSpace) );
|
|
x.nFree = ROUNDDOWN8(pParse->szOpAlloc - n); /* Bytes of unused memory */
|
|
@@ -79668,6 +84962,7 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady(
|
|
};
|
|
int iFirst, mx, i;
|
|
if( nMem<10 ) nMem = 10;
|
|
+ p->explain = pParse->explain;
|
|
if( pParse->explain==2 ){
|
|
sqlite3VdbeSetNumCols(p, 4);
|
|
iFirst = 8;
|
|
@@ -79685,10 +84980,10 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady(
|
|
p->expired = 0;
|
|
|
|
/* Memory for registers, parameters, cursor, etc, is allocated in one or two
|
|
- ** passes. On the first pass, we try to reuse unused memory at the
|
|
+ ** passes. On the first pass, we try to reuse unused memory at the
|
|
** end of the opcode array. If we are unable to satisfy all memory
|
|
** requirements by reusing the opcode array tail, then the second
|
|
- ** pass will fill in the remainder using a fresh memory allocation.
|
|
+ ** pass will fill in the remainder using a fresh memory allocation.
|
|
**
|
|
** This two-pass approach that reuses as much memory as possible from
|
|
** the leftover memory at the end of the opcode array. This can significantly
|
|
@@ -79699,9 +84994,6 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady(
|
|
p->aVar = allocSpace(&x, 0, nVar*sizeof(Mem));
|
|
p->apArg = allocSpace(&x, 0, nArg*sizeof(Mem*));
|
|
p->apCsr = allocSpace(&x, 0, nCursor*sizeof(VdbeCursor*));
|
|
-#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
|
|
- p->anExec = allocSpace(&x, 0, p->nOp*sizeof(i64));
|
|
-#endif
|
|
if( x.nNeeded ){
|
|
x.pSpace = p->pFree = sqlite3DbMallocRawNN(db, x.nNeeded);
|
|
x.nFree = x.nNeeded;
|
|
@@ -79710,15 +85002,9 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady(
|
|
p->aVar = allocSpace(&x, p->aVar, nVar*sizeof(Mem));
|
|
p->apArg = allocSpace(&x, p->apArg, nArg*sizeof(Mem*));
|
|
p->apCsr = allocSpace(&x, p->apCsr, nCursor*sizeof(VdbeCursor*));
|
|
-#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
|
|
- p->anExec = allocSpace(&x, p->anExec, p->nOp*sizeof(i64));
|
|
-#endif
|
|
}
|
|
}
|
|
|
|
- p->pVList = pParse->pVList;
|
|
- pParse->pVList = 0;
|
|
- p->explain = pParse->explain;
|
|
if( db->mallocFailed ){
|
|
p->nVar = 0;
|
|
p->nCursor = 0;
|
|
@@ -79730,36 +85016,26 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady(
|
|
p->nMem = nMem;
|
|
initMemArray(p->aMem, nMem, db, MEM_Undefined);
|
|
memset(p->apCsr, 0, nCursor*sizeof(VdbeCursor*));
|
|
-#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
|
|
- memset(p->anExec, 0, p->nOp*sizeof(i64));
|
|
-#endif
|
|
}
|
|
sqlite3VdbeRewind(p);
|
|
}
|
|
|
|
/*
|
|
-** Close a VDBE cursor and release all the resources that cursor
|
|
+** Close a VDBE cursor and release all the resources that cursor
|
|
** happens to hold.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){
|
|
- if( pCx==0 ){
|
|
- return;
|
|
- }
|
|
- assert( pCx->pBtx==0 || pCx->eCurType==CURTYPE_BTREE );
|
|
+ if( pCx ) sqlite3VdbeFreeCursorNN(p,pCx);
|
|
+}
|
|
+SQLITE_PRIVATE void sqlite3VdbeFreeCursorNN(Vdbe *p, VdbeCursor *pCx){
|
|
switch( pCx->eCurType ){
|
|
case CURTYPE_SORTER: {
|
|
sqlite3VdbeSorterClose(p->db, pCx);
|
|
break;
|
|
}
|
|
case CURTYPE_BTREE: {
|
|
- if( pCx->isEphemeral ){
|
|
- if( pCx->pBtx ) sqlite3BtreeClose(pCx->pBtx);
|
|
- /* The pCx->pCursor will be close automatically, if it exists, by
|
|
- ** the call above. */
|
|
- }else{
|
|
- assert( pCx->uc.pCursor!=0 );
|
|
- sqlite3BtreeCloseCursor(pCx->uc.pCursor);
|
|
- }
|
|
+ assert( pCx->uc.pCursor!=0 );
|
|
+ sqlite3BtreeCloseCursor(pCx->uc.pCursor);
|
|
break;
|
|
}
|
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
|
@@ -79779,14 +85055,12 @@ SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){
|
|
** Close all cursors in the current frame.
|
|
*/
|
|
static void closeCursorsInFrame(Vdbe *p){
|
|
- if( p->apCsr ){
|
|
- int i;
|
|
- for(i=0; i<p->nCursor; i++){
|
|
- VdbeCursor *pC = p->apCsr[i];
|
|
- if( pC ){
|
|
- sqlite3VdbeFreeCursor(p, pC);
|
|
- p->apCsr[i] = 0;
|
|
- }
|
|
+ int i;
|
|
+ for(i=0; i<p->nCursor; i++){
|
|
+ VdbeCursor *pC = p->apCsr[i];
|
|
+ if( pC ){
|
|
+ sqlite3VdbeFreeCursorNN(p, pC);
|
|
+ p->apCsr[i] = 0;
|
|
}
|
|
}
|
|
}
|
|
@@ -79799,9 +85073,6 @@ static void closeCursorsInFrame(Vdbe *p){
|
|
SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *pFrame){
|
|
Vdbe *v = pFrame->v;
|
|
closeCursorsInFrame(v);
|
|
-#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
|
|
- v->anExec = pFrame->anExec;
|
|
-#endif
|
|
v->aOp = pFrame->aOp;
|
|
v->nOp = pFrame->nOp;
|
|
v->aMem = pFrame->aMem;
|
|
@@ -79820,7 +85091,7 @@ SQLITE_PRIVATE int sqlite3VdbeFrameRestore(VdbeFrame *pFrame){
|
|
/*
|
|
** Close all cursors.
|
|
**
|
|
-** Also release any dynamic memory held by the VM in the Vdbe.aMem memory
|
|
+** Also release any dynamic memory held by the VM in the Vdbe.aMem memory
|
|
** cell array. This is necessary as the memory cell array may contain
|
|
** pointers to VdbeFrame objects, which may in turn contain pointers to
|
|
** open cursors.
|
|
@@ -79835,9 +85106,7 @@ static void closeAllCursors(Vdbe *p){
|
|
}
|
|
assert( p->nFrame==0 );
|
|
closeCursorsInFrame(p);
|
|
- if( p->aMem ){
|
|
- releaseMemArray(p->aMem, p->nMem);
|
|
- }
|
|
+ releaseMemArray(p->aMem, p->nMem);
|
|
while( p->pDelFrame ){
|
|
VdbeFrame *pDel = p->pDelFrame;
|
|
p->pDelFrame = pDel->pParent;
|
|
@@ -79906,43 +85175,43 @@ SQLITE_PRIVATE int sqlite3VdbeSetColName(
|
|
** A read or write transaction may or may not be active on database handle
|
|
** db. If a transaction is active, commit it. If there is a
|
|
** write-transaction spanning more than one database file, this routine
|
|
-** takes care of the master journal trickery.
|
|
+** takes care of the super-journal trickery.
|
|
*/
|
|
static int vdbeCommit(sqlite3 *db, Vdbe *p){
|
|
int i;
|
|
int nTrans = 0; /* Number of databases with an active write-transaction
|
|
** that are candidates for a two-phase commit using a
|
|
- ** master-journal */
|
|
+ ** super-journal */
|
|
int rc = SQLITE_OK;
|
|
int needXcommit = 0;
|
|
|
|
#ifdef SQLITE_OMIT_VIRTUALTABLE
|
|
- /* With this option, sqlite3VtabSync() is defined to be simply
|
|
- ** SQLITE_OK so p is not used.
|
|
+ /* With this option, sqlite3VtabSync() is defined to be simply
|
|
+ ** SQLITE_OK so p is not used.
|
|
*/
|
|
UNUSED_PARAMETER(p);
|
|
#endif
|
|
|
|
/* Before doing anything else, call the xSync() callback for any
|
|
** virtual module tables written in this transaction. This has to
|
|
- ** be done before determining whether a master journal file is
|
|
+ ** be done before determining whether a super-journal file is
|
|
** required, as an xSync() callback may add an attached database
|
|
** to the transaction.
|
|
*/
|
|
rc = sqlite3VtabSync(db, p);
|
|
|
|
/* This loop determines (a) if the commit hook should be invoked and
|
|
- ** (b) how many database files have open write transactions, not
|
|
- ** including the temp database. (b) is important because if more than
|
|
- ** one database file has an open write transaction, a master journal
|
|
+ ** (b) how many database files have open write transactions, not
|
|
+ ** including the temp database. (b) is important because if more than
|
|
+ ** one database file has an open write transaction, a super-journal
|
|
** file is required for an atomic commit.
|
|
- */
|
|
- for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
|
|
+ */
|
|
+ for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
|
|
Btree *pBt = db->aDb[i].pBt;
|
|
- if( sqlite3BtreeIsInTrans(pBt) ){
|
|
- /* Whether or not a database might need a master journal depends upon
|
|
+ if( sqlite3BtreeTxnState(pBt)==SQLITE_TXN_WRITE ){
|
|
+ /* Whether or not a database might need a super-journal depends upon
|
|
** its journal mode (among other things). This matrix determines which
|
|
- ** journal modes use a master journal and which do not */
|
|
+ ** journal modes use a super-journal and which do not */
|
|
static const u8 aMJNeeded[] = {
|
|
/* DELETE */ 1,
|
|
/* PERSIST */ 1,
|
|
@@ -79958,7 +85227,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
|
|
if( db->aDb[i].safety_level!=PAGER_SYNCHRONOUS_OFF
|
|
&& aMJNeeded[sqlite3PagerGetJournalMode(pPager)]
|
|
&& sqlite3PagerIsMemdb(pPager)==0
|
|
- ){
|
|
+ ){
|
|
assert( i!=1 );
|
|
nTrans++;
|
|
}
|
|
@@ -79980,11 +85249,11 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
|
|
|
|
/* The simple case - no more than one database file (not counting the
|
|
** TEMP database) has a transaction active. There is no need for the
|
|
- ** master-journal.
|
|
+ ** super-journal.
|
|
**
|
|
** If the return value of sqlite3BtreeGetFilename() is a zero length
|
|
- ** string, it means the main database is :memory: or a temp file. In
|
|
- ** that case we do not support atomic multi-file commits, so use the
|
|
+ ** string, it means the main database is :memory: or a temp file. In
|
|
+ ** that case we do not support atomic multi-file commits, so use the
|
|
** simple case then too.
|
|
*/
|
|
if( 0==sqlite3Strlen30(sqlite3BtreeGetFilename(db->aDb[0].pBt))
|
|
@@ -79997,7 +85266,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
|
|
}
|
|
}
|
|
|
|
- /* Do the commit only if all databases successfully complete phase 1.
|
|
+ /* Do the commit only if all databases successfully complete phase 1.
|
|
** If one of the BtreeCommitPhaseOne() calls fails, this indicates an
|
|
** IO error while deleting or truncating a journal file. It is unlikely,
|
|
** but could happen. In this case abandon processing and return the error.
|
|
@@ -80014,124 +85283,125 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
|
|
}
|
|
|
|
/* The complex case - There is a multi-file write-transaction active.
|
|
- ** This requires a master journal file to ensure the transaction is
|
|
+ ** This requires a super-journal file to ensure the transaction is
|
|
** committed atomically.
|
|
*/
|
|
#ifndef SQLITE_OMIT_DISKIO
|
|
else{
|
|
sqlite3_vfs *pVfs = db->pVfs;
|
|
- char *zMaster = 0; /* File-name for the master journal */
|
|
+ char *zSuper = 0; /* File-name for the super-journal */
|
|
char const *zMainFile = sqlite3BtreeGetFilename(db->aDb[0].pBt);
|
|
- sqlite3_file *pMaster = 0;
|
|
+ sqlite3_file *pSuperJrnl = 0;
|
|
i64 offset = 0;
|
|
int res;
|
|
int retryCount = 0;
|
|
int nMainFile;
|
|
|
|
- /* Select a master journal file name */
|
|
+ /* Select a super-journal file name */
|
|
nMainFile = sqlite3Strlen30(zMainFile);
|
|
- zMaster = sqlite3MPrintf(db, "%s-mjXXXXXX9XXz%c%c", zMainFile, 0, 0);
|
|
- if( zMaster==0 ) return SQLITE_NOMEM_BKPT;
|
|
+ zSuper = sqlite3MPrintf(db, "%.4c%s%.16c", 0,zMainFile,0);
|
|
+ if( zSuper==0 ) return SQLITE_NOMEM_BKPT;
|
|
+ zSuper += 4;
|
|
do {
|
|
u32 iRandom;
|
|
if( retryCount ){
|
|
if( retryCount>100 ){
|
|
- sqlite3_log(SQLITE_FULL, "MJ delete: %s", zMaster);
|
|
- sqlite3OsDelete(pVfs, zMaster, 0);
|
|
+ sqlite3_log(SQLITE_FULL, "MJ delete: %s", zSuper);
|
|
+ sqlite3OsDelete(pVfs, zSuper, 0);
|
|
break;
|
|
}else if( retryCount==1 ){
|
|
- sqlite3_log(SQLITE_FULL, "MJ collide: %s", zMaster);
|
|
+ sqlite3_log(SQLITE_FULL, "MJ collide: %s", zSuper);
|
|
}
|
|
}
|
|
retryCount++;
|
|
sqlite3_randomness(sizeof(iRandom), &iRandom);
|
|
- sqlite3_snprintf(13, &zMaster[nMainFile], "-mj%06X9%02X",
|
|
+ sqlite3_snprintf(13, &zSuper[nMainFile], "-mj%06X9%02X",
|
|
(iRandom>>8)&0xffffff, iRandom&0xff);
|
|
- /* The antipenultimate character of the master journal name must
|
|
+ /* The antipenultimate character of the super-journal name must
|
|
** be "9" to avoid name collisions when using 8+3 filenames. */
|
|
- assert( zMaster[sqlite3Strlen30(zMaster)-3]=='9' );
|
|
- sqlite3FileSuffix3(zMainFile, zMaster);
|
|
- rc = sqlite3OsAccess(pVfs, zMaster, SQLITE_ACCESS_EXISTS, &res);
|
|
+ assert( zSuper[sqlite3Strlen30(zSuper)-3]=='9' );
|
|
+ sqlite3FileSuffix3(zMainFile, zSuper);
|
|
+ rc = sqlite3OsAccess(pVfs, zSuper, SQLITE_ACCESS_EXISTS, &res);
|
|
}while( rc==SQLITE_OK && res );
|
|
if( rc==SQLITE_OK ){
|
|
- /* Open the master journal. */
|
|
- rc = sqlite3OsOpenMalloc(pVfs, zMaster, &pMaster,
|
|
+ /* Open the super-journal. */
|
|
+ rc = sqlite3OsOpenMalloc(pVfs, zSuper, &pSuperJrnl,
|
|
SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|
|
|
- SQLITE_OPEN_EXCLUSIVE|SQLITE_OPEN_MASTER_JOURNAL, 0
|
|
+ SQLITE_OPEN_EXCLUSIVE|SQLITE_OPEN_SUPER_JOURNAL, 0
|
|
);
|
|
}
|
|
if( rc!=SQLITE_OK ){
|
|
- sqlite3DbFree(db, zMaster);
|
|
+ sqlite3DbFree(db, zSuper-4);
|
|
return rc;
|
|
}
|
|
-
|
|
+
|
|
/* Write the name of each database file in the transaction into the new
|
|
- ** master journal file. If an error occurs at this point close
|
|
- ** and delete the master journal file. All the individual journal files
|
|
- ** still have 'null' as the master journal pointer, so they will roll
|
|
+ ** super-journal file. If an error occurs at this point close
|
|
+ ** and delete the super-journal file. All the individual journal files
|
|
+ ** still have 'null' as the super-journal pointer, so they will roll
|
|
** back independently if a failure occurs.
|
|
*/
|
|
for(i=0; i<db->nDb; i++){
|
|
Btree *pBt = db->aDb[i].pBt;
|
|
- if( sqlite3BtreeIsInTrans(pBt) ){
|
|
+ if( sqlite3BtreeTxnState(pBt)==SQLITE_TXN_WRITE ){
|
|
char const *zFile = sqlite3BtreeGetJournalname(pBt);
|
|
if( zFile==0 ){
|
|
continue; /* Ignore TEMP and :memory: databases */
|
|
}
|
|
assert( zFile[0]!=0 );
|
|
- rc = sqlite3OsWrite(pMaster, zFile, sqlite3Strlen30(zFile)+1, offset);
|
|
+ rc = sqlite3OsWrite(pSuperJrnl, zFile, sqlite3Strlen30(zFile)+1,offset);
|
|
offset += sqlite3Strlen30(zFile)+1;
|
|
if( rc!=SQLITE_OK ){
|
|
- sqlite3OsCloseFree(pMaster);
|
|
- sqlite3OsDelete(pVfs, zMaster, 0);
|
|
- sqlite3DbFree(db, zMaster);
|
|
+ sqlite3OsCloseFree(pSuperJrnl);
|
|
+ sqlite3OsDelete(pVfs, zSuper, 0);
|
|
+ sqlite3DbFree(db, zSuper-4);
|
|
return rc;
|
|
}
|
|
}
|
|
}
|
|
|
|
- /* Sync the master journal file. If the IOCAP_SEQUENTIAL device
|
|
+ /* Sync the super-journal file. If the IOCAP_SEQUENTIAL device
|
|
** flag is set this is not required.
|
|
*/
|
|
- if( 0==(sqlite3OsDeviceCharacteristics(pMaster)&SQLITE_IOCAP_SEQUENTIAL)
|
|
- && SQLITE_OK!=(rc = sqlite3OsSync(pMaster, SQLITE_SYNC_NORMAL))
|
|
+ if( 0==(sqlite3OsDeviceCharacteristics(pSuperJrnl)&SQLITE_IOCAP_SEQUENTIAL)
|
|
+ && SQLITE_OK!=(rc = sqlite3OsSync(pSuperJrnl, SQLITE_SYNC_NORMAL))
|
|
){
|
|
- sqlite3OsCloseFree(pMaster);
|
|
- sqlite3OsDelete(pVfs, zMaster, 0);
|
|
- sqlite3DbFree(db, zMaster);
|
|
+ sqlite3OsCloseFree(pSuperJrnl);
|
|
+ sqlite3OsDelete(pVfs, zSuper, 0);
|
|
+ sqlite3DbFree(db, zSuper-4);
|
|
return rc;
|
|
}
|
|
|
|
/* Sync all the db files involved in the transaction. The same call
|
|
- ** sets the master journal pointer in each individual journal. If
|
|
- ** an error occurs here, do not delete the master journal file.
|
|
+ ** sets the super-journal pointer in each individual journal. If
|
|
+ ** an error occurs here, do not delete the super-journal file.
|
|
**
|
|
** If the error occurs during the first call to
|
|
** sqlite3BtreeCommitPhaseOne(), then there is a chance that the
|
|
- ** master journal file will be orphaned. But we cannot delete it,
|
|
- ** in case the master journal file name was written into the journal
|
|
+ ** super-journal file will be orphaned. But we cannot delete it,
|
|
+ ** in case the super-journal file name was written into the journal
|
|
** file before the failure occurred.
|
|
*/
|
|
- for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
|
|
+ for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
|
|
Btree *pBt = db->aDb[i].pBt;
|
|
if( pBt ){
|
|
- rc = sqlite3BtreeCommitPhaseOne(pBt, zMaster);
|
|
+ rc = sqlite3BtreeCommitPhaseOne(pBt, zSuper);
|
|
}
|
|
}
|
|
- sqlite3OsCloseFree(pMaster);
|
|
+ sqlite3OsCloseFree(pSuperJrnl);
|
|
assert( rc!=SQLITE_BUSY );
|
|
if( rc!=SQLITE_OK ){
|
|
- sqlite3DbFree(db, zMaster);
|
|
+ sqlite3DbFree(db, zSuper-4);
|
|
return rc;
|
|
}
|
|
|
|
- /* Delete the master journal file. This commits the transaction. After
|
|
+ /* Delete the super-journal file. This commits the transaction. After
|
|
** doing this the directory is synced again before any individual
|
|
** transaction files are deleted.
|
|
*/
|
|
- rc = sqlite3OsDelete(pVfs, zMaster, 1);
|
|
- sqlite3DbFree(db, zMaster);
|
|
- zMaster = 0;
|
|
+ rc = sqlite3OsDelete(pVfs, zSuper, 1);
|
|
+ sqlite3DbFree(db, zSuper-4);
|
|
+ zSuper = 0;
|
|
if( rc ){
|
|
return rc;
|
|
}
|
|
@@ -80145,7 +85415,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
|
|
*/
|
|
disable_simulated_io_errors();
|
|
sqlite3BeginBenignMalloc();
|
|
- for(i=0; i<db->nDb; i++){
|
|
+ for(i=0; i<db->nDb; i++){
|
|
Btree *pBt = db->aDb[i].pBt;
|
|
if( pBt ){
|
|
sqlite3BtreeCommitPhaseTwo(pBt, 1);
|
|
@@ -80161,7 +85431,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
|
|
return rc;
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** This routine checks that the sqlite3.nVdbeActive count variable
|
|
** matches the number of vdbe's in the list sqlite3.pVdbe that are
|
|
** currently active. An assertion fails if the two counts do not match.
|
|
@@ -80183,7 +85453,7 @@ static void checkActiveVdbeCnt(sqlite3 *db){
|
|
if( p->readOnly==0 ) nWrite++;
|
|
if( p->bIsReader ) nRead++;
|
|
}
|
|
- p = p->pNext;
|
|
+ p = p->pVNext;
|
|
}
|
|
assert( cnt==db->nVdbeActive );
|
|
assert( nWrite==db->nVdbeWrite );
|
|
@@ -80197,10 +85467,10 @@ static void checkActiveVdbeCnt(sqlite3 *db){
|
|
** If the Vdbe passed as the first argument opened a statement-transaction,
|
|
** close it now. Argument eOp must be either SAVEPOINT_ROLLBACK or
|
|
** SAVEPOINT_RELEASE. If it is SAVEPOINT_ROLLBACK, then the statement
|
|
-** transaction is rolled back. If eOp is SAVEPOINT_RELEASE, then the
|
|
+** transaction is rolled back. If eOp is SAVEPOINT_RELEASE, then the
|
|
** statement transaction is committed.
|
|
**
|
|
-** If an IO error occurs, an SQLITE_IOERR_XXX error code is returned.
|
|
+** If an IO error occurs, an SQLITE_IOERR_XXX error code is returned.
|
|
** Otherwise SQLITE_OK.
|
|
*/
|
|
static SQLITE_NOINLINE int vdbeCloseStatement(Vdbe *p, int eOp){
|
|
@@ -80213,7 +85483,7 @@ static SQLITE_NOINLINE int vdbeCloseStatement(Vdbe *p, int eOp){
|
|
assert( db->nStatement>0 );
|
|
assert( p->iStatement==(db->nStatement+db->nSavepoint) );
|
|
|
|
- for(i=0; i<db->nDb; i++){
|
|
+ for(i=0; i<db->nDb; i++){
|
|
int rc2 = SQLITE_OK;
|
|
Btree *pBt = db->aDb[i].pBt;
|
|
if( pBt ){
|
|
@@ -80240,8 +85510,8 @@ static SQLITE_NOINLINE int vdbeCloseStatement(Vdbe *p, int eOp){
|
|
}
|
|
}
|
|
|
|
- /* If the statement transaction is being rolled back, also restore the
|
|
- ** database handles deferred constraint counter to the value it had when
|
|
+ /* If the statement transaction is being rolled back, also restore the
|
|
+ ** database handles deferred constraint counter to the value it had when
|
|
** the statement transaction was opened. */
|
|
if( eOp==SAVEPOINT_ROLLBACK ){
|
|
db->nDeferredCons = p->nStmtDefCons;
|
|
@@ -80258,25 +85528,26 @@ SQLITE_PRIVATE int sqlite3VdbeCloseStatement(Vdbe *p, int eOp){
|
|
|
|
|
|
/*
|
|
-** This function is called when a transaction opened by the database
|
|
-** handle associated with the VM passed as an argument is about to be
|
|
+** This function is called when a transaction opened by the database
|
|
+** handle associated with the VM passed as an argument is about to be
|
|
** committed. If there are outstanding deferred foreign key constraint
|
|
** violations, return SQLITE_ERROR. Otherwise, SQLITE_OK.
|
|
**
|
|
-** If there are outstanding FK violations and this function returns
|
|
+** If there are outstanding FK violations and this function returns
|
|
** SQLITE_ERROR, set the result of the VM to SQLITE_CONSTRAINT_FOREIGNKEY
|
|
** and write an error message to it. Then return SQLITE_ERROR.
|
|
*/
|
|
#ifndef SQLITE_OMIT_FOREIGN_KEY
|
|
SQLITE_PRIVATE int sqlite3VdbeCheckFk(Vdbe *p, int deferred){
|
|
sqlite3 *db = p->db;
|
|
- if( (deferred && (db->nDeferredCons+db->nDeferredImmCons)>0)
|
|
- || (!deferred && p->nFkConstraint>0)
|
|
+ if( (deferred && (db->nDeferredCons+db->nDeferredImmCons)>0)
|
|
+ || (!deferred && p->nFkConstraint>0)
|
|
){
|
|
p->rc = SQLITE_CONSTRAINT_FOREIGNKEY;
|
|
p->errorAction = OE_Abort;
|
|
sqlite3VdbeError(p, "FOREIGN KEY constraint failed");
|
|
- return SQLITE_ERROR;
|
|
+ if( (p->prepFlags & SQLITE_PREPARE_SAVESQL)==0 ) return SQLITE_ERROR;
|
|
+ return SQLITE_CONSTRAINT_FOREIGNKEY;
|
|
}
|
|
return SQLITE_OK;
|
|
}
|
|
@@ -80287,9 +85558,9 @@ SQLITE_PRIVATE int sqlite3VdbeCheckFk(Vdbe *p, int deferred){
|
|
** has made changes and is in autocommit mode, then commit those
|
|
** changes. If a rollback is needed, then do the rollback.
|
|
**
|
|
-** This routine is the only way to move the state of a VM from
|
|
-** SQLITE_MAGIC_RUN to SQLITE_MAGIC_HALT. It is harmless to
|
|
-** call this on a VM that is in the SQLITE_MAGIC_HALT state.
|
|
+** This routine is the only way to move the sqlite3eOpenState of a VM from
|
|
+** SQLITE_STATE_RUN to SQLITE_STATE_HALT. It is harmless to
|
|
+** call this on a VM that is in the SQLITE_STATE_HALT state.
|
|
**
|
|
** Return an error code. If the commit could not complete because of
|
|
** lock contention, return SQLITE_BUSY. If SQLITE_BUSY is returned, it
|
|
@@ -80301,7 +85572,7 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
|
|
|
|
/* This function contains the logic that determines if a statement or
|
|
** transaction will be committed or rolled back as a result of the
|
|
- ** execution of this virtual machine.
|
|
+ ** execution of this virtual machine.
|
|
**
|
|
** If any of the following errors occur:
|
|
**
|
|
@@ -80315,9 +85586,7 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
|
|
** one, or the complete transaction if there is no statement transaction.
|
|
*/
|
|
|
|
- if( p->magic!=VDBE_MAGIC_RUN ){
|
|
- return SQLITE_OK;
|
|
- }
|
|
+ assert( p->eVdbeState==VDBE_RUN_STATE );
|
|
if( db->mallocFailed ){
|
|
p->rc = SQLITE_NOMEM_BKPT;
|
|
}
|
|
@@ -80326,7 +85595,7 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
|
|
|
|
/* No commit or rollback needed if the program never started or if the
|
|
** SQL statement does not read or write a database file. */
|
|
- if( p->pc>=0 && p->bIsReader ){
|
|
+ if( p->bIsReader ){
|
|
int mrc; /* Primary error code from p->rc */
|
|
int eStatementOp = 0;
|
|
int isSpecialError; /* Set to true if a 'special' error */
|
|
@@ -80335,20 +85604,26 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
|
|
sqlite3VdbeEnter(p);
|
|
|
|
/* Check for one of the special errors */
|
|
- mrc = p->rc & 0xff;
|
|
- isSpecialError = mrc==SQLITE_NOMEM || mrc==SQLITE_IOERR
|
|
- || mrc==SQLITE_INTERRUPT || mrc==SQLITE_FULL;
|
|
+ if( p->rc ){
|
|
+ mrc = p->rc & 0xff;
|
|
+ isSpecialError = mrc==SQLITE_NOMEM
|
|
+ || mrc==SQLITE_IOERR
|
|
+ || mrc==SQLITE_INTERRUPT
|
|
+ || mrc==SQLITE_FULL;
|
|
+ }else{
|
|
+ mrc = isSpecialError = 0;
|
|
+ }
|
|
if( isSpecialError ){
|
|
- /* If the query was read-only and the error code is SQLITE_INTERRUPT,
|
|
- ** no rollback is necessary. Otherwise, at least a savepoint
|
|
- ** transaction must be rolled back to restore the database to a
|
|
+ /* If the query was read-only and the error code is SQLITE_INTERRUPT,
|
|
+ ** no rollback is necessary. Otherwise, at least a savepoint
|
|
+ ** transaction must be rolled back to restore the database to a
|
|
** consistent state.
|
|
**
|
|
** Even if the statement is read-only, it is important to perform
|
|
- ** a statement or transaction rollback operation. If the error
|
|
+ ** a statement or transaction rollback operation. If the error
|
|
** occurred while writing to the journal, sub-journal or database
|
|
** file as part of an effort to free up cache space (see function
|
|
- ** pagerStress() in pager.c), the rollback is required to restore
|
|
+ ** pagerStress() in pager.c), the rollback is required to restore
|
|
** the pager to a consistent state.
|
|
*/
|
|
if( !p->readOnly || mrc!=SQLITE_INTERRUPT ){
|
|
@@ -80370,16 +85645,16 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
|
|
if( p->rc==SQLITE_OK || (p->errorAction==OE_Fail && !isSpecialError) ){
|
|
sqlite3VdbeCheckFk(p, 0);
|
|
}
|
|
-
|
|
- /* If the auto-commit flag is set and this is the only active writer
|
|
- ** VM, then we do either a commit or rollback of the current transaction.
|
|
+
|
|
+ /* If the auto-commit flag is set and this is the only active writer
|
|
+ ** VM, then we do either a commit or rollback of the current transaction.
|
|
**
|
|
- ** Note: This block also runs if one of the special errors handled
|
|
- ** above has occurred.
|
|
+ ** Note: This block also runs if one of the special errors handled
|
|
+ ** above has occurred.
|
|
*/
|
|
- if( !sqlite3VtabInSync(db)
|
|
- && db->autoCommit
|
|
- && db->nVdbeWrite==(p->readOnly==0)
|
|
+ if( !sqlite3VtabInSync(db)
|
|
+ && db->autoCommit
|
|
+ && db->nVdbeWrite==(p->readOnly==0)
|
|
){
|
|
if( p->rc==SQLITE_OK || (p->errorAction==OE_Fail && !isSpecialError) ){
|
|
rc = sqlite3VdbeCheckFk(p, 1);
|
|
@@ -80389,10 +85664,13 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
|
|
return SQLITE_ERROR;
|
|
}
|
|
rc = SQLITE_CONSTRAINT_FOREIGNKEY;
|
|
- }else{
|
|
- /* The auto-commit flag is true, the vdbe program was successful
|
|
+ }else if( db->flags & SQLITE_CorruptRdOnly ){
|
|
+ rc = SQLITE_CORRUPT;
|
|
+ db->flags &= ~SQLITE_CorruptRdOnly;
|
|
+ }else{
|
|
+ /* The auto-commit flag is true, the vdbe program was successful
|
|
** or hit an 'OR FAIL' constraint and there are no deferred foreign
|
|
- ** key constraints to hold up the transaction. This means a commit
|
|
+ ** key constraints to hold up the transaction. This means a commit
|
|
** is required. */
|
|
rc = vdbeCommit(db, p);
|
|
}
|
|
@@ -80426,7 +85704,7 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
|
|
p->nChange = 0;
|
|
}
|
|
}
|
|
-
|
|
+
|
|
/* If eStatementOp is non-zero, then a statement transaction needs to
|
|
** be committed or rolled back. Call sqlite3VdbeCloseStatement() to
|
|
** do so. If this operation returns an error, and the current statement
|
|
@@ -80447,9 +85725,9 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
|
|
p->nChange = 0;
|
|
}
|
|
}
|
|
-
|
|
+
|
|
/* If this was an INSERT, UPDATE or DELETE and no statement transaction
|
|
- ** has been rolled back, update the database connection change-counter.
|
|
+ ** has been rolled back, update the database connection change-counter.
|
|
*/
|
|
if( p->changeCntOn ){
|
|
if( eStatementOp!=SAVEPOINT_ROLLBACK ){
|
|
@@ -80465,22 +85743,20 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
|
|
}
|
|
|
|
/* We have successfully halted and closed the VM. Record this fact. */
|
|
- if( p->pc>=0 ){
|
|
- db->nVdbeActive--;
|
|
- if( !p->readOnly ) db->nVdbeWrite--;
|
|
- if( p->bIsReader ) db->nVdbeRead--;
|
|
- assert( db->nVdbeActive>=db->nVdbeRead );
|
|
- assert( db->nVdbeRead>=db->nVdbeWrite );
|
|
- assert( db->nVdbeWrite>=0 );
|
|
- }
|
|
- p->magic = VDBE_MAGIC_HALT;
|
|
+ db->nVdbeActive--;
|
|
+ if( !p->readOnly ) db->nVdbeWrite--;
|
|
+ if( p->bIsReader ) db->nVdbeRead--;
|
|
+ assert( db->nVdbeActive>=db->nVdbeRead );
|
|
+ assert( db->nVdbeRead>=db->nVdbeWrite );
|
|
+ assert( db->nVdbeWrite>=0 );
|
|
+ p->eVdbeState = VDBE_HALT_STATE;
|
|
checkActiveVdbeCnt(db);
|
|
if( db->mallocFailed ){
|
|
p->rc = SQLITE_NOMEM_BKPT;
|
|
}
|
|
|
|
/* If the auto-commit flag is set to true, then any locks that were held
|
|
- ** by connection db have now been released. Call sqlite3ConnectionUnlocked()
|
|
+ ** by connection db have now been released. Call sqlite3ConnectionUnlocked()
|
|
** to invoke any required unlock-notify callbacks.
|
|
*/
|
|
if( db->autoCommit ){
|
|
@@ -80502,7 +85778,7 @@ SQLITE_PRIVATE void sqlite3VdbeResetStepResult(Vdbe *p){
|
|
|
|
/*
|
|
** Copy the error code and error message belonging to the VDBE passed
|
|
-** as the first argument to its database handle (so that they will be
|
|
+** as the first argument to its database handle (so that they will be
|
|
** returned by calls to sqlite3_errcode() and sqlite3_errmsg()).
|
|
**
|
|
** This function does not clear the VDBE error code or message, just
|
|
@@ -80522,12 +85798,13 @@ SQLITE_PRIVATE int sqlite3VdbeTransferError(Vdbe *p){
|
|
sqlite3ValueSetNull(db->pErr);
|
|
}
|
|
db->errCode = rc;
|
|
+ db->errByteOffset = -1;
|
|
return rc;
|
|
}
|
|
|
|
#ifdef SQLITE_ENABLE_SQLLOG
|
|
/*
|
|
-** If an SQLITE_CONFIG_SQLLOG hook is registered and the VM has been run,
|
|
+** If an SQLITE_CONFIG_SQLLOG hook is registered and the VM has been run,
|
|
** invoke it.
|
|
*/
|
|
static void vdbeInvokeSqllog(Vdbe *v){
|
|
@@ -80554,8 +85831,8 @@ static void vdbeInvokeSqllog(Vdbe *v){
|
|
** again.
|
|
**
|
|
** To look at it another way, this routine resets the state of the
|
|
-** virtual machine from VDBE_MAGIC_RUN or VDBE_MAGIC_HALT back to
|
|
-** VDBE_MAGIC_INIT.
|
|
+** virtual machine from VDBE_RUN_STATE or VDBE_HALT_STATE back to
|
|
+** VDBE_READY_STATE.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){
|
|
#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
|
|
@@ -80569,7 +85846,7 @@ SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){
|
|
** error, then it might not have been halted properly. So halt
|
|
** it now.
|
|
*/
|
|
- sqlite3VdbeHalt(p);
|
|
+ if( p->eVdbeState==VDBE_RUN_STATE ) sqlite3VdbeHalt(p);
|
|
|
|
/* If the VDBE has been run even partially, then transfer the error code
|
|
** and error message from the VDBE into the main database structure. But
|
|
@@ -80578,29 +85855,28 @@ SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){
|
|
*/
|
|
if( p->pc>=0 ){
|
|
vdbeInvokeSqllog(p);
|
|
- sqlite3VdbeTransferError(p);
|
|
- if( p->runOnlyOnce ) p->expired = 1;
|
|
- }else if( p->rc && p->expired ){
|
|
- /* The expired flag was set on the VDBE before the first call
|
|
- ** to sqlite3_step(). For consistency (since sqlite3_step() was
|
|
- ** called), set the database error in this case as well.
|
|
- */
|
|
- sqlite3ErrorWithMsg(db, p->rc, p->zErrMsg ? "%s" : 0, p->zErrMsg);
|
|
+ if( db->pErr || p->zErrMsg ){
|
|
+ sqlite3VdbeTransferError(p);
|
|
+ }else{
|
|
+ db->errCode = p->rc;
|
|
+ }
|
|
}
|
|
|
|
/* Reset register contents and reclaim error message memory.
|
|
*/
|
|
#ifdef SQLITE_DEBUG
|
|
- /* Execute assert() statements to ensure that the Vdbe.apCsr[] and
|
|
+ /* Execute assert() statements to ensure that the Vdbe.apCsr[] and
|
|
** Vdbe.aMem[] arrays have already been cleaned up. */
|
|
if( p->apCsr ) for(i=0; i<p->nCursor; i++) assert( p->apCsr[i]==0 );
|
|
if( p->aMem ){
|
|
for(i=0; i<p->nMem; i++) assert( p->aMem[i].flags==MEM_Undefined );
|
|
}
|
|
#endif
|
|
- sqlite3DbFree(db, p->zErrMsg);
|
|
- p->zErrMsg = 0;
|
|
- p->pResultSet = 0;
|
|
+ if( p->zErrMsg ){
|
|
+ sqlite3DbFree(db, p->zErrMsg);
|
|
+ p->zErrMsg = 0;
|
|
+ }
|
|
+ p->pResultRow = 0;
|
|
#ifdef SQLITE_DEBUG
|
|
p->nWrite = 0;
|
|
#endif
|
|
@@ -80628,10 +85904,12 @@ SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){
|
|
}
|
|
for(i=0; i<p->nOp; i++){
|
|
char zHdr[100];
|
|
+ i64 cnt = p->aOp[i].nExec;
|
|
+ i64 cycles = p->aOp[i].nCycle;
|
|
sqlite3_snprintf(sizeof(zHdr), zHdr, "%6u %12llu %8llu ",
|
|
- p->aOp[i].cnt,
|
|
- p->aOp[i].cycles,
|
|
- p->aOp[i].cnt>0 ? p->aOp[i].cycles/p->aOp[i].cnt : 0
|
|
+ cnt,
|
|
+ cycles,
|
|
+ cnt>0 ? cycles/cnt : 0
|
|
);
|
|
fprintf(out, "%s", zHdr);
|
|
sqlite3VdbePrintOp(out, i, &p->aOp[i]);
|
|
@@ -80640,17 +85918,19 @@ SQLITE_PRIVATE int sqlite3VdbeReset(Vdbe *p){
|
|
}
|
|
}
|
|
#endif
|
|
- p->magic = VDBE_MAGIC_RESET;
|
|
return p->rc & db->errMask;
|
|
}
|
|
-
|
|
+
|
|
/*
|
|
** Clean up and delete a VDBE after execution. Return an integer which is
|
|
** the result code. Write any error message text into *pzErrMsg.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3VdbeFinalize(Vdbe *p){
|
|
int rc = SQLITE_OK;
|
|
- if( p->magic==VDBE_MAGIC_RUN || p->magic==VDBE_MAGIC_HALT ){
|
|
+ assert( VDBE_RUN_STATE>VDBE_READY_STATE );
|
|
+ assert( VDBE_HALT_STATE>VDBE_READY_STATE );
|
|
+ assert( VDBE_INIT_STATE<VDBE_READY_STATE );
|
|
+ if( p->eVdbeState>=VDBE_READY_STATE ){
|
|
rc = sqlite3VdbeReset(p);
|
|
assert( (rc & p->db->errMask)==rc );
|
|
}
|
|
@@ -80664,8 +85944,8 @@ SQLITE_PRIVATE int sqlite3VdbeFinalize(Vdbe *p){
|
|
** the first argument.
|
|
**
|
|
** Or, if iOp is greater than or equal to zero, then the destructor is
|
|
-** only invoked for those auxiliary data pointers created by the user
|
|
-** function invoked by the OP_Function opcode at instruction iOp of
|
|
+** only invoked for those auxiliary data pointers created by the user
|
|
+** function invoked by the OP_Function opcode at instruction iOp of
|
|
** VM pVdbe, and only then if:
|
|
**
|
|
** * the associated function parameter is the 32nd or later (counting
|
|
@@ -80702,23 +85982,26 @@ SQLITE_PRIVATE void sqlite3VdbeDeleteAuxData(sqlite3 *db, AuxData **pp, int iOp,
|
|
** VdbeDelete() also unlinks the Vdbe from the list of VMs associated with
|
|
** the database connection and frees the object itself.
|
|
*/
|
|
-SQLITE_PRIVATE void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){
|
|
+static void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){
|
|
SubProgram *pSub, *pNext;
|
|
+ assert( db!=0 );
|
|
assert( p->db==0 || p->db==db );
|
|
- releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
|
|
+ if( p->aColName ){
|
|
+ releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
|
|
+ sqlite3DbNNFreeNN(db, p->aColName);
|
|
+ }
|
|
for(pSub=p->pProgram; pSub; pSub=pNext){
|
|
pNext = pSub->pNext;
|
|
vdbeFreeOpArray(db, pSub->aOp, pSub->nOp);
|
|
sqlite3DbFree(db, pSub);
|
|
}
|
|
- if( p->magic!=VDBE_MAGIC_INIT ){
|
|
+ if( p->eVdbeState!=VDBE_INIT_STATE ){
|
|
releaseMemArray(p->aVar, p->nVar);
|
|
- sqlite3DbFree(db, p->pVList);
|
|
- sqlite3DbFree(db, p->pFree);
|
|
+ if( p->pVList ) sqlite3DbNNFreeNN(db, p->pVList);
|
|
+ if( p->pFree ) sqlite3DbNNFreeNN(db, p->pFree);
|
|
}
|
|
vdbeFreeOpArray(db, p->aOp, p->nOp);
|
|
- sqlite3DbFree(db, p->aColName);
|
|
- sqlite3DbFree(db, p->zSql);
|
|
+ if( p->zSql ) sqlite3DbNNFreeNN(db, p->zSql);
|
|
#ifdef SQLITE_ENABLE_NORMALIZE
|
|
sqlite3DbFree(db, p->zNormSql);
|
|
{
|
|
@@ -80748,20 +86031,17 @@ SQLITE_PRIVATE void sqlite3VdbeDelete(Vdbe *p){
|
|
|
|
assert( p!=0 );
|
|
db = p->db;
|
|
+ assert( db!=0 );
|
|
assert( sqlite3_mutex_held(db->mutex) );
|
|
sqlite3VdbeClearObject(db, p);
|
|
- if( p->pPrev ){
|
|
- p->pPrev->pNext = p->pNext;
|
|
- }else{
|
|
- assert( db->pVdbe==p );
|
|
- db->pVdbe = p->pNext;
|
|
- }
|
|
- if( p->pNext ){
|
|
- p->pNext->pPrev = p->pPrev;
|
|
+ if( db->pnBytesFreed==0 ){
|
|
+ assert( p->ppVPrev!=0 );
|
|
+ *p->ppVPrev = p->pVNext;
|
|
+ if( p->pVNext ){
|
|
+ p->pVNext->ppVPrev = p->ppVPrev;
|
|
+ }
|
|
}
|
|
- p->magic = VDBE_MAGIC_DEAD;
|
|
- p->db = 0;
|
|
- sqlite3DbFreeNN(db, p);
|
|
+ sqlite3DbNNFreeNN(db, p);
|
|
}
|
|
|
|
/*
|
|
@@ -80777,7 +86057,7 @@ SQLITE_PRIVATE int SQLITE_NOINLINE sqlite3VdbeFinishMoveto(VdbeCursor *p){
|
|
assert( p->deferredMoveto );
|
|
assert( p->isTable );
|
|
assert( p->eCurType==CURTYPE_BTREE );
|
|
- rc = sqlite3BtreeMovetoUnpacked(p->uc.pCursor, 0, p->movetoTarget, 0, &res);
|
|
+ rc = sqlite3BtreeTableMoveto(p->uc.pCursor, p->movetoTarget, 0, &res);
|
|
if( rc ) return rc;
|
|
if( res!=0 ) return SQLITE_CORRUPT_BKPT;
|
|
#ifdef SQLITE_TEST
|
|
@@ -80795,7 +86075,7 @@ SQLITE_PRIVATE int SQLITE_NOINLINE sqlite3VdbeFinishMoveto(VdbeCursor *p){
|
|
** is supposed to be pointing. If the row was deleted out from under the
|
|
** cursor, set the cursor to point to a NULL row.
|
|
*/
|
|
-static int SQLITE_NOINLINE handleMovedCursor(VdbeCursor *p){
|
|
+SQLITE_PRIVATE int SQLITE_NOINLINE sqlite3VdbeHandleMovedCursor(VdbeCursor *p){
|
|
int isDifferentRow, rc;
|
|
assert( p->eCurType==CURTYPE_BTREE );
|
|
assert( p->uc.pCursor!=0 );
|
|
@@ -80811,40 +86091,9 @@ static int SQLITE_NOINLINE handleMovedCursor(VdbeCursor *p){
|
|
** if need be. Return any I/O error from the restore operation.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3VdbeCursorRestore(VdbeCursor *p){
|
|
- assert( p->eCurType==CURTYPE_BTREE );
|
|
- if( sqlite3BtreeCursorHasMoved(p->uc.pCursor) ){
|
|
- return handleMovedCursor(p);
|
|
- }
|
|
- return SQLITE_OK;
|
|
-}
|
|
-
|
|
-/*
|
|
-** Make sure the cursor p is ready to read or write the row to which it
|
|
-** was last positioned. Return an error code if an OOM fault or I/O error
|
|
-** prevents us from positioning the cursor to its correct position.
|
|
-**
|
|
-** If a MoveTo operation is pending on the given cursor, then do that
|
|
-** MoveTo now. If no move is pending, check to see if the row has been
|
|
-** deleted out from under the cursor and if it has, mark the row as
|
|
-** a NULL row.
|
|
-**
|
|
-** If the cursor is already pointing to the correct row and that row has
|
|
-** not been deleted out from under the cursor, then this routine is a no-op.
|
|
-*/
|
|
-SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor **pp, int *piCol){
|
|
- VdbeCursor *p = *pp;
|
|
- assert( p->eCurType==CURTYPE_BTREE || p->eCurType==CURTYPE_PSEUDO );
|
|
- if( p->deferredMoveto ){
|
|
- int iMap;
|
|
- if( p->aAltMap && (iMap = p->aAltMap[1+*piCol])>0 ){
|
|
- *pp = p->pAltCursor;
|
|
- *piCol = iMap - 1;
|
|
- return SQLITE_OK;
|
|
- }
|
|
- return sqlite3VdbeFinishMoveto(p);
|
|
- }
|
|
+ assert( p->eCurType==CURTYPE_BTREE || IsNullCursor(p) );
|
|
if( sqlite3BtreeCursorHasMoved(p->uc.pCursor) ){
|
|
- return handleMovedCursor(p);
|
|
+ return sqlite3VdbeHandleMovedCursor(p);
|
|
}
|
|
return SQLITE_OK;
|
|
}
|
|
@@ -80855,7 +86104,7 @@ SQLITE_PRIVATE int sqlite3VdbeCursorMoveto(VdbeCursor **pp, int *piCol){
|
|
** sqlite3VdbeSerialType()
|
|
** sqlite3VdbeSerialTypeLen()
|
|
** sqlite3VdbeSerialLen()
|
|
-** sqlite3VdbeSerialPut()
|
|
+** sqlite3VdbeSerialPut() <--- in-lined into OP_MakeRecord as of 2022-04-02
|
|
** sqlite3VdbeSerialGet()
|
|
**
|
|
** encapsulate the code that serializes values for storage in SQLite
|
|
@@ -80967,8 +86216,8 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialType(Mem *pMem, int file_format, u32 *pLen){
|
|
/*
|
|
** The sizes for serial types less than 128
|
|
*/
|
|
-static const u8 sqlite3SmallTypeSizes[] = {
|
|
- /* 0 1 2 3 4 5 6 7 8 9 */
|
|
+SQLITE_PRIVATE const u8 sqlite3SmallTypeSizes[128] = {
|
|
+ /* 0 1 2 3 4 5 6 7 8 9 */
|
|
/* 0 */ 0, 1, 2, 3, 4, 6, 8, 8, 0, 0,
|
|
/* 10 */ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3,
|
|
/* 20 */ 4, 4, 5, 5, 6, 6, 7, 7, 8, 8,
|
|
@@ -80991,19 +86240,19 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialTypeLen(u32 serial_type){
|
|
if( serial_type>=128 ){
|
|
return (serial_type-12)/2;
|
|
}else{
|
|
- assert( serial_type<12
|
|
+ assert( serial_type<12
|
|
|| sqlite3SmallTypeSizes[serial_type]==(serial_type - 12)/2 );
|
|
return sqlite3SmallTypeSizes[serial_type];
|
|
}
|
|
}
|
|
SQLITE_PRIVATE u8 sqlite3VdbeOneByteSerialTypeLen(u8 serial_type){
|
|
assert( serial_type<128 );
|
|
- return sqlite3SmallTypeSizes[serial_type];
|
|
+ return sqlite3SmallTypeSizes[serial_type];
|
|
}
|
|
|
|
/*
|
|
-** If we are on an architecture with mixed-endian floating
|
|
-** points (ex: ARM7) then swap the lower 4 bytes with the
|
|
+** If we are on an architecture with mixed-endian floating
|
|
+** points (ex: ARM7) then swap the lower 4 bytes with the
|
|
** upper 4 bytes. Return the result.
|
|
**
|
|
** For most architectures, this is a no-op.
|
|
@@ -81025,7 +86274,7 @@ SQLITE_PRIVATE u8 sqlite3VdbeOneByteSerialTypeLen(u8 serial_type){
|
|
** (2007-08-30) Frank van Vugt has studied this problem closely
|
|
** and has send his findings to the SQLite developers. Frank
|
|
** writes that some Linux kernels offer floating point hardware
|
|
-** emulation that uses only 32-bit mantissas instead of a full
|
|
+** emulation that uses only 32-bit mantissas instead of a full
|
|
** 48-bits as required by the IEEE standard. (This is the
|
|
** CONFIG_FPE_FASTFPE option.) On such systems, floating point
|
|
** byte swapping becomes very complicated. To avoid problems,
|
|
@@ -81036,7 +86285,7 @@ SQLITE_PRIVATE u8 sqlite3VdbeOneByteSerialTypeLen(u8 serial_type){
|
|
** so we trust him.
|
|
*/
|
|
#ifdef SQLITE_MIXED_ENDIAN_64BIT_FLOAT
|
|
-static u64 floatSwap(u64 in){
|
|
+SQLITE_PRIVATE u64 sqlite3FloatSwap(u64 in){
|
|
union {
|
|
u64 r;
|
|
u32 i[2];
|
|
@@ -81049,59 +86298,8 @@ static u64 floatSwap(u64 in){
|
|
u.i[1] = t;
|
|
return u.r;
|
|
}
|
|
-# define swapMixedEndianFloat(X) X = floatSwap(X)
|
|
-#else
|
|
-# define swapMixedEndianFloat(X)
|
|
-#endif
|
|
+#endif /* SQLITE_MIXED_ENDIAN_64BIT_FLOAT */
|
|
|
|
-/*
|
|
-** Write the serialized data blob for the value stored in pMem into
|
|
-** buf. It is assumed that the caller has allocated sufficient space.
|
|
-** Return the number of bytes written.
|
|
-**
|
|
-** nBuf is the amount of space left in buf[]. The caller is responsible
|
|
-** for allocating enough space to buf[] to hold the entire field, exclusive
|
|
-** of the pMem->u.nZero bytes for a MEM_Zero value.
|
|
-**
|
|
-** Return the number of bytes actually written into buf[]. The number
|
|
-** of bytes in the zero-filled tail is included in the return value only
|
|
-** if those bytes were zeroed in buf[].
|
|
-*/
|
|
-SQLITE_PRIVATE u32 sqlite3VdbeSerialPut(u8 *buf, Mem *pMem, u32 serial_type){
|
|
- u32 len;
|
|
-
|
|
- /* Integer and Real */
|
|
- if( serial_type<=7 && serial_type>0 ){
|
|
- u64 v;
|
|
- u32 i;
|
|
- if( serial_type==7 ){
|
|
- assert( sizeof(v)==sizeof(pMem->u.r) );
|
|
- memcpy(&v, &pMem->u.r, sizeof(v));
|
|
- swapMixedEndianFloat(v);
|
|
- }else{
|
|
- v = pMem->u.i;
|
|
- }
|
|
- len = i = sqlite3SmallTypeSizes[serial_type];
|
|
- assert( i>0 );
|
|
- do{
|
|
- buf[--i] = (u8)(v&0xFF);
|
|
- v >>= 8;
|
|
- }while( i );
|
|
- return len;
|
|
- }
|
|
-
|
|
- /* String or blob */
|
|
- if( serial_type>=12 ){
|
|
- assert( pMem->n + ((pMem->flags & MEM_Zero)?pMem->u.nZero:0)
|
|
- == (int)sqlite3VdbeSerialTypeLen(serial_type) );
|
|
- len = pMem->n;
|
|
- if( len>0 ) memcpy(buf, pMem->z, len);
|
|
- return len;
|
|
- }
|
|
-
|
|
- /* NULL or constants 0 or 1 */
|
|
- return 0;
|
|
-}
|
|
|
|
/* Input "x" is a sequence of unsigned characters that represent a
|
|
** big-endian integer. Return the equivalent native integer
|
|
@@ -81114,14 +86312,14 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialPut(u8 *buf, Mem *pMem, u32 serial_type){
|
|
|
|
/*
|
|
** Deserialize the data blob pointed to by buf as serial type serial_type
|
|
-** and store the result in pMem. Return the number of bytes read.
|
|
+** and store the result in pMem.
|
|
**
|
|
** This function is implemented as two separate routines for performance.
|
|
** The few cases that require local variables are broken out into a separate
|
|
** routine so that in most cases the overhead of moving the stack pointer
|
|
** is avoided.
|
|
-*/
|
|
-static u32 serialGet(
|
|
+*/
|
|
+static void serialGet(
|
|
const unsigned char *buf, /* Buffer to deserialize from */
|
|
u32 serial_type, /* Serial type to deserialize */
|
|
Mem *pMem /* Memory cell to write value into */
|
|
@@ -81155,9 +86353,8 @@ static u32 serialGet(
|
|
memcpy(&pMem->u.r, &x, sizeof(x));
|
|
pMem->flags = IsNaN(x) ? MEM_Null : MEM_Real;
|
|
}
|
|
- return 8;
|
|
}
|
|
-SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(
|
|
+SQLITE_PRIVATE void sqlite3VdbeSerialGet(
|
|
const unsigned char *buf, /* Buffer to deserialize from */
|
|
u32 serial_type, /* Serial type to deserialize */
|
|
Mem *pMem /* Memory cell to write value into */
|
|
@@ -81168,13 +86365,13 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(
|
|
pMem->flags = MEM_Null|MEM_Zero;
|
|
pMem->n = 0;
|
|
pMem->u.nZero = 0;
|
|
- break;
|
|
+ return;
|
|
}
|
|
case 11: /* Reserved for future use */
|
|
case 0: { /* Null */
|
|
/* EVIDENCE-OF: R-24078-09375 Value is a NULL. */
|
|
pMem->flags = MEM_Null;
|
|
- break;
|
|
+ return;
|
|
}
|
|
case 1: {
|
|
/* EVIDENCE-OF: R-44885-25196 Value is an 8-bit twos-complement
|
|
@@ -81182,7 +86379,7 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(
|
|
pMem->u.i = ONE_BYTE_INT(buf);
|
|
pMem->flags = MEM_Int;
|
|
testcase( pMem->u.i<0 );
|
|
- return 1;
|
|
+ return;
|
|
}
|
|
case 2: { /* 2-byte signed integer */
|
|
/* EVIDENCE-OF: R-49794-35026 Value is a big-endian 16-bit
|
|
@@ -81190,7 +86387,7 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(
|
|
pMem->u.i = TWO_BYTE_INT(buf);
|
|
pMem->flags = MEM_Int;
|
|
testcase( pMem->u.i<0 );
|
|
- return 2;
|
|
+ return;
|
|
}
|
|
case 3: { /* 3-byte signed integer */
|
|
/* EVIDENCE-OF: R-37839-54301 Value is a big-endian 24-bit
|
|
@@ -81198,19 +86395,19 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(
|
|
pMem->u.i = THREE_BYTE_INT(buf);
|
|
pMem->flags = MEM_Int;
|
|
testcase( pMem->u.i<0 );
|
|
- return 3;
|
|
+ return;
|
|
}
|
|
case 4: { /* 4-byte signed integer */
|
|
/* EVIDENCE-OF: R-01849-26079 Value is a big-endian 32-bit
|
|
** twos-complement integer. */
|
|
pMem->u.i = FOUR_BYTE_INT(buf);
|
|
-#ifdef __HP_cc
|
|
+#ifdef __HP_cc
|
|
/* Work around a sign-extension bug in the HP compiler for HP/UX */
|
|
if( buf[0]&0x80 ) pMem->u.i |= 0xffffffff80000000LL;
|
|
#endif
|
|
pMem->flags = MEM_Int;
|
|
testcase( pMem->u.i<0 );
|
|
- return 4;
|
|
+ return;
|
|
}
|
|
case 5: { /* 6-byte signed integer */
|
|
/* EVIDENCE-OF: R-50385-09674 Value is a big-endian 48-bit
|
|
@@ -81218,13 +86415,14 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(
|
|
pMem->u.i = FOUR_BYTE_UINT(buf+2) + (((i64)1)<<32)*TWO_BYTE_INT(buf);
|
|
pMem->flags = MEM_Int;
|
|
testcase( pMem->u.i<0 );
|
|
- return 6;
|
|
+ return;
|
|
}
|
|
case 6: /* 8-byte signed integer */
|
|
case 7: { /* IEEE floating point */
|
|
/* These use local variables, so do them in a separate routine
|
|
** to avoid having to move the frame pointer in the common case */
|
|
- return serialGet(buf,serial_type,pMem);
|
|
+ serialGet(buf,serial_type,pMem);
|
|
+ return;
|
|
}
|
|
case 8: /* Integer 0 */
|
|
case 9: { /* Integer 1 */
|
|
@@ -81232,7 +86430,7 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(
|
|
/* EVIDENCE-OF: R-18143-12121 Value is the integer 1. */
|
|
pMem->u.i = serial_type-8;
|
|
pMem->flags = MEM_Int;
|
|
- return 0;
|
|
+ return;
|
|
}
|
|
default: {
|
|
/* EVIDENCE-OF: R-14606-31564 Value is a BLOB that is (N-12)/2 bytes in
|
|
@@ -81243,10 +86441,10 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(
|
|
pMem->z = (char *)buf;
|
|
pMem->n = (serial_type-12)/2;
|
|
pMem->flags = aFlag[serial_type&1];
|
|
- return pMem->n;
|
|
+ return;
|
|
}
|
|
}
|
|
- return 0;
|
|
+ return;
|
|
}
|
|
/*
|
|
** This routine is used to allocate sufficient space for an UnpackedRecord
|
|
@@ -81256,7 +86454,7 @@ SQLITE_PRIVATE u32 sqlite3VdbeSerialGet(
|
|
** The space is either allocated using sqlite3DbMallocRaw() or from within
|
|
** the unaligned buffer passed via the second and third arguments (presumably
|
|
** stack space). If the former, then *ppFree is set to a pointer that should
|
|
-** be eventually freed by the caller using sqlite3DbFree(). Or, if the
|
|
+** be eventually freed by the caller using sqlite3DbFree(). Or, if the
|
|
** allocation comes from the pSpace/szSpace buffer, *ppFree is set to NULL
|
|
** before returning.
|
|
**
|
|
@@ -81267,10 +86465,10 @@ SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(
|
|
){
|
|
UnpackedRecord *p; /* Unpacked record to return */
|
|
int nByte; /* Number of bytes required for *p */
|
|
- nByte = ROUND8(sizeof(UnpackedRecord)) + sizeof(Mem)*(pKeyInfo->nKeyField+1);
|
|
+ nByte = ROUND8P(sizeof(UnpackedRecord)) + sizeof(Mem)*(pKeyInfo->nKeyField+1);
|
|
p = (UnpackedRecord *)sqlite3DbMallocRaw(pKeyInfo->db, nByte);
|
|
if( !p ) return 0;
|
|
- p->aMem = (Mem*)&((char*)p)[ROUND8(sizeof(UnpackedRecord))];
|
|
+ p->aMem = (Mem*)&((char*)p)[ROUND8P(sizeof(UnpackedRecord))];
|
|
assert( pKeyInfo->aSortFlags!=0 );
|
|
p->pKeyInfo = pKeyInfo;
|
|
p->nField = pKeyInfo->nKeyField + 1;
|
|
@@ -81278,10 +86476,10 @@ SQLITE_PRIVATE UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(
|
|
}
|
|
|
|
/*
|
|
-** Given the nKey-byte encoding of a record in pKey[], populate the
|
|
+** Given the nKey-byte encoding of a record in pKey[], populate the
|
|
** UnpackedRecord structure indicated by the fourth argument with the
|
|
** contents of the decoded record.
|
|
-*/
|
|
+*/
|
|
SQLITE_PRIVATE void sqlite3VdbeRecordUnpack(
|
|
KeyInfo *pKeyInfo, /* Information about the record format */
|
|
int nKey, /* Size of the binary record */
|
|
@@ -81289,7 +86487,7 @@ SQLITE_PRIVATE void sqlite3VdbeRecordUnpack(
|
|
UnpackedRecord *p /* Populate this structure before returning. */
|
|
){
|
|
const unsigned char *aKey = (const unsigned char *)pKey;
|
|
- u32 d;
|
|
+ u32 d;
|
|
u32 idx; /* Offset in aKey[] to read from */
|
|
u16 u; /* Unsigned loop counter */
|
|
u32 szHdr;
|
|
@@ -81309,13 +86507,14 @@ SQLITE_PRIVATE void sqlite3VdbeRecordUnpack(
|
|
/* pMem->flags = 0; // sqlite3VdbeSerialGet() will set this for us */
|
|
pMem->szMalloc = 0;
|
|
pMem->z = 0;
|
|
- d += sqlite3VdbeSerialGet(&aKey[d], serial_type, pMem);
|
|
+ sqlite3VdbeSerialGet(&aKey[d], serial_type, pMem);
|
|
+ d += sqlite3VdbeSerialTypeLen(serial_type);
|
|
pMem++;
|
|
if( (++u)>=p->nField ) break;
|
|
}
|
|
if( d>(u32)nKey && u ){
|
|
assert( CORRUPT_DB );
|
|
- /* In a corrupt record entry, the last pMem might have been set up using
|
|
+ /* In a corrupt record entry, the last pMem might have been set up using
|
|
** uninitialized memory. Overwrite its value with NULL, to prevent
|
|
** warnings from MSAN. */
|
|
sqlite3VdbeMemSetNull(pMem-1);
|
|
@@ -81359,13 +86558,13 @@ static int vdbeRecordCompareDebug(
|
|
|
|
/* Compilers may complain that mem1.u.i is potentially uninitialized.
|
|
** We could initialize it, as shown here, to silence those complaints.
|
|
- ** But in fact, mem1.u.i will never actually be used uninitialized, and doing
|
|
+ ** But in fact, mem1.u.i will never actually be used uninitialized, and doing
|
|
** the unnecessary initialization has a measurable negative performance
|
|
** impact, since this routine is a very high runner. And so, we choose
|
|
** to ignore the compiler warnings and leave this variable uninitialized.
|
|
*/
|
|
/* mem1.u.i = 0; // not needed, here to silence compiler warning */
|
|
-
|
|
+
|
|
idx1 = getVarint32(aKey1, szHdr1);
|
|
if( szHdr1>98307 ) return SQLITE_CORRUPT;
|
|
d1 = szHdr1;
|
|
@@ -81386,14 +86585,15 @@ static int vdbeRecordCompareDebug(
|
|
** sqlite3VdbeSerialTypeLen() in the common case.
|
|
*/
|
|
if( d1+(u64)serial_type1+2>(u64)nKey1
|
|
- && d1+(u64)sqlite3VdbeSerialTypeLen(serial_type1)>(u64)nKey1
|
|
+ && d1+(u64)sqlite3VdbeSerialTypeLen(serial_type1)>(u64)nKey1
|
|
){
|
|
break;
|
|
}
|
|
|
|
/* Extract the values to be compared.
|
|
*/
|
|
- d1 += sqlite3VdbeSerialGet(&aKey1[d1], serial_type1, &mem1);
|
|
+ sqlite3VdbeSerialGet(&aKey1[d1], serial_type1, &mem1);
|
|
+ d1 += sqlite3VdbeSerialTypeLen(serial_type1);
|
|
|
|
/* Do the comparison
|
|
*/
|
|
@@ -81402,7 +86602,7 @@ static int vdbeRecordCompareDebug(
|
|
if( rc!=0 ){
|
|
assert( mem1.szMalloc==0 ); /* See comment below */
|
|
if( (pKeyInfo->aSortFlags[i] & KEYINFO_ORDER_BIGNULL)
|
|
- && ((mem1.flags & MEM_Null) || (pPKey2->aMem[i].flags & MEM_Null))
|
|
+ && ((mem1.flags & MEM_Null) || (pPKey2->aMem[i].flags & MEM_Null))
|
|
){
|
|
rc = -rc;
|
|
}
|
|
@@ -81448,7 +86648,7 @@ static int vdbeRecordCompareDebug(
|
|
** incorrectly.
|
|
*/
|
|
static void vdbeAssertFieldCountWithinLimits(
|
|
- int nKey, const void *pKey, /* The record to verify */
|
|
+ int nKey, const void *pKey, /* The record to verify */
|
|
const KeyInfo *pKeyInfo /* Compare size with this KeyInfo */
|
|
){
|
|
int nField = 0;
|
|
@@ -81474,7 +86674,7 @@ static void vdbeAssertFieldCountWithinLimits(
|
|
/*
|
|
** Both *pMem1 and *pMem2 contain string values. Compare the two values
|
|
** using the collation sequence pColl. As usual, return a negative , zero
|
|
-** or positive value if *pMem1 is less than, equal to or greater than
|
|
+** or positive value if *pMem1 is less than, equal to or greater than
|
|
** *pMem2, respectively. Similar in spirit to "rc = (*pMem1) - (*pMem2);".
|
|
*/
|
|
static int vdbeCompareMemString(
|
|
@@ -81504,8 +86704,8 @@ static int vdbeCompareMemString(
|
|
}else{
|
|
rc = pColl->xCmp(pColl->pUser, c1.n, v1, c2.n, v2);
|
|
}
|
|
- sqlite3VdbeMemRelease(&c1);
|
|
- sqlite3VdbeMemRelease(&c2);
|
|
+ sqlite3VdbeMemReleaseMalloc(&c1);
|
|
+ sqlite3VdbeMemReleaseMalloc(&c2);
|
|
return rc;
|
|
}
|
|
}
|
|
@@ -81560,12 +86760,15 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3BlobCompare(const Mem *pB1, const Mem
|
|
** number. Return negative, zero, or positive if the first (i64) is less than,
|
|
** equal to, or greater than the second (double).
|
|
*/
|
|
-static int sqlite3IntFloatCompare(i64 i, double r){
|
|
+SQLITE_PRIVATE int sqlite3IntFloatCompare(i64 i, double r){
|
|
if( sizeof(LONGDOUBLE_TYPE)>8 ){
|
|
LONGDOUBLE_TYPE x = (LONGDOUBLE_TYPE)i;
|
|
+ testcase( x<r );
|
|
+ testcase( x>r );
|
|
+ testcase( x==r );
|
|
if( x<r ) return -1;
|
|
- if( x>r ) return +1;
|
|
- return 0;
|
|
+ if( x>r ) return +1; /*NO_TEST*/ /* work around bugs in gcov */
|
|
+ return 0; /*NO_TEST*/ /* work around bugs in gcov */
|
|
}else{
|
|
i64 y;
|
|
double s;
|
|
@@ -81598,7 +86801,7 @@ SQLITE_PRIVATE int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const C
|
|
f2 = pMem2->flags;
|
|
combined_flags = f1|f2;
|
|
assert( !sqlite3VdbeMemIsRowSet(pMem1) && !sqlite3VdbeMemIsRowSet(pMem2) );
|
|
-
|
|
+
|
|
/* If one value is NULL, it is less than the other. If both values
|
|
** are NULL, return 0.
|
|
*/
|
|
@@ -81661,7 +86864,7 @@ SQLITE_PRIVATE int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const C
|
|
}
|
|
|
|
assert( pMem1->enc==pMem2->enc || pMem1->db->mallocFailed );
|
|
- assert( pMem1->enc==SQLITE_UTF8 ||
|
|
+ assert( pMem1->enc==SQLITE_UTF8 ||
|
|
pMem1->enc==SQLITE_UTF16LE || pMem1->enc==SQLITE_UTF16BE );
|
|
|
|
/* The collation sequence must be defined at this point, even if
|
|
@@ -81676,7 +86879,7 @@ SQLITE_PRIVATE int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const C
|
|
/* If a NULL pointer was passed as the collate function, fall through
|
|
** to the blob case and use memcmp(). */
|
|
}
|
|
-
|
|
+
|
|
/* Both values must be blobs. Compare using memcmp(). */
|
|
return sqlite3BlobCompare(pMem1, pMem2);
|
|
}
|
|
@@ -81684,7 +86887,7 @@ SQLITE_PRIVATE int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const C
|
|
|
|
/*
|
|
** The first argument passed to this function is a serial-type that
|
|
-** corresponds to an integer - all values between 1 and 9 inclusive
|
|
+** corresponds to an integer - all values between 1 and 9 inclusive
|
|
** except 7. The second points to a buffer containing an integer value
|
|
** serialized according to serial_type. This function deserializes
|
|
** and returns the value.
|
|
@@ -81726,7 +86929,7 @@ static i64 vdbeRecordDecodeInt(u32 serial_type, const u8 *aKey){
|
|
/*
|
|
** This function compares the two table rows or index records
|
|
** specified by {nKey1, pKey1} and pPKey2. It returns a negative, zero
|
|
-** or positive integer if key1 is less than, equal to or
|
|
+** or positive integer if key1 is less than, equal to or
|
|
** greater than key2. The {nKey1, pKey1} key must be a blob
|
|
** created by the OP_MakeRecord opcode of the VDBE. The pPKey2
|
|
** key must be a parsed key such as obtained from
|
|
@@ -81735,12 +86938,12 @@ static i64 vdbeRecordDecodeInt(u32 serial_type, const u8 *aKey){
|
|
** If argument bSkip is non-zero, it is assumed that the caller has already
|
|
** determined that the first fields of the keys are equal.
|
|
**
|
|
-** Key1 and Key2 do not have to contain the same number of fields. If all
|
|
-** fields that appear in both keys are equal, then pPKey2->default_rc is
|
|
+** Key1 and Key2 do not have to contain the same number of fields. If all
|
|
+** fields that appear in both keys are equal, then pPKey2->default_rc is
|
|
** returned.
|
|
**
|
|
-** If database corruption is discovered, set pPKey2->errCode to
|
|
-** SQLITE_CORRUPT and return 0. If an OOM error is encountered,
|
|
+** If database corruption is discovered, set pPKey2->errCode to
|
|
+** SQLITE_CORRUPT and return 0. If an OOM error is encountered,
|
|
** pPKey2->errCode is set to SQLITE_NOMEM and, if it is not NULL, the
|
|
** malloc-failed flag set on database handle (pPKey2->pKeyInfo->db).
|
|
*/
|
|
@@ -81763,29 +86966,37 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
|
|
** two elements in the keys are equal. Fix the various stack variables so
|
|
** that this routine begins comparing at the second field. */
|
|
if( bSkip ){
|
|
- u32 s1;
|
|
- idx1 = 1 + getVarint32(&aKey1[1], s1);
|
|
+ u32 s1 = aKey1[1];
|
|
+ if( s1<0x80 ){
|
|
+ idx1 = 2;
|
|
+ }else{
|
|
+ idx1 = 1 + sqlite3GetVarint32(&aKey1[1], &s1);
|
|
+ }
|
|
szHdr1 = aKey1[0];
|
|
d1 = szHdr1 + sqlite3VdbeSerialTypeLen(s1);
|
|
i = 1;
|
|
pRhs++;
|
|
}else{
|
|
- idx1 = getVarint32(aKey1, szHdr1);
|
|
+ if( (szHdr1 = aKey1[0])<0x80 ){
|
|
+ idx1 = 1;
|
|
+ }else{
|
|
+ idx1 = sqlite3GetVarint32(aKey1, &szHdr1);
|
|
+ }
|
|
d1 = szHdr1;
|
|
i = 0;
|
|
}
|
|
- if( d1>(unsigned)nKey1 ){
|
|
+ if( d1>(unsigned)nKey1 ){
|
|
pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT;
|
|
return 0; /* Corruption */
|
|
}
|
|
|
|
VVA_ONLY( mem1.szMalloc = 0; ) /* Only needed by assert() statements */
|
|
- assert( pPKey2->pKeyInfo->nAllField>=pPKey2->nField
|
|
+ assert( pPKey2->pKeyInfo->nAllField>=pPKey2->nField
|
|
|| CORRUPT_DB );
|
|
assert( pPKey2->pKeyInfo->aSortFlags!=0 );
|
|
assert( pPKey2->pKeyInfo->nKeyField>0 );
|
|
assert( idx1<=szHdr1 || CORRUPT_DB );
|
|
- do{
|
|
+ while( 1 /*exit-by-break*/ ){
|
|
u32 serial_type;
|
|
|
|
/* RHS is an integer */
|
|
@@ -81795,7 +87006,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
|
|
serial_type = aKey1[idx1];
|
|
testcase( serial_type==12 );
|
|
if( serial_type>=10 ){
|
|
- rc = +1;
|
|
+ rc = serial_type==10 ? -1 : +1;
|
|
}else if( serial_type==0 ){
|
|
rc = -1;
|
|
}else if( serial_type==7 ){
|
|
@@ -81817,10 +87028,10 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
|
|
serial_type = aKey1[idx1];
|
|
if( serial_type>=10 ){
|
|
/* Serial types 12 or greater are strings and blobs (greater than
|
|
- ** numbers). Types 10 and 11 are currently "reserved for future
|
|
+ ** 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. */
|
|
- rc = +1;
|
|
+ rc = serial_type==10 ? -1 : +1;
|
|
}else if( serial_type==0 ){
|
|
rc = -1;
|
|
}else{
|
|
@@ -81839,7 +87050,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
|
|
|
|
/* RHS is a string */
|
|
else if( pRhs->flags & MEM_Str ){
|
|
- getVarint32(&aKey1[idx1], serial_type);
|
|
+ getVarint32NR(&aKey1[idx1], serial_type);
|
|
testcase( serial_type==12 );
|
|
if( serial_type<12 ){
|
|
rc = -1;
|
|
@@ -81865,7 +87076,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
|
|
}else{
|
|
int nCmp = MIN(mem1.n, pRhs->n);
|
|
rc = memcmp(&aKey1[d1], pRhs->z, nCmp);
|
|
- if( rc==0 ) rc = mem1.n - pRhs->n;
|
|
+ if( rc==0 ) rc = mem1.n - pRhs->n;
|
|
}
|
|
}
|
|
}
|
|
@@ -81873,7 +87084,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
|
|
/* RHS is a blob */
|
|
else if( pRhs->flags & MEM_Blob ){
|
|
assert( (pRhs->flags & MEM_Zero)==0 || pRhs->n==0 );
|
|
- getVarint32(&aKey1[idx1], serial_type);
|
|
+ getVarint32NR(&aKey1[idx1], serial_type);
|
|
testcase( serial_type==12 );
|
|
if( serial_type<12 || (serial_type & 0x01) ){
|
|
rc = -1;
|
|
@@ -81901,7 +87112,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
|
|
/* RHS is null */
|
|
else{
|
|
serial_type = aKey1[idx1];
|
|
- rc = (serial_type!=0);
|
|
+ rc = (serial_type!=0 && serial_type!=10);
|
|
}
|
|
|
|
if( rc!=0 ){
|
|
@@ -81923,8 +87134,13 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
|
|
if( i==pPKey2->nField ) break;
|
|
pRhs++;
|
|
d1 += sqlite3VdbeSerialTypeLen(serial_type);
|
|
+ if( d1>(unsigned)nKey1 ) break;
|
|
idx1 += sqlite3VarintLen(serial_type);
|
|
- }while( idx1<(unsigned)szHdr1 && d1<=(unsigned)nKey1 );
|
|
+ if( idx1>=(unsigned)szHdr1 ){
|
|
+ pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT;
|
|
+ return 0; /* Corrupt index */
|
|
+ }
|
|
+ }
|
|
|
|
/* No memory allocation is ever used on mem1. Prove this using
|
|
** the following assert(). If the assert() fails, it indicates a
|
|
@@ -81934,8 +87150,8 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
|
|
/* rc==0 here means that one or both of the keys ran out of fields and
|
|
** all the fields up to that point were equal. Return the default_rc
|
|
** value. */
|
|
- assert( CORRUPT_DB
|
|
- || vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, pPKey2->default_rc)
|
|
+ assert( CORRUPT_DB
|
|
+ || vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, pPKey2->default_rc)
|
|
|| pPKey2->pKeyInfo->db->mallocFailed
|
|
);
|
|
pPKey2->eqSeen = 1;
|
|
@@ -81950,8 +87166,8 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompare(
|
|
|
|
|
|
/*
|
|
-** This function is an optimized version of sqlite3VdbeRecordCompare()
|
|
-** that (a) the first field of pPKey2 is an integer, and (b) the
|
|
+** This function is an optimized version of sqlite3VdbeRecordCompare()
|
|
+** that (a) the first field of pPKey2 is an integer, and (b) the
|
|
** size-of-header varint at the start of (pKey1/nKey1) fits in a single
|
|
** byte (i.e. is less than 128).
|
|
**
|
|
@@ -82006,7 +87222,7 @@ static int vdbeRecordCompareInt(
|
|
testcase( lhs<0 );
|
|
break;
|
|
}
|
|
- case 8:
|
|
+ case 8:
|
|
lhs = 0;
|
|
break;
|
|
case 9:
|
|
@@ -82014,11 +87230,11 @@ static int vdbeRecordCompareInt(
|
|
break;
|
|
|
|
/* This case could be removed without changing the results of running
|
|
- ** this code. Including it causes gcc to generate a faster switch
|
|
+ ** this code. Including it causes gcc to generate a faster switch
|
|
** statement (since the range of switch targets now starts at zero and
|
|
** is contiguous) but does not cause any duplicate code to be generated
|
|
- ** (as gcc is clever enough to combine the two like cases). Other
|
|
- ** compilers might be similar. */
|
|
+ ** (as gcc is clever enough to combine the two like cases). Other
|
|
+ ** compilers might be similar. */
|
|
case 0: case 7:
|
|
return sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2);
|
|
|
|
@@ -82026,13 +87242,14 @@ static int vdbeRecordCompareInt(
|
|
return sqlite3VdbeRecordCompare(nKey1, pKey1, pPKey2);
|
|
}
|
|
|
|
- v = pPKey2->aMem[0].u.i;
|
|
+ assert( pPKey2->u.i == pPKey2->aMem[0].u.i );
|
|
+ v = pPKey2->u.i;
|
|
if( v>lhs ){
|
|
res = pPKey2->r1;
|
|
}else if( v<lhs ){
|
|
res = pPKey2->r2;
|
|
}else if( pPKey2->nField>1 ){
|
|
- /* The first fields of the two keys are equal. Compare the trailing
|
|
+ /* The first fields of the two keys are equal. Compare the trailing
|
|
** fields. */
|
|
res = sqlite3VdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 1);
|
|
}else{
|
|
@@ -82047,9 +87264,9 @@ static int vdbeRecordCompareInt(
|
|
}
|
|
|
|
/*
|
|
-** This function is an optimized version of sqlite3VdbeRecordCompare()
|
|
+** This function is an optimized version of sqlite3VdbeRecordCompare()
|
|
** that (a) the first field of pPKey2 is a string, that (b) the first field
|
|
-** uses the collation sequence BINARY and (c) that the size-of-header varint
|
|
+** uses the collation sequence BINARY and (c) that the size-of-header varint
|
|
** at the start of (pKey1/nKey1) fits in a single byte.
|
|
*/
|
|
static int vdbeRecordCompareString(
|
|
@@ -82061,11 +87278,20 @@ static int vdbeRecordCompareString(
|
|
int res;
|
|
|
|
assert( pPKey2->aMem[0].flags & MEM_Str );
|
|
+ assert( pPKey2->aMem[0].n == pPKey2->n );
|
|
+ assert( pPKey2->aMem[0].z == pPKey2->u.z );
|
|
vdbeAssertFieldCountWithinLimits(nKey1, pKey1, pPKey2->pKeyInfo);
|
|
- getVarint32(&aKey1[1], serial_type);
|
|
+ serial_type = (signed char)(aKey1[1]);
|
|
+
|
|
+vrcs_restart:
|
|
if( serial_type<12 ){
|
|
+ if( serial_type<0 ){
|
|
+ sqlite3GetVarint32(&aKey1[1], (u32*)&serial_type);
|
|
+ if( serial_type>=12 ) goto vrcs_restart;
|
|
+ assert( CORRUPT_DB );
|
|
+ }
|
|
res = pPKey2->r1; /* (pKey1/nKey1) is a number or a null */
|
|
- }else if( !(serial_type & 0x01) ){
|
|
+ }else if( !(serial_type & 0x01) ){
|
|
res = pPKey2->r2; /* (pKey1/nKey1) is a blob */
|
|
}else{
|
|
int nCmp;
|
|
@@ -82077,15 +87303,15 @@ static int vdbeRecordCompareString(
|
|
pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT;
|
|
return 0; /* Corruption */
|
|
}
|
|
- nCmp = MIN( pPKey2->aMem[0].n, nStr );
|
|
- res = memcmp(&aKey1[szHdr], pPKey2->aMem[0].z, nCmp);
|
|
+ nCmp = MIN( pPKey2->n, nStr );
|
|
+ res = memcmp(&aKey1[szHdr], pPKey2->u.z, nCmp);
|
|
|
|
if( res>0 ){
|
|
res = pPKey2->r2;
|
|
}else if( res<0 ){
|
|
res = pPKey2->r1;
|
|
}else{
|
|
- res = nStr - pPKey2->aMem[0].n;
|
|
+ res = nStr - pPKey2->n;
|
|
if( res==0 ){
|
|
if( pPKey2->nField>1 ){
|
|
res = sqlite3VdbeRecordCompareWithSkip(nKey1, pKey1, pPKey2, 1);
|
|
@@ -82117,7 +87343,7 @@ SQLITE_PRIVATE RecordCompare sqlite3VdbeFindCompare(UnpackedRecord *p){
|
|
/* varintRecordCompareInt() and varintRecordCompareString() both assume
|
|
** that the size-of-header varint that occurs at the start of each record
|
|
** fits in a single byte (i.e. is 127 or less). varintRecordCompareInt()
|
|
- ** also assumes that it is safe to overread a buffer by at least the
|
|
+ ** also assumes that it is safe to overread a buffer by at least the
|
|
** maximum possible legal header size plus 8 bytes. Because there is
|
|
** guaranteed to be at least 74 (but not 136) bytes of padding following each
|
|
** buffer passed to varintRecordCompareInt() this makes it convenient to
|
|
@@ -82140,6 +87366,7 @@ SQLITE_PRIVATE RecordCompare sqlite3VdbeFindCompare(UnpackedRecord *p){
|
|
p->r2 = 1;
|
|
}
|
|
if( (flags & MEM_Int) ){
|
|
+ p->u.i = p->aMem[0].u.i;
|
|
return vdbeRecordCompareInt;
|
|
}
|
|
testcase( flags & MEM_Real );
|
|
@@ -82149,6 +87376,8 @@ SQLITE_PRIVATE RecordCompare sqlite3VdbeFindCompare(UnpackedRecord *p){
|
|
&& p->pKeyInfo->aColl[0]==0
|
|
){
|
|
assert( flags & MEM_Str );
|
|
+ p->u.z = p->aMem[0].z;
|
|
+ p->n = p->aMem[0].n;
|
|
return vdbeRecordCompareString;
|
|
}
|
|
}
|
|
@@ -82175,7 +87404,7 @@ SQLITE_PRIVATE int sqlite3VdbeIdxRowid(sqlite3 *db, BtCursor *pCur, i64 *rowid){
|
|
/* Get the size of the index entry. Only indices entries of less
|
|
** than 2GiB are support - anything large must be database corruption.
|
|
** Any corruption is detected in sqlite3BtreeParseCellPtr(), though, so
|
|
- ** this code can safely assume that nCellKey is 32-bits
|
|
+ ** this code can safely assume that nCellKey is 32-bits
|
|
*/
|
|
assert( sqlite3BtreeCursorIsValid(pCur) );
|
|
nCellKey = sqlite3BtreePayloadSize(pCur);
|
|
@@ -82183,15 +87412,15 @@ SQLITE_PRIVATE int sqlite3VdbeIdxRowid(sqlite3 *db, BtCursor *pCur, i64 *rowid){
|
|
|
|
/* Read in the complete content of the index entry */
|
|
sqlite3VdbeMemInit(&m, db, 0);
|
|
- rc = sqlite3VdbeMemFromBtree(pCur, 0, (u32)nCellKey, &m);
|
|
+ rc = sqlite3VdbeMemFromBtreeZeroOffset(pCur, (u32)nCellKey, &m);
|
|
if( rc ){
|
|
return rc;
|
|
}
|
|
|
|
/* The index entry must begin with a header size */
|
|
- (void)getVarint32((u8*)m.z, szHdr);
|
|
+ getVarint32NR((u8*)m.z, szHdr);
|
|
testcase( szHdr==3 );
|
|
- testcase( szHdr==m.n );
|
|
+ testcase( szHdr==(u32)m.n );
|
|
testcase( szHdr>0x7fffffff );
|
|
assert( m.n>=0 );
|
|
if( unlikely(szHdr<3 || szHdr>(unsigned)m.n) ){
|
|
@@ -82200,7 +87429,7 @@ SQLITE_PRIVATE int sqlite3VdbeIdxRowid(sqlite3 *db, BtCursor *pCur, i64 *rowid){
|
|
|
|
/* The last field of the index should be an integer - the ROWID.
|
|
** Verify that the last entry really is an integer. */
|
|
- (void)getVarint32((u8*)&m.z[szHdr-1], typeRowid);
|
|
+ getVarint32NR((u8*)&m.z[szHdr-1], typeRowid);
|
|
testcase( typeRowid==1 );
|
|
testcase( typeRowid==2 );
|
|
testcase( typeRowid==3 );
|
|
@@ -82221,14 +87450,14 @@ SQLITE_PRIVATE int sqlite3VdbeIdxRowid(sqlite3 *db, BtCursor *pCur, i64 *rowid){
|
|
/* Fetch the integer off the end of the index record */
|
|
sqlite3VdbeSerialGet((u8*)&m.z[m.n-lenRowid], typeRowid, &v);
|
|
*rowid = v.u.i;
|
|
- sqlite3VdbeMemRelease(&m);
|
|
+ sqlite3VdbeMemReleaseMalloc(&m);
|
|
return SQLITE_OK;
|
|
|
|
/* Jump here if database corruption is detected after m has been
|
|
** allocated. Free the m object and return SQLITE_CORRUPT. */
|
|
idx_rowid_corruption:
|
|
testcase( m.szMalloc!=0 );
|
|
- sqlite3VdbeMemRelease(&m);
|
|
+ sqlite3VdbeMemReleaseMalloc(&m);
|
|
return SQLITE_CORRUPT_BKPT;
|
|
}
|
|
|
|
@@ -82240,7 +87469,7 @@ SQLITE_PRIVATE int sqlite3VdbeIdxRowid(sqlite3 *db, BtCursor *pCur, i64 *rowid){
|
|
**
|
|
** pUnpacked is either created without a rowid or is truncated so that it
|
|
** omits the rowid at the end. The rowid at the end of the index entry
|
|
-** is ignored as well. Hence, this routine only compares the prefixes
|
|
+** is ignored as well. Hence, this routine only compares the prefixes
|
|
** of the keys prior to the final rowid, not the entire key.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(
|
|
@@ -82265,20 +87494,20 @@ SQLITE_PRIVATE int sqlite3VdbeIdxKeyCompare(
|
|
return SQLITE_CORRUPT_BKPT;
|
|
}
|
|
sqlite3VdbeMemInit(&m, db, 0);
|
|
- rc = sqlite3VdbeMemFromBtree(pCur, 0, (u32)nCellKey, &m);
|
|
+ rc = sqlite3VdbeMemFromBtreeZeroOffset(pCur, (u32)nCellKey, &m);
|
|
if( rc ){
|
|
return rc;
|
|
}
|
|
*res = sqlite3VdbeRecordCompareWithSkip(m.n, m.z, pUnpacked, 0);
|
|
- sqlite3VdbeMemRelease(&m);
|
|
+ sqlite3VdbeMemReleaseMalloc(&m);
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
/*
|
|
** This routine sets the value to be returned by subsequent calls to
|
|
-** sqlite3_changes() on the database handle 'db'.
|
|
+** sqlite3_changes() on the database handle 'db'.
|
|
*/
|
|
-SQLITE_PRIVATE void sqlite3VdbeSetChanges(sqlite3 *db, int nChange){
|
|
+SQLITE_PRIVATE void sqlite3VdbeSetChanges(sqlite3 *db, i64 nChange){
|
|
assert( sqlite3_mutex_held(db->mutex) );
|
|
db->nChange = nChange;
|
|
db->nTotalChange += nChange;
|
|
@@ -82312,7 +87541,7 @@ SQLITE_PRIVATE void sqlite3VdbeCountChanges(Vdbe *v){
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3ExpirePreparedStatements(sqlite3 *db, int iCode){
|
|
Vdbe *p;
|
|
- for(p = db->pVdbe; p; p=p->pNext){
|
|
+ for(p = db->pVdbe; p; p=p->pVNext){
|
|
p->expired = iCode+1;
|
|
}
|
|
}
|
|
@@ -82333,7 +87562,7 @@ SQLITE_PRIVATE u8 sqlite3VdbePrepareFlags(Vdbe *v){
|
|
|
|
/*
|
|
** Return a pointer to an sqlite3_value structure containing the value bound
|
|
-** parameter iVar of VM v. Except, if the value is an SQL NULL, return
|
|
+** parameter iVar of VM v. Except, if the value is an SQL NULL, return
|
|
** 0 instead. Unless it is NULL, apply affinity aff (one of the SQLITE_AFF_*
|
|
** constants) to the value before returning it.
|
|
**
|
|
@@ -82425,7 +87654,7 @@ SQLITE_PRIVATE void sqlite3VtabImportErrmsg(Vdbe *p, sqlite3_vtab *pVtab){
|
|
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
|
|
|
|
/*
|
|
-** If the second argument is not NULL, release any allocations associated
|
|
+** If the second argument is not NULL, release any allocations associated
|
|
** with the memory cells in the p->aMem[] array. Also free the UnpackedRecord
|
|
** structure itself, using sqlite3DbFree().
|
|
**
|
|
@@ -82433,13 +87662,14 @@ SQLITE_PRIVATE void sqlite3VtabImportErrmsg(Vdbe *p, sqlite3_vtab *pVtab){
|
|
** the vdbeUnpackRecord() function found in vdbeapi.c.
|
|
*/
|
|
static void vdbeFreeUnpacked(sqlite3 *db, int nField, UnpackedRecord *p){
|
|
+ assert( db!=0 );
|
|
if( p ){
|
|
int i;
|
|
for(i=0; i<nField; i++){
|
|
Mem *pMem = &p->aMem[i];
|
|
- if( pMem->zMalloc ) sqlite3VdbeMemRelease(pMem);
|
|
+ if( pMem->zMalloc ) sqlite3VdbeMemReleaseMalloc(pMem);
|
|
}
|
|
- sqlite3DbFreeNN(db, p);
|
|
+ sqlite3DbNNFreeNN(db, p);
|
|
}
|
|
}
|
|
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
|
|
@@ -82458,7 +87688,8 @@ SQLITE_PRIVATE void sqlite3VdbePreUpdateHook(
|
|
const char *zDb, /* Database name */
|
|
Table *pTab, /* Modified table */
|
|
i64 iKey1, /* Initial key value */
|
|
- int iReg /* Register for new.* record */
|
|
+ int iReg, /* Register for new.* record */
|
|
+ int iBlobWrite
|
|
){
|
|
sqlite3 *db = v->db;
|
|
i64 iKey2;
|
|
@@ -82479,7 +87710,9 @@ SQLITE_PRIVATE void sqlite3VdbePreUpdateHook(
|
|
}
|
|
}
|
|
|
|
- assert( pCsr->nField==pTab->nCol
|
|
+ assert( pCsr!=0 );
|
|
+ assert( pCsr->eCurType==CURTYPE_BTREE );
|
|
+ assert( pCsr->nField==pTab->nCol
|
|
|| (pCsr->nField==pTab->nCol+1 && op==SQLITE_DELETE && iReg==-1)
|
|
);
|
|
|
|
@@ -82494,6 +87727,7 @@ SQLITE_PRIVATE void sqlite3VdbePreUpdateHook(
|
|
preupdate.iKey1 = iKey1;
|
|
preupdate.iKey2 = iKey2;
|
|
preupdate.pTab = pTab;
|
|
+ preupdate.iBlobWrite = iBlobWrite;
|
|
|
|
db->pPreUpdate = &preupdate;
|
|
db->xPreUpdateCallback(db->pPreUpdateArg, db, op, zDb, zTbl, iKey1, iKey2);
|
|
@@ -82506,7 +87740,7 @@ SQLITE_PRIVATE void sqlite3VdbePreUpdateHook(
|
|
for(i=0; i<pCsr->nField; i++){
|
|
sqlite3VdbeMemRelease(&preupdate.aNew[i]);
|
|
}
|
|
- sqlite3DbFreeNN(db, preupdate.aNew);
|
|
+ sqlite3DbNNFreeNN(db, preupdate.aNew);
|
|
}
|
|
}
|
|
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
|
|
@@ -82530,6 +87764,7 @@ SQLITE_PRIVATE void sqlite3VdbePreUpdateHook(
|
|
*/
|
|
/* #include "sqliteInt.h" */
|
|
/* #include "vdbeInt.h" */
|
|
+/* #include "opcodes.h" */
|
|
|
|
#ifndef SQLITE_OMIT_DEPRECATED
|
|
/*
|
|
@@ -82588,7 +87823,7 @@ static SQLITE_NOINLINE void invokeProfileCallback(sqlite3 *db, Vdbe *p){
|
|
}
|
|
#endif
|
|
if( db->mTrace & SQLITE_TRACE_PROFILE ){
|
|
- db->xTrace(SQLITE_TRACE_PROFILE, db->pTraceArg, p, (void*)&iElapse);
|
|
+ db->trace.xV2(SQLITE_TRACE_PROFILE, db->pTraceArg, p, (void*)&iElapse);
|
|
}
|
|
p->startTime = 0;
|
|
}
|
|
@@ -82623,7 +87858,9 @@ SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt){
|
|
if( vdbeSafety(v) ) return SQLITE_MISUSE_BKPT;
|
|
sqlite3_mutex_enter(db->mutex);
|
|
checkProfileCallback(db, v);
|
|
- rc = sqlite3VdbeFinalize(v);
|
|
+ assert( v->eVdbeState>=VDBE_READY_STATE );
|
|
+ rc = sqlite3VdbeReset(v);
|
|
+ sqlite3VdbeDelete(v);
|
|
rc = sqlite3ApiExit(db, rc);
|
|
sqlite3LeaveMutexAndCloseZombie(db);
|
|
}
|
|
@@ -82831,6 +88068,9 @@ SQLITE_API int sqlite3_value_type(sqlite3_value* pVal){
|
|
#endif
|
|
return aType[pVal->flags&MEM_AffMask];
|
|
}
|
|
+SQLITE_API int sqlite3_value_encoding(sqlite3_value *pVal){
|
|
+ return pVal->enc;
|
|
+}
|
|
|
|
/* Return true if a parameter to xUpdate represents an unchanged column */
|
|
SQLITE_API int sqlite3_value_nochange(sqlite3_value *pVal){
|
|
@@ -82860,6 +88100,9 @@ SQLITE_API sqlite3_value *sqlite3_value_dup(const sqlite3_value *pOrig){
|
|
sqlite3ValueFree(pNew);
|
|
pNew = 0;
|
|
}
|
|
+ }else if( pNew->flags & MEM_Null ){
|
|
+ /* Do not duplicate pointer values */
|
|
+ pNew->flags &= ~(MEM_Term|MEM_Subtype);
|
|
}
|
|
return pNew;
|
|
}
|
|
@@ -82870,15 +88113,15 @@ SQLITE_API sqlite3_value *sqlite3_value_dup(const sqlite3_value *pOrig){
|
|
SQLITE_API void sqlite3_value_free(sqlite3_value *pOld){
|
|
sqlite3ValueFree(pOld);
|
|
}
|
|
-
|
|
+
|
|
|
|
/**************************** sqlite3_result_ *******************************
|
|
** The following routines are used by user-defined functions to specify
|
|
** the function result.
|
|
**
|
|
** The setStrOrError() function calls sqlite3VdbeMemSetStr() to store the
|
|
-** result as a string or blob but if the string or blob is too large, it
|
|
-** then sets the error code to SQLITE_TOOBIG
|
|
+** result as a string or blob. Appropriate errors are set if the string/blob
|
|
+** is too big or if an OOM occurs.
|
|
**
|
|
** The invokeValueDestructor(P,X) routine invokes destructor function X()
|
|
** on value P is not going to be used and need to be destroyed.
|
|
@@ -82890,7 +88133,21 @@ static void setResultStrOrError(
|
|
u8 enc, /* Encoding of z. 0 for BLOBs */
|
|
void (*xDel)(void*) /* Destructor function */
|
|
){
|
|
- if( sqlite3VdbeMemSetStr(pCtx->pOut, z, n, enc, xDel)==SQLITE_TOOBIG ){
|
|
+ Mem *pOut = pCtx->pOut;
|
|
+ int rc = sqlite3VdbeMemSetStr(pOut, z, n, enc, xDel);
|
|
+ if( rc ){
|
|
+ if( rc==SQLITE_TOOBIG ){
|
|
+ sqlite3_result_error_toobig(pCtx);
|
|
+ }else{
|
|
+ /* The only errors possible from sqlite3VdbeMemSetStr are
|
|
+ ** SQLITE_TOOBIG and SQLITE_NOMEM */
|
|
+ assert( rc==SQLITE_NOMEM );
|
|
+ sqlite3_result_error_nomem(pCtx);
|
|
+ }
|
|
+ return;
|
|
+ }
|
|
+ sqlite3VdbeChangeEncoding(pOut, pCtx->enc);
|
|
+ if( sqlite3VdbeMemTooBig(pOut) ){
|
|
sqlite3_result_error_toobig(pCtx);
|
|
}
|
|
}
|
|
@@ -82907,13 +88164,13 @@ static int invokeValueDestructor(
|
|
}else{
|
|
xDel((void*)p);
|
|
}
|
|
- if( pCtx ) sqlite3_result_error_toobig(pCtx);
|
|
+ sqlite3_result_error_toobig(pCtx);
|
|
return SQLITE_TOOBIG;
|
|
}
|
|
SQLITE_API void sqlite3_result_blob(
|
|
- sqlite3_context *pCtx,
|
|
- const void *z,
|
|
- int n,
|
|
+ sqlite3_context *pCtx,
|
|
+ const void *z,
|
|
+ int n,
|
|
void (*xDel)(void *)
|
|
){
|
|
assert( n>=0 );
|
|
@@ -82921,8 +88178,8 @@ SQLITE_API void sqlite3_result_blob(
|
|
setResultStrOrError(pCtx, z, n, 0, xDel);
|
|
}
|
|
SQLITE_API void sqlite3_result_blob64(
|
|
- sqlite3_context *pCtx,
|
|
- const void *z,
|
|
+ sqlite3_context *pCtx,
|
|
+ const void *z,
|
|
sqlite3_uint64 n,
|
|
void (*xDel)(void *)
|
|
){
|
|
@@ -82981,8 +88238,8 @@ SQLITE_API void sqlite3_result_subtype(sqlite3_context *pCtx, unsigned int eSubt
|
|
pOut->flags |= MEM_Subtype;
|
|
}
|
|
SQLITE_API void sqlite3_result_text(
|
|
- sqlite3_context *pCtx,
|
|
- const char *z,
|
|
+ sqlite3_context *pCtx,
|
|
+ const char *z,
|
|
int n,
|
|
void (*xDel)(void *)
|
|
){
|
|
@@ -82990,15 +88247,18 @@ SQLITE_API void sqlite3_result_text(
|
|
setResultStrOrError(pCtx, z, n, SQLITE_UTF8, xDel);
|
|
}
|
|
SQLITE_API void sqlite3_result_text64(
|
|
- sqlite3_context *pCtx,
|
|
- const char *z,
|
|
+ sqlite3_context *pCtx,
|
|
+ const char *z,
|
|
sqlite3_uint64 n,
|
|
void (*xDel)(void *),
|
|
unsigned char enc
|
|
){
|
|
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
|
|
assert( xDel!=SQLITE_DYNAMIC );
|
|
- if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE;
|
|
+ if( enc!=SQLITE_UTF8 ){
|
|
+ if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE;
|
|
+ n &= ~(u64)1;
|
|
+ }
|
|
if( n>0x7fffffff ){
|
|
(void)invokeValueDestructor(z, xDel, pCtx);
|
|
}else{
|
|
@@ -83007,49 +88267,58 @@ SQLITE_API void sqlite3_result_text64(
|
|
}
|
|
#ifndef SQLITE_OMIT_UTF16
|
|
SQLITE_API void sqlite3_result_text16(
|
|
- sqlite3_context *pCtx,
|
|
- const void *z,
|
|
- int n,
|
|
+ sqlite3_context *pCtx,
|
|
+ const void *z,
|
|
+ int n,
|
|
void (*xDel)(void *)
|
|
){
|
|
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
|
|
- setResultStrOrError(pCtx, z, n, SQLITE_UTF16NATIVE, xDel);
|
|
+ setResultStrOrError(pCtx, z, n & ~(u64)1, SQLITE_UTF16NATIVE, xDel);
|
|
}
|
|
SQLITE_API void sqlite3_result_text16be(
|
|
- sqlite3_context *pCtx,
|
|
- const void *z,
|
|
- int n,
|
|
+ sqlite3_context *pCtx,
|
|
+ const void *z,
|
|
+ int n,
|
|
void (*xDel)(void *)
|
|
){
|
|
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
|
|
- setResultStrOrError(pCtx, z, n, SQLITE_UTF16BE, xDel);
|
|
+ setResultStrOrError(pCtx, z, n & ~(u64)1, SQLITE_UTF16BE, xDel);
|
|
}
|
|
SQLITE_API void sqlite3_result_text16le(
|
|
- sqlite3_context *pCtx,
|
|
- const void *z,
|
|
- int n,
|
|
+ sqlite3_context *pCtx,
|
|
+ const void *z,
|
|
+ int n,
|
|
void (*xDel)(void *)
|
|
){
|
|
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
|
|
- setResultStrOrError(pCtx, z, n, SQLITE_UTF16LE, xDel);
|
|
+ setResultStrOrError(pCtx, z, n & ~(u64)1, SQLITE_UTF16LE, xDel);
|
|
}
|
|
#endif /* SQLITE_OMIT_UTF16 */
|
|
SQLITE_API void sqlite3_result_value(sqlite3_context *pCtx, sqlite3_value *pValue){
|
|
+ Mem *pOut = pCtx->pOut;
|
|
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
|
|
- sqlite3VdbeMemCopy(pCtx->pOut, pValue);
|
|
+ sqlite3VdbeMemCopy(pOut, pValue);
|
|
+ sqlite3VdbeChangeEncoding(pOut, pCtx->enc);
|
|
+ if( sqlite3VdbeMemTooBig(pOut) ){
|
|
+ sqlite3_result_error_toobig(pCtx);
|
|
+ }
|
|
}
|
|
SQLITE_API void sqlite3_result_zeroblob(sqlite3_context *pCtx, int n){
|
|
- assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
|
|
- sqlite3VdbeMemSetZeroBlob(pCtx->pOut, n);
|
|
+ sqlite3_result_zeroblob64(pCtx, n>0 ? n : 0);
|
|
}
|
|
SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context *pCtx, u64 n){
|
|
Mem *pOut = pCtx->pOut;
|
|
assert( sqlite3_mutex_held(pOut->db->mutex) );
|
|
if( n>(u64)pOut->db->aLimit[SQLITE_LIMIT_LENGTH] ){
|
|
+ sqlite3_result_error_toobig(pCtx);
|
|
return SQLITE_TOOBIG;
|
|
}
|
|
+#ifndef SQLITE_OMIT_INCRBLOB
|
|
sqlite3VdbeMemSetZeroBlob(pCtx->pOut, (int)n);
|
|
return SQLITE_OK;
|
|
+#else
|
|
+ return sqlite3VdbeMemSetZeroBlob(pCtx->pOut, (int)n);
|
|
+#endif
|
|
}
|
|
SQLITE_API void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){
|
|
pCtx->isError = errCode ? errCode : -1;
|
|
@@ -83057,8 +88326,8 @@ SQLITE_API void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){
|
|
if( pCtx->pVdbe ) pCtx->pVdbe->rcApp = errCode;
|
|
#endif
|
|
if( pCtx->pOut->flags & MEM_Null ){
|
|
- sqlite3VdbeMemSetStr(pCtx->pOut, sqlite3ErrStr(errCode), -1,
|
|
- SQLITE_UTF8, SQLITE_STATIC);
|
|
+ setResultStrOrError(pCtx, sqlite3ErrStr(errCode), -1, SQLITE_UTF8,
|
|
+ SQLITE_STATIC);
|
|
}
|
|
}
|
|
|
|
@@ -83066,7 +88335,7 @@ SQLITE_API void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){
|
|
SQLITE_API void sqlite3_result_error_toobig(sqlite3_context *pCtx){
|
|
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
|
|
pCtx->isError = SQLITE_TOOBIG;
|
|
- sqlite3VdbeMemSetStr(pCtx->pOut, "string or blob too big", -1,
|
|
+ sqlite3VdbeMemSetStr(pCtx->pOut, "string or blob too big", -1,
|
|
SQLITE_UTF8, SQLITE_STATIC);
|
|
}
|
|
|
|
@@ -83083,7 +88352,7 @@ SQLITE_API void sqlite3_result_error_nomem(sqlite3_context *pCtx){
|
|
** a MEM_IntReal value. See the SQLITE_TESTCTRL_RESULT_INTREAL
|
|
** test-control.
|
|
*/
|
|
-SQLITE_PRIVATE void sqlite3ResultIntReal(sqlite3_context *pCtx){
|
|
+SQLITE_PRIVATE void sqlite3ResultIntReal(sqlite3_context *pCtx){
|
|
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
|
|
if( pCtx->pOut->flags & MEM_Int ){
|
|
pCtx->pOut->flags &= ~MEM_Int;
|
|
@@ -83094,7 +88363,7 @@ SQLITE_PRIVATE void sqlite3ResultIntReal(sqlite3_context *pCtx){
|
|
|
|
|
|
/*
|
|
-** This function is called after a transaction has been committed. It
|
|
+** This function is called after a transaction has been committed. It
|
|
** invokes callbacks registered with sqlite3_wal_hook() as required.
|
|
*/
|
|
static int doWalCallbacks(sqlite3 *db){
|
|
@@ -83123,7 +88392,7 @@ static int doWalCallbacks(sqlite3 *db){
|
|
** statement is completely executed or an error occurs.
|
|
**
|
|
** This routine implements the bulk of the logic behind the sqlite_step()
|
|
-** API. The only thing omitted is the automatic recompile if a
|
|
+** API. The only thing omitted is the automatic recompile if a
|
|
** schema change has occurred. That detail is handled by the
|
|
** outer sqlite3_step() wrapper procedure.
|
|
*/
|
|
@@ -83132,73 +88401,83 @@ static int sqlite3Step(Vdbe *p){
|
|
int rc;
|
|
|
|
assert(p);
|
|
- if( p->magic!=VDBE_MAGIC_RUN ){
|
|
- /* We used to require that sqlite3_reset() be called before retrying
|
|
- ** sqlite3_step() after any error or after SQLITE_DONE. But beginning
|
|
- ** with version 3.7.0, we changed this so that sqlite3_reset() would
|
|
- ** be called automatically instead of throwing the SQLITE_MISUSE error.
|
|
- ** This "automatic-reset" change is not technically an incompatibility,
|
|
- ** since any application that receives an SQLITE_MISUSE is broken by
|
|
- ** definition.
|
|
- **
|
|
- ** Nevertheless, some published applications that were originally written
|
|
- ** for version 3.6.23 or earlier do in fact depend on SQLITE_MISUSE
|
|
- ** returns, and those were broken by the automatic-reset change. As a
|
|
- ** a work-around, the SQLITE_OMIT_AUTORESET compile-time restores the
|
|
- ** legacy behavior of returning SQLITE_MISUSE for cases where the
|
|
- ** previous sqlite3_step() returned something other than a SQLITE_LOCKED
|
|
- ** or SQLITE_BUSY error.
|
|
- */
|
|
-#ifdef SQLITE_OMIT_AUTORESET
|
|
- if( (rc = p->rc&0xff)==SQLITE_BUSY || rc==SQLITE_LOCKED ){
|
|
- sqlite3_reset((sqlite3_stmt*)p);
|
|
- }else{
|
|
- return SQLITE_MISUSE_BKPT;
|
|
- }
|
|
-#else
|
|
- sqlite3_reset((sqlite3_stmt*)p);
|
|
-#endif
|
|
- }
|
|
-
|
|
- /* Check that malloc() has not failed. If it has, return early. */
|
|
db = p->db;
|
|
- if( db->mallocFailed ){
|
|
- p->rc = SQLITE_NOMEM;
|
|
- return SQLITE_NOMEM_BKPT;
|
|
- }
|
|
+ if( p->eVdbeState!=VDBE_RUN_STATE ){
|
|
+ restart_step:
|
|
+ if( p->eVdbeState==VDBE_READY_STATE ){
|
|
+ if( p->expired ){
|
|
+ p->rc = SQLITE_SCHEMA;
|
|
+ rc = SQLITE_ERROR;
|
|
+ if( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 ){
|
|
+ /* If this statement was prepared using saved SQL and an
|
|
+ ** error has occurred, then return the error code in p->rc to the
|
|
+ ** caller. Set the error code in the database handle to the same
|
|
+ ** value.
|
|
+ */
|
|
+ rc = sqlite3VdbeTransferError(p);
|
|
+ }
|
|
+ goto end_of_step;
|
|
+ }
|
|
|
|
- if( p->pc<0 && p->expired ){
|
|
- p->rc = SQLITE_SCHEMA;
|
|
- rc = SQLITE_ERROR;
|
|
- goto end_of_step;
|
|
- }
|
|
- if( p->pc<0 ){
|
|
- /* If there are no other statements currently running, then
|
|
- ** reset the interrupt flag. This prevents a call to sqlite3_interrupt
|
|
- ** from interrupting a statement that has not yet started.
|
|
- */
|
|
- if( db->nVdbeActive==0 ){
|
|
- db->u1.isInterrupted = 0;
|
|
- }
|
|
+ /* If there are no other statements currently running, then
|
|
+ ** reset the interrupt flag. This prevents a call to sqlite3_interrupt
|
|
+ ** from interrupting a statement that has not yet started.
|
|
+ */
|
|
+ if( db->nVdbeActive==0 ){
|
|
+ AtomicStore(&db->u1.isInterrupted, 0);
|
|
+ }
|
|
|
|
- assert( db->nVdbeWrite>0 || db->autoCommit==0
|
|
- || (db->nDeferredCons==0 && db->nDeferredImmCons==0)
|
|
- );
|
|
+ assert( db->nVdbeWrite>0 || db->autoCommit==0
|
|
+ || (db->nDeferredCons==0 && db->nDeferredImmCons==0)
|
|
+ );
|
|
|
|
#ifndef SQLITE_OMIT_TRACE
|
|
- if( (db->mTrace & (SQLITE_TRACE_PROFILE|SQLITE_TRACE_XPROFILE))!=0
|
|
- && !db->init.busy && p->zSql ){
|
|
- sqlite3OsCurrentTimeInt64(db->pVfs, &p->startTime);
|
|
- }else{
|
|
- assert( p->startTime==0 );
|
|
- }
|
|
+ if( (db->mTrace & (SQLITE_TRACE_PROFILE|SQLITE_TRACE_XPROFILE))!=0
|
|
+ && !db->init.busy && p->zSql ){
|
|
+ sqlite3OsCurrentTimeInt64(db->pVfs, &p->startTime);
|
|
+ }else{
|
|
+ assert( p->startTime==0 );
|
|
+ }
|
|
#endif
|
|
|
|
- db->nVdbeActive++;
|
|
- if( p->readOnly==0 ) db->nVdbeWrite++;
|
|
- if( p->bIsReader ) db->nVdbeRead++;
|
|
- p->pc = 0;
|
|
+ db->nVdbeActive++;
|
|
+ if( p->readOnly==0 ) db->nVdbeWrite++;
|
|
+ if( p->bIsReader ) db->nVdbeRead++;
|
|
+ p->pc = 0;
|
|
+ p->eVdbeState = VDBE_RUN_STATE;
|
|
+ }else
|
|
+
|
|
+ if( ALWAYS(p->eVdbeState==VDBE_HALT_STATE) ){
|
|
+ /* We used to require that sqlite3_reset() be called before retrying
|
|
+ ** sqlite3_step() after any error or after SQLITE_DONE. But beginning
|
|
+ ** with version 3.7.0, we changed this so that sqlite3_reset() would
|
|
+ ** be called automatically instead of throwing the SQLITE_MISUSE error.
|
|
+ ** This "automatic-reset" change is not technically an incompatibility,
|
|
+ ** since any application that receives an SQLITE_MISUSE is broken by
|
|
+ ** definition.
|
|
+ **
|
|
+ ** Nevertheless, some published applications that were originally written
|
|
+ ** for version 3.6.23 or earlier do in fact depend on SQLITE_MISUSE
|
|
+ ** returns, and those were broken by the automatic-reset change. As a
|
|
+ ** a work-around, the SQLITE_OMIT_AUTORESET compile-time restores the
|
|
+ ** legacy behavior of returning SQLITE_MISUSE for cases where the
|
|
+ ** previous sqlite3_step() returned something other than a SQLITE_LOCKED
|
|
+ ** or SQLITE_BUSY error.
|
|
+ */
|
|
+#ifdef SQLITE_OMIT_AUTORESET
|
|
+ if( (rc = p->rc&0xff)==SQLITE_BUSY || rc==SQLITE_LOCKED ){
|
|
+ sqlite3_reset((sqlite3_stmt*)p);
|
|
+ }else{
|
|
+ return SQLITE_MISUSE_BKPT;
|
|
+ }
|
|
+#else
|
|
+ sqlite3_reset((sqlite3_stmt*)p);
|
|
+#endif
|
|
+ assert( p->eVdbeState==VDBE_READY_STATE );
|
|
+ goto restart_step;
|
|
+ }
|
|
}
|
|
+
|
|
#ifdef SQLITE_DEBUG
|
|
p->rcApp = SQLITE_OK;
|
|
#endif
|
|
@@ -83213,47 +88492,44 @@ static int sqlite3Step(Vdbe *p){
|
|
db->nVdbeExec--;
|
|
}
|
|
|
|
- if( rc!=SQLITE_ROW ){
|
|
+ if( rc==SQLITE_ROW ){
|
|
+ assert( p->rc==SQLITE_OK );
|
|
+ assert( db->mallocFailed==0 );
|
|
+ db->errCode = SQLITE_ROW;
|
|
+ return SQLITE_ROW;
|
|
+ }else{
|
|
#ifndef SQLITE_OMIT_TRACE
|
|
/* If the statement completed successfully, invoke the profile callback */
|
|
checkProfileCallback(db, p);
|
|
#endif
|
|
-
|
|
+ p->pResultRow = 0;
|
|
if( rc==SQLITE_DONE && db->autoCommit ){
|
|
assert( p->rc==SQLITE_OK );
|
|
p->rc = doWalCallbacks(db);
|
|
if( p->rc!=SQLITE_OK ){
|
|
rc = SQLITE_ERROR;
|
|
}
|
|
+ }else if( rc!=SQLITE_DONE && (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 ){
|
|
+ /* If this statement was prepared using saved SQL and an
|
|
+ ** error has occurred, then return the error code in p->rc to the
|
|
+ ** caller. Set the error code in the database handle to the same value.
|
|
+ */
|
|
+ rc = sqlite3VdbeTransferError(p);
|
|
}
|
|
}
|
|
|
|
db->errCode = rc;
|
|
if( SQLITE_NOMEM==sqlite3ApiExit(p->db, p->rc) ){
|
|
p->rc = SQLITE_NOMEM_BKPT;
|
|
+ if( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0 ) rc = p->rc;
|
|
}
|
|
end_of_step:
|
|
- /* At this point local variable rc holds the value that should be
|
|
- ** returned if this statement was compiled using the legacy
|
|
- ** sqlite3_prepare() interface. According to the docs, this can only
|
|
- ** be one of the values in the first assert() below. Variable p->rc
|
|
- ** contains the value that would be returned if sqlite3_finalize()
|
|
- ** were called on statement p.
|
|
- */
|
|
- assert( rc==SQLITE_ROW || rc==SQLITE_DONE || rc==SQLITE_ERROR
|
|
+ /* There are only a limited number of result codes allowed from the
|
|
+ ** statements prepared using the legacy sqlite3_prepare() interface */
|
|
+ assert( (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0
|
|
+ || rc==SQLITE_ROW || rc==SQLITE_DONE || rc==SQLITE_ERROR
|
|
|| (rc&0xff)==SQLITE_BUSY || rc==SQLITE_MISUSE
|
|
);
|
|
- assert( (p->rc!=SQLITE_ROW && p->rc!=SQLITE_DONE) || p->rc==p->rcApp );
|
|
- if( rc!=SQLITE_ROW
|
|
- && rc!=SQLITE_DONE
|
|
- && (p->prepFlags & SQLITE_PREPARE_SAVESQL)!=0
|
|
- ){
|
|
- /* If this statement was prepared using saved SQL and an
|
|
- ** error has occurred, then return the error code in p->rc to the
|
|
- ** caller. Set the error code in the database handle to the same value.
|
|
- */
|
|
- rc = sqlite3VdbeTransferError(p);
|
|
- }
|
|
return (rc&db->errMask);
|
|
}
|
|
|
|
@@ -83273,21 +88549,20 @@ SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){
|
|
}
|
|
db = v->db;
|
|
sqlite3_mutex_enter(db->mutex);
|
|
- v->doingRerun = 0;
|
|
while( (rc = sqlite3Step(v))==SQLITE_SCHEMA
|
|
&& cnt++ < SQLITE_MAX_SCHEMA_RETRY ){
|
|
int savedPc = v->pc;
|
|
rc = sqlite3Reprepare(v);
|
|
if( rc!=SQLITE_OK ){
|
|
- /* This case occurs after failing to recompile an sql statement.
|
|
- ** The error message from the SQL compiler has already been loaded
|
|
- ** into the database handle. This block copies the error message
|
|
+ /* This case occurs after failing to recompile an sql statement.
|
|
+ ** The error message from the SQL compiler has already been loaded
|
|
+ ** into the database handle. This block copies the error message
|
|
** from the database handle into the statement and sets the statement
|
|
- ** program counter to 0 to ensure that when the statement is
|
|
+ ** program counter to 0 to ensure that when the statement is
|
|
** finalized or reset the parser error message is available via
|
|
** sqlite3_errmsg() and sqlite3_errcode().
|
|
*/
|
|
- const char *zErr = (const char *)sqlite3_value_text(db->pErr);
|
|
+ const char *zErr = (const char *)sqlite3_value_text(db->pErr);
|
|
sqlite3DbFree(db, v->zErrMsg);
|
|
if( !db->mallocFailed ){
|
|
v->zErrMsg = sqlite3DbStrDup(db, zErr);
|
|
@@ -83299,7 +88574,13 @@ SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){
|
|
break;
|
|
}
|
|
sqlite3_reset(pStmt);
|
|
- if( savedPc>=0 ) v->doingRerun = 1;
|
|
+ if( savedPc>=0 ){
|
|
+ /* Setting minWriteFileFormat to 254 is a signal to the OP_Init and
|
|
+ ** OP_Trace opcodes to *not* perform SQLITE_TRACE_STMT because it has
|
|
+ ** already been done once on a prior invocation that failed due to
|
|
+ ** SQLITE_SCHEMA. tag-20220401a */
|
|
+ v->minWriteFileFormat = 254;
|
|
+ }
|
|
assert( v->expired==0 );
|
|
}
|
|
sqlite3_mutex_leave(db->mutex);
|
|
@@ -83350,6 +88631,88 @@ SQLITE_API int sqlite3_vtab_nochange(sqlite3_context *p){
|
|
return sqlite3_value_nochange(p->pOut);
|
|
}
|
|
|
|
+/*
|
|
+** The destructor function for a ValueList object. This needs to be
|
|
+** a separate function, unknowable to the application, to ensure that
|
|
+** calls to sqlite3_vtab_in_first()/sqlite3_vtab_in_next() that are not
|
|
+** preceeded by activation of IN processing via sqlite3_vtab_int() do not
|
|
+** try to access a fake ValueList object inserted by a hostile extension.
|
|
+*/
|
|
+SQLITE_PRIVATE void sqlite3VdbeValueListFree(void *pToDelete){
|
|
+ sqlite3_free(pToDelete);
|
|
+}
|
|
+
|
|
+/*
|
|
+** Implementation of sqlite3_vtab_in_first() (if bNext==0) and
|
|
+** sqlite3_vtab_in_next() (if bNext!=0).
|
|
+*/
|
|
+static int valueFromValueList(
|
|
+ sqlite3_value *pVal, /* Pointer to the ValueList object */
|
|
+ sqlite3_value **ppOut, /* Store the next value from the list here */
|
|
+ int bNext /* 1 for _next(). 0 for _first() */
|
|
+){
|
|
+ int rc;
|
|
+ ValueList *pRhs;
|
|
+
|
|
+ *ppOut = 0;
|
|
+ if( pVal==0 ) return SQLITE_MISUSE;
|
|
+ if( (pVal->flags & MEM_Dyn)==0 || pVal->xDel!=sqlite3VdbeValueListFree ){
|
|
+ return SQLITE_ERROR;
|
|
+ }else{
|
|
+ assert( (pVal->flags&(MEM_TypeMask|MEM_Term|MEM_Subtype)) ==
|
|
+ (MEM_Null|MEM_Term|MEM_Subtype) );
|
|
+ assert( pVal->eSubtype=='p' );
|
|
+ assert( pVal->u.zPType!=0 && strcmp(pVal->u.zPType,"ValueList")==0 );
|
|
+ pRhs = (ValueList*)pVal->z;
|
|
+ }
|
|
+ if( bNext ){
|
|
+ rc = sqlite3BtreeNext(pRhs->pCsr, 0);
|
|
+ }else{
|
|
+ int dummy = 0;
|
|
+ rc = sqlite3BtreeFirst(pRhs->pCsr, &dummy);
|
|
+ assert( rc==SQLITE_OK || sqlite3BtreeEof(pRhs->pCsr) );
|
|
+ if( sqlite3BtreeEof(pRhs->pCsr) ) rc = SQLITE_DONE;
|
|
+ }
|
|
+ if( rc==SQLITE_OK ){
|
|
+ u32 sz; /* Size of current row in bytes */
|
|
+ Mem sMem; /* Raw content of current row */
|
|
+ memset(&sMem, 0, sizeof(sMem));
|
|
+ sz = sqlite3BtreePayloadSize(pRhs->pCsr);
|
|
+ rc = sqlite3VdbeMemFromBtreeZeroOffset(pRhs->pCsr,(int)sz,&sMem);
|
|
+ if( rc==SQLITE_OK ){
|
|
+ u8 *zBuf = (u8*)sMem.z;
|
|
+ u32 iSerial;
|
|
+ sqlite3_value *pOut = pRhs->pOut;
|
|
+ int iOff = 1 + getVarint32(&zBuf[1], iSerial);
|
|
+ sqlite3VdbeSerialGet(&zBuf[iOff], iSerial, pOut);
|
|
+ pOut->enc = ENC(pOut->db);
|
|
+ if( (pOut->flags & MEM_Ephem)!=0 && sqlite3VdbeMemMakeWriteable(pOut) ){
|
|
+ rc = SQLITE_NOMEM;
|
|
+ }else{
|
|
+ *ppOut = pOut;
|
|
+ }
|
|
+ }
|
|
+ sqlite3VdbeMemRelease(&sMem);
|
|
+ }
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Set the iterator value pVal to point to the first value in the set.
|
|
+** Set (*ppOut) to point to this value before returning.
|
|
+*/
|
|
+SQLITE_API int sqlite3_vtab_in_first(sqlite3_value *pVal, sqlite3_value **ppOut){
|
|
+ return valueFromValueList(pVal, ppOut, 0);
|
|
+}
|
|
+
|
|
+/*
|
|
+** Set the iterator value pVal to point to the next value in the set.
|
|
+** Set (*ppOut) to point to this value before returning.
|
|
+*/
|
|
+SQLITE_API int sqlite3_vtab_in_next(sqlite3_value *pVal, sqlite3_value **ppOut){
|
|
+ return valueFromValueList(pVal, ppOut, 1);
|
|
+}
|
|
+
|
|
/*
|
|
** Return the current time for a statement. If the current time
|
|
** is requested more than once within the same run of a single prepared
|
|
@@ -83449,9 +88812,9 @@ SQLITE_API void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){
|
|
** access code.
|
|
*/
|
|
SQLITE_API void sqlite3_set_auxdata(
|
|
- sqlite3_context *pCtx,
|
|
- int iArg,
|
|
- void *pAux,
|
|
+ sqlite3_context *pCtx,
|
|
+ int iArg,
|
|
+ void *pAux,
|
|
void (*xDelete)(void*)
|
|
){
|
|
AuxData *pAuxData;
|
|
@@ -83493,7 +88856,7 @@ SQLITE_API void sqlite3_set_auxdata(
|
|
|
|
#ifndef SQLITE_OMIT_DEPRECATED
|
|
/*
|
|
-** Return the number of times the Step function of an aggregate has been
|
|
+** Return the number of times the Step function of an aggregate has been
|
|
** called.
|
|
**
|
|
** This function is deprecated. Do not use it for new code. It is
|
|
@@ -83521,7 +88884,7 @@ SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt){
|
|
*/
|
|
SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt){
|
|
Vdbe *pVm = (Vdbe *)pStmt;
|
|
- if( pVm==0 || pVm->pResultSet==0 ) return 0;
|
|
+ if( pVm==0 || pVm->pResultRow==0 ) return 0;
|
|
return pVm->nResColumn;
|
|
}
|
|
|
|
@@ -83538,21 +88901,21 @@ static const Mem *columnNullValue(void){
|
|
** these assert()s from failing, when building with SQLITE_DEBUG defined
|
|
** using gcc, we force nullMem to be 8-byte aligned using the magical
|
|
** __attribute__((aligned(8))) macro. */
|
|
- static const Mem nullMem
|
|
+ static const Mem nullMem
|
|
#if defined(SQLITE_DEBUG) && defined(__GNUC__)
|
|
- __attribute__((aligned(8)))
|
|
+ __attribute__((aligned(8)))
|
|
#endif
|
|
= {
|
|
/* .u = */ {0},
|
|
+ /* .z = */ (char*)0,
|
|
+ /* .n = */ (int)0,
|
|
/* .flags = */ (u16)MEM_Null,
|
|
/* .enc = */ (u8)0,
|
|
/* .eSubtype = */ (u8)0,
|
|
- /* .n = */ (int)0,
|
|
- /* .z = */ (char*)0,
|
|
- /* .zMalloc = */ (char*)0,
|
|
+ /* .db = */ (sqlite3*)0,
|
|
/* .szMalloc = */ (int)0,
|
|
/* .uTemp = */ (u32)0,
|
|
- /* .db = */ (sqlite3*)0,
|
|
+ /* .zMalloc = */ (char*)0,
|
|
/* .xDel = */ (void(*)(void*))0,
|
|
#ifdef SQLITE_DEBUG
|
|
/* .pScopyFrom = */ (Mem*)0,
|
|
@@ -83576,8 +88939,8 @@ static Mem *columnMem(sqlite3_stmt *pStmt, int i){
|
|
if( pVm==0 ) return (Mem*)columnNullValue();
|
|
assert( pVm->db );
|
|
sqlite3_mutex_enter(pVm->db->mutex);
|
|
- if( pVm->pResultSet!=0 && i<pVm->nResColumn && i>=0 ){
|
|
- pOut = &pVm->pResultSet[i];
|
|
+ if( pVm->pResultRow!=0 && i<pVm->nResColumn && i>=0 ){
|
|
+ pOut = &pVm->pResultRow[i];
|
|
}else{
|
|
sqlite3Error(pVm->db, SQLITE_RANGE);
|
|
pOut = (Mem*)columnNullValue();
|
|
@@ -83586,9 +88949,9 @@ static Mem *columnMem(sqlite3_stmt *pStmt, int i){
|
|
}
|
|
|
|
/*
|
|
-** This function is called after invoking an sqlite3_value_XXX function on a
|
|
+** This function is called after invoking an sqlite3_value_XXX function on a
|
|
** column value (i.e. a value returned by evaluating an SQL expression in the
|
|
-** select list of a SELECT statement) that may cause a malloc() failure. If
|
|
+** select list of a SELECT statement) that may cause a malloc() failure. If
|
|
** malloc() has failed, the threads mallocFailed flag is cleared and the result
|
|
** code of statement pStmt set to SQLITE_NOMEM.
|
|
**
|
|
@@ -83627,8 +88990,8 @@ SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt *pStmt, int i){
|
|
const void *val;
|
|
val = sqlite3_value_blob( columnMem(pStmt,i) );
|
|
/* Even though there is no encoding conversion, value_blob() might
|
|
- ** need to call malloc() to expand the result of a zeroblob()
|
|
- ** expression.
|
|
+ ** need to call malloc() to expand the result of a zeroblob()
|
|
+ ** expression.
|
|
*/
|
|
columnMallocFailure(pStmt);
|
|
return val;
|
|
@@ -83829,11 +89192,11 @@ SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt *pStmt, int N){
|
|
|
|
|
|
/******************************* sqlite3_bind_ ***************************
|
|
-**
|
|
+**
|
|
** Routines used to attach values to wildcards in a compiled SQL statement.
|
|
*/
|
|
/*
|
|
-** Unbind the value bound to variable i in virtual machine p. This is the
|
|
+** 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.
|
|
**
|
|
@@ -83843,34 +89206,33 @@ SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt *pStmt, int N){
|
|
** The error code stored in database p->db is overwritten with the return
|
|
** value in any case.
|
|
*/
|
|
-static int vdbeUnbind(Vdbe *p, int i){
|
|
+static int vdbeUnbind(Vdbe *p, unsigned int i){
|
|
Mem *pVar;
|
|
if( vdbeSafetyNotNull(p) ){
|
|
return SQLITE_MISUSE_BKPT;
|
|
}
|
|
sqlite3_mutex_enter(p->db->mutex);
|
|
- if( p->magic!=VDBE_MAGIC_RUN || p->pc>=0 ){
|
|
+ if( p->eVdbeState!=VDBE_READY_STATE ){
|
|
sqlite3Error(p->db, SQLITE_MISUSE);
|
|
sqlite3_mutex_leave(p->db->mutex);
|
|
- sqlite3_log(SQLITE_MISUSE,
|
|
+ sqlite3_log(SQLITE_MISUSE,
|
|
"bind on a busy prepared statement: [%s]", p->zSql);
|
|
return SQLITE_MISUSE_BKPT;
|
|
}
|
|
- if( i<1 || i>p->nVar ){
|
|
+ if( i>=(unsigned int)p->nVar ){
|
|
sqlite3Error(p->db, SQLITE_RANGE);
|
|
sqlite3_mutex_leave(p->db->mutex);
|
|
return SQLITE_RANGE;
|
|
}
|
|
- i--;
|
|
pVar = &p->aVar[i];
|
|
sqlite3VdbeMemRelease(pVar);
|
|
pVar->flags = MEM_Null;
|
|
p->db->errCode = SQLITE_OK;
|
|
|
|
- /* If the bit corresponding to this variable in Vdbe.expmask is set, then
|
|
+ /* If the bit corresponding to this variable in Vdbe.expmask is set, then
|
|
** binding a new value to this variable invalidates the current query plan.
|
|
**
|
|
- ** IMPLEMENTATION-OF: R-48440-37595 If the specific value bound to host
|
|
+ ** IMPLEMENTATION-OF: R-57496-20354 If the specific value bound to a host
|
|
** parameter in the WHERE clause might influence the choice of query plan
|
|
** for a statement, then the statement will be automatically recompiled,
|
|
** as if there had been a schema change, on the first sqlite3_step() call
|
|
@@ -83890,7 +89252,7 @@ static int bindText(
|
|
sqlite3_stmt *pStmt, /* The statement to bind against */
|
|
int i, /* Index of the parameter to bind */
|
|
const void *zData, /* Pointer to the data to be bound */
|
|
- int nData, /* Number of bytes of data to be bound */
|
|
+ i64 nData, /* Number of bytes of data to be bound */
|
|
void (*xDel)(void*), /* Destructor for the data */
|
|
u8 encoding /* Encoding for the data */
|
|
){
|
|
@@ -83898,7 +89260,7 @@ static int bindText(
|
|
Mem *pVar;
|
|
int rc;
|
|
|
|
- rc = vdbeUnbind(p, i);
|
|
+ rc = vdbeUnbind(p, (u32)(i-1));
|
|
if( rc==SQLITE_OK ){
|
|
if( zData!=0 ){
|
|
pVar = &p->aVar[i-1];
|
|
@@ -83923,10 +89285,10 @@ static int bindText(
|
|
** Bind a blob value to an SQL statement variable.
|
|
*/
|
|
SQLITE_API int sqlite3_bind_blob(
|
|
- sqlite3_stmt *pStmt,
|
|
- int i,
|
|
- const void *zData,
|
|
- int nData,
|
|
+ sqlite3_stmt *pStmt,
|
|
+ int i,
|
|
+ const void *zData,
|
|
+ int nData,
|
|
void (*xDel)(void*)
|
|
){
|
|
#ifdef SQLITE_ENABLE_API_ARMOR
|
|
@@ -83935,23 +89297,19 @@ SQLITE_API int sqlite3_bind_blob(
|
|
return bindText(pStmt, i, zData, nData, xDel, 0);
|
|
}
|
|
SQLITE_API int sqlite3_bind_blob64(
|
|
- sqlite3_stmt *pStmt,
|
|
- int i,
|
|
- const void *zData,
|
|
- sqlite3_uint64 nData,
|
|
+ sqlite3_stmt *pStmt,
|
|
+ int i,
|
|
+ const void *zData,
|
|
+ sqlite3_uint64 nData,
|
|
void (*xDel)(void*)
|
|
){
|
|
assert( xDel!=SQLITE_DYNAMIC );
|
|
- if( nData>0x7fffffff ){
|
|
- return invokeValueDestructor(zData, xDel, 0);
|
|
- }else{
|
|
- return bindText(pStmt, i, zData, (int)nData, xDel, 0);
|
|
- }
|
|
+ return bindText(pStmt, i, zData, nData, xDel, 0);
|
|
}
|
|
SQLITE_API int sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){
|
|
int rc;
|
|
Vdbe *p = (Vdbe *)pStmt;
|
|
- rc = vdbeUnbind(p, i);
|
|
+ rc = vdbeUnbind(p, (u32)(i-1));
|
|
if( rc==SQLITE_OK ){
|
|
sqlite3VdbeMemSetDouble(&p->aVar[i-1], rValue);
|
|
sqlite3_mutex_leave(p->db->mutex);
|
|
@@ -83964,7 +89322,7 @@ SQLITE_API int sqlite3_bind_int(sqlite3_stmt *p, int i, int iValue){
|
|
SQLITE_API int sqlite3_bind_int64(sqlite3_stmt *pStmt, int i, sqlite_int64 iValue){
|
|
int rc;
|
|
Vdbe *p = (Vdbe *)pStmt;
|
|
- rc = vdbeUnbind(p, i);
|
|
+ rc = vdbeUnbind(p, (u32)(i-1));
|
|
if( rc==SQLITE_OK ){
|
|
sqlite3VdbeMemSetInt64(&p->aVar[i-1], iValue);
|
|
sqlite3_mutex_leave(p->db->mutex);
|
|
@@ -83974,7 +89332,7 @@ SQLITE_API int sqlite3_bind_int64(sqlite3_stmt *pStmt, int i, sqlite_int64 iValu
|
|
SQLITE_API int sqlite3_bind_null(sqlite3_stmt *pStmt, int i){
|
|
int rc;
|
|
Vdbe *p = (Vdbe*)pStmt;
|
|
- rc = vdbeUnbind(p, i);
|
|
+ rc = vdbeUnbind(p, (u32)(i-1));
|
|
if( rc==SQLITE_OK ){
|
|
sqlite3_mutex_leave(p->db->mutex);
|
|
}
|
|
@@ -83989,7 +89347,7 @@ SQLITE_API int sqlite3_bind_pointer(
|
|
){
|
|
int rc;
|
|
Vdbe *p = (Vdbe*)pStmt;
|
|
- rc = vdbeUnbind(p, i);
|
|
+ rc = vdbeUnbind(p, (u32)(i-1));
|
|
if( rc==SQLITE_OK ){
|
|
sqlite3VdbeMemSetPointer(&p->aVar[i-1], pPtr, zPTtype, xDestructor);
|
|
sqlite3_mutex_leave(p->db->mutex);
|
|
@@ -83998,40 +89356,39 @@ SQLITE_API int sqlite3_bind_pointer(
|
|
}
|
|
return rc;
|
|
}
|
|
-SQLITE_API int sqlite3_bind_text(
|
|
- sqlite3_stmt *pStmt,
|
|
- int i,
|
|
- const char *zData,
|
|
- int nData,
|
|
+SQLITE_API int sqlite3_bind_text(
|
|
+ sqlite3_stmt *pStmt,
|
|
+ int i,
|
|
+ const char *zData,
|
|
+ int nData,
|
|
void (*xDel)(void*)
|
|
){
|
|
return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF8);
|
|
}
|
|
-SQLITE_API int sqlite3_bind_text64(
|
|
- sqlite3_stmt *pStmt,
|
|
- int i,
|
|
- const char *zData,
|
|
- sqlite3_uint64 nData,
|
|
+SQLITE_API int sqlite3_bind_text64(
|
|
+ sqlite3_stmt *pStmt,
|
|
+ int i,
|
|
+ const char *zData,
|
|
+ sqlite3_uint64 nData,
|
|
void (*xDel)(void*),
|
|
unsigned char enc
|
|
){
|
|
assert( xDel!=SQLITE_DYNAMIC );
|
|
- if( nData>0x7fffffff ){
|
|
- return invokeValueDestructor(zData, xDel, 0);
|
|
- }else{
|
|
+ if( enc!=SQLITE_UTF8 ){
|
|
if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE;
|
|
- return bindText(pStmt, i, zData, (int)nData, xDel, enc);
|
|
+ nData &= ~(u16)1;
|
|
}
|
|
+ return bindText(pStmt, i, zData, nData, xDel, enc);
|
|
}
|
|
#ifndef SQLITE_OMIT_UTF16
|
|
SQLITE_API int sqlite3_bind_text16(
|
|
- sqlite3_stmt *pStmt,
|
|
- int i,
|
|
- const void *zData,
|
|
- int nData,
|
|
+ sqlite3_stmt *pStmt,
|
|
+ int i,
|
|
+ const void *zData,
|
|
+ int n,
|
|
void (*xDel)(void*)
|
|
){
|
|
- return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF16NATIVE);
|
|
+ return bindText(pStmt, i, zData, n & ~(u64)1, xDel, SQLITE_UTF16NATIVE);
|
|
}
|
|
#endif /* SQLITE_OMIT_UTF16 */
|
|
SQLITE_API int sqlite3_bind_value(sqlite3_stmt *pStmt, int i, const sqlite3_value *pValue){
|
|
@@ -84042,7 +89399,10 @@ SQLITE_API int sqlite3_bind_value(sqlite3_stmt *pStmt, int i, const sqlite3_valu
|
|
break;
|
|
}
|
|
case SQLITE_FLOAT: {
|
|
- rc = sqlite3_bind_double(pStmt, i, pValue->u.r);
|
|
+ assert( pValue->flags & (MEM_Real|MEM_IntReal) );
|
|
+ rc = sqlite3_bind_double(pStmt, i,
|
|
+ (pValue->flags & MEM_Real) ? pValue->u.r : (double)pValue->u.i
|
|
+ );
|
|
break;
|
|
}
|
|
case SQLITE_BLOB: {
|
|
@@ -84068,9 +89428,13 @@ SQLITE_API int sqlite3_bind_value(sqlite3_stmt *pStmt, int i, const sqlite3_valu
|
|
SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){
|
|
int rc;
|
|
Vdbe *p = (Vdbe *)pStmt;
|
|
- rc = vdbeUnbind(p, i);
|
|
+ rc = vdbeUnbind(p, (u32)(i-1));
|
|
if( rc==SQLITE_OK ){
|
|
+#ifndef SQLITE_OMIT_INCRBLOB
|
|
sqlite3VdbeMemSetZeroBlob(&p->aVar[i-1], n);
|
|
+#else
|
|
+ rc = sqlite3VdbeMemSetZeroBlob(&p->aVar[i-1], n);
|
|
+#endif
|
|
sqlite3_mutex_leave(p->db->mutex);
|
|
}
|
|
return rc;
|
|
@@ -84092,7 +89456,7 @@ SQLITE_API int sqlite3_bind_zeroblob64(sqlite3_stmt *pStmt, int i, sqlite3_uint6
|
|
|
|
/*
|
|
** Return the number of wildcards that can be potentially bound to.
|
|
-** This routine is added to support DBD::SQLite.
|
|
+** This routine is added to support DBD::SQLite.
|
|
*/
|
|
SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt *pStmt){
|
|
Vdbe *p = (Vdbe*)pStmt;
|
|
@@ -84203,7 +89567,7 @@ SQLITE_API int sqlite3_stmt_isexplain(sqlite3_stmt *pStmt){
|
|
*/
|
|
SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt *pStmt){
|
|
Vdbe *v = (Vdbe*)pStmt;
|
|
- return v!=0 && v->magic==VDBE_MAGIC_RUN && v->pc>=0;
|
|
+ return v!=0 && v->eVdbeState==VDBE_RUN_STATE;
|
|
}
|
|
|
|
/*
|
|
@@ -84224,7 +89588,7 @@ SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt){
|
|
if( pStmt==0 ){
|
|
pNext = (sqlite3_stmt*)pDb->pVdbe;
|
|
}else{
|
|
- pNext = (sqlite3_stmt*)((Vdbe*)pStmt)->pNext;
|
|
+ pNext = (sqlite3_stmt*)((Vdbe*)pStmt)->pVNext;
|
|
}
|
|
sqlite3_mutex_leave(pDb->mutex);
|
|
return pNext;
|
|
@@ -84237,7 +89601,7 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt *pStmt, int op, int resetFlag){
|
|
Vdbe *pVdbe = (Vdbe*)pStmt;
|
|
u32 v;
|
|
#ifdef SQLITE_ENABLE_API_ARMOR
|
|
- if( !pStmt
|
|
+ if( !pStmt
|
|
|| (op!=SQLITE_STMTSTATUS_MEMUSED && (op<0||op>=ArraySize(pVdbe->aCounter)))
|
|
){
|
|
(void)SQLITE_MISUSE_BKPT;
|
|
@@ -84249,9 +89613,11 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt *pStmt, int op, int resetFlag){
|
|
sqlite3_mutex_enter(db->mutex);
|
|
v = 0;
|
|
db->pnBytesFreed = (int*)&v;
|
|
- sqlite3VdbeClearObject(db, pVdbe);
|
|
- sqlite3DbFree(db, pVdbe);
|
|
+ assert( db->lookaside.pEnd==db->lookaside.pTrueEnd );
|
|
+ db->lookaside.pEnd = db->lookaside.pStart;
|
|
+ sqlite3VdbeDelete(pVdbe);
|
|
db->pnBytesFreed = 0;
|
|
+ db->lookaside.pEnd = db->lookaside.pTrueEnd;
|
|
sqlite3_mutex_leave(db->mutex);
|
|
}else{
|
|
v = pVdbe->aCounter[op];
|
|
@@ -84316,8 +89682,8 @@ SQLITE_API const char *sqlite3_normalized_sql(sqlite3_stmt *pStmt){
|
|
** if successful, or a NULL pointer if an OOM error is encountered.
|
|
*/
|
|
static UnpackedRecord *vdbeUnpackRecord(
|
|
- KeyInfo *pKeyInfo,
|
|
- int nKey,
|
|
+ KeyInfo *pKeyInfo,
|
|
+ int nKey,
|
|
const void *pKey
|
|
){
|
|
UnpackedRecord *pRet; /* Return value */
|
|
@@ -84358,6 +89724,7 @@ SQLITE_API int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppVa
|
|
u32 nRec;
|
|
u8 *aRec;
|
|
|
|
+ assert( p->pCsr->eCurType==CURTYPE_BTREE );
|
|
nRec = sqlite3BtreePayloadSize(p->pCsr->uc.pCursor);
|
|
aRec = sqlite3DbMallocRaw(db, nRec);
|
|
if( !aRec ) goto preupdate_old_out;
|
|
@@ -84409,7 +89776,7 @@ SQLITE_API int sqlite3_preupdate_count(sqlite3 *db){
|
|
** only. It returns zero if the change that caused the callback was made
|
|
** immediately by a user SQL statement. Or, if the change was made by a
|
|
** trigger program, it returns the number of trigger programs currently
|
|
-** on the stack (1 for a top-level trigger, 2 for a trigger fired by a
|
|
+** on the stack (1 for a top-level trigger, 2 for a trigger fired by a
|
|
** top-level trigger etc.).
|
|
**
|
|
** For the purposes of the previous paragraph, a foreign key CASCADE, SET NULL
|
|
@@ -84421,6 +89788,17 @@ SQLITE_API int sqlite3_preupdate_depth(sqlite3 *db){
|
|
}
|
|
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
|
|
|
|
+#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
|
|
+/*
|
|
+** This function is designed to be called from within a pre-update callback
|
|
+** only.
|
|
+*/
|
|
+SQLITE_API int sqlite3_preupdate_blobwrite(sqlite3 *db){
|
|
+ PreUpdate *p = db->pPreUpdate;
|
|
+ return (p ? p->iBlobWrite : -1);
|
|
+}
|
|
+#endif
|
|
+
|
|
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
|
|
/*
|
|
** This function is called from within a pre-update callback to retrieve
|
|
@@ -84501,23 +89879,60 @@ SQLITE_API int sqlite3_preupdate_new(sqlite3 *db, int iIdx, sqlite3_value **ppVa
|
|
/*
|
|
** Return status data for a single loop within query pStmt.
|
|
*/
|
|
-SQLITE_API int sqlite3_stmt_scanstatus(
|
|
+SQLITE_API int sqlite3_stmt_scanstatus_v2(
|
|
sqlite3_stmt *pStmt, /* Prepared statement being queried */
|
|
- int idx, /* Index of loop to report on */
|
|
+ int iScan, /* Index of loop to report on */
|
|
int iScanStatusOp, /* Which metric to return */
|
|
+ int flags,
|
|
void *pOut /* OUT: Write the answer here */
|
|
){
|
|
Vdbe *p = (Vdbe*)pStmt;
|
|
ScanStatus *pScan;
|
|
- if( idx<0 || idx>=p->nScan ) return 1;
|
|
- pScan = &p->aScan[idx];
|
|
+ int idx;
|
|
+
|
|
+ if( iScan<0 ){
|
|
+ int ii;
|
|
+ if( iScanStatusOp==SQLITE_SCANSTAT_NCYCLE ){
|
|
+ i64 res = 0;
|
|
+ for(ii=0; ii<p->nOp; ii++){
|
|
+ res += p->aOp[ii].nCycle;
|
|
+ }
|
|
+ *(i64*)pOut = res;
|
|
+ return 0;
|
|
+ }
|
|
+ return 1;
|
|
+ }
|
|
+ if( flags & SQLITE_SCANSTAT_COMPLEX ){
|
|
+ idx = iScan;
|
|
+ pScan = &p->aScan[idx];
|
|
+ }else{
|
|
+ /* If the COMPLEX flag is clear, then this function must ignore any
|
|
+ ** ScanStatus structures with ScanStatus.addrLoop set to 0. */
|
|
+ for(idx=0; idx<p->nScan; idx++){
|
|
+ pScan = &p->aScan[idx];
|
|
+ if( pScan->zName ){
|
|
+ iScan--;
|
|
+ if( iScan<0 ) break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ if( idx>=p->nScan ) return 1;
|
|
+
|
|
switch( iScanStatusOp ){
|
|
case SQLITE_SCANSTAT_NLOOP: {
|
|
- *(sqlite3_int64*)pOut = p->anExec[pScan->addrLoop];
|
|
+ if( pScan->addrLoop>0 ){
|
|
+ *(sqlite3_int64*)pOut = p->aOp[pScan->addrLoop].nExec;
|
|
+ }else{
|
|
+ *(sqlite3_int64*)pOut = -1;
|
|
+ }
|
|
break;
|
|
}
|
|
case SQLITE_SCANSTAT_NVISIT: {
|
|
- *(sqlite3_int64*)pOut = p->anExec[pScan->addrVisit];
|
|
+ if( pScan->addrVisit>0 ){
|
|
+ *(sqlite3_int64*)pOut = p->aOp[pScan->addrVisit].nExec;
|
|
+ }else{
|
|
+ *(sqlite3_int64*)pOut = -1;
|
|
+ }
|
|
break;
|
|
}
|
|
case SQLITE_SCANSTAT_EST: {
|
|
@@ -84550,6 +89965,45 @@ SQLITE_API int sqlite3_stmt_scanstatus(
|
|
}
|
|
break;
|
|
}
|
|
+ case SQLITE_SCANSTAT_PARENTID: {
|
|
+ if( pScan->addrExplain ){
|
|
+ *(int*)pOut = p->aOp[ pScan->addrExplain ].p2;
|
|
+ }else{
|
|
+ *(int*)pOut = -1;
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+ case SQLITE_SCANSTAT_NCYCLE: {
|
|
+ i64 res = 0;
|
|
+ if( pScan->aAddrRange[0]==0 ){
|
|
+ res = -1;
|
|
+ }else{
|
|
+ int ii;
|
|
+ for(ii=0; ii<ArraySize(pScan->aAddrRange); ii+=2){
|
|
+ int iIns = pScan->aAddrRange[ii];
|
|
+ int iEnd = pScan->aAddrRange[ii+1];
|
|
+ if( iIns==0 ) break;
|
|
+ if( iIns>0 ){
|
|
+ while( iIns<=iEnd ){
|
|
+ res += p->aOp[iIns].nCycle;
|
|
+ iIns++;
|
|
+ }
|
|
+ }else{
|
|
+ int iOp;
|
|
+ for(iOp=0; iOp<p->nOp; iOp++){
|
|
+ Op *pOp = &p->aOp[iOp];
|
|
+ if( pOp->p1!=iEnd ) continue;
|
|
+ if( (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_NCYCLE)==0 ){
|
|
+ continue;
|
|
+ }
|
|
+ res += p->aOp[iOp].nCycle;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ *(i64*)pOut = res;
|
|
+ break;
|
|
+ }
|
|
default: {
|
|
return 1;
|
|
}
|
|
@@ -84557,12 +90011,29 @@ SQLITE_API int sqlite3_stmt_scanstatus(
|
|
return 0;
|
|
}
|
|
|
|
+/*
|
|
+** Return status data for a single loop within query pStmt.
|
|
+*/
|
|
+SQLITE_API int sqlite3_stmt_scanstatus(
|
|
+ sqlite3_stmt *pStmt, /* Prepared statement being queried */
|
|
+ int iScan, /* Index of loop to report on */
|
|
+ int iScanStatusOp, /* Which metric to return */
|
|
+ void *pOut /* OUT: Write the answer here */
|
|
+){
|
|
+ return sqlite3_stmt_scanstatus_v2(pStmt, iScan, iScanStatusOp, 0, pOut);
|
|
+}
|
|
+
|
|
/*
|
|
** Zero all counters associated with the sqlite3_stmt_scanstatus() data.
|
|
*/
|
|
SQLITE_API void sqlite3_stmt_scanstatus_reset(sqlite3_stmt *pStmt){
|
|
Vdbe *p = (Vdbe*)pStmt;
|
|
- memset(p->anExec, 0, p->nOp * sizeof(i64));
|
|
+ int ii;
|
|
+ for(ii=0; ii<p->nOp; ii++){
|
|
+ Op *pOp = &p->aOp[ii];
|
|
+ pOp->nExec = 0;
|
|
+ pOp->nCycle = 0;
|
|
+ }
|
|
}
|
|
#endif /* SQLITE_ENABLE_STMT_SCANSTATUS */
|
|
|
|
@@ -84618,8 +90089,8 @@ static int findNextHostParameter(const char *zSql, int *pnToken){
|
|
/*
|
|
** This function returns a pointer to a nul-terminated string in memory
|
|
** obtained from sqlite3DbMalloc(). If sqlite3.nVdbeExec is 1, then the
|
|
-** string contains a copy of zRawSql but with host parameters expanded to
|
|
-** their current bindings. Or, if sqlite3.nVdbeExec is greater than 1,
|
|
+** string contains a copy of zRawSql but with host parameters expanded to
|
|
+** their current bindings. Or, if sqlite3.nVdbeExec is greater than 1,
|
|
** then the returned string holds a copy of zRawSql with "-- " prepended
|
|
** to each line of text.
|
|
**
|
|
@@ -84654,11 +90125,9 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql(
|
|
#ifndef SQLITE_OMIT_UTF16
|
|
Mem utf8; /* Used to convert UTF16 into UTF8 for display */
|
|
#endif
|
|
- char zBase[100]; /* Initial working space */
|
|
|
|
db = p->db;
|
|
- sqlite3StrAccumInit(&out, 0, zBase, sizeof(zBase),
|
|
- db->aLimit[SQLITE_LIMIT_LENGTH]);
|
|
+ sqlite3StrAccumInit(&out, 0, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]);
|
|
if( db->nVdbeExec>1 ){
|
|
while( *zRawSql ){
|
|
const char *zStart = zRawSql;
|
|
@@ -84695,7 +90164,7 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql(
|
|
assert( idx>0 );
|
|
}
|
|
zRawSql += nToken;
|
|
- nextIndex = idx + 1;
|
|
+ nextIndex = MAX(idx + 1, nextIndex);
|
|
assert( idx>0 && idx<=p->nVar );
|
|
pVar = &p->aVar[idx-1];
|
|
if( pVar->flags & MEM_Null ){
|
|
@@ -84725,7 +90194,7 @@ SQLITE_PRIVATE char *sqlite3VdbeExpandSql(
|
|
nOut = SQLITE_TRACE_SIZE_LIMIT;
|
|
while( nOut<pVar->n && (pVar->z[nOut]&0xc0)==0x80 ){ nOut++; }
|
|
}
|
|
-#endif
|
|
+#endif
|
|
sqlite3_str_appendf(&out, "'%.*q'", nOut, pVar->z);
|
|
#ifdef SQLITE_TRACE_SIZE_LIMIT
|
|
if( nOut<pVar->n ){
|
|
@@ -84900,6 +90369,9 @@ SQLITE_API int sqlite3_found_count = 0;
|
|
*/
|
|
static void test_trace_breakpoint(int pc, Op *pOp, Vdbe *v){
|
|
static int n = 0;
|
|
+ (void)pc;
|
|
+ (void)pOp;
|
|
+ (void)v;
|
|
n++;
|
|
}
|
|
#endif
|
|
@@ -84918,7 +90390,7 @@ static void test_trace_breakpoint(int pc, Op *pOp, Vdbe *v){
|
|
**
|
|
** In other words, if M is 2, then I is either 0 (for fall-through) or
|
|
** 1 (for when the branch is taken). If M is 3, the I is 0 for an
|
|
-** ordinary fall-through, I is 1 if the branch was taken, and I is 2
|
|
+** ordinary fall-through, I is 1 if the branch was taken, and I is 2
|
|
** if the result of comparison is NULL. For M=3, I=2 the jump may or
|
|
** may not be taken, depending on the SQLITE_JUMPIFNULL flags in p5.
|
|
** When M is 4, that means that an OP_Jump is being run. I is 0, 1, or 2
|
|
@@ -85008,11 +90480,10 @@ static VdbeCursor *allocateCursor(
|
|
Vdbe *p, /* The virtual machine */
|
|
int iCur, /* Index of the new VdbeCursor */
|
|
int nField, /* Number of fields in the table or index */
|
|
- int iDb, /* Database the cursor belongs to, or -1 */
|
|
u8 eCurType /* Type of the new cursor */
|
|
){
|
|
/* Find the memory cell that will be used to store the blob of memory
|
|
- ** required for this VdbeCursor structure. It is convenient to use a
|
|
+ ** required for this VdbeCursor structure. It is convenient to use a
|
|
** vdbe memory cell to manage the memory allocation required for a
|
|
** VdbeCursor structure for the following reasons:
|
|
**
|
|
@@ -85033,32 +90504,44 @@ static VdbeCursor *allocateCursor(
|
|
|
|
int nByte;
|
|
VdbeCursor *pCx = 0;
|
|
- nByte =
|
|
- ROUND8(sizeof(VdbeCursor)) + 2*sizeof(u32)*nField +
|
|
+ nByte =
|
|
+ ROUND8P(sizeof(VdbeCursor)) + 2*sizeof(u32)*nField +
|
|
(eCurType==CURTYPE_BTREE?sqlite3BtreeCursorSize():0);
|
|
|
|
assert( iCur>=0 && iCur<p->nCursor );
|
|
if( p->apCsr[iCur] ){ /*OPTIMIZATION-IF-FALSE*/
|
|
- /* Before calling sqlite3VdbeFreeCursor(), ensure the isEphemeral flag
|
|
- ** is clear. Otherwise, if this is an ephemeral cursor created by
|
|
- ** OP_OpenDup, the cursor will not be closed and will still be part
|
|
- ** of a BtShared.pCursor list. */
|
|
- if( p->apCsr[iCur]->pBtx==0 ) p->apCsr[iCur]->isEphemeral = 0;
|
|
- sqlite3VdbeFreeCursor(p, p->apCsr[iCur]);
|
|
+ sqlite3VdbeFreeCursorNN(p, p->apCsr[iCur]);
|
|
p->apCsr[iCur] = 0;
|
|
}
|
|
- if( SQLITE_OK==sqlite3VdbeMemClearAndResize(pMem, nByte) ){
|
|
- p->apCsr[iCur] = pCx = (VdbeCursor*)pMem->z;
|
|
- memset(pCx, 0, offsetof(VdbeCursor,pAltCursor));
|
|
- pCx->eCurType = eCurType;
|
|
- pCx->iDb = iDb;
|
|
- pCx->nField = nField;
|
|
- pCx->aOffset = &pCx->aType[nField];
|
|
- if( eCurType==CURTYPE_BTREE ){
|
|
- pCx->uc.pCursor = (BtCursor*)
|
|
- &pMem->z[ROUND8(sizeof(VdbeCursor))+2*sizeof(u32)*nField];
|
|
- sqlite3BtreeCursorZero(pCx->uc.pCursor);
|
|
+
|
|
+ /* There used to be a call to sqlite3VdbeMemClearAndResize() to make sure
|
|
+ ** the pMem used to hold space for the cursor has enough storage available
|
|
+ ** in pMem->zMalloc. But for the special case of the aMem[] entries used
|
|
+ ** to hold cursors, it is faster to in-line the logic. */
|
|
+ assert( pMem->flags==MEM_Undefined );
|
|
+ assert( (pMem->flags & MEM_Dyn)==0 );
|
|
+ assert( pMem->szMalloc==0 || pMem->z==pMem->zMalloc );
|
|
+ if( pMem->szMalloc<nByte ){
|
|
+ if( pMem->szMalloc>0 ){
|
|
+ sqlite3DbFreeNN(pMem->db, pMem->zMalloc);
|
|
+ }
|
|
+ pMem->z = pMem->zMalloc = sqlite3DbMallocRaw(pMem->db, nByte);
|
|
+ if( pMem->zMalloc==0 ){
|
|
+ pMem->szMalloc = 0;
|
|
+ return 0;
|
|
}
|
|
+ pMem->szMalloc = nByte;
|
|
+ }
|
|
+
|
|
+ p->apCsr[iCur] = pCx = (VdbeCursor*)pMem->zMalloc;
|
|
+ memset(pCx, 0, offsetof(VdbeCursor,pAltCursor));
|
|
+ pCx->eCurType = eCurType;
|
|
+ pCx->nField = nField;
|
|
+ pCx->aOffset = &pCx->aType[nField];
|
|
+ if( eCurType==CURTYPE_BTREE ){
|
|
+ pCx->uc.pCursor = (BtCursor*)
|
|
+ &pMem->z[ROUND8P(sizeof(VdbeCursor))+2*sizeof(u32)*nField];
|
|
+ sqlite3BtreeCursorZero(pCx->uc.pCursor);
|
|
}
|
|
return pCx;
|
|
}
|
|
@@ -85070,7 +90553,8 @@ static VdbeCursor *allocateCursor(
|
|
** return false.
|
|
*/
|
|
static int alsoAnInt(Mem *pRec, double rValue, i64 *piValue){
|
|
- i64 iValue = (double)rValue;
|
|
+ i64 iValue;
|
|
+ iValue = sqlite3RealToI64(rValue);
|
|
if( sqlite3RealSameAsInt(rValue,iValue) ){
|
|
*piValue = iValue;
|
|
return 1;
|
|
@@ -85120,12 +90604,16 @@ static void applyNumericAffinity(Mem *pRec, int bTryForInt){
|
|
** SQLITE_AFF_INTEGER:
|
|
** SQLITE_AFF_REAL:
|
|
** SQLITE_AFF_NUMERIC:
|
|
-** Try to convert pRec to an integer representation or a
|
|
+** Try to convert pRec to an integer representation or a
|
|
** floating-point representation if an integer representation
|
|
** is not possible. Note that the integer representation is
|
|
** always preferred, even if the affinity is REAL, because
|
|
** an integer representation is more space efficient on disk.
|
|
**
|
|
+** SQLITE_AFF_FLEXNUM:
|
|
+** If the value is text, then try to convert it into a number of
|
|
+** some kind (integer or real) but do not make any other changes.
|
|
+**
|
|
** SQLITE_AFF_TEXT:
|
|
** Convert pRec to a text representation.
|
|
**
|
|
@@ -85140,18 +90628,18 @@ static void applyAffinity(
|
|
){
|
|
if( affinity>=SQLITE_AFF_NUMERIC ){
|
|
assert( affinity==SQLITE_AFF_INTEGER || affinity==SQLITE_AFF_REAL
|
|
- || affinity==SQLITE_AFF_NUMERIC );
|
|
+ || affinity==SQLITE_AFF_NUMERIC || affinity==SQLITE_AFF_FLEXNUM );
|
|
if( (pRec->flags & MEM_Int)==0 ){ /*OPTIMIZATION-IF-FALSE*/
|
|
- if( (pRec->flags & MEM_Real)==0 ){
|
|
+ if( (pRec->flags & (MEM_Real|MEM_IntReal))==0 ){
|
|
if( pRec->flags & MEM_Str ) applyNumericAffinity(pRec,1);
|
|
- }else{
|
|
+ }else if( affinity<=SQLITE_AFF_REAL ){
|
|
sqlite3VdbeIntegerAffinity(pRec);
|
|
}
|
|
}
|
|
}else if( affinity==SQLITE_AFF_TEXT ){
|
|
/* Only attempt the conversion to TEXT if there is an integer or real
|
|
** representation (blob and NULL do not get converted) but no string
|
|
- ** representation. It would be harmless to repeat the conversion if
|
|
+ ** representation. It would be harmless to repeat the conversion if
|
|
** there is already a string rep, but it is pointless to waste those
|
|
** CPU cycles. */
|
|
if( 0==(pRec->flags&MEM_Str) ){ /*OPTIMIZATION-IF-FALSE*/
|
|
@@ -85183,12 +90671,12 @@ SQLITE_API int sqlite3_value_numeric_type(sqlite3_value *pVal){
|
|
}
|
|
|
|
/*
|
|
-** Exported version of applyAffinity(). This one works on sqlite3_value*,
|
|
+** Exported version of applyAffinity(). This one works on sqlite3_value*,
|
|
** not the internal Mem* type.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3ValueApplyAffinity(
|
|
- sqlite3_value *pVal,
|
|
- u8 affinity,
|
|
+ sqlite3_value *pVal,
|
|
+ u8 affinity,
|
|
u8 enc
|
|
){
|
|
applyAffinity((Mem *)pVal, affinity, enc);
|
|
@@ -85205,7 +90693,10 @@ static u16 SQLITE_NOINLINE computeNumericType(Mem *pMem){
|
|
sqlite3_int64 ix;
|
|
assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal))==0 );
|
|
assert( (pMem->flags & (MEM_Str|MEM_Blob))!=0 );
|
|
- ExpandBlob(pMem);
|
|
+ if( ExpandBlob(pMem) ){
|
|
+ pMem->u.i = 0;
|
|
+ return MEM_Int;
|
|
+ }
|
|
rc = sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc);
|
|
if( rc<=0 ){
|
|
if( rc==0 && sqlite3Atoi64(pMem->z, &ix, pMem->n, pMem->enc)<=1 ){
|
|
@@ -85223,23 +90714,24 @@ static u16 SQLITE_NOINLINE computeNumericType(Mem *pMem){
|
|
|
|
/*
|
|
** Return the numeric type for pMem, either MEM_Int or MEM_Real or both or
|
|
-** none.
|
|
+** none.
|
|
**
|
|
** Unlike applyNumericAffinity(), this routine does not modify pMem->flags.
|
|
** But it does set pMem->u.r and pMem->u.i appropriately.
|
|
*/
|
|
static u16 numericType(Mem *pMem){
|
|
- if( pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal) ){
|
|
+ assert( (pMem->flags & MEM_Null)==0
|
|
+ || pMem->db==0 || pMem->db->mallocFailed );
|
|
+ if( pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal|MEM_Null) ){
|
|
testcase( pMem->flags & MEM_Int );
|
|
testcase( pMem->flags & MEM_Real );
|
|
testcase( pMem->flags & MEM_IntReal );
|
|
- return pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal);
|
|
- }
|
|
- if( pMem->flags & (MEM_Str|MEM_Blob) ){
|
|
- testcase( pMem->flags & MEM_Str );
|
|
- testcase( pMem->flags & MEM_Blob );
|
|
- return computeNumericType(pMem);
|
|
+ return pMem->flags & (MEM_Int|MEM_Real|MEM_IntReal|MEM_Null);
|
|
}
|
|
+ assert( pMem->flags & (MEM_Str|MEM_Blob) );
|
|
+ testcase( pMem->flags & MEM_Str );
|
|
+ testcase( pMem->flags & MEM_Blob );
|
|
+ return computeNumericType(pMem);
|
|
return 0;
|
|
}
|
|
|
|
@@ -85343,6 +90835,11 @@ static void registerTrace(int iReg, Mem *p){
|
|
printf("\n");
|
|
sqlite3VdbeCheckMemInvariants(p);
|
|
}
|
|
+/**/ void sqlite3PrintMem(Mem *pMem){
|
|
+ memTracePrint(pMem);
|
|
+ printf("\n");
|
|
+ fflush(stdout);
|
|
+}
|
|
#endif
|
|
|
|
#ifdef SQLITE_DEBUG
|
|
@@ -85363,113 +90860,13 @@ SQLITE_PRIVATE void sqlite3VdbeRegisterDump(Vdbe *v){
|
|
# define REGISTER_TRACE(R,M)
|
|
#endif
|
|
|
|
-
|
|
-#ifdef VDBE_PROFILE
|
|
-
|
|
-/*
|
|
-** hwtime.h contains inline assembler code for implementing
|
|
-** high-performance timing routines.
|
|
-*/
|
|
-/************** Include hwtime.h in the middle of vdbe.c *********************/
|
|
-/************** Begin file hwtime.h ******************************************/
|
|
-/*
|
|
-** 2008 May 27
|
|
-**
|
|
-** The author disclaims copyright to this source code. In place of
|
|
-** a legal notice, here is a blessing:
|
|
-**
|
|
-** May you do good and not evil.
|
|
-** May you find forgiveness for yourself and forgive others.
|
|
-** May you share freely, never taking more than you give.
|
|
-**
|
|
-******************************************************************************
|
|
-**
|
|
-** This file contains inline asm code for retrieving "high-performance"
|
|
-** counters for x86 and x86_64 class CPUs.
|
|
-*/
|
|
-#ifndef SQLITE_HWTIME_H
|
|
-#define SQLITE_HWTIME_H
|
|
-
|
|
-/*
|
|
-** The following routine only works on pentium-class (or newer) processors.
|
|
-** It uses the RDTSC opcode to read the cycle count value out of the
|
|
-** processor and returns that value. This can be used for high-res
|
|
-** profiling.
|
|
-*/
|
|
-#if !defined(__STRICT_ANSI__) && \
|
|
- (defined(__GNUC__) || defined(_MSC_VER)) && \
|
|
- (defined(i386) || defined(__i386__) || defined(_M_IX86))
|
|
-
|
|
- #if defined(__GNUC__)
|
|
-
|
|
- __inline__ sqlite_uint64 sqlite3Hwtime(void){
|
|
- unsigned int lo, hi;
|
|
- __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
|
|
- return (sqlite_uint64)hi << 32 | lo;
|
|
- }
|
|
-
|
|
- #elif defined(_MSC_VER)
|
|
-
|
|
- __declspec(naked) __inline sqlite_uint64 __cdecl sqlite3Hwtime(void){
|
|
- __asm {
|
|
- rdtsc
|
|
- ret ; return value at EDX:EAX
|
|
- }
|
|
- }
|
|
-
|
|
- #endif
|
|
-
|
|
-#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__x86_64__))
|
|
-
|
|
- __inline__ sqlite_uint64 sqlite3Hwtime(void){
|
|
- unsigned long val;
|
|
- __asm__ __volatile__ ("rdtsc" : "=A" (val));
|
|
- return val;
|
|
- }
|
|
-
|
|
-#elif !defined(__STRICT_ANSI__) && (defined(__GNUC__) && defined(__ppc__))
|
|
-
|
|
- __inline__ sqlite_uint64 sqlite3Hwtime(void){
|
|
- unsigned long long retval;
|
|
- unsigned long junk;
|
|
- __asm__ __volatile__ ("\n\
|
|
- 1: mftbu %1\n\
|
|
- mftb %L0\n\
|
|
- mftbu %0\n\
|
|
- cmpw %0,%1\n\
|
|
- bne 1b"
|
|
- : "=r" (retval), "=r" (junk));
|
|
- return retval;
|
|
- }
|
|
-
|
|
-#else
|
|
-
|
|
- /*
|
|
- ** asm() is needed for hardware timing support. Without asm(),
|
|
- ** disable the sqlite3Hwtime() routine.
|
|
- **
|
|
- ** sqlite3Hwtime() is only used for some obscure debugging
|
|
- ** and analysis configurations, not in any deliverable, so this
|
|
- ** should not be a great loss.
|
|
- */
|
|
-SQLITE_PRIVATE sqlite_uint64 sqlite3Hwtime(void){ return ((sqlite_uint64)0); }
|
|
-
|
|
-#endif
|
|
-
|
|
-#endif /* !defined(SQLITE_HWTIME_H) */
|
|
-
|
|
-/************** End of hwtime.h **********************************************/
|
|
-/************** Continuing where we left off in vdbe.c ***********************/
|
|
-
|
|
-#endif
|
|
-
|
|
#ifndef NDEBUG
|
|
/*
|
|
** This function is only called from within an assert() expression. It
|
|
** checks that the sqlite3.nTransaction variable is correctly set to
|
|
-** the number of non-transaction savepoints currently in the
|
|
+** the number of non-transaction savepoints currently in the
|
|
** linked list starting at sqlite3.pSavepoint.
|
|
-**
|
|
+**
|
|
** Usage:
|
|
**
|
|
** assert( checkSavepointCount(db) );
|
|
@@ -85506,50 +90903,86 @@ static Mem *out2Prerelease(Vdbe *p, VdbeOp *pOp){
|
|
}
|
|
}
|
|
|
|
+/*
|
|
+** Compute a bloom filter hash using pOp->p4.i registers from aMem[] beginning
|
|
+** with pOp->p3. Return the hash.
|
|
+*/
|
|
+static u64 filterHash(const Mem *aMem, const Op *pOp){
|
|
+ int i, mx;
|
|
+ u64 h = 0;
|
|
+
|
|
+ assert( pOp->p4type==P4_INT32 );
|
|
+ for(i=pOp->p3, mx=i+pOp->p4.i; i<mx; i++){
|
|
+ const Mem *p = &aMem[i];
|
|
+ if( p->flags & (MEM_Int|MEM_IntReal) ){
|
|
+ h += p->u.i;
|
|
+ }else if( p->flags & MEM_Real ){
|
|
+ h += sqlite3VdbeIntValue(p);
|
|
+ }else if( p->flags & (MEM_Str|MEM_Blob) ){
|
|
+ /* no-op */
|
|
+ }
|
|
+ }
|
|
+ return h;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Return the symbolic name for the data type of a pMem
|
|
+*/
|
|
+static const char *vdbeMemTypeName(Mem *pMem){
|
|
+ static const char *azTypes[] = {
|
|
+ /* SQLITE_INTEGER */ "INT",
|
|
+ /* SQLITE_FLOAT */ "REAL",
|
|
+ /* SQLITE_TEXT */ "TEXT",
|
|
+ /* SQLITE_BLOB */ "BLOB",
|
|
+ /* SQLITE_NULL */ "NULL"
|
|
+ };
|
|
+ return azTypes[sqlite3_value_type(pMem)-1];
|
|
+}
|
|
|
|
/*
|
|
** Execute as much of a VDBE program as we can.
|
|
-** This is the core of sqlite3_step().
|
|
+** This is the core of sqlite3_step().
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3VdbeExec(
|
|
Vdbe *p /* The VDBE */
|
|
){
|
|
Op *aOp = p->aOp; /* Copy of p->aOp */
|
|
Op *pOp = aOp; /* Current operation */
|
|
-#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
|
|
- Op *pOrigOp; /* Value of pOp at the top of the loop */
|
|
-#endif
|
|
#ifdef SQLITE_DEBUG
|
|
+ Op *pOrigOp; /* Value of pOp at the top of the loop */
|
|
int nExtraDelete = 0; /* Verifies FORDELETE and AUXDELETE flags */
|
|
+ u8 iCompareIsInit = 0; /* iCompare is initialized */
|
|
#endif
|
|
int rc = SQLITE_OK; /* Value to return */
|
|
sqlite3 *db = p->db; /* The database */
|
|
u8 resetSchemaOnFault = 0; /* Reset schema after an error if positive */
|
|
u8 encoding = ENC(db); /* The database encoding */
|
|
int iCompare = 0; /* Result of last comparison */
|
|
- unsigned nVmStep = 0; /* Number of virtual machine steps */
|
|
+ u64 nVmStep = 0; /* Number of virtual machine steps */
|
|
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
|
|
- unsigned nProgressLimit; /* Invoke xProgress() when nVmStep reaches this */
|
|
+ u64 nProgressLimit; /* Invoke xProgress() when nVmStep reaches this */
|
|
#endif
|
|
Mem *aMem = p->aMem; /* Copy of p->aMem */
|
|
Mem *pIn1 = 0; /* 1st input operand */
|
|
Mem *pIn2 = 0; /* 2nd input operand */
|
|
Mem *pIn3 = 0; /* 3rd input operand */
|
|
Mem *pOut = 0; /* Output operand */
|
|
-#ifdef VDBE_PROFILE
|
|
- u64 start; /* CPU clock count at start of opcode */
|
|
+#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || defined(VDBE_PROFILE)
|
|
+ u64 *pnCycle = 0;
|
|
#endif
|
|
/*** INSERT STACK UNION HERE ***/
|
|
|
|
- assert( p->magic==VDBE_MAGIC_RUN ); /* sqlite3_step() verifies this */
|
|
- sqlite3VdbeEnter(p);
|
|
+ assert( p->eVdbeState==VDBE_RUN_STATE ); /* sqlite3_step() verifies this */
|
|
+ if( DbMaskNonZero(p->lockMask) ){
|
|
+ sqlite3VdbeEnter(p);
|
|
+ }
|
|
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
|
|
if( db->xProgress ){
|
|
u32 iPrior = p->aCounter[SQLITE_STMTSTATUS_VM_STEP];
|
|
assert( 0 < db->nProgressOps );
|
|
nProgressLimit = db->nProgressOps - (iPrior % db->nProgressOps);
|
|
}else{
|
|
- nProgressLimit = 0xffffffff;
|
|
+ nProgressLimit = LARGEST_UINT64;
|
|
}
|
|
#endif
|
|
if( p->rc==SQLITE_NOMEM ){
|
|
@@ -85558,12 +90991,13 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
|
|
goto no_mem;
|
|
}
|
|
assert( p->rc==SQLITE_OK || (p->rc&0xff)==SQLITE_BUSY );
|
|
+ testcase( p->rc!=SQLITE_OK );
|
|
+ p->rc = SQLITE_OK;
|
|
assert( p->bIsReader || p->readOnly!=0 );
|
|
p->iCurrentTime = 0;
|
|
assert( p->explain==0 );
|
|
- p->pResultSet = 0;
|
|
db->busyHandler.nBusy = 0;
|
|
- if( db->u1.isInterrupted ) goto abort_due_to_interrupt;
|
|
+ if( AtomicLoad(&db->u1.isInterrupted) ) goto abort_due_to_interrupt;
|
|
sqlite3VdbeIOTraceSql(p);
|
|
#ifdef SQLITE_DEBUG
|
|
sqlite3BeginBenignMalloc();
|
|
@@ -85598,12 +91032,14 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
|
|
assert( rc==SQLITE_OK );
|
|
|
|
assert( pOp>=aOp && pOp<&aOp[p->nOp]);
|
|
-#ifdef VDBE_PROFILE
|
|
- start = sqlite3NProfileCnt ? sqlite3NProfileCnt : sqlite3Hwtime();
|
|
-#endif
|
|
nVmStep++;
|
|
-#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
|
|
- if( p->anExec ) p->anExec[(int)(pOp-aOp)]++;
|
|
+#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || defined(VDBE_PROFILE)
|
|
+ pOp->nExec++;
|
|
+ pnCycle = &pOp->nCycle;
|
|
+# ifdef VDBE_PROFILE
|
|
+ if( sqlite3NProfileCnt==0 )
|
|
+# endif
|
|
+ *pnCycle -= sqlite3Hwtime();
|
|
#endif
|
|
|
|
/* Only allow tracing if SQLITE_DEBUG is defined.
|
|
@@ -85614,7 +91050,7 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
|
|
test_trace_breakpoint((int)(pOp - aOp),pOp,p);
|
|
}
|
|
#endif
|
|
-
|
|
+
|
|
|
|
/* Check to see if we need to simulate an interrupt. This only happens
|
|
** if we have a special test build.
|
|
@@ -85665,10 +91101,10 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
|
|
}
|
|
}
|
|
#endif
|
|
-#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
|
|
+#ifdef SQLITE_DEBUG
|
|
pOrigOp = pOp;
|
|
#endif
|
|
-
|
|
+
|
|
switch( pOp->opcode ){
|
|
|
|
/*****************************************************************************
|
|
@@ -85709,7 +91145,7 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
|
|
/* Opcode: Goto * P2 * * *
|
|
**
|
|
** An unconditional jump to address P2.
|
|
-** The next instruction executed will be
|
|
+** The next instruction executed will be
|
|
** the one at index P2 from the beginning of
|
|
** the program.
|
|
**
|
|
@@ -85739,7 +91175,7 @@ case OP_Goto: { /* jump */
|
|
/* Opcodes that are used as the bottom of a loop (OP_Next, OP_Prev,
|
|
** OP_VNext, or OP_SorterNext) all jump here upon
|
|
** completion. Check to see if sqlite3_interrupt() has been called
|
|
- ** or if the progress callback needs to be invoked.
|
|
+ ** or if the progress callback needs to be invoked.
|
|
**
|
|
** This code uses unstructured "goto" statements and does not look clean.
|
|
** But that is not due to sloppy coding habits. The code is written this
|
|
@@ -85747,7 +91183,7 @@ case OP_Goto: { /* jump */
|
|
** checks on every opcode. This helps sqlite3_step() to run about 1.5%
|
|
** faster according to "valgrind --tool=cachegrind" */
|
|
check_for_interrupt:
|
|
- if( db->u1.isInterrupted ) goto abort_due_to_interrupt;
|
|
+ if( AtomicLoad(&db->u1.isInterrupted) ) goto abort_due_to_interrupt;
|
|
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
|
|
/* Call the progress callback if it is configured and the required number
|
|
** of VDBE ops have been executed (either since this invocation of
|
|
@@ -85759,13 +91195,13 @@ case OP_Goto: { /* jump */
|
|
assert( db->nProgressOps!=0 );
|
|
nProgressLimit += db->nProgressOps;
|
|
if( db->xProgress(db->pProgressArg) ){
|
|
- nProgressLimit = 0xffffffff;
|
|
+ nProgressLimit = LARGEST_UINT64;
|
|
rc = SQLITE_INTERRUPT;
|
|
goto abort_due_to_error;
|
|
}
|
|
}
|
|
#endif
|
|
-
|
|
+
|
|
break;
|
|
}
|
|
|
|
@@ -85782,24 +91218,39 @@ case OP_Gosub: { /* jump */
|
|
pIn1->flags = MEM_Int;
|
|
pIn1->u.i = (int)(pOp-aOp);
|
|
REGISTER_TRACE(pOp->p1, pIn1);
|
|
-
|
|
- /* Most jump operations do a goto to this spot in order to update
|
|
- ** the pOp pointer. */
|
|
-jump_to_p2:
|
|
- pOp = &aOp[pOp->p2 - 1];
|
|
- break;
|
|
+ goto jump_to_p2_and_check_for_interrupt;
|
|
}
|
|
|
|
-/* Opcode: Return P1 * * * *
|
|
+/* Opcode: Return P1 P2 P3 * *
|
|
+**
|
|
+** Jump to the address stored in register P1. If P1 is a return address
|
|
+** register, then this accomplishes a return from a subroutine.
|
|
+**
|
|
+** If P3 is 1, then the jump is only taken if register P1 holds an integer
|
|
+** values, otherwise execution falls through to the next opcode, and the
|
|
+** OP_Return becomes a no-op. If P3 is 0, then register P1 must hold an
|
|
+** integer or else an assert() is raised. P3 should be set to 1 when
|
|
+** this opcode is used in combination with OP_BeginSubrtn, and set to 0
|
|
+** otherwise.
|
|
**
|
|
-** Jump to the next instruction after the address in register P1. After
|
|
-** the jump, register P1 becomes undefined.
|
|
+** The value in register P1 is unchanged by this opcode.
|
|
+**
|
|
+** P2 is not used by the byte-code engine. However, if P2 is positive
|
|
+** and also less than the current address, then the "EXPLAIN" output
|
|
+** formatter in the CLI will indent all opcodes from the P2 opcode up
|
|
+** to be not including the current Return. P2 should be the first opcode
|
|
+** in the subroutine from which this opcode is returning. Thus the P2
|
|
+** value is a byte-code indentation hint. See tag-20220407a in
|
|
+** wherecode.c and shell.c.
|
|
*/
|
|
case OP_Return: { /* in1 */
|
|
pIn1 = &aMem[pOp->p1];
|
|
- assert( pIn1->flags==MEM_Int );
|
|
- pOp = &aOp[pIn1->u.i];
|
|
- pIn1->flags = MEM_Undefined;
|
|
+ if( pIn1->flags & MEM_Int ){
|
|
+ if( pOp->p3 ){ VdbeBranchTaken(1, 2); }
|
|
+ pOp = &aOp[pIn1->u.i];
|
|
+ }else if( ALWAYS(pOp->p3) ){
|
|
+ VdbeBranchTaken(0, 2);
|
|
+ }
|
|
break;
|
|
}
|
|
|
|
@@ -85822,7 +91273,14 @@ case OP_InitCoroutine: { /* jump */
|
|
assert( !VdbeMemDynamic(pOut) );
|
|
pOut->u.i = pOp->p3 - 1;
|
|
pOut->flags = MEM_Int;
|
|
- if( pOp->p2 ) goto jump_to_p2;
|
|
+ if( pOp->p2==0 ) break;
|
|
+
|
|
+ /* Most jump operations do a goto to this spot in order to update
|
|
+ ** the pOp pointer. */
|
|
+jump_to_p2:
|
|
+ assert( pOp->p2>0 ); /* There are never any jumps to instruction 0 */
|
|
+ assert( pOp->p2<p->nOp ); /* Jumps must be in range */
|
|
+ pOp = &aOp[pOp->p2 - 1];
|
|
break;
|
|
}
|
|
|
|
@@ -85887,6 +91345,7 @@ case OP_HaltIfNull: { /* in3 */
|
|
#endif
|
|
if( (pIn3->flags & MEM_Null)==0 ) break;
|
|
/* Fall through into OP_Halt */
|
|
+ /* no break */ deliberate_fall_through
|
|
}
|
|
|
|
/* Opcode: Halt P1 P2 * P4 P5
|
|
@@ -85900,7 +91359,7 @@ case OP_HaltIfNull: { /* in3 */
|
|
** whether or not to rollback the current transaction. Do not rollback
|
|
** if P2==OE_Fail. Do the rollback if P2==OE_Rollback. If P2==OE_Abort,
|
|
** then back out all changes that have occurred during this execution of the
|
|
-** VDBE, but do not rollback the transaction.
|
|
+** VDBE, but do not rollback the transaction.
|
|
**
|
|
** If P4 is not null then it is an error message string.
|
|
**
|
|
@@ -85923,11 +91382,16 @@ case OP_Halt: {
|
|
VdbeFrame *pFrame;
|
|
int pcx;
|
|
|
|
- pcx = (int)(pOp - aOp);
|
|
#ifdef SQLITE_DEBUG
|
|
if( pOp->p2==OE_Abort ){ sqlite3VdbeAssertAbortable(p); }
|
|
#endif
|
|
- if( pOp->p1==SQLITE_OK && p->pFrame ){
|
|
+
|
|
+ /* A deliberately coded "OP_Halt SQLITE_INTERNAL * * * *" opcode indicates
|
|
+ ** something is wrong with the code generator. Raise an assertion in order
|
|
+ ** to bring this to the attention of fuzzers and other testing tools. */
|
|
+ assert( pOp->p1!=SQLITE_INTERNAL );
|
|
+
|
|
+ if( p->pFrame && pOp->p1==SQLITE_OK ){
|
|
/* Halt the sub-program. Return control to the parent frame. */
|
|
pFrame = p->pFrame;
|
|
p->pFrame = pFrame->pParent;
|
|
@@ -85935,7 +91399,7 @@ case OP_Halt: {
|
|
sqlite3VdbeSetChanges(db, p->nChange);
|
|
pcx = sqlite3VdbeFrameRestore(pFrame);
|
|
if( pOp->p2==OE_Ignore ){
|
|
- /* Instruction pcx is the OP_Program that invoked the sub-program
|
|
+ /* Instruction pcx is the OP_Program that invoked the sub-program
|
|
** currently being halted. If the p2 instruction of this OP_Halt
|
|
** instruction is set to OE_Ignore, then the sub-program is throwing
|
|
** an IGNORE exception. In this case jump to the address specified
|
|
@@ -85949,7 +91413,6 @@ case OP_Halt: {
|
|
}
|
|
p->rc = pOp->p1;
|
|
p->errorAction = (u8)pOp->p2;
|
|
- p->pc = pcx;
|
|
assert( pOp->p5<=4 );
|
|
if( p->rc ){
|
|
if( pOp->p5 ){
|
|
@@ -85966,6 +91429,7 @@ case OP_Halt: {
|
|
}else{
|
|
sqlite3VdbeError(p, "%s", pOp->p4.z);
|
|
}
|
|
+ pcx = (int)(pOp - aOp);
|
|
sqlite3_log(pOp->p1, "abort at %d in [%s]: %s", pcx, p->zSql, p->zErrMsg);
|
|
}
|
|
rc = sqlite3VdbeHalt(p);
|
|
@@ -86023,7 +91487,7 @@ case OP_Real: { /* same as TK_FLOAT, out2 */
|
|
/* Opcode: String8 * P2 * P4 *
|
|
** Synopsis: r[P2]='P4'
|
|
**
|
|
-** P4 points to a nul terminated UTF-8 string. This opcode is transformed
|
|
+** P4 points to a nul terminated UTF-8 string. This opcode is transformed
|
|
** into a String opcode before it is executed for the first time. During
|
|
** this transformation, the length of string P4 is computed and stored
|
|
** as the P1 parameter.
|
|
@@ -86057,8 +91521,9 @@ case OP_String8: { /* same as TK_STRING, out2 */
|
|
pOp->opcode = OP_String;
|
|
assert( rc==SQLITE_OK );
|
|
/* Fall through to the next case, OP_String */
|
|
+ /* no break */ deliberate_fall_through
|
|
}
|
|
-
|
|
+
|
|
/* Opcode: String P1 P2 P3 P4 P5
|
|
** Synopsis: r[P2]='P4' (len=P1)
|
|
**
|
|
@@ -86090,6 +91555,28 @@ case OP_String: { /* out2 */
|
|
break;
|
|
}
|
|
|
|
+/* Opcode: BeginSubrtn * P2 * * *
|
|
+** Synopsis: r[P2]=NULL
|
|
+**
|
|
+** Mark the beginning of a subroutine that can be entered in-line
|
|
+** or that can be called using OP_Gosub. The subroutine should
|
|
+** be terminated by an OP_Return instruction that has a P1 operand that
|
|
+** is the same as the P2 operand to this opcode and that has P3 set to 1.
|
|
+** If the subroutine is entered in-line, then the OP_Return will simply
|
|
+** fall through. But if the subroutine is entered using OP_Gosub, then
|
|
+** the OP_Return will jump back to the first instruction after the OP_Gosub.
|
|
+**
|
|
+** This routine works by loading a NULL into the P2 register. When the
|
|
+** return address register contains a NULL, the OP_Return instruction is
|
|
+** a no-op that simply falls through to the next instruction (assuming that
|
|
+** the OP_Return opcode has a P3 value of 1). Thus if the subroutine is
|
|
+** entered in-line, then the OP_Return will cause in-line execution to
|
|
+** continue. But if the subroutine is entered via OP_Gosub, then the
|
|
+** OP_Return will cause a return to the address following the OP_Gosub.
|
|
+**
|
|
+** This opcode is identical to OP_Null. It has a different name
|
|
+** only to make the byte code easier to read and verify.
|
|
+*/
|
|
/* Opcode: Null P1 P2 P3 * *
|
|
** Synopsis: r[P2..P3]=NULL
|
|
**
|
|
@@ -86102,6 +91589,7 @@ case OP_String: { /* out2 */
|
|
** NULL values will not compare equal even if SQLITE_NULLEQ is set on
|
|
** OP_Ne or OP_Eq.
|
|
*/
|
|
+case OP_BeginSubrtn:
|
|
case OP_Null: { /* out2 */
|
|
int cnt;
|
|
u16 nullFlag;
|
|
@@ -86143,12 +91631,18 @@ case OP_SoftNull: {
|
|
** Synopsis: r[P2]=P4 (len=P1)
|
|
**
|
|
** P4 points to a blob of data P1 bytes long. Store this
|
|
-** blob in register P2.
|
|
+** blob in register P2. If P4 is a NULL pointer, then construct
|
|
+** a zero-filled blob that is P1 bytes long in P2.
|
|
*/
|
|
case OP_Blob: { /* out2 */
|
|
assert( pOp->p1 <= SQLITE_MAX_LENGTH );
|
|
pOut = out2Prerelease(p, pOp);
|
|
- sqlite3VdbeMemSetStr(pOut, pOp->p4.z, pOp->p1, 0, 0);
|
|
+ if( pOp->p4.z==0 ){
|
|
+ sqlite3VdbeMemSetZeroBlob(pOut, pOp->p1);
|
|
+ if( sqlite3VdbeMemExpandBlob(pOut) ) goto no_mem;
|
|
+ }else{
|
|
+ sqlite3VdbeMemSetStr(pOut, pOp->p4.z, pOp->p1, 0, 0);
|
|
+ }
|
|
pOut->enc = encoding;
|
|
UPDATE_MAX_BLOBSIZE(pOut);
|
|
break;
|
|
@@ -86226,11 +91720,16 @@ case OP_Move: {
|
|
break;
|
|
}
|
|
|
|
-/* Opcode: Copy P1 P2 P3 * *
|
|
+/* Opcode: Copy P1 P2 P3 * P5
|
|
** Synopsis: r[P2@P3+1]=r[P1@P3+1]
|
|
**
|
|
** Make a copy of registers P1..P1+P3 into registers P2..P2+P3.
|
|
**
|
|
+** If the 0x0002 bit of P5 is set then also clear the MEM_Subtype flag in the
|
|
+** destination. The 0x0001 bit of P5 indicates that this Copy opcode cannot
|
|
+** be merged. The 0x0001 bit is used by the query planner and does not
|
|
+** come into play during query execution.
|
|
+**
|
|
** This instruction makes a deep copy of the value. A duplicate
|
|
** is made of any string or blob constant. See also OP_SCopy.
|
|
*/
|
|
@@ -86245,6 +91744,9 @@ case OP_Copy: {
|
|
memAboutToChange(p, pOut);
|
|
sqlite3VdbeMemShallowCopy(pOut, pIn1, MEM_Ephem);
|
|
Deephemeralize(pOut);
|
|
+ if( (pOut->flags & MEM_Subtype)!=0 && (pOp->p5 & 0x0002)!=0 ){
|
|
+ pOut->flags &= ~MEM_Subtype;
|
|
+ }
|
|
#ifdef SQLITE_DEBUG
|
|
pOut->pScopyFrom = 0;
|
|
#endif
|
|
@@ -86297,6 +91799,24 @@ case OP_IntCopy: { /* out2 */
|
|
break;
|
|
}
|
|
|
|
+/* Opcode: FkCheck * * * * *
|
|
+**
|
|
+** Halt with an SQLITE_CONSTRAINT error if there are any unresolved
|
|
+** foreign key constraint violations. If there are no foreign key
|
|
+** constraint violations, this is a no-op.
|
|
+**
|
|
+** FK constraint violations are also checked when the prepared statement
|
|
+** exits. This opcode is used to raise foreign key constraint errors prior
|
|
+** to returning results such as a row change count or the result of a
|
|
+** RETURNING clause.
|
|
+*/
|
|
+case OP_FkCheck: {
|
|
+ if( (rc = sqlite3VdbeCheckFk(p,0))!=SQLITE_OK ){
|
|
+ goto abort_due_to_error;
|
|
+ }
|
|
+ break;
|
|
+}
|
|
+
|
|
/* Opcode: ResultRow P1 P2 * * *
|
|
** Synopsis: output=r[P1@P2]
|
|
**
|
|
@@ -86307,73 +91827,32 @@ case OP_IntCopy: { /* out2 */
|
|
** the result row.
|
|
*/
|
|
case OP_ResultRow: {
|
|
- Mem *pMem;
|
|
- int i;
|
|
assert( p->nResColumn==pOp->p2 );
|
|
- assert( pOp->p1>0 );
|
|
+ assert( pOp->p1>0 || CORRUPT_DB );
|
|
assert( pOp->p1+pOp->p2<=(p->nMem+1 - p->nCursor)+1 );
|
|
|
|
- /* If this statement has violated immediate foreign key constraints, do
|
|
- ** not return the number of rows modified. And do not RELEASE the statement
|
|
- ** transaction. It needs to be rolled back. */
|
|
- if( SQLITE_OK!=(rc = sqlite3VdbeCheckFk(p, 0)) ){
|
|
- assert( db->flags&SQLITE_CountRows );
|
|
- assert( p->usesStmtJournal );
|
|
- goto abort_due_to_error;
|
|
- }
|
|
-
|
|
- /* If the SQLITE_CountRows flag is set in sqlite3.flags mask, then
|
|
- ** DML statements invoke this opcode to return the number of rows
|
|
- ** modified to the user. This is the only way that a VM that
|
|
- ** opens a statement transaction may invoke this opcode.
|
|
- **
|
|
- ** In case this is such a statement, close any statement transaction
|
|
- ** opened by this VM before returning control to the user. This is to
|
|
- ** ensure that statement-transactions are always nested, not overlapping.
|
|
- ** If the open statement-transaction is not closed here, then the user
|
|
- ** may step another VM that opens its own statement transaction. This
|
|
- ** may lead to overlapping statement transactions.
|
|
- **
|
|
- ** The statement transaction is never a top-level transaction. Hence
|
|
- ** the RELEASE call below can never fail.
|
|
- */
|
|
- assert( p->iStatement==0 || db->flags&SQLITE_CountRows );
|
|
- rc = sqlite3VdbeCloseStatement(p, SAVEPOINT_RELEASE);
|
|
- assert( rc==SQLITE_OK );
|
|
-
|
|
- /* Invalidate all ephemeral cursor row caches */
|
|
p->cacheCtr = (p->cacheCtr + 2)|1;
|
|
-
|
|
- /* Make sure the results of the current row are \000 terminated
|
|
- ** and have an assigned type. The results are de-ephemeralized as
|
|
- ** a side effect.
|
|
- */
|
|
- pMem = p->pResultSet = &aMem[pOp->p1];
|
|
- for(i=0; i<pOp->p2; i++){
|
|
- assert( memIsValid(&pMem[i]) );
|
|
- Deephemeralize(&pMem[i]);
|
|
- assert( (pMem[i].flags & MEM_Ephem)==0
|
|
- || (pMem[i].flags & (MEM_Str|MEM_Blob))==0 );
|
|
- sqlite3VdbeMemNulTerminate(&pMem[i]);
|
|
- REGISTER_TRACE(pOp->p1+i, &pMem[i]);
|
|
+ p->pResultRow = &aMem[pOp->p1];
|
|
#ifdef SQLITE_DEBUG
|
|
- /* The registers in the result will not be used again when the
|
|
- ** prepared statement restarts. This is because sqlite3_column()
|
|
- ** APIs might have caused type conversions of made other changes to
|
|
- ** the register values. Therefore, we can go ahead and break any
|
|
- ** OP_SCopy dependencies. */
|
|
- pMem[i].pScopyFrom = 0;
|
|
-#endif
|
|
+ {
|
|
+ Mem *pMem = p->pResultRow;
|
|
+ int i;
|
|
+ for(i=0; i<pOp->p2; i++){
|
|
+ assert( memIsValid(&pMem[i]) );
|
|
+ REGISTER_TRACE(pOp->p1+i, &pMem[i]);
|
|
+ /* The registers in the result will not be used again when the
|
|
+ ** prepared statement restarts. This is because sqlite3_column()
|
|
+ ** APIs might have caused type conversions of made other changes to
|
|
+ ** the register values. Therefore, we can go ahead and break any
|
|
+ ** OP_SCopy dependencies. */
|
|
+ pMem[i].pScopyFrom = 0;
|
|
+ }
|
|
}
|
|
+#endif
|
|
if( db->mallocFailed ) goto no_mem;
|
|
-
|
|
if( db->mTrace & SQLITE_TRACE_ROW ){
|
|
- db->xTrace(SQLITE_TRACE_ROW, db->pTraceArg, p, 0);
|
|
+ db->trace.xV2(SQLITE_TRACE_ROW, db->pTraceArg, p, 0);
|
|
}
|
|
-
|
|
-
|
|
- /* Return SQLITE_ROW
|
|
- */
|
|
p->pc = (int)(pOp - aOp) + 1;
|
|
rc = SQLITE_ROW;
|
|
goto vdbe_return;
|
|
@@ -86400,7 +91879,6 @@ case OP_Concat: { /* same as TK_CONCAT, in1, in2, out3 */
|
|
pIn1 = &aMem[pOp->p1];
|
|
pIn2 = &aMem[pOp->p2];
|
|
pOut = &aMem[pOp->p3];
|
|
- testcase( pIn1==pIn2 );
|
|
testcase( pOut==pIn2 );
|
|
assert( pIn1!=pOut );
|
|
flags1 = pIn1->flags;
|
|
@@ -86429,7 +91907,7 @@ case OP_Concat: { /* same as TK_CONCAT, in1, in2, out3 */
|
|
if( nByte>db->aLimit[SQLITE_LIMIT_LENGTH] ){
|
|
goto too_big;
|
|
}
|
|
- if( sqlite3VdbeMemGrow(pOut, (int)nByte+3, pOut==pIn2) ){
|
|
+ if( sqlite3VdbeMemGrow(pOut, (int)nByte+2, pOut==pIn2) ){
|
|
goto no_mem;
|
|
}
|
|
MemSetTypeFlag(pOut, MEM_Str);
|
|
@@ -86441,9 +91919,9 @@ case OP_Concat: { /* same as TK_CONCAT, in1, in2, out3 */
|
|
memcpy(&pOut->z[pIn2->n], pIn1->z, pIn1->n);
|
|
assert( (pIn1->flags & MEM_Dyn) == (flags1 & MEM_Dyn) );
|
|
pIn1->flags = flags1;
|
|
+ if( encoding>SQLITE_UTF8 ) nByte &= ~1;
|
|
pOut->z[nByte]=0;
|
|
pOut->z[nByte+1] = 0;
|
|
- pOut->z[nByte+2] = 0;
|
|
pOut->flags |= MEM_Term;
|
|
pOut->n = (int)nByte;
|
|
pOut->enc = encoding;
|
|
@@ -86477,15 +91955,15 @@ case OP_Concat: { /* same as TK_CONCAT, in1, in2, out3 */
|
|
** Synopsis: r[P3]=r[P2]/r[P1]
|
|
**
|
|
** Divide the value in register P1 by the value in register P2
|
|
-** and store the result in register P3 (P3=P2/P1). If the value in
|
|
-** register P1 is zero, then the result is NULL. If either input is
|
|
+** and store the result in register P3 (P3=P2/P1). If the value in
|
|
+** register P1 is zero, then the result is NULL. If either input is
|
|
** NULL, the result is NULL.
|
|
*/
|
|
/* Opcode: Remainder P1 P2 P3 * *
|
|
** Synopsis: r[P3]=r[P2]%r[P1]
|
|
**
|
|
-** Compute the remainder after integer register P2 is divided by
|
|
-** register P1 and store the result in register P3.
|
|
+** Compute the remainder after integer register P2 is divided by
|
|
+** register P1 and store the result in register P3.
|
|
** If the value in register P1 is zero the result is NULL.
|
|
** If either operand is NULL, the result is NULL.
|
|
*/
|
|
@@ -86494,7 +91972,6 @@ case OP_Subtract: /* same as TK_MINUS, in1, in2, out3 */
|
|
case OP_Multiply: /* same as TK_STAR, in1, in2, out3 */
|
|
case OP_Divide: /* same as TK_SLASH, in1, in2, out3 */
|
|
case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
|
|
- u16 flags; /* Combined MEM_* flags from both inputs */
|
|
u16 type1; /* Numeric type of left operand */
|
|
u16 type2; /* Numeric type of right operand */
|
|
i64 iA; /* Integer value of left operand */
|
|
@@ -86503,12 +91980,12 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
|
|
double rB; /* Real value of right operand */
|
|
|
|
pIn1 = &aMem[pOp->p1];
|
|
- type1 = numericType(pIn1);
|
|
+ type1 = pIn1->flags;
|
|
pIn2 = &aMem[pOp->p2];
|
|
- type2 = numericType(pIn2);
|
|
+ type2 = pIn2->flags;
|
|
pOut = &aMem[pOp->p3];
|
|
- flags = pIn1->flags | pIn2->flags;
|
|
if( (type1 & type2 & MEM_Int)!=0 ){
|
|
+int_math:
|
|
iA = pIn1->u.i;
|
|
iB = pIn2->u.i;
|
|
switch( pOp->opcode ){
|
|
@@ -86530,9 +92007,12 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
|
|
}
|
|
pOut->u.i = iB;
|
|
MemSetTypeFlag(pOut, MEM_Int);
|
|
- }else if( (flags & MEM_Null)!=0 ){
|
|
+ }else if( ((type1 | type2) & MEM_Null)!=0 ){
|
|
goto arithmetic_result_is_null;
|
|
}else{
|
|
+ type1 = numericType(pIn1);
|
|
+ type2 = numericType(pIn2);
|
|
+ if( (type1 & type2 & MEM_Int)!=0 ) goto int_math;
|
|
fp_math:
|
|
rA = sqlite3VdbeRealValue(pIn1);
|
|
rB = sqlite3VdbeRealValue(pIn2);
|
|
@@ -86680,7 +92160,7 @@ case OP_ShiftRight: { /* same as TK_RSHIFT, in1, in2, out3 */
|
|
|
|
/* Opcode: AddImm P1 P2 * * *
|
|
** Synopsis: r[P1]=r[P1]+P2
|
|
-**
|
|
+**
|
|
** Add the constant P2 to the value in register P1.
|
|
** The result is always an integer.
|
|
**
|
|
@@ -86695,7 +92175,7 @@ case OP_AddImm: { /* in1 */
|
|
}
|
|
|
|
/* Opcode: MustBeInt P1 P2 * * *
|
|
-**
|
|
+**
|
|
** Force the value in register P1 to be an integer. If the value
|
|
** in P1 is not an integer and cannot be converted into an integer
|
|
** without data loss, then jump immediately to P2, or if P2==0
|
|
@@ -86747,7 +92227,7 @@ case OP_RealAffinity: { /* in1 */
|
|
** Synopsis: affinity(r[P1])
|
|
**
|
|
** Force the value in register P1 to be the type defined by P2.
|
|
-**
|
|
+**
|
|
** <ul>
|
|
** <li> P2=='A' → BLOB
|
|
** <li> P2=='B' → TEXT
|
|
@@ -86781,18 +92261,17 @@ case OP_Cast: { /* in1 */
|
|
** Synopsis: IF r[P3]==r[P1]
|
|
**
|
|
** Compare the values in register P1 and P3. If reg(P3)==reg(P1) then
|
|
-** jump to address P2. Or if the SQLITE_STOREP2 flag is set in P5, then
|
|
-** store the result of comparison in register P2.
|
|
+** jump to address P2.
|
|
**
|
|
** The SQLITE_AFF_MASK portion of P5 must be an affinity character -
|
|
-** SQLITE_AFF_TEXT, SQLITE_AFF_INTEGER, and so forth. An attempt is made
|
|
+** SQLITE_AFF_TEXT, SQLITE_AFF_INTEGER, and so forth. An attempt is made
|
|
** to coerce both inputs according to this affinity before the
|
|
** comparison is made. If the SQLITE_AFF_MASK is 0x00, then numeric
|
|
** affinity is used. Note that the affinity conversions are stored
|
|
** back into the input registers P1 and P3. So this opcode can cause
|
|
** persistent changes to registers P1 and P3.
|
|
**
|
|
-** Once any conversions have taken place, and neither value is NULL,
|
|
+** Once any conversions have taken place, and neither value is NULL,
|
|
** the values are compared. If both values are blobs then memcmp() is
|
|
** used to determine the results of the comparison. If both values
|
|
** are text, then the appropriate collating function specified in
|
|
@@ -86808,9 +92287,8 @@ case OP_Cast: { /* in1 */
|
|
** If neither operand is NULL the result is the same as it would be if
|
|
** the SQLITE_NULLEQ flag were omitted from P5.
|
|
**
|
|
-** If both SQLITE_STOREP2 and SQLITE_KEEPNULL flags are set then the
|
|
-** content of r[P2] is only changed if the new value is NULL or 0 (false).
|
|
-** In other words, a prior r[P2] value will not be overwritten by 1 (true).
|
|
+** This opcode saves the result of comparison for use by the new
|
|
+** OP_Jump opcode.
|
|
*/
|
|
/* Opcode: Ne P1 P2 P3 P4 P5
|
|
** Synopsis: IF r[P3]!=r[P1]
|
|
@@ -86818,31 +92296,26 @@ case OP_Cast: { /* in1 */
|
|
** This works just like the Eq opcode except that the jump is taken if
|
|
** the operands in registers P1 and P3 are not equal. See the Eq opcode for
|
|
** additional information.
|
|
-**
|
|
-** If both SQLITE_STOREP2 and SQLITE_KEEPNULL flags are set then the
|
|
-** content of r[P2] is only changed if the new value is NULL or 1 (true).
|
|
-** In other words, a prior r[P2] value will not be overwritten by 0 (false).
|
|
*/
|
|
/* Opcode: Lt P1 P2 P3 P4 P5
|
|
** Synopsis: IF r[P3]<r[P1]
|
|
**
|
|
** Compare the values in register P1 and P3. If reg(P3)<reg(P1) then
|
|
-** jump to address P2. Or if the SQLITE_STOREP2 flag is set in P5 store
|
|
-** the result of comparison (0 or 1 or NULL) into register P2.
|
|
+** jump to address P2.
|
|
**
|
|
** If the SQLITE_JUMPIFNULL bit of P5 is set and either reg(P1) or
|
|
-** reg(P3) is NULL then the take the jump. If the SQLITE_JUMPIFNULL
|
|
+** reg(P3) is NULL then the take the jump. If the SQLITE_JUMPIFNULL
|
|
** bit is clear then fall through if either operand is NULL.
|
|
**
|
|
** The SQLITE_AFF_MASK portion of P5 must be an affinity character -
|
|
-** SQLITE_AFF_TEXT, SQLITE_AFF_INTEGER, and so forth. An attempt is made
|
|
+** SQLITE_AFF_TEXT, SQLITE_AFF_INTEGER, and so forth. An attempt is made
|
|
** to coerce both inputs according to this affinity before the
|
|
** comparison is made. If the SQLITE_AFF_MASK is 0x00, then numeric
|
|
** affinity is used. Note that the affinity conversions are stored
|
|
** back into the input registers P1 and P3. So this opcode can cause
|
|
** persistent changes to registers P1 and P3.
|
|
**
|
|
-** Once any conversions have taken place, and neither value is NULL,
|
|
+** Once any conversions have taken place, and neither value is NULL,
|
|
** the values are compared. If both values are blobs then memcmp() is
|
|
** used to determine the results of the comparison. If both values
|
|
** are text, then the appropriate collating function specified in
|
|
@@ -86851,6 +92324,9 @@ case OP_Cast: { /* in1 */
|
|
** numeric, then a numeric comparison is used. If the two values
|
|
** are of different types, then numbers are considered less than
|
|
** strings and strings are considered less than blobs.
|
|
+**
|
|
+** This opcode saves the result of comparison for use by the new
|
|
+** OP_Jump opcode.
|
|
*/
|
|
/* Opcode: Le P1 P2 P3 P4 P5
|
|
** Synopsis: IF r[P3]<=r[P1]
|
|
@@ -86888,6 +92364,33 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
|
|
pIn3 = &aMem[pOp->p3];
|
|
flags1 = pIn1->flags;
|
|
flags3 = pIn3->flags;
|
|
+ if( (flags1 & flags3 & MEM_Int)!=0 ){
|
|
+ /* Common case of comparison of two integers */
|
|
+ if( pIn3->u.i > pIn1->u.i ){
|
|
+ if( sqlite3aGTb[pOp->opcode] ){
|
|
+ VdbeBranchTaken(1, (pOp->p5 & SQLITE_NULLEQ)?2:3);
|
|
+ goto jump_to_p2;
|
|
+ }
|
|
+ iCompare = +1;
|
|
+ VVA_ONLY( iCompareIsInit = 1; )
|
|
+ }else if( pIn3->u.i < pIn1->u.i ){
|
|
+ if( sqlite3aLTb[pOp->opcode] ){
|
|
+ VdbeBranchTaken(1, (pOp->p5 & SQLITE_NULLEQ)?2:3);
|
|
+ goto jump_to_p2;
|
|
+ }
|
|
+ iCompare = -1;
|
|
+ VVA_ONLY( iCompareIsInit = 1; )
|
|
+ }else{
|
|
+ if( sqlite3aEQb[pOp->opcode] ){
|
|
+ VdbeBranchTaken(1, (pOp->p5 & SQLITE_NULLEQ)?2:3);
|
|
+ goto jump_to_p2;
|
|
+ }
|
|
+ iCompare = 0;
|
|
+ VVA_ONLY( iCompareIsInit = 1; )
|
|
+ }
|
|
+ VdbeBranchTaken(0, (pOp->p5 & SQLITE_NULLEQ)?2:3);
|
|
+ break;
|
|
+ }
|
|
if( (flags1 | flags3)&MEM_Null ){
|
|
/* One or both operands are NULL */
|
|
if( pOp->p5 & SQLITE_NULLEQ ){
|
|
@@ -86910,43 +92413,30 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
|
|
** then the result is always NULL.
|
|
** The jump is taken if the SQLITE_JUMPIFNULL bit is set.
|
|
*/
|
|
- if( pOp->p5 & SQLITE_STOREP2 ){
|
|
- pOut = &aMem[pOp->p2];
|
|
- iCompare = 1; /* Operands are not equal */
|
|
- memAboutToChange(p, pOut);
|
|
- MemSetTypeFlag(pOut, MEM_Null);
|
|
- REGISTER_TRACE(pOp->p2, pOut);
|
|
- }else{
|
|
- VdbeBranchTaken(2,3);
|
|
- if( pOp->p5 & SQLITE_JUMPIFNULL ){
|
|
- goto jump_to_p2;
|
|
- }
|
|
+ VdbeBranchTaken(2,3);
|
|
+ if( pOp->p5 & SQLITE_JUMPIFNULL ){
|
|
+ goto jump_to_p2;
|
|
}
|
|
+ iCompare = 1; /* Operands are not equal */
|
|
+ VVA_ONLY( iCompareIsInit = 1; )
|
|
break;
|
|
}
|
|
}else{
|
|
- /* Neither operand is NULL. Do a comparison. */
|
|
+ /* Neither operand is NULL and we couldn't do the special high-speed
|
|
+ ** integer comparison case. So do a general-case comparison. */
|
|
affinity = pOp->p5 & SQLITE_AFF_MASK;
|
|
if( affinity>=SQLITE_AFF_NUMERIC ){
|
|
if( (flags1 | flags3)&MEM_Str ){
|
|
if( (flags1 & (MEM_Int|MEM_IntReal|MEM_Real|MEM_Str))==MEM_Str ){
|
|
applyNumericAffinity(pIn1,0);
|
|
- testcase( flags3!=pIn3->flags );
|
|
+ assert( flags3==pIn3->flags || CORRUPT_DB );
|
|
flags3 = pIn3->flags;
|
|
}
|
|
if( (flags3 & (MEM_Int|MEM_IntReal|MEM_Real|MEM_Str))==MEM_Str ){
|
|
applyNumericAffinity(pIn3,0);
|
|
}
|
|
}
|
|
- /* Handle the common case of integer comparison here, as an
|
|
- ** optimization, to avoid a call to sqlite3MemCompare() */
|
|
- if( (pIn1->flags & pIn3->flags & MEM_Int)!=0 ){
|
|
- if( pIn3->u.i > pIn1->u.i ){ res = +1; goto compare_op; }
|
|
- if( pIn3->u.i < pIn1->u.i ){ res = -1; goto compare_op; }
|
|
- res = 0;
|
|
- goto compare_op;
|
|
- }
|
|
- }else if( affinity==SQLITE_AFF_TEXT ){
|
|
+ }else if( affinity==SQLITE_AFF_TEXT && ((flags1 | flags3) & MEM_Str)!=0 ){
|
|
if( (flags1 & MEM_Str)==0 && (flags1&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){
|
|
testcase( pIn1->flags & MEM_Int );
|
|
testcase( pIn1->flags & MEM_Real );
|
|
@@ -86954,7 +92444,7 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
|
|
sqlite3VdbeMemStringify(pIn1, encoding, 1);
|
|
testcase( (flags1&MEM_Dyn) != (pIn1->flags&MEM_Dyn) );
|
|
flags1 = (pIn1->flags & ~MEM_TypeMask) | (flags1 & MEM_TypeMask);
|
|
- if( pIn1==pIn3 ) flags3 = flags1 | MEM_Str;
|
|
+ if( NEVER(pIn1==pIn3) ) flags3 = flags1 | MEM_Str;
|
|
}
|
|
if( (flags3 & MEM_Str)==0 && (flags3&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){
|
|
testcase( pIn3->flags & MEM_Int );
|
|
@@ -86968,7 +92458,7 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
|
|
assert( pOp->p4type==P4_COLLSEQ || pOp->p4.pColl==0 );
|
|
res = sqlite3MemCompare(pIn3, pIn1, pOp->p4.pColl);
|
|
}
|
|
-compare_op:
|
|
+
|
|
/* At this point, res is negative, zero, or positive if reg[P1] is
|
|
** less than, equal to, or greater than reg[P3], respectively. Compute
|
|
** the answer to this operator in res2, depending on what the comparison
|
|
@@ -86977,16 +92467,15 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
|
|
** order: NE, EQ, GT, LE, LT, GE */
|
|
assert( OP_Eq==OP_Ne+1 ); assert( OP_Gt==OP_Ne+2 ); assert( OP_Le==OP_Ne+3 );
|
|
assert( OP_Lt==OP_Ne+4 ); assert( OP_Ge==OP_Ne+5 );
|
|
- if( res<0 ){ /* ne, eq, gt, le, lt, ge */
|
|
- static const unsigned char aLTb[] = { 1, 0, 0, 1, 1, 0 };
|
|
- res2 = aLTb[pOp->opcode - OP_Ne];
|
|
+ if( res<0 ){
|
|
+ res2 = sqlite3aLTb[pOp->opcode];
|
|
}else if( res==0 ){
|
|
- static const unsigned char aEQb[] = { 0, 1, 0, 1, 0, 1 };
|
|
- res2 = aEQb[pOp->opcode - OP_Ne];
|
|
+ res2 = sqlite3aEQb[pOp->opcode];
|
|
}else{
|
|
- static const unsigned char aGTb[] = { 1, 0, 1, 0, 0, 1 };
|
|
- res2 = aGTb[pOp->opcode - OP_Ne];
|
|
+ res2 = sqlite3aGTb[pOp->opcode];
|
|
}
|
|
+ iCompare = res;
|
|
+ VVA_ONLY( iCompareIsInit = 1; )
|
|
|
|
/* Undo any changes made by applyAffinity() to the input registers. */
|
|
assert( (pIn3->flags & MEM_Dyn) == (flags3 & MEM_Dyn) );
|
|
@@ -86994,67 +92483,40 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
|
|
assert( (pIn1->flags & MEM_Dyn) == (flags1 & MEM_Dyn) );
|
|
pIn1->flags = flags1;
|
|
|
|
- if( pOp->p5 & SQLITE_STOREP2 ){
|
|
- pOut = &aMem[pOp->p2];
|
|
- iCompare = res;
|
|
- if( (pOp->p5 & SQLITE_KEEPNULL)!=0 ){
|
|
- /* The KEEPNULL flag prevents OP_Eq from overwriting a NULL with 1
|
|
- ** and prevents OP_Ne from overwriting NULL with 0. This flag
|
|
- ** is only used in contexts where either:
|
|
- ** (1) op==OP_Eq && (r[P2]==NULL || r[P2]==0)
|
|
- ** (2) op==OP_Ne && (r[P2]==NULL || r[P2]==1)
|
|
- ** Therefore it is not necessary to check the content of r[P2] for
|
|
- ** NULL. */
|
|
- assert( pOp->opcode==OP_Ne || pOp->opcode==OP_Eq );
|
|
- assert( res2==0 || res2==1 );
|
|
- testcase( res2==0 && pOp->opcode==OP_Eq );
|
|
- testcase( res2==1 && pOp->opcode==OP_Eq );
|
|
- testcase( res2==0 && pOp->opcode==OP_Ne );
|
|
- testcase( res2==1 && pOp->opcode==OP_Ne );
|
|
- if( (pOp->opcode==OP_Eq)==res2 ) break;
|
|
- }
|
|
- memAboutToChange(p, pOut);
|
|
- MemSetTypeFlag(pOut, MEM_Int);
|
|
- pOut->u.i = res2;
|
|
- REGISTER_TRACE(pOp->p2, pOut);
|
|
- }else{
|
|
- VdbeBranchTaken(res2!=0, (pOp->p5 & SQLITE_NULLEQ)?2:3);
|
|
- if( res2 ){
|
|
- goto jump_to_p2;
|
|
- }
|
|
+ VdbeBranchTaken(res2!=0, (pOp->p5 & SQLITE_NULLEQ)?2:3);
|
|
+ if( res2 ){
|
|
+ goto jump_to_p2;
|
|
}
|
|
break;
|
|
}
|
|
|
|
-/* Opcode: ElseNotEq * P2 * * *
|
|
+/* Opcode: ElseEq * P2 * * *
|
|
**
|
|
** This opcode must follow an OP_Lt or OP_Gt comparison operator. There
|
|
** can be zero or more OP_ReleaseReg opcodes intervening, but no other
|
|
** opcodes are allowed to occur between this instruction and the previous
|
|
-** OP_Lt or OP_Gt. Furthermore, the prior OP_Lt or OP_Gt must have the
|
|
-** SQLITE_STOREP2 bit set in the P5 field.
|
|
+** 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 NULL or false (0), then then
|
|
-** jump to P2. If the result of an OP_Eq comparison on the two previous
|
|
-** operands would have been true (1), then fall through.
|
|
+** 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_ElseNotEq: { /* same as TK_ESCAPE, jump */
|
|
+case OP_ElseEq: { /* same as TK_ESCAPE, jump */
|
|
|
|
#ifdef SQLITE_DEBUG
|
|
/* Verify the preconditions of this opcode - that it follows an OP_Lt or
|
|
- ** OP_Gt with the SQLITE_STOREP2 flag set, with zero or more intervening
|
|
- ** OP_ReleaseReg opcodes */
|
|
+ ** OP_Gt with zero or more intervening OP_ReleaseReg opcodes */
|
|
int iAddr;
|
|
for(iAddr = (int)(pOp - aOp) - 1; ALWAYS(iAddr>=0); iAddr--){
|
|
if( aOp[iAddr].opcode==OP_ReleaseReg ) continue;
|
|
assert( aOp[iAddr].opcode==OP_Lt || aOp[iAddr].opcode==OP_Gt );
|
|
- assert( aOp[iAddr].p5 & SQLITE_STOREP2 );
|
|
break;
|
|
}
|
|
#endif /* SQLITE_DEBUG */
|
|
- VdbeBranchTaken(iCompare!=0, 2);
|
|
- if( iCompare!=0 ) goto jump_to_p2;
|
|
+ assert( iCompareIsInit );
|
|
+ VdbeBranchTaken(iCompare==0, 2);
|
|
+ if( iCompare==0 ) goto jump_to_p2;
|
|
break;
|
|
}
|
|
|
|
@@ -87064,9 +92526,8 @@ case OP_ElseNotEq: { /* same as TK_ESCAPE, jump */
|
|
** Set the permutation used by the OP_Compare operator in the next
|
|
** instruction. The permutation is stored in the P4 operand.
|
|
**
|
|
-** The permutation is only valid until the next OP_Compare that has
|
|
-** the OPFLAG_PERMUTE bit set in P5. Typically the OP_Permutation should
|
|
-** occur immediately prior to the OP_Compare.
|
|
+** The permutation is only valid for the next opcode which must be
|
|
+** an OP_Compare that has the OPFLAG_PERMUTE bit set in P5.
|
|
**
|
|
** The first integer in the P4 integer array is the length of the array
|
|
** and does not become part of the permutation.
|
|
@@ -87098,6 +92559,8 @@ case OP_Permutation: {
|
|
** The comparison is a sort comparison, so NULLs compare equal,
|
|
** NULLs are less than numbers, numbers are less than strings,
|
|
** and strings are less than blobs.
|
|
+**
|
|
+** This opcode must be immediately followed by an OP_Jump opcode.
|
|
*/
|
|
case OP_Compare: {
|
|
int n;
|
|
@@ -87105,10 +92568,10 @@ case OP_Compare: {
|
|
int p1;
|
|
int p2;
|
|
const KeyInfo *pKeyInfo;
|
|
- int idx;
|
|
+ u32 idx;
|
|
CollSeq *pColl; /* Collating sequence to use on this term */
|
|
int bRev; /* True for DESCENDING sort order */
|
|
- int *aPermute; /* The permutation */
|
|
+ u32 *aPermute; /* The permutation */
|
|
|
|
if( (pOp->p5 & OPFLAG_PERMUTE)==0 ){
|
|
aPermute = 0;
|
|
@@ -87128,7 +92591,7 @@ case OP_Compare: {
|
|
#ifdef SQLITE_DEBUG
|
|
if( aPermute ){
|
|
int k, mx = 0;
|
|
- for(k=0; k<n; k++) if( aPermute[k]>mx ) mx = aPermute[k];
|
|
+ for(k=0; k<n; k++) if( aPermute[k]>(u32)mx ) mx = aPermute[k];
|
|
assert( p1>0 && p1+mx<=(p->nMem+1 - p->nCursor)+1 );
|
|
assert( p2>0 && p2+mx<=(p->nMem+1 - p->nCursor)+1 );
|
|
}else{
|
|
@@ -87137,7 +92600,7 @@ case OP_Compare: {
|
|
}
|
|
#endif /* SQLITE_DEBUG */
|
|
for(i=0; i<n; i++){
|
|
- idx = aPermute ? aPermute[i] : i;
|
|
+ idx = aPermute ? aPermute[i] : (u32)i;
|
|
assert( memIsValid(&aMem[p1+idx]) );
|
|
assert( memIsValid(&aMem[p2+idx]) );
|
|
REGISTER_TRACE(p1+idx, &aMem[p1+idx]);
|
|
@@ -87146,8 +92609,9 @@ case OP_Compare: {
|
|
pColl = pKeyInfo->aColl[i];
|
|
bRev = (pKeyInfo->aSortFlags[i] & KEYINFO_ORDER_DESC);
|
|
iCompare = sqlite3MemCompare(&aMem[p1+idx], &aMem[p2+idx], pColl);
|
|
+ VVA_ONLY( iCompareIsInit = 1; )
|
|
if( iCompare ){
|
|
- if( (pKeyInfo->aSortFlags[i] & KEYINFO_ORDER_BIGNULL)
|
|
+ if( (pKeyInfo->aSortFlags[i] & KEYINFO_ORDER_BIGNULL)
|
|
&& ((aMem[p1+idx].flags & MEM_Null) || (aMem[p2+idx].flags & MEM_Null))
|
|
){
|
|
iCompare = -iCompare;
|
|
@@ -87156,6 +92620,7 @@ case OP_Compare: {
|
|
break;
|
|
}
|
|
}
|
|
+ assert( pOp[1].opcode==OP_Jump );
|
|
break;
|
|
}
|
|
|
|
@@ -87164,8 +92629,12 @@ case OP_Compare: {
|
|
** 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
|
|
** equal to, or greater than the P2 vector, respectively.
|
|
+**
|
|
+** This opcode must immediately follow an OP_Compare opcode.
|
|
*/
|
|
case OP_Jump: { /* jump */
|
|
+ assert( pOp>aOp && pOp[-1].opcode==OP_Compare );
|
|
+ assert( iCompareIsInit );
|
|
if( iCompare<0 ){
|
|
VdbeBranchTaken(0,4); pOp = &aOp[pOp->p1 - 1];
|
|
}else if( iCompare==0 ){
|
|
@@ -87227,13 +92696,13 @@ case OP_Or: { /* same as TK_OR, in1, in2, out3 */
|
|
** IS NOT FALSE operators.
|
|
**
|
|
** Interpret the value in register P1 as a boolean value. Store that
|
|
-** boolean (a 0 or 1) in register P2. Or if the value in register P1 is
|
|
+** boolean (a 0 or 1) in register P2. Or if the value in register P1 is
|
|
** NULL, then the P3 is stored in register P2. Invert the answer if P4
|
|
** is 1.
|
|
**
|
|
** The logic is summarized like this:
|
|
**
|
|
-** <ul>
|
|
+** <ul>
|
|
** <li> If P3==0 and P4==0 then r[P2] := r[P1] IS TRUE
|
|
** <li> If P3==1 and P4==1 then r[P2] := r[P1] IS FALSE
|
|
** <li> If P3==0 and P4==1 then r[P2] := r[P1] IS NOT TRUE
|
|
@@ -87253,7 +92722,7 @@ case OP_IsTrue: { /* in1, out2 */
|
|
** Synopsis: r[P2]= !r[P1]
|
|
**
|
|
** Interpret the value in register P1 as a boolean value. Store the
|
|
-** boolean complement in register P2. If the value in register P1 is
|
|
+** boolean complement in register P2. If the value in register P1 is
|
|
** NULL, then a NULL is stored in P2.
|
|
*/
|
|
case OP_Not: { /* same as TK_NOT, in1, out2 */
|
|
@@ -87365,10 +92834,115 @@ case OP_IsNull: { /* same as TK_ISNULL, jump, in1 */
|
|
break;
|
|
}
|
|
|
|
+/* Opcode: IsType P1 P2 P3 P4 P5
|
|
+** Synopsis: if typeof(P1.P3) in P5 goto P2
|
|
+**
|
|
+** Jump to P2 if the type of a column in a btree is one of the types specified
|
|
+** by the P5 bitmask.
|
|
+**
|
|
+** P1 is normally a cursor on a btree for which the row decode cache is
|
|
+** valid through at least column P3. In other words, there should have been
|
|
+** a prior OP_Column for column P3 or greater. If the cursor is not valid,
|
|
+** then this opcode might give spurious results.
|
|
+** The the btree row has fewer than P3 columns, then use P4 as the
|
|
+** datatype.
|
|
+**
|
|
+** If P1 is -1, then P3 is a register number and the datatype is taken
|
|
+** from the value in that register.
|
|
+**
|
|
+** P5 is a bitmask of data types. SQLITE_INTEGER is the least significant
|
|
+** (0x01) bit. SQLITE_FLOAT is the 0x02 bit. SQLITE_TEXT is 0x04.
|
|
+** SQLITE_BLOB is 0x08. SQLITE_NULL is 0x10.
|
|
+**
|
|
+** 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.
|
|
+**
|
|
+*/
|
|
+case OP_IsType: { /* jump */
|
|
+ VdbeCursor *pC;
|
|
+ u16 typeMask;
|
|
+ u32 serialType;
|
|
+
|
|
+ assert( pOp->p1>=(-1) && pOp->p1<p->nCursor );
|
|
+ assert( pOp->p1>=0 || (pOp->p3>=0 && pOp->p3<=(p->nMem+1 - p->nCursor)) );
|
|
+ if( pOp->p1>=0 ){
|
|
+ pC = p->apCsr[pOp->p1];
|
|
+ assert( pC!=0 );
|
|
+ assert( pOp->p3>=0 );
|
|
+ if( pOp->p3<pC->nHdrParsed ){
|
|
+ serialType = pC->aType[pOp->p3];
|
|
+ if( serialType>=12 ){
|
|
+ if( serialType&1 ){
|
|
+ typeMask = 0x04; /* SQLITE_TEXT */
|
|
+ }else{
|
|
+ typeMask = 0x08; /* SQLITE_BLOB */
|
|
+ }
|
|
+ }else{
|
|
+ static const unsigned char aMask[] = {
|
|
+ 0x10, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x2,
|
|
+ 0x01, 0x01, 0x10, 0x10
|
|
+ };
|
|
+ testcase( serialType==0 );
|
|
+ testcase( serialType==1 );
|
|
+ testcase( serialType==2 );
|
|
+ testcase( serialType==3 );
|
|
+ testcase( serialType==4 );
|
|
+ testcase( serialType==5 );
|
|
+ testcase( serialType==6 );
|
|
+ testcase( serialType==7 );
|
|
+ testcase( serialType==8 );
|
|
+ testcase( serialType==9 );
|
|
+ testcase( serialType==10 );
|
|
+ testcase( serialType==11 );
|
|
+ typeMask = aMask[serialType];
|
|
+ }
|
|
+ }else{
|
|
+ typeMask = 1 << (pOp->p4.i - 1);
|
|
+ testcase( typeMask==0x01 );
|
|
+ testcase( typeMask==0x02 );
|
|
+ testcase( typeMask==0x04 );
|
|
+ testcase( typeMask==0x08 );
|
|
+ testcase( typeMask==0x10 );
|
|
+ }
|
|
+ }else{
|
|
+ assert( memIsValid(&aMem[pOp->p3]) );
|
|
+ typeMask = 1 << (sqlite3_value_type((sqlite3_value*)&aMem[pOp->p3])-1);
|
|
+ testcase( typeMask==0x01 );
|
|
+ testcase( typeMask==0x02 );
|
|
+ testcase( typeMask==0x04 );
|
|
+ testcase( typeMask==0x08 );
|
|
+ testcase( typeMask==0x10 );
|
|
+ }
|
|
+ VdbeBranchTaken( (typeMask & pOp->p5)!=0, 2);
|
|
+ if( typeMask & pOp->p5 ){
|
|
+ goto jump_to_p2;
|
|
+ }
|
|
+ break;
|
|
+}
|
|
+
|
|
+/* 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
|
|
+** register P2. If either registers P1 or P3 are NULL then put
|
|
+** a NULL in register P2.
|
|
+*/
|
|
+case OP_ZeroOrNull: { /* in1, in2, out2, in3 */
|
|
+ if( (aMem[pOp->p1].flags & MEM_Null)!=0
|
|
+ || (aMem[pOp->p3].flags & MEM_Null)!=0
|
|
+ ){
|
|
+ sqlite3VdbeMemSetNull(aMem + pOp->p2);
|
|
+ }else{
|
|
+ sqlite3VdbeMemSetInt64(aMem + pOp->p2, 0);
|
|
+ }
|
|
+ break;
|
|
+}
|
|
+
|
|
/* Opcode: NotNull P1 P2 * * *
|
|
** Synopsis: if r[P1]!=NULL goto P2
|
|
**
|
|
-** Jump to P2 if the value in register P1 is not NULL.
|
|
+** Jump to P2 if the value in register P1 is not NULL.
|
|
*/
|
|
case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */
|
|
pIn1 = &aMem[pOp->p1];
|
|
@@ -87386,11 +92960,14 @@ case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */
|
|
** If it is, then set register P3 to NULL and jump immediately to P2.
|
|
** If P1 is not on a NULL row, then fall through without making any
|
|
** changes.
|
|
+**
|
|
+** If P1 is not an open cursor, then this opcode is a no-op.
|
|
*/
|
|
case OP_IfNullRow: { /* jump */
|
|
+ VdbeCursor *pC;
|
|
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
|
- assert( p->apCsr[pOp->p1]!=0 );
|
|
- if( p->apCsr[pOp->p1]->nullRow ){
|
|
+ pC = p->apCsr[pOp->p1];
|
|
+ if( ALWAYS(pC) && pC->nullRow ){
|
|
sqlite3VdbeMemSetNull(aMem + pOp->p3);
|
|
goto jump_to_p2;
|
|
}
|
|
@@ -87418,22 +92995,30 @@ case OP_Offset: { /* out3 */
|
|
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
|
pC = p->apCsr[pOp->p1];
|
|
pOut = &p->aMem[pOp->p3];
|
|
- if( NEVER(pC==0) || pC->eCurType!=CURTYPE_BTREE ){
|
|
+ if( pC==0 || pC->eCurType!=CURTYPE_BTREE ){
|
|
sqlite3VdbeMemSetNull(pOut);
|
|
}else{
|
|
- sqlite3VdbeMemSetInt64(pOut, sqlite3BtreeOffset(pC->uc.pCursor));
|
|
+ if( pC->deferredMoveto ){
|
|
+ rc = sqlite3VdbeFinishMoveto(pC);
|
|
+ if( rc ) goto abort_due_to_error;
|
|
+ }
|
|
+ if( sqlite3BtreeEof(pC->uc.pCursor) ){
|
|
+ sqlite3VdbeMemSetNull(pOut);
|
|
+ }else{
|
|
+ sqlite3VdbeMemSetInt64(pOut, sqlite3BtreeOffset(pC->uc.pCursor));
|
|
+ }
|
|
}
|
|
break;
|
|
}
|
|
#endif /* SQLITE_ENABLE_OFFSET_SQL_FUNC */
|
|
|
|
/* Opcode: Column P1 P2 P3 P4 P5
|
|
-** Synopsis: r[P3]=PX
|
|
+** Synopsis: r[P3]=PX cursor P1 column P2
|
|
**
|
|
** Interpret the data that cursor P1 points to as a structure built using
|
|
** the MakeRecord instruction. (See the MakeRecord opcode for additional
|
|
** information about the format of the data.) Extract the P2-th column
|
|
-** from this record. If there are less that (P2+1)
|
|
+** from this record. If there are less than (P2+1)
|
|
** values in the record, extract a NULL.
|
|
**
|
|
** The value extracted is stored in register P3.
|
|
@@ -87442,15 +93027,17 @@ case OP_Offset: { /* out3 */
|
|
** if the P4 argument is a P4_MEM use the value of the P4 argument as
|
|
** the result.
|
|
**
|
|
-** If the OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG bits are set on P5 then
|
|
-** the result is guaranteed to only be used as the argument of a length()
|
|
-** or typeof() function, respectively. The loading of large blobs can be
|
|
-** skipped for length() and all content loading can be skipped for typeof().
|
|
+** If the OPFLAG_LENGTHARG bit is set in P5 then the result is guaranteed
|
|
+** to only be used by the length() function or the equivalent. The content
|
|
+** of large blobs is not loaded, thus saving CPU cycles. If the
|
|
+** OPFLAG_TYPEOFARG bit is set then the result will only be used by the
|
|
+** typeof() function or the IS NULL or IS NOT NULL operators or the
|
|
+** equivalent. In this case, all content loading can be omitted.
|
|
*/
|
|
-case OP_Column: {
|
|
- int p2; /* column number to retrieve */
|
|
+case OP_Column: { /* ncycle */
|
|
+ u32 p2; /* column number to retrieve */
|
|
VdbeCursor *pC; /* The VDBE cursor */
|
|
- BtCursor *pCrsr; /* The BTree cursor */
|
|
+ BtCursor *pCrsr; /* The B-Tree cursor corresponding to pC */
|
|
u32 *aOffset; /* aOffset[i] is offset to start of data for i-th column */
|
|
int len; /* The length of the serialized data for the column */
|
|
int i; /* Loop counter */
|
|
@@ -87464,43 +93051,53 @@ case OP_Column: {
|
|
Mem *pReg; /* PseudoTable input register */
|
|
|
|
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
|
+ assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
|
|
pC = p->apCsr[pOp->p1];
|
|
- assert( pC!=0 );
|
|
- p2 = pOp->p2;
|
|
-
|
|
- /* If the cursor cache is stale (meaning it is not currently point at
|
|
- ** the correct row) then bring it up-to-date by doing the necessary
|
|
- ** B-Tree seek. */
|
|
- rc = sqlite3VdbeCursorMoveto(&pC, &p2);
|
|
- if( rc ) goto abort_due_to_error;
|
|
+ p2 = (u32)pOp->p2;
|
|
|
|
- assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
|
|
- pDest = &aMem[pOp->p3];
|
|
- memAboutToChange(p, pDest);
|
|
+op_column_restart:
|
|
assert( pC!=0 );
|
|
- assert( p2<pC->nField );
|
|
+ assert( p2<(u32)pC->nField
|
|
+ || (pC->eCurType==CURTYPE_PSEUDO && pC->seekResult==0) );
|
|
aOffset = pC->aOffset;
|
|
+ assert( aOffset==pC->aType+pC->nField );
|
|
assert( pC->eCurType!=CURTYPE_VTAB );
|
|
assert( pC->eCurType!=CURTYPE_PSEUDO || pC->nullRow );
|
|
assert( pC->eCurType!=CURTYPE_SORTER );
|
|
|
|
if( pC->cacheStatus!=p->cacheCtr ){ /*OPTIMIZATION-IF-FALSE*/
|
|
if( pC->nullRow ){
|
|
- if( pC->eCurType==CURTYPE_PSEUDO ){
|
|
+ if( pC->eCurType==CURTYPE_PSEUDO && pC->seekResult>0 ){
|
|
/* For the special case of as pseudo-cursor, the seekResult field
|
|
** identifies the register that holds the record */
|
|
- assert( pC->seekResult>0 );
|
|
pReg = &aMem[pC->seekResult];
|
|
assert( pReg->flags & MEM_Blob );
|
|
assert( memIsValid(pReg) );
|
|
pC->payloadSize = pC->szRow = pReg->n;
|
|
pC->aRow = (u8*)pReg->z;
|
|
}else{
|
|
+ pDest = &aMem[pOp->p3];
|
|
+ memAboutToChange(p, pDest);
|
|
sqlite3VdbeMemSetNull(pDest);
|
|
goto op_column_out;
|
|
}
|
|
}else{
|
|
pCrsr = pC->uc.pCursor;
|
|
+ if( pC->deferredMoveto ){
|
|
+ u32 iMap;
|
|
+ assert( !pC->isEphemeral );
|
|
+ if( pC->ub.aAltMap && (iMap = pC->ub.aAltMap[1+p2])>0 ){
|
|
+ pC = pC->pAltCursor;
|
|
+ p2 = iMap - 1;
|
|
+ goto op_column_restart;
|
|
+ }
|
|
+ rc = sqlite3VdbeFinishMoveto(pC);
|
|
+ if( rc ) goto abort_due_to_error;
|
|
+ }else if( sqlite3BtreeCursorHasMoved(pCrsr) ){
|
|
+ rc = sqlite3VdbeHandleMovedCursor(pC);
|
|
+ if( rc ) goto abort_due_to_error;
|
|
+ goto op_column_restart;
|
|
+ }
|
|
assert( pC->eCurType==CURTYPE_BTREE );
|
|
assert( pCrsr );
|
|
assert( sqlite3BtreeCursorIsValid(pCrsr) );
|
|
@@ -87508,15 +93105,15 @@ case OP_Column: {
|
|
pC->aRow = sqlite3BtreePayloadFetch(pCrsr, &pC->szRow);
|
|
assert( pC->szRow<=pC->payloadSize );
|
|
assert( pC->szRow<=65536 ); /* Maximum page size is 64KiB */
|
|
- if( pC->payloadSize > (u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){
|
|
- goto too_big;
|
|
- }
|
|
}
|
|
pC->cacheStatus = p->cacheCtr;
|
|
- pC->iHdrOffset = getVarint32(pC->aRow, aOffset[0]);
|
|
+ if( (aOffset[0] = pC->aRow[0])<0x80 ){
|
|
+ pC->iHdrOffset = 1;
|
|
+ }else{
|
|
+ pC->iHdrOffset = sqlite3GetVarint32(pC->aRow, aOffset);
|
|
+ }
|
|
pC->nHdrParsed = 0;
|
|
|
|
-
|
|
if( pC->szRow<aOffset[0] ){ /*OPTIMIZATION-IF-FALSE*/
|
|
/* pC->aRow does not have to hold the entire row, but it does at least
|
|
** need to cover the header of the record. If pC->aRow does not contain
|
|
@@ -87556,6 +93153,10 @@ case OP_Column: {
|
|
testcase( aOffset[0]==0 );
|
|
goto op_column_read_header;
|
|
}
|
|
+ }else if( sqlite3BtreeCursorHasMoved(pC->uc.pCursor) ){
|
|
+ rc = sqlite3VdbeHandleMovedCursor(pC);
|
|
+ if( rc ) goto abort_due_to_error;
|
|
+ goto op_column_restart;
|
|
}
|
|
|
|
/* Make sure at least the first p2+1 entries of the header have been
|
|
@@ -87563,19 +93164,19 @@ case OP_Column: {
|
|
*/
|
|
if( pC->nHdrParsed<=p2 ){
|
|
/* If there is more header available for parsing in the record, try
|
|
- ** to extract additional fields up through the p2+1-th field
|
|
+ ** to extract additional fields up through the p2+1-th field
|
|
*/
|
|
if( pC->iHdrOffset<aOffset[0] ){
|
|
/* Make sure zData points to enough of the record to cover the header. */
|
|
if( pC->aRow==0 ){
|
|
memset(&sMem, 0, sizeof(sMem));
|
|
- rc = sqlite3VdbeMemFromBtree(pC->uc.pCursor, 0, aOffset[0], &sMem);
|
|
+ rc = sqlite3VdbeMemFromBtreeZeroOffset(pC->uc.pCursor,aOffset[0],&sMem);
|
|
if( rc!=SQLITE_OK ) goto abort_due_to_error;
|
|
zData = (u8*)sMem.z;
|
|
}else{
|
|
zData = pC->aRow;
|
|
}
|
|
-
|
|
+
|
|
/* Fill in pC->aType[i] and aOffset[i] values through the p2-th field. */
|
|
op_column_read_header:
|
|
i = pC->nHdrParsed;
|
|
@@ -87593,7 +93194,7 @@ case OP_Column: {
|
|
offset64 += sqlite3VdbeSerialTypeLen(t);
|
|
}
|
|
aOffset[++i] = (u32)(offset64 & 0xffffffff);
|
|
- }while( i<=p2 && zHdr<zEndHdr );
|
|
+ }while( (u32)i<=p2 && zHdr<zEndHdr );
|
|
|
|
/* The record is corrupt if any of the following are true:
|
|
** (1) the bytes of the header extend past the declared header size
|
|
@@ -87624,6 +93225,8 @@ case OP_Column: {
|
|
** columns. So the result will be either the default value or a NULL.
|
|
*/
|
|
if( pC->nHdrParsed<=p2 ){
|
|
+ pDest = &aMem[pOp->p3];
|
|
+ memAboutToChange(p, pDest);
|
|
if( pOp->p4type==P4_MEM ){
|
|
sqlite3VdbeMemShallowCopy(pDest, pOp->p4.pMem, MEM_Static);
|
|
}else{
|
|
@@ -87641,6 +93244,8 @@ case OP_Column: {
|
|
*/
|
|
assert( p2<pC->nHdrParsed );
|
|
assert( rc==SQLITE_OK );
|
|
+ pDest = &aMem[pOp->p3];
|
|
+ memAboutToChange(p, pDest);
|
|
assert( sqlite3VdbeCheckMemInvariants(pDest) );
|
|
if( VdbeMemDynamic(pDest) ){
|
|
sqlite3VdbeMemSetNull(pDest);
|
|
@@ -87661,6 +93266,7 @@ case OP_Column: {
|
|
pDest->n = len = (t-12)/2;
|
|
pDest->enc = encoding;
|
|
if( pDest->szMalloc < len+2 ){
|
|
+ if( len>db->aLimit[SQLITE_LIMIT_LENGTH] ) goto too_big;
|
|
pDest->flags = MEM_Null;
|
|
if( sqlite3VdbeMemGrow(pDest, len+2, 0) ) goto no_mem;
|
|
}else{
|
|
@@ -87683,7 +93289,7 @@ case OP_Column: {
|
|
** 2. the length(X) function if X is a blob, and
|
|
** 3. if the content length is zero.
|
|
** So we might as well use bogus content rather than reading
|
|
- ** content from disk.
|
|
+ ** content from disk.
|
|
**
|
|
** Although sqlite3VdbeSerialGet() may read at most 8 bytes from the
|
|
** buffer passed to it, debugging function VdbeMemPrettyPrint() may
|
|
@@ -87693,6 +93299,7 @@ case OP_Column: {
|
|
*/
|
|
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);
|
|
@@ -87715,6 +93322,110 @@ case OP_Column: {
|
|
}
|
|
}
|
|
|
|
+/* Opcode: TypeCheck P1 P2 P3 P4 *
|
|
+** Synopsis: typecheck(r[P1@P2])
|
|
+**
|
|
+** Apply affinities to the range of P2 registers beginning with P1.
|
|
+** Take the affinities from the Table object in P4. If any value
|
|
+** cannot be coerced into the correct type, then raise an error.
|
|
+**
|
|
+** This opcode is similar to OP_Affinity except that this opcode
|
|
+** forces the register type to the Table column type. This is used
|
|
+** to implement "strict affinity".
|
|
+**
|
|
+** GENERATED ALWAYS AS ... STATIC columns are only checked if P3
|
|
+** is zero. When P3 is non-zero, no type checking occurs for
|
|
+** static generated columns. Virtual columns are computed at query time
|
|
+** and so they are never checked.
|
|
+**
|
|
+** Preconditions:
|
|
+**
|
|
+** <ul>
|
|
+** <li> P2 should be the number of non-virtual columns in the
|
|
+** table of P4.
|
|
+** <li> Table P4 should be a STRICT table.
|
|
+** </ul>
|
|
+**
|
|
+** If any precondition is false, an assertion fault occurs.
|
|
+*/
|
|
+case OP_TypeCheck: {
|
|
+ Table *pTab;
|
|
+ Column *aCol;
|
|
+ int i;
|
|
+
|
|
+ assert( pOp->p4type==P4_TABLE );
|
|
+ pTab = pOp->p4.pTab;
|
|
+ assert( pTab->tabFlags & TF_Strict );
|
|
+ assert( pTab->nNVCol==pOp->p2 );
|
|
+ aCol = pTab->aCol;
|
|
+ pIn1 = &aMem[pOp->p1];
|
|
+ for(i=0; i<pTab->nCol; i++){
|
|
+ if( aCol[i].colFlags & COLFLAG_GENERATED ){
|
|
+ if( aCol[i].colFlags & COLFLAG_VIRTUAL ) continue;
|
|
+ if( pOp->p3 ){ pIn1++; continue; }
|
|
+ }
|
|
+ assert( pIn1 < &aMem[pOp->p1+pOp->p2] );
|
|
+ applyAffinity(pIn1, aCol[i].affinity, encoding);
|
|
+ if( (pIn1->flags & MEM_Null)==0 ){
|
|
+ switch( aCol[i].eCType ){
|
|
+ case COLTYPE_BLOB: {
|
|
+ if( (pIn1->flags & MEM_Blob)==0 ) goto vdbe_type_error;
|
|
+ break;
|
|
+ }
|
|
+ case COLTYPE_INTEGER:
|
|
+ case COLTYPE_INT: {
|
|
+ if( (pIn1->flags & MEM_Int)==0 ) goto vdbe_type_error;
|
|
+ break;
|
|
+ }
|
|
+ case COLTYPE_TEXT: {
|
|
+ if( (pIn1->flags & MEM_Str)==0 ) goto vdbe_type_error;
|
|
+ break;
|
|
+ }
|
|
+ case COLTYPE_REAL: {
|
|
+ testcase( (pIn1->flags & (MEM_Real|MEM_IntReal))==MEM_Real );
|
|
+ assert( (pIn1->flags & MEM_IntReal)==0 );
|
|
+ if( pIn1->flags & MEM_Int ){
|
|
+ /* When applying REAL affinity, if the result is still an MEM_Int
|
|
+ ** that will fit in 6 bytes, then change the type to MEM_IntReal
|
|
+ ** so that we keep the high-resolution integer value but know that
|
|
+ ** the type really wants to be REAL. */
|
|
+ testcase( pIn1->u.i==140737488355328LL );
|
|
+ testcase( pIn1->u.i==140737488355327LL );
|
|
+ testcase( pIn1->u.i==-140737488355328LL );
|
|
+ testcase( pIn1->u.i==-140737488355329LL );
|
|
+ if( pIn1->u.i<=140737488355327LL && pIn1->u.i>=-140737488355328LL){
|
|
+ pIn1->flags |= MEM_IntReal;
|
|
+ pIn1->flags &= ~MEM_Int;
|
|
+ }else{
|
|
+ pIn1->u.r = (double)pIn1->u.i;
|
|
+ pIn1->flags |= MEM_Real;
|
|
+ pIn1->flags &= ~MEM_Int;
|
|
+ }
|
|
+ }else if( (pIn1->flags & (MEM_Real|MEM_IntReal))==0 ){
|
|
+ goto vdbe_type_error;
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+ default: {
|
|
+ /* COLTYPE_ANY. Accept anything. */
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ REGISTER_TRACE((int)(pIn1-aMem), pIn1);
|
|
+ pIn1++;
|
|
+ }
|
|
+ assert( pIn1 == &aMem[pOp->p1+pOp->p2] );
|
|
+ break;
|
|
+
|
|
+vdbe_type_error:
|
|
+ sqlite3VdbeError(p, "cannot store %s value in %s column %s.%s",
|
|
+ vdbeMemTypeName(pIn1), sqlite3StdType[aCol[i].eCType-1],
|
|
+ pTab->zName, aCol[i].zCnName);
|
|
+ rc = SQLITE_CONSTRAINT_DATATYPE;
|
|
+ goto abort_due_to_error;
|
|
+}
|
|
+
|
|
/* Opcode: Affinity P1 P2 * P4 *
|
|
** Synopsis: affinity(r[P1@P2])
|
|
**
|
|
@@ -87777,6 +93488,17 @@ case OP_Affinity: {
|
|
** macros defined in sqliteInt.h.
|
|
**
|
|
** If P4 is NULL then all index fields have the affinity BLOB.
|
|
+**
|
|
+** The meaning of P5 depends on whether or not the SQLITE_ENABLE_NULL_TRIM
|
|
+** compile-time option is enabled:
|
|
+**
|
|
+** * If SQLITE_ENABLE_NULL_TRIM is enabled, then the P5 is the index
|
|
+** of the right-most table that can be null-trimmed.
|
|
+**
|
|
+** * If SQLITE_ENABLE_NULL_TRIM is omitted, then P5 has the value
|
|
+** OPFLAG_NOCHNG_MAGIC if the OP_MakeRecord opcode is allowed to
|
|
+** accept no-change records with serial_type 10. This value is
|
|
+** only used inside an assert() and does not affect the end result.
|
|
*/
|
|
case OP_MakeRecord: {
|
|
Mem *pRec; /* The new record */
|
|
@@ -87790,7 +93512,6 @@ case OP_MakeRecord: {
|
|
Mem *pLast; /* Last field of the record */
|
|
int nField; /* Number of fields in the record */
|
|
char *zAffinity; /* The affinity string for the record */
|
|
- int file_format; /* File format to use for encoding */
|
|
u32 len; /* Length of a field */
|
|
u8 *zHdr; /* Where to write next byte of the header */
|
|
u8 *zPayload; /* Where to write next byte of the payload */
|
|
@@ -87799,13 +93520,13 @@ case OP_MakeRecord: {
|
|
** like this:
|
|
**
|
|
** ------------------------------------------------------------------------
|
|
- ** | hdr-size | type 0 | type 1 | ... | type N-1 | data0 | ... | data N-1 |
|
|
+ ** | hdr-size | type 0 | type 1 | ... | type N-1 | data0 | ... | data N-1 |
|
|
** ------------------------------------------------------------------------
|
|
**
|
|
** Data(0) is taken from register P1. Data(1) comes from register P1+1
|
|
** and so forth.
|
|
**
|
|
- ** Each type field is a varint representing the serial type of the
|
|
+ ** Each type field is a varint representing the serial type of the
|
|
** corresponding data element (see sqlite3VdbeSerialType()). The
|
|
** hdr-size field is also a varint which is the offset from the beginning
|
|
** of the record to data0.
|
|
@@ -87819,7 +93540,6 @@ case OP_MakeRecord: {
|
|
pData0 = &aMem[nField];
|
|
nField = pOp->p2;
|
|
pLast = &pData0[nField-1];
|
|
- file_format = p->minWriteFileFormat;
|
|
|
|
/* Identify the output register */
|
|
assert( pOp->p3<pOp->p1 || pOp->p3>=pOp->p1+pOp->p2 );
|
|
@@ -87895,7 +93615,9 @@ case OP_MakeRecord: {
|
|
** Give such values a special internal-use-only serial-type of 10
|
|
** so that they can be passed through to xUpdate and have
|
|
** a true sqlite3_value_nochange(). */
|
|
+#ifndef SQLITE_ENABLE_NULL_TRIM
|
|
assert( pOp->p5==OPFLAG_NOCHNG_MAGIC || CORRUPT_DB );
|
|
+#endif
|
|
pRec->uTemp = 10;
|
|
}else{
|
|
pRec->uTemp = 0;
|
|
@@ -87916,10 +93638,10 @@ case OP_MakeRecord: {
|
|
testcase( uu==127 ); testcase( uu==128 );
|
|
testcase( uu==32767 ); testcase( uu==32768 );
|
|
testcase( uu==8388607 ); testcase( uu==8388608 );
|
|
- testcase( uu==2147483647 ); testcase( uu==2147483648 );
|
|
+ testcase( uu==2147483647 ); testcase( uu==2147483648LL );
|
|
testcase( uu==140737488355327LL ); testcase( uu==140737488355328LL );
|
|
if( uu<=127 ){
|
|
- if( (i&1)==i && file_format>=4 ){
|
|
+ if( (i&1)==i && p->minWriteFileFormat>=4 ){
|
|
pRec->uTemp = 8+(u32)uu;
|
|
}else{
|
|
nData++;
|
|
@@ -87994,7 +93716,7 @@ case OP_MakeRecord: {
|
|
}
|
|
nByte = nHdr+nData;
|
|
|
|
- /* Make sure the output register has a buffer large enough to store
|
|
+ /* Make sure the output register has a buffer large enough to store
|
|
** the new record. The output register (pOp->p3) is not allowed to
|
|
** be one of the input registers (because the following call to
|
|
** sqlite3VdbeMemClearAndResize() could clobber the value before it is used).
|
|
@@ -88024,18 +93746,60 @@ case OP_MakeRecord: {
|
|
zPayload = zHdr + nHdr;
|
|
|
|
/* Write the record */
|
|
- zHdr += putVarint32(zHdr, nHdr);
|
|
+ if( nHdr<0x80 ){
|
|
+ *(zHdr++) = nHdr;
|
|
+ }else{
|
|
+ zHdr += sqlite3PutVarint(zHdr,nHdr);
|
|
+ }
|
|
assert( pData0<=pLast );
|
|
pRec = pData0;
|
|
- do{
|
|
+ while( 1 /*exit-by-break*/ ){
|
|
serial_type = pRec->uTemp;
|
|
/* EVIDENCE-OF: R-06529-47362 Following the size varint are one or more
|
|
- ** additional varints, one per column. */
|
|
- zHdr += putVarint32(zHdr, serial_type); /* serial type */
|
|
- /* EVIDENCE-OF: R-64536-51728 The values for each column in the record
|
|
+ ** additional varints, one per column.
|
|
+ ** EVIDENCE-OF: R-64536-51728 The values for each column in the record
|
|
** immediately follow the header. */
|
|
- zPayload += sqlite3VdbeSerialPut(zPayload, pRec, serial_type); /* content */
|
|
- }while( (++pRec)<=pLast );
|
|
+ if( serial_type<=7 ){
|
|
+ *(zHdr++) = serial_type;
|
|
+ if( serial_type==0 ){
|
|
+ /* 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));
|
|
+ swapMixedEndianFloat(v);
|
|
+ }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;
|
|
+ }
|
|
+ zPayload += len;
|
|
+ }
|
|
+ }else if( serial_type<0x80 ){
|
|
+ *(zHdr++) = serial_type;
|
|
+ if( serial_type>=14 && pRec->n>0 ){
|
|
+ assert( pRec->z!=0 );
|
|
+ memcpy(zPayload, pRec->z, pRec->n);
|
|
+ zPayload += pRec->n;
|
|
+ }
|
|
+ }else{
|
|
+ zHdr += sqlite3PutVarint(zHdr, serial_type);
|
|
+ if( pRec->n ){
|
|
+ assert( pRec->z!=0 );
|
|
+ memcpy(zPayload, pRec->z, pRec->n);
|
|
+ zPayload += pRec->n;
|
|
+ }
|
|
+ }
|
|
+ if( pRec==pLast ) break;
|
|
+ pRec++;
|
|
+ }
|
|
assert( nHdr==(int)(zHdr - (u8*)pOut->z) );
|
|
assert( nByte==(int)(zPayload - (u8*)pOut->z) );
|
|
|
|
@@ -88044,13 +93808,16 @@ case OP_MakeRecord: {
|
|
break;
|
|
}
|
|
|
|
-/* Opcode: Count P1 P2 * * *
|
|
+/* Opcode: Count P1 P2 P3 * *
|
|
** Synopsis: r[P2]=count()
|
|
**
|
|
-** Store the number of entries (an integer value) in the table or index
|
|
-** opened by cursor P1 in register P2
|
|
+** Store the number of entries (an integer value) in the table or index
|
|
+** opened by cursor P1 in register P2.
|
|
+**
|
|
+** If P3==0, then an exact count is obtained, which involves visiting
|
|
+** every btree page of the table. But if P3 is non-zero, an estimate
|
|
+** is returned based on the current cursor position.
|
|
*/
|
|
-#ifndef SQLITE_OMIT_BTREECOUNT
|
|
case OP_Count: { /* out2 */
|
|
i64 nEntry;
|
|
BtCursor *pCrsr;
|
|
@@ -88058,14 +93825,17 @@ case OP_Count: { /* out2 */
|
|
assert( p->apCsr[pOp->p1]->eCurType==CURTYPE_BTREE );
|
|
pCrsr = p->apCsr[pOp->p1]->uc.pCursor;
|
|
assert( pCrsr );
|
|
- nEntry = 0; /* Not needed. Only used to silence a warning. */
|
|
- rc = sqlite3BtreeCount(db, pCrsr, &nEntry);
|
|
- if( rc ) goto abort_due_to_error;
|
|
+ if( pOp->p3 ){
|
|
+ nEntry = sqlite3BtreeRowCountEst(pCrsr);
|
|
+ }else{
|
|
+ nEntry = 0; /* Not needed. Only used to silence a warning. */
|
|
+ rc = sqlite3BtreeCount(db, pCrsr, &nEntry);
|
|
+ if( rc ) goto abort_due_to_error;
|
|
+ }
|
|
pOut = out2Prerelease(p, pOp);
|
|
pOut->u.i = nEntry;
|
|
goto check_for_interrupt;
|
|
}
|
|
-#endif
|
|
|
|
/* Opcode: Savepoint P1 * * P4 *
|
|
**
|
|
@@ -88088,7 +93858,7 @@ case OP_Savepoint: {
|
|
zName = pOp->p4.z;
|
|
|
|
/* Assert that the p1 parameter is valid. Also that if there is no open
|
|
- ** transaction, then there cannot be any savepoints.
|
|
+ ** transaction, then there cannot be any savepoints.
|
|
*/
|
|
assert( db->pSavepoint==0 || db->autoCommit==0 );
|
|
assert( p1==SAVEPOINT_BEGIN||p1==SAVEPOINT_RELEASE||p1==SAVEPOINT_ROLLBACK );
|
|
@@ -88098,7 +93868,7 @@ case OP_Savepoint: {
|
|
|
|
if( p1==SAVEPOINT_BEGIN ){
|
|
if( db->nVdbeWrite>0 ){
|
|
- /* A new savepoint cannot be created if there are active write
|
|
+ /* A new savepoint cannot be created if there are active write
|
|
** statements (i.e. open read/write incremental blob handles).
|
|
*/
|
|
sqlite3VdbeError(p, "cannot open savepoint - SQL statements in progress");
|
|
@@ -88122,7 +93892,7 @@ case OP_Savepoint: {
|
|
if( pNew ){
|
|
pNew->zName = (char *)&pNew[1];
|
|
memcpy(pNew->zName, zName, nName+1);
|
|
-
|
|
+
|
|
/* If there is no open transaction, then mark this as a special
|
|
** "transaction savepoint". */
|
|
if( db->autoCommit ){
|
|
@@ -88146,7 +93916,7 @@ case OP_Savepoint: {
|
|
/* Find the named savepoint. If there is no such savepoint, then an
|
|
** an error is returned to the user. */
|
|
for(
|
|
- pSavepoint = db->pSavepoint;
|
|
+ pSavepoint = db->pSavepoint;
|
|
pSavepoint && sqlite3StrICmp(pSavepoint->zName, zName);
|
|
pSavepoint = pSavepoint->pNext
|
|
){
|
|
@@ -88156,7 +93926,7 @@ case OP_Savepoint: {
|
|
sqlite3VdbeError(p, "no such savepoint: %s", zName);
|
|
rc = SQLITE_ERROR;
|
|
}else if( db->nVdbeWrite>0 && p1==SAVEPOINT_RELEASE ){
|
|
- /* It is not possible to release (commit) a savepoint if there are
|
|
+ /* It is not possible to release (commit) a savepoint if there are
|
|
** active write statements.
|
|
*/
|
|
sqlite3VdbeError(p, "cannot release savepoint - "
|
|
@@ -88165,8 +93935,8 @@ case OP_Savepoint: {
|
|
}else{
|
|
|
|
/* Determine whether or not this is a transaction savepoint. If so,
|
|
- ** and this is a RELEASE command, then the current transaction
|
|
- ** is committed.
|
|
+ ** and this is a RELEASE command, then the current transaction
|
|
+ ** is committed.
|
|
*/
|
|
int isTransaction = pSavepoint->pNext==0 && db->isTransactionSavepoint;
|
|
if( isTransaction && p1==SAVEPOINT_RELEASE ){
|
|
@@ -88214,8 +93984,8 @@ case OP_Savepoint: {
|
|
}
|
|
}
|
|
if( rc ) goto abort_due_to_error;
|
|
-
|
|
- /* Regardless of whether this is a RELEASE or ROLLBACK, destroy all
|
|
+
|
|
+ /* Regardless of whether this is a RELEASE or ROLLBACK, destroy all
|
|
** savepoints nested inside of the savepoint being operated on. */
|
|
while( db->pSavepoint!=pSavepoint ){
|
|
pTmp = db->pSavepoint;
|
|
@@ -88224,8 +93994,8 @@ case OP_Savepoint: {
|
|
db->nSavepoint--;
|
|
}
|
|
|
|
- /* If it is a RELEASE, then destroy the savepoint being operated on
|
|
- ** too. If it is a ROLLBACK TO, then set the number of deferred
|
|
+ /* If it is a RELEASE, then destroy the savepoint being operated on
|
|
+ ** too. If it is a ROLLBACK TO, then set the number of deferred
|
|
** constraint violations present in the database to the value stored
|
|
** when the savepoint was created. */
|
|
if( p1==SAVEPOINT_RELEASE ){
|
|
@@ -88248,7 +94018,10 @@ case OP_Savepoint: {
|
|
}
|
|
}
|
|
if( rc ) goto abort_due_to_error;
|
|
-
|
|
+ if( p->eVdbeState==VDBE_HALT_STATE ){
|
|
+ rc = SQLITE_DONE;
|
|
+ goto vdbe_return;
|
|
+ }
|
|
break;
|
|
}
|
|
|
|
@@ -88279,7 +94052,7 @@ case OP_AutoCommit: {
|
|
db->autoCommit = 1;
|
|
}else if( desiredAutoCommit && db->nVdbeWrite>0 ){
|
|
/* If this instruction implements a COMMIT and other VMs are writing
|
|
- ** return an error indicating that the other VMs must complete first.
|
|
+ ** return an error indicating that the other VMs must complete first.
|
|
*/
|
|
sqlite3VdbeError(p, "cannot commit transaction - "
|
|
"SQL statements in progress");
|
|
@@ -88308,7 +94081,7 @@ case OP_AutoCommit: {
|
|
(!desiredAutoCommit)?"cannot start a transaction within a transaction":(
|
|
(iRollback)?"cannot rollback - no transaction is active":
|
|
"cannot commit - no transaction is active"));
|
|
-
|
|
+
|
|
rc = SQLITE_ERROR;
|
|
goto abort_due_to_error;
|
|
}
|
|
@@ -88319,9 +94092,10 @@ case OP_AutoCommit: {
|
|
**
|
|
** Begin a transaction on database P1 if a transaction is not already
|
|
** active.
|
|
-** If P2 is non-zero, then a write-transaction is started, or if a
|
|
+** If P2 is non-zero, then a write-transaction is started, or if a
|
|
** read-transaction is already active, it is upgraded to a write-transaction.
|
|
-** If P2 is zero, then a read-transaction is started.
|
|
+** If P2 is zero, then a read-transaction is started. If P2 is 2 or more
|
|
+** then an exclusive transaction is started.
|
|
**
|
|
** P1 is the index of the database file on which the transaction is
|
|
** started. Index 0 is the main database file and index 1 is the
|
|
@@ -88351,17 +94125,28 @@ case OP_AutoCommit: {
|
|
*/
|
|
case OP_Transaction: {
|
|
Btree *pBt;
|
|
+ Db *pDb;
|
|
int iMeta = 0;
|
|
|
|
assert( p->bIsReader );
|
|
assert( p->readOnly==0 || pOp->p2==0 );
|
|
+ assert( pOp->p2>=0 && pOp->p2<=2 );
|
|
assert( pOp->p1>=0 && pOp->p1<db->nDb );
|
|
assert( DbMaskTest(p->btreeMask, pOp->p1) );
|
|
- if( pOp->p2 && (db->flags & SQLITE_QueryOnly)!=0 ){
|
|
- rc = SQLITE_READONLY;
|
|
+ assert( rc==SQLITE_OK );
|
|
+ if( pOp->p2 && (db->flags & (SQLITE_QueryOnly|SQLITE_CorruptRdOnly))!=0 ){
|
|
+ if( db->flags & SQLITE_QueryOnly ){
|
|
+ /* Writes prohibited by the "PRAGMA query_only=TRUE" statement */
|
|
+ rc = SQLITE_READONLY;
|
|
+ }else{
|
|
+ /* Writes prohibited due to a prior SQLITE_CORRUPT in the current
|
|
+ ** transaction */
|
|
+ rc = SQLITE_CORRUPT;
|
|
+ }
|
|
goto abort_due_to_error;
|
|
}
|
|
- pBt = db->aDb[pOp->p1].pBt;
|
|
+ pDb = &db->aDb[pOp->p1];
|
|
+ pBt = pDb->pBt;
|
|
|
|
if( pBt ){
|
|
rc = sqlite3BtreeBeginTrans(pBt, pOp->p2, &iMeta);
|
|
@@ -88378,12 +94163,12 @@ case OP_Transaction: {
|
|
|
|
if( p->usesStmtJournal
|
|
&& pOp->p2
|
|
- && (db->autoCommit==0 || db->nVdbeRead>1)
|
|
+ && (db->autoCommit==0 || db->nVdbeRead>1)
|
|
){
|
|
- assert( sqlite3BtreeIsInTrans(pBt) );
|
|
+ assert( sqlite3BtreeTxnState(pBt)==SQLITE_TXN_WRITE );
|
|
if( p->iStatement==0 ){
|
|
assert( db->nStatement>=0 && db->nSavepoint>=0 );
|
|
- db->nStatement++;
|
|
+ db->nStatement++;
|
|
p->iStatement = db->nSavepoint + db->nStatement;
|
|
}
|
|
|
|
@@ -88400,9 +94185,9 @@ case OP_Transaction: {
|
|
}
|
|
}
|
|
assert( pOp->p5==0 || pOp->p4type==P4_INT32 );
|
|
- if( pOp->p5
|
|
- && (iMeta!=pOp->p3
|
|
- || db->aDb[pOp->p1].pSchema->iGeneration!=pOp->p4.i)
|
|
+ if( rc==SQLITE_OK
|
|
+ && pOp->p5
|
|
+ && (iMeta!=pOp->p3 || pDb->pSchema->iGeneration!=pOp->p4.i)
|
|
){
|
|
/*
|
|
** IMPLEMENTATION-OF: R-03189-51135 As each SQL statement runs, the schema
|
|
@@ -88411,7 +94196,7 @@ case OP_Transaction: {
|
|
*/
|
|
sqlite3DbFree(db, p->zErrMsg);
|
|
p->zErrMsg = sqlite3DbStrDup(db, "database schema has changed");
|
|
- /* If the schema-cookie from the database file matches the cookie
|
|
+ /* If the schema-cookie from the database file matches the cookie
|
|
** stored with the in-memory representation of the schema, do
|
|
** not reload the schema from the database file.
|
|
**
|
|
@@ -88421,7 +94206,7 @@ case OP_Transaction: {
|
|
** prepared queries. If such a query is out-of-date, we do not want to
|
|
** discard the database schema, as the user code implementing the
|
|
** v-table would have to be ready for the sqlite3_vtab structure itself
|
|
- ** to be invalidated whenever sqlite3_step() is called from within
|
|
+ ** to be invalidated whenever sqlite3_step() is called from within
|
|
** a v-table method.
|
|
*/
|
|
if( db->aDb[pOp->p1].pSchema->schema_cookie!=iMeta ){
|
|
@@ -88429,6 +94214,11 @@ case OP_Transaction: {
|
|
}
|
|
p->expired = 1;
|
|
rc = SQLITE_SCHEMA;
|
|
+
|
|
+ /* Set changeCntOn to 0 to prevent the value returned by sqlite3_changes()
|
|
+ ** from being modified in sqlite3VdbeHalt(). If this statement is
|
|
+ ** reprepared, changeCntOn will be set again. */
|
|
+ p->changeCntOn = 0;
|
|
}
|
|
if( rc ) goto abort_due_to_error;
|
|
break;
|
|
@@ -88465,15 +94255,20 @@ case OP_ReadCookie: { /* out2 */
|
|
break;
|
|
}
|
|
|
|
-/* Opcode: SetCookie P1 P2 P3 * *
|
|
+/* Opcode: SetCookie P1 P2 P3 * P5
|
|
**
|
|
** Write the integer value P3 into cookie number P2 of database P1.
|
|
** P2==1 is the schema version. P2==2 is the database format.
|
|
-** P2==3 is the recommended pager cache
|
|
-** size, and so forth. P1==0 is the main database file and P1==1 is the
|
|
+** P2==3 is the recommended pager cache
|
|
+** size, and so forth. P1==0 is the main database file and P1==1 is the
|
|
** database file used to store temporary tables.
|
|
**
|
|
** A transaction must be started before executing this opcode.
|
|
+**
|
|
+** If P2 is the SCHEMA_VERSION cookie (cookie number 1) then the internal
|
|
+** schema version is set to P3-P5. The "PRAGMA schema_version=N" statement
|
|
+** has P5 set to 1, so that the internal schema version will be different
|
|
+** from the database schema version, resulting in a schema reset.
|
|
*/
|
|
case OP_SetCookie: {
|
|
Db *pDb;
|
|
@@ -88490,8 +94285,9 @@ case OP_SetCookie: {
|
|
rc = sqlite3BtreeUpdateMeta(pDb->pBt, pOp->p2, pOp->p3);
|
|
if( pOp->p2==BTREE_SCHEMA_VERSION ){
|
|
/* When the schema cookie changes, record the new cookie internally */
|
|
- pDb->pSchema->schema_cookie = pOp->p3;
|
|
+ *(u32*)&pDb->pSchema->schema_cookie = *(u32*)&pOp->p3 - pOp->p5;
|
|
db->mDbFlags |= DBFLAG_SchemaChange;
|
|
+ sqlite3FkClearTriggerCache(db, pOp->p1);
|
|
}else if( pOp->p2==BTREE_FILE_FORMAT ){
|
|
/* Record changes in the file format */
|
|
pDb->pSchema->file_format = pOp->p3;
|
|
@@ -88510,8 +94306,8 @@ case OP_SetCookie: {
|
|
** Synopsis: root=P2 iDb=P3
|
|
**
|
|
** Open a read-only cursor for the database table whose root page is
|
|
-** P2 in a database file. The database file is determined by P3.
|
|
-** P3==0 means the main database, P3==1 means the database used for
|
|
+** P2 in a database file. The database file is determined by P3.
|
|
+** P3==0 means the main database, P3==1 means the database used for
|
|
** temporary tables, and P3>1 means used the corresponding attached
|
|
** database. Give the new cursor an identifier of P1. The P1
|
|
** values need not be contiguous but all P1 values should be small integers.
|
|
@@ -88521,14 +94317,14 @@ case OP_SetCookie: {
|
|
** <ul>
|
|
** <li> <b>0x02 OPFLAG_SEEKEQ</b>: This cursor will only be used for
|
|
** equality lookups (implemented as a pair of opcodes OP_SeekGE/OP_IdxGT
|
|
-** of OP_SeekLE/OP_IdxGT)
|
|
+** of OP_SeekLE/OP_IdxLT)
|
|
** </ul>
|
|
**
|
|
** The P4 value may be either an integer (P4_INT32) or a pointer to
|
|
-** a KeyInfo structure (P4_KEYINFO). If it is a pointer to a KeyInfo
|
|
+** a KeyInfo structure (P4_KEYINFO). If it is a pointer to a KeyInfo
|
|
** object, then table being opened must be an [index b-tree] where the
|
|
-** KeyInfo object defines the content and collating
|
|
-** sequence of that index b-tree. Otherwise, if P4 is an integer
|
|
+** KeyInfo object defines the content and collating
|
|
+** sequence of that index b-tree. Otherwise, if P4 is an integer
|
|
** value, then the table being opened must be a [table b-tree] with a
|
|
** number of columns no less than the value of P4.
|
|
**
|
|
@@ -88551,7 +94347,7 @@ case OP_SetCookie: {
|
|
** <ul>
|
|
** <li> <b>0x02 OPFLAG_SEEKEQ</b>: This cursor will only be used for
|
|
** equality lookups (implemented as a pair of opcodes OP_SeekGE/OP_IdxGT
|
|
-** of OP_SeekLE/OP_IdxGT)
|
|
+** of OP_SeekLE/OP_IdxLT)
|
|
** </ul>
|
|
**
|
|
** See also: OP_OpenRead, OP_OpenWrite
|
|
@@ -88564,10 +94360,10 @@ case OP_SetCookie: {
|
|
** OPFLAG_P2ISREG bit is set in P5 - see below).
|
|
**
|
|
** The P4 value may be either an integer (P4_INT32) or a pointer to
|
|
-** a KeyInfo structure (P4_KEYINFO). If it is a pointer to a KeyInfo
|
|
+** a KeyInfo structure (P4_KEYINFO). If it is a pointer to a KeyInfo
|
|
** object, then table being opened must be an [index b-tree] where the
|
|
-** KeyInfo object defines the content and collating
|
|
-** sequence of that index b-tree. Otherwise, if P4 is an integer
|
|
+** KeyInfo object defines the content and collating
|
|
+** sequence of that index b-tree. Otherwise, if P4 is an integer
|
|
** value, then the table being opened must be a [table b-tree] with a
|
|
** number of columns no less than the value of P4.
|
|
**
|
|
@@ -88575,7 +94371,7 @@ case OP_SetCookie: {
|
|
** <ul>
|
|
** <li> <b>0x02 OPFLAG_SEEKEQ</b>: This cursor will only be used for
|
|
** equality lookups (implemented as a pair of opcodes OP_SeekGE/OP_IdxGT
|
|
-** of OP_SeekLE/OP_IdxGT)
|
|
+** of OP_SeekLE/OP_IdxLT)
|
|
** <li> <b>0x08 OPFLAG_FORDELETE</b>: This cursor is used only to seek
|
|
** and subsequently delete entries in an index btree. This is a
|
|
** hint to the storage engine that the storage engine is allowed to
|
|
@@ -88590,10 +94386,10 @@ case OP_SetCookie: {
|
|
**
|
|
** See also: OP_OpenRead, OP_ReopenIdx
|
|
*/
|
|
-case OP_ReopenIdx: {
|
|
+case OP_ReopenIdx: { /* ncycle */
|
|
int nField;
|
|
KeyInfo *pKeyInfo;
|
|
- int p2;
|
|
+ u32 p2;
|
|
int iDb;
|
|
int wrFlag;
|
|
Btree *pX;
|
|
@@ -88605,11 +94401,13 @@ case OP_ReopenIdx: {
|
|
pCur = p->apCsr[pOp->p1];
|
|
if( pCur && pCur->pgnoRoot==(u32)pOp->p2 ){
|
|
assert( pCur->iDb==pOp->p3 ); /* Guaranteed by the code generator */
|
|
+ assert( pCur->eCurType==CURTYPE_BTREE );
|
|
+ sqlite3BtreeClearCursor(pCur->uc.pCursor);
|
|
goto open_cursor_set_hints;
|
|
}
|
|
/* If the cursor is not currently open or is open on a different
|
|
** index, then fall through into OP_OpenRead to force a reopen */
|
|
-case OP_OpenRead:
|
|
+case OP_OpenRead: /* ncycle */
|
|
case OP_OpenWrite:
|
|
|
|
assert( pOp->opcode==OP_OpenWrite || pOp->p5==0 || pOp->p5==OPFLAG_SEEKEQ );
|
|
@@ -88624,7 +94422,7 @@ case OP_OpenWrite:
|
|
|
|
nField = 0;
|
|
pKeyInfo = 0;
|
|
- p2 = pOp->p2;
|
|
+ p2 = (u32)pOp->p2;
|
|
iDb = pOp->p3;
|
|
assert( iDb>=0 && iDb<db->nDb );
|
|
assert( DbMaskTest(p->btreeMask, iDb) );
|
|
@@ -88643,7 +94441,7 @@ case OP_OpenWrite:
|
|
}
|
|
if( pOp->p5 & OPFLAG_P2ISREG ){
|
|
assert( p2>0 );
|
|
- assert( p2<=(p->nMem+1 - p->nCursor) );
|
|
+ assert( p2<=(u32)(p->nMem+1 - p->nCursor) );
|
|
assert( pOp->opcode==OP_OpenWrite );
|
|
pIn2 = &aMem[p2];
|
|
assert( memIsValid(pIn2) );
|
|
@@ -88667,8 +94465,9 @@ case OP_OpenWrite:
|
|
assert( pOp->p1>=0 );
|
|
assert( nField>=0 );
|
|
testcase( nField==0 ); /* Table with INTEGER PRIMARY KEY and nothing else */
|
|
- pCur = allocateCursor(p, pOp->p1, nField, iDb, CURTYPE_BTREE);
|
|
+ pCur = allocateCursor(p, pOp->p1, nField, CURTYPE_BTREE);
|
|
if( pCur==0 ) goto no_mem;
|
|
+ pCur->iDb = iDb;
|
|
pCur->nullRow = 1;
|
|
pCur->isOrdered = 1;
|
|
pCur->pgnoRoot = p2;
|
|
@@ -88680,16 +94479,14 @@ case OP_OpenWrite:
|
|
/* Set the VdbeCursor.isTable variable. Previous versions of
|
|
** SQLite used to check if the root-page flags were sane at this point
|
|
** and report database corruption if they were not, but this check has
|
|
- ** since moved into the btree layer. */
|
|
+ ** since moved into the btree layer. */
|
|
pCur->isTable = pOp->p4type!=P4_KEYINFO;
|
|
|
|
open_cursor_set_hints:
|
|
assert( OPFLAG_BULKCSR==BTREE_BULKLOAD );
|
|
assert( OPFLAG_SEEKEQ==BTREE_SEEK_EQ );
|
|
testcase( pOp->p5 & OPFLAG_BULKCSR );
|
|
-#ifdef SQLITE_ENABLE_CURSOR_HINTS
|
|
testcase( pOp->p2 & OPFLAG_SEEKEQ );
|
|
-#endif
|
|
sqlite3BtreeCursorHintFlags(pCur->uc.pCursor,
|
|
(pOp->p5 & (OPFLAG_BULKCSR|OPFLAG_SEEKEQ)));
|
|
if( rc ) goto abort_due_to_error;
|
|
@@ -88704,15 +94501,15 @@ case OP_OpenWrite:
|
|
**
|
|
** Duplicate ephemeral cursors are used for self-joins of materialized views.
|
|
*/
|
|
-case OP_OpenDup: {
|
|
+case OP_OpenDup: { /* ncycle */
|
|
VdbeCursor *pOrig; /* The original cursor to be duplicated */
|
|
VdbeCursor *pCx; /* The new cursor */
|
|
|
|
pOrig = p->apCsr[pOp->p2];
|
|
assert( pOrig );
|
|
- assert( pOrig->pBtx!=0 ); /* Only ephemeral cursors can be duplicated */
|
|
+ assert( pOrig->isEphemeral ); /* Only ephemeral cursors can be duplicated */
|
|
|
|
- pCx = allocateCursor(p, pOp->p1, pOrig->nField, -1, CURTYPE_BTREE);
|
|
+ pCx = allocateCursor(p, pOp->p1, pOrig->nField, CURTYPE_BTREE);
|
|
if( pCx==0 ) goto no_mem;
|
|
pCx->nullRow = 1;
|
|
pCx->isEphemeral = 1;
|
|
@@ -88720,7 +94517,10 @@ case OP_OpenDup: {
|
|
pCx->isTable = pOrig->isTable;
|
|
pCx->pgnoRoot = pOrig->pgnoRoot;
|
|
pCx->isOrdered = pOrig->isOrdered;
|
|
- rc = sqlite3BtreeCursor(pOrig->pBtx, pCx->pgnoRoot, BTREE_WRCSR,
|
|
+ pCx->ub.pBtx = pOrig->ub.pBtx;
|
|
+ pCx->noReuse = 1;
|
|
+ pOrig->noReuse = 1;
|
|
+ rc = sqlite3BtreeCursor(pCx->ub.pBtx, pCx->pgnoRoot, BTREE_WRCSR,
|
|
pCx->pKeyInfo, pCx->uc.pCursor);
|
|
/* The sqlite3BtreeCursor() routine can only fail for the first cursor
|
|
** opened for a database. Since there is already an open cursor when this
|
|
@@ -88730,11 +94530,11 @@ case OP_OpenDup: {
|
|
}
|
|
|
|
|
|
-/* Opcode: OpenEphemeral P1 P2 * P4 P5
|
|
+/* Opcode: OpenEphemeral P1 P2 P3 P4 P5
|
|
** Synopsis: nColumn=P2
|
|
**
|
|
** Open a new cursor P1 to a transient table.
|
|
-** The cursor is always opened read/write even if
|
|
+** The cursor is always opened read/write even if
|
|
** the main database is read-only. The ephemeral
|
|
** table is deleted automatically when the cursor is closed.
|
|
**
|
|
@@ -88750,6 +94550,10 @@ case OP_OpenDup: {
|
|
** in btree.h. These flags control aspects of the operation of
|
|
** the btree. The BTREE_OMIT_JOURNAL and BTREE_SINGLE flags are
|
|
** added automatically.
|
|
+**
|
|
+** If P3 is positive, then reg[P3] is modified slightly so that it
|
|
+** can be used as zero-length data for OP_Insert. This is an optimization
|
|
+** that avoids an extra OP_Blob opcode to initialize that register.
|
|
*/
|
|
/* Opcode: OpenAutoindex P1 P2 * P4 *
|
|
** Synopsis: nColumn=P2
|
|
@@ -88759,12 +94563,12 @@ case OP_OpenDup: {
|
|
** by this opcode will be used for automatically created transient
|
|
** indices in joins.
|
|
*/
|
|
-case OP_OpenAutoindex:
|
|
-case OP_OpenEphemeral: {
|
|
+case OP_OpenAutoindex: /* ncycle */
|
|
+case OP_OpenEphemeral: { /* ncycle */
|
|
VdbeCursor *pCx;
|
|
KeyInfo *pKeyInfo;
|
|
|
|
- static const int vfsFlags =
|
|
+ static const int vfsFlags =
|
|
SQLITE_OPEN_READWRITE |
|
|
SQLITE_OPEN_CREATE |
|
|
SQLITE_OPEN_EXCLUSIVE |
|
|
@@ -88772,50 +94576,63 @@ case OP_OpenEphemeral: {
|
|
SQLITE_OPEN_TRANSIENT_DB;
|
|
assert( pOp->p1>=0 );
|
|
assert( pOp->p2>=0 );
|
|
+ if( pOp->p3>0 ){
|
|
+ /* Make register reg[P3] into a value that can be used as the data
|
|
+ ** form sqlite3BtreeInsert() where the length of the data is zero. */
|
|
+ assert( pOp->p2==0 ); /* Only used when number of columns is zero */
|
|
+ assert( pOp->opcode==OP_OpenEphemeral );
|
|
+ assert( aMem[pOp->p3].flags & MEM_Null );
|
|
+ aMem[pOp->p3].n = 0;
|
|
+ aMem[pOp->p3].z = "";
|
|
+ }
|
|
pCx = p->apCsr[pOp->p1];
|
|
- if( pCx && pCx->pBtx ){
|
|
- /* If the ephermeral table is already open, erase all existing content
|
|
- ** so that the table is empty again, rather than creating a new table. */
|
|
+ if( pCx && !pCx->noReuse && ALWAYS(pOp->p2<=pCx->nField) ){
|
|
+ /* If the ephermeral table is already open and has no duplicates from
|
|
+ ** OP_OpenDup, then erase all existing content so that the table is
|
|
+ ** empty again, rather than creating a new table. */
|
|
assert( pCx->isEphemeral );
|
|
pCx->seqCount = 0;
|
|
pCx->cacheStatus = CACHE_STALE;
|
|
- rc = sqlite3BtreeClearTable(pCx->pBtx, pCx->pgnoRoot, 0);
|
|
+ rc = sqlite3BtreeClearTable(pCx->ub.pBtx, pCx->pgnoRoot, 0);
|
|
}else{
|
|
- pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, CURTYPE_BTREE);
|
|
+ pCx = allocateCursor(p, pOp->p1, pOp->p2, CURTYPE_BTREE);
|
|
if( pCx==0 ) goto no_mem;
|
|
pCx->isEphemeral = 1;
|
|
- rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->pBtx,
|
|
+ rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->ub.pBtx,
|
|
BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5,
|
|
vfsFlags);
|
|
if( rc==SQLITE_OK ){
|
|
- rc = sqlite3BtreeBeginTrans(pCx->pBtx, 1, 0);
|
|
- }
|
|
- if( rc==SQLITE_OK ){
|
|
- /* If a transient index is required, create it by calling
|
|
- ** sqlite3BtreeCreateTable() with the BTREE_BLOBKEY flag before
|
|
- ** opening it. If a transient table is required, just use the
|
|
- ** automatically created table with root-page 1 (an BLOB_INTKEY table).
|
|
- */
|
|
- if( (pCx->pKeyInfo = pKeyInfo = pOp->p4.pKeyInfo)!=0 ){
|
|
- assert( pOp->p4type==P4_KEYINFO );
|
|
- rc = sqlite3BtreeCreateTable(pCx->pBtx, (int*)&pCx->pgnoRoot,
|
|
- BTREE_BLOBKEY | pOp->p5);
|
|
- if( rc==SQLITE_OK ){
|
|
- assert( pCx->pgnoRoot==MASTER_ROOT+1 );
|
|
- assert( pKeyInfo->db==db );
|
|
- assert( pKeyInfo->enc==ENC(db) );
|
|
- rc = sqlite3BtreeCursor(pCx->pBtx, pCx->pgnoRoot, BTREE_WRCSR,
|
|
- pKeyInfo, pCx->uc.pCursor);
|
|
+ rc = sqlite3BtreeBeginTrans(pCx->ub.pBtx, 1, 0);
|
|
+ if( rc==SQLITE_OK ){
|
|
+ /* If a transient index is required, create it by calling
|
|
+ ** sqlite3BtreeCreateTable() with the BTREE_BLOBKEY flag before
|
|
+ ** opening it. If a transient table is required, just use the
|
|
+ ** automatically created table with root-page 1 (an BLOB_INTKEY table).
|
|
+ */
|
|
+ if( (pCx->pKeyInfo = pKeyInfo = pOp->p4.pKeyInfo)!=0 ){
|
|
+ assert( pOp->p4type==P4_KEYINFO );
|
|
+ rc = sqlite3BtreeCreateTable(pCx->ub.pBtx, &pCx->pgnoRoot,
|
|
+ BTREE_BLOBKEY | pOp->p5);
|
|
+ if( rc==SQLITE_OK ){
|
|
+ assert( pCx->pgnoRoot==SCHEMA_ROOT+1 );
|
|
+ assert( pKeyInfo->db==db );
|
|
+ assert( pKeyInfo->enc==ENC(db) );
|
|
+ rc = sqlite3BtreeCursor(pCx->ub.pBtx, pCx->pgnoRoot, BTREE_WRCSR,
|
|
+ pKeyInfo, pCx->uc.pCursor);
|
|
+ }
|
|
+ pCx->isTable = 0;
|
|
+ }else{
|
|
+ pCx->pgnoRoot = SCHEMA_ROOT;
|
|
+ rc = sqlite3BtreeCursor(pCx->ub.pBtx, SCHEMA_ROOT, BTREE_WRCSR,
|
|
+ 0, pCx->uc.pCursor);
|
|
+ pCx->isTable = 1;
|
|
}
|
|
- pCx->isTable = 0;
|
|
- }else{
|
|
- pCx->pgnoRoot = MASTER_ROOT;
|
|
- rc = sqlite3BtreeCursor(pCx->pBtx, MASTER_ROOT, BTREE_WRCSR,
|
|
- 0, pCx->uc.pCursor);
|
|
- pCx->isTable = 1;
|
|
+ }
|
|
+ pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED);
|
|
+ if( rc ){
|
|
+ sqlite3BtreeClose(pCx->ub.pBtx);
|
|
}
|
|
}
|
|
- pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED);
|
|
}
|
|
if( rc ) goto abort_due_to_error;
|
|
pCx->nullRow = 1;
|
|
@@ -88837,7 +94654,7 @@ case OP_SorterOpen: {
|
|
|
|
assert( pOp->p1>=0 );
|
|
assert( pOp->p2>=0 );
|
|
- pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, CURTYPE_SORTER);
|
|
+ pCx = allocateCursor(p, pOp->p1, pOp->p2, CURTYPE_SORTER);
|
|
if( pCx==0 ) goto no_mem;
|
|
pCx->pKeyInfo = pOp->p4.pKeyInfo;
|
|
assert( pCx->pKeyInfo->db==db );
|
|
@@ -88870,7 +94687,7 @@ case OP_SequenceTest: {
|
|
**
|
|
** Open a new cursor that points to a fake table that contains a single
|
|
** row of data. The content of that one row is the content of memory
|
|
-** register P2. In other words, cursor P1 becomes an alias for the
|
|
+** register P2. In other words, cursor P1 becomes an alias for the
|
|
** MEM_Blob content contained in register P2.
|
|
**
|
|
** A pseudo-table created by this opcode is used to hold a single
|
|
@@ -88886,7 +94703,7 @@ case OP_OpenPseudo: {
|
|
|
|
assert( pOp->p1>=0 );
|
|
assert( pOp->p3>=0 );
|
|
- pCx = allocateCursor(p, pOp->p1, pOp->p3, -1, CURTYPE_PSEUDO);
|
|
+ pCx = allocateCursor(p, pOp->p1, pOp->p3, CURTYPE_PSEUDO);
|
|
if( pCx==0 ) goto no_mem;
|
|
pCx->nullRow = 1;
|
|
pCx->seekResult = pOp->p2;
|
|
@@ -88905,7 +94722,7 @@ case OP_OpenPseudo: {
|
|
** Close a cursor previously opened as P1. If P1 is not
|
|
** currently open, this instruction is a no-op.
|
|
*/
|
|
-case OP_Close: {
|
|
+case OP_Close: { /* ncycle */
|
|
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
|
sqlite3VdbeFreeCursor(p, p->apCsr[pOp->p1]);
|
|
p->apCsr[pOp->p1] = 0;
|
|
@@ -88935,21 +94752,23 @@ case OP_ColumnsUsed: {
|
|
/* Opcode: SeekGE P1 P2 P3 P4 *
|
|
** Synopsis: key=r[P3@P4]
|
|
**
|
|
-** If cursor P1 refers to an SQL table (B-Tree that uses integer keys),
|
|
-** use the value in register P3 as the key. If cursor P1 refers
|
|
-** to an SQL index, then P3 is the first in an array of P4 registers
|
|
-** that are used as an unpacked index key.
|
|
+** If cursor P1 refers to an SQL table (B-Tree that uses integer keys),
|
|
+** use the value in register P3 as the key. If cursor P1 refers
|
|
+** to an SQL index, then P3 is the first in an array of P4 registers
|
|
+** that are used as an unpacked index key.
|
|
**
|
|
-** Reposition cursor P1 so that it points to the smallest entry that
|
|
-** is greater than or equal to the key value. If there are no records
|
|
+** Reposition cursor P1 so that it points to the smallest entry that
|
|
+** is greater than or equal to the key value. If there are no records
|
|
** greater than or equal to the key and P2 is not zero, then jump to P2.
|
|
**
|
|
** If the cursor P1 was opened using the OPFLAG_SEEKEQ flag, then this
|
|
-** opcode will always land on a record that equally equals the key, or
|
|
-** else jump immediately to P2. When the cursor is OPFLAG_SEEKEQ, this
|
|
-** opcode must be followed by an IdxLE opcode with the same arguments.
|
|
-** The IdxLE opcode will be skipped if this opcode succeeds, but the
|
|
-** IdxLE opcode will be used on subsequent loop iterations.
|
|
+** opcode will either land on a record that exactly matches the key, or
|
|
+** else it will cause a jump to P2. When the cursor is OPFLAG_SEEKEQ,
|
|
+** this opcode must be followed by an IdxLE opcode with the same arguments.
|
|
+** The IdxGT opcode will be skipped if this opcode succeeds, but the
|
|
+** IdxGT opcode will be used on subsequent loop iterations. The
|
|
+** OPFLAG_SEEKEQ flags is a hint to the btree layer to say that this
|
|
+** is an equality search.
|
|
**
|
|
** This opcode leaves the cursor configured to move in forward order,
|
|
** from the beginning toward the end. In other words, the cursor is
|
|
@@ -88960,13 +94779,13 @@ case OP_ColumnsUsed: {
|
|
/* Opcode: SeekGT P1 P2 P3 P4 *
|
|
** Synopsis: key=r[P3@P4]
|
|
**
|
|
-** If cursor P1 refers to an SQL table (B-Tree that uses integer keys),
|
|
-** use the value in register P3 as a key. If cursor P1 refers
|
|
-** to an SQL index, then P3 is the first in an array of P4 registers
|
|
-** that are used as an unpacked index key.
|
|
+** If cursor P1 refers to an SQL table (B-Tree that uses integer keys),
|
|
+** use the value in register P3 as a key. If cursor P1 refers
|
|
+** to an SQL index, then P3 is the first in an array of P4 registers
|
|
+** that are used as an unpacked index key.
|
|
**
|
|
-** Reposition cursor P1 so that it points to the smallest entry that
|
|
-** is greater than the key value. If there are no records greater than
|
|
+** Reposition cursor P1 so that it points to the smallest entry that
|
|
+** is greater than the key value. If there are no records greater than
|
|
** the key and P2 is not zero, then jump to P2.
|
|
**
|
|
** This opcode leaves the cursor configured to move in forward order,
|
|
@@ -88975,16 +94794,16 @@ case OP_ColumnsUsed: {
|
|
**
|
|
** See also: Found, NotFound, SeekLt, SeekGe, SeekLe
|
|
*/
|
|
-/* Opcode: SeekLT P1 P2 P3 P4 *
|
|
+/* Opcode: SeekLT P1 P2 P3 P4 *
|
|
** Synopsis: key=r[P3@P4]
|
|
**
|
|
-** If cursor P1 refers to an SQL table (B-Tree that uses integer keys),
|
|
-** use the value in register P3 as a key. If cursor P1 refers
|
|
-** to an SQL index, then P3 is the first in an array of P4 registers
|
|
-** that are used as an unpacked index key.
|
|
+** If cursor P1 refers to an SQL table (B-Tree that uses integer keys),
|
|
+** use the value in register P3 as a key. If cursor P1 refers
|
|
+** to an SQL index, then P3 is the first in an array of P4 registers
|
|
+** that are used as an unpacked index key.
|
|
**
|
|
-** Reposition cursor P1 so that it points to the largest entry that
|
|
-** is less than the key value. If there are no records less than
|
|
+** Reposition cursor P1 so that it points to the largest entry that
|
|
+** is less than the key value. If there are no records less than
|
|
** the key and P2 is not zero, then jump to P2.
|
|
**
|
|
** This opcode leaves the cursor configured to move in reverse order,
|
|
@@ -88996,13 +94815,13 @@ case OP_ColumnsUsed: {
|
|
/* Opcode: SeekLE P1 P2 P3 P4 *
|
|
** Synopsis: key=r[P3@P4]
|
|
**
|
|
-** If cursor P1 refers to an SQL table (B-Tree that uses integer keys),
|
|
-** use the value in register P3 as a key. If cursor P1 refers
|
|
-** to an SQL index, then P3 is the first in an array of P4 registers
|
|
-** that are used as an unpacked index key.
|
|
+** If cursor P1 refers to an SQL table (B-Tree that uses integer keys),
|
|
+** use the value in register P3 as a key. If cursor P1 refers
|
|
+** to an SQL index, then P3 is the first in an array of P4 registers
|
|
+** that are used as an unpacked index key.
|
|
**
|
|
-** Reposition cursor P1 so that it points to the largest entry that
|
|
-** is less than or equal to the key value. If there are no records
|
|
+** Reposition cursor P1 so that it points to the largest entry that
|
|
+** is less than or equal to the key value. If there are no records
|
|
** less than or equal to the key and P2 is not zero, then jump to P2.
|
|
**
|
|
** This opcode leaves the cursor configured to move in reverse order,
|
|
@@ -89010,18 +94829,20 @@ case OP_ColumnsUsed: {
|
|
** configured to use Prev, not Next.
|
|
**
|
|
** If the cursor P1 was opened using the OPFLAG_SEEKEQ flag, then this
|
|
-** opcode will always land on a record that equally equals the key, or
|
|
-** else jump immediately to P2. When the cursor is OPFLAG_SEEKEQ, this
|
|
-** opcode must be followed by an IdxGE opcode with the same arguments.
|
|
+** opcode will either land on a record that exactly matches the key, or
|
|
+** else it will cause a jump to P2. When the cursor is OPFLAG_SEEKEQ,
|
|
+** this opcode must be followed by an IdxLE opcode with the same arguments.
|
|
** The IdxGE opcode will be skipped if this opcode succeeds, but the
|
|
-** IdxGE opcode will be used on subsequent loop iterations.
|
|
+** IdxGE opcode will be used on subsequent loop iterations. The
|
|
+** OPFLAG_SEEKEQ flags is a hint to the btree layer to say that this
|
|
+** is an equality search.
|
|
**
|
|
** See also: Found, NotFound, SeekGt, SeekGe, SeekLt
|
|
*/
|
|
-case OP_SeekLT: /* jump, in3, group */
|
|
-case OP_SeekLE: /* jump, in3, group */
|
|
-case OP_SeekGE: /* jump, in3, group */
|
|
-case OP_SeekGT: { /* jump, in3, group */
|
|
+case OP_SeekLT: /* jump, in3, group, ncycle */
|
|
+case OP_SeekLE: /* jump, in3, group, ncycle */
|
|
+case OP_SeekGE: /* jump, in3, group, ncycle */
|
|
+case OP_SeekGT: { /* jump, in3, group, ncycle */
|
|
int res; /* Comparison result */
|
|
int oc; /* Opcode */
|
|
VdbeCursor *pC; /* The cursor to seek */
|
|
@@ -89051,7 +94872,7 @@ case OP_SeekGT: { /* jump, in3, group */
|
|
pC->cacheStatus = CACHE_STALE;
|
|
if( pC->isTable ){
|
|
u16 flags3, newType;
|
|
- /* The BTREE_SEEK_EQ flag is only set on index cursors */
|
|
+ /* The OPFLAG_SEEKEQ/BTREE_SEEK_EQ flag is only set on index cursors */
|
|
assert( sqlite3BtreeCursorHasHint(pC->uc.pCursor, BTREE_SEEK_EQ)==0
|
|
|| CORRUPT_DB );
|
|
|
|
@@ -89070,6 +94891,7 @@ case OP_SeekGT: { /* jump, in3, group */
|
|
/* If the P3 value could not be converted into an integer without
|
|
** loss of information, then special processing is required... */
|
|
if( (newType & (MEM_Int|MEM_IntReal))==0 ){
|
|
+ int c;
|
|
if( (newType & MEM_Real)==0 ){
|
|
if( (newType & MEM_Null) || oc>=OP_SeekGE ){
|
|
VdbeBranchTaken(1,2);
|
|
@@ -89079,7 +94901,8 @@ case OP_SeekGT: { /* jump, in3, group */
|
|
if( rc!=SQLITE_OK ) goto abort_due_to_error;
|
|
goto seek_not_found;
|
|
}
|
|
- }else
|
|
+ }
|
|
+ c = sqlite3IntFloatCompare(iKey, pIn3->u.r);
|
|
|
|
/* If the approximation iKey is larger than the actual real search
|
|
** term, substitute >= for > and < for <=. e.g. if the search term
|
|
@@ -89088,7 +94911,7 @@ case OP_SeekGT: { /* jump, in3, group */
|
|
** (x > 4.9) -> (x >= 5)
|
|
** (x <= 4.9) -> (x < 5)
|
|
*/
|
|
- if( pIn3->u.r<(double)iKey ){
|
|
+ if( c>0 ){
|
|
assert( OP_SeekGE==(OP_SeekGT-1) );
|
|
assert( OP_SeekLT==(OP_SeekLE-1) );
|
|
assert( (OP_SeekLE & 0x0001)==(OP_SeekGT & 0x0001) );
|
|
@@ -89097,27 +94920,30 @@ case OP_SeekGT: { /* jump, in3, group */
|
|
|
|
/* If the approximation iKey is smaller than the actual real search
|
|
** term, substitute <= for < and > for >=. */
|
|
- else if( pIn3->u.r>(double)iKey ){
|
|
+ else if( c<0 ){
|
|
assert( OP_SeekLE==(OP_SeekLT+1) );
|
|
assert( OP_SeekGT==(OP_SeekGE+1) );
|
|
assert( (OP_SeekLT & 0x0001)==(OP_SeekGE & 0x0001) );
|
|
if( (oc & 0x0001)==(OP_SeekLT & 0x0001) ) oc++;
|
|
}
|
|
}
|
|
- rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, 0, (u64)iKey, 0, &res);
|
|
+ rc = sqlite3BtreeTableMoveto(pC->uc.pCursor, (u64)iKey, 0, &res);
|
|
pC->movetoTarget = iKey; /* Used by OP_Delete */
|
|
if( rc!=SQLITE_OK ){
|
|
goto abort_due_to_error;
|
|
}
|
|
}else{
|
|
- /* For a cursor with the BTREE_SEEK_EQ hint, only the OP_SeekGE and
|
|
- ** OP_SeekLE opcodes are allowed, and these must be immediately followed
|
|
- ** by an OP_IdxGT or OP_IdxLT opcode, respectively, with the same key.
|
|
+ /* For a cursor with the OPFLAG_SEEKEQ/BTREE_SEEK_EQ hint, only the
|
|
+ ** OP_SeekGE and OP_SeekLE opcodes are allowed, and these must be
|
|
+ ** immediately followed by an OP_IdxGT or OP_IdxLT opcode, respectively,
|
|
+ ** with the same key.
|
|
*/
|
|
if( sqlite3BtreeCursorHasHint(pC->uc.pCursor, BTREE_SEEK_EQ) ){
|
|
eqOnly = 1;
|
|
assert( pOp->opcode==OP_SeekGE || pOp->opcode==OP_SeekLE );
|
|
assert( pOp[1].opcode==OP_IdxLT || pOp[1].opcode==OP_IdxGT );
|
|
+ assert( pOp->opcode==OP_SeekGE || pOp[1].opcode==OP_IdxLT );
|
|
+ assert( pOp->opcode==OP_SeekLE || pOp[1].opcode==OP_IdxGT );
|
|
assert( pOp[1].p1==pOp[0].p1 );
|
|
assert( pOp[1].p2==pOp[0].p2 );
|
|
assert( pOp[1].p3==pOp[0].p3 );
|
|
@@ -89145,10 +94971,16 @@ case OP_SeekGT: { /* jump, in3, group */
|
|
|
|
r.aMem = &aMem[pOp->p3];
|
|
#ifdef SQLITE_DEBUG
|
|
- { int i; for(i=0; i<r.nField; i++) assert( memIsValid(&r.aMem[i]) ); }
|
|
+ {
|
|
+ int i;
|
|
+ for(i=0; i<r.nField; i++){
|
|
+ assert( memIsValid(&r.aMem[i]) );
|
|
+ if( i>0 ) REGISTER_TRACE(pOp->p3+i, &r.aMem[i]);
|
|
+ }
|
|
+ }
|
|
#endif
|
|
r.eqSeen = 0;
|
|
- rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, &r, 0, 0, &res);
|
|
+ rc = sqlite3BtreeIndexMoveto(pC->uc.pCursor, &r, &res);
|
|
if( rc!=SQLITE_OK ){
|
|
goto abort_due_to_error;
|
|
}
|
|
@@ -89207,34 +95039,234 @@ case OP_SeekGT: { /* jump, in3, group */
|
|
break;
|
|
}
|
|
|
|
-/* Opcode: SeekHit P1 P2 * * *
|
|
-** Synopsis: seekHit=P2
|
|
+
|
|
+/* Opcode: SeekScan P1 P2 * * P5
|
|
+** Synopsis: Scan-ahead up to P1 rows
|
|
+**
|
|
+** This opcode is a prefix opcode to OP_SeekGE. In other words, this
|
|
+** opcode must be immediately followed by OP_SeekGE. This constraint is
|
|
+** checked by assert() statements.
|
|
+**
|
|
+** This opcode uses the P1 through P4 operands of the subsequent
|
|
+** OP_SeekGE. In the text that follows, the operands of the subsequent
|
|
+** OP_SeekGE opcode are denoted as SeekOP.P1 through SeekOP.P4. Only
|
|
+** the P1, P2 and P5 operands of this opcode are also used, and are called
|
|
+** This.P1, This.P2 and This.P5.
|
|
+**
|
|
+** This opcode helps to optimize IN operators on a multi-column index
|
|
+** where the IN operator is on the later terms of the index by avoiding
|
|
+** unnecessary seeks on the btree, substituting steps to the next row
|
|
+** of the b-tree instead. A correct answer is obtained if this opcode
|
|
+** is omitted or is a no-op.
|
|
+**
|
|
+** The SeekGE.P3 and SeekGE.P4 operands identify an unpacked key which
|
|
+** is the desired entry that we want the cursor SeekGE.P1 to be pointing
|
|
+** to. Call this SeekGE.P3/P4 row the "target".
|
|
+**
|
|
+** If the SeekGE.P1 cursor is not currently pointing to a valid row,
|
|
+** then this opcode is a no-op and control passes through into the OP_SeekGE.
|
|
+**
|
|
+** If the SeekGE.P1 cursor is pointing to a valid row, then that row
|
|
+** might be the target row, or it might be near and slightly before the
|
|
+** target row, or it might be after the target row. If the cursor is
|
|
+** currently before the target row, then this opcode attempts to position
|
|
+** the cursor on or after the target row by invoking sqlite3BtreeStep()
|
|
+** on the cursor between 1 and This.P1 times.
|
|
+**
|
|
+** The This.P5 parameter is a flag that indicates what to do if the
|
|
+** cursor ends up pointing at a valid row that is past the target
|
|
+** 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
|
|
+** 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
|
|
+** loop terminate.
|
|
+**
|
|
+** Possible outcomes from this opcode:<ol>
|
|
+**
|
|
+** <li> If the cursor is initally not pointed to any valid row, then
|
|
+** fall through into the subsequent OP_SeekGE opcode.
|
|
+**
|
|
+** <li> If the cursor is left pointing to a row that is before the target
|
|
+** row, even after making as many as This.P1 calls to
|
|
+** sqlite3BtreeNext(), then also fall through into OP_SeekGE.
|
|
+**
|
|
+** <li> If the cursor is left pointing at the target row, either because it
|
|
+** was at the target row to begin with or because one or more
|
|
+** sqlite3BtreeNext() calls moved the cursor to the target row,
|
|
+** then jump to This.P2..,
|
|
+**
|
|
+** <li> If the cursor started out before the target row and a call to
|
|
+** to sqlite3BtreeNext() moved the cursor off the end of the index
|
|
+** (indicating that the target row definitely does not exist in the
|
|
+** btree) then jump to SeekGE.P2, ending the loop.
|
|
+**
|
|
+** <li> If the cursor ends up on a valid row that is past the target row
|
|
+** (indicating that the target row does not exist in the btree) then
|
|
+** jump to SeekOP.P2 if This.P5==0 or to This.P2 if This.P5>0.
|
|
+** </ol>
|
|
+*/
|
|
+case OP_SeekScan: { /* ncycle */
|
|
+ VdbeCursor *pC;
|
|
+ int res;
|
|
+ int nStep;
|
|
+ UnpackedRecord r;
|
|
+
|
|
+ assert( pOp[1].opcode==OP_SeekGE );
|
|
+
|
|
+ /* If pOp->p5 is clear, then pOp->p2 points to the first instruction past the
|
|
+ ** OP_IdxGT that follows the OP_SeekGE. Otherwise, it points to the first
|
|
+ ** opcode past the OP_SeekGE itself. */
|
|
+ assert( pOp->p2>=(int)(pOp-aOp)+2 );
|
|
+#ifdef SQLITE_DEBUG
|
|
+ if( pOp->p5==0 ){
|
|
+ /* There are no inequality constraints following the IN constraint. */
|
|
+ assert( pOp[1].p1==aOp[pOp->p2-1].p1 );
|
|
+ assert( pOp[1].p2==aOp[pOp->p2-1].p2 );
|
|
+ assert( pOp[1].p3==aOp[pOp->p2-1].p3 );
|
|
+ assert( aOp[pOp->p2-1].opcode==OP_IdxGT
|
|
+ || aOp[pOp->p2-1].opcode==OP_IdxGE );
|
|
+ testcase( aOp[pOp->p2-1].opcode==OP_IdxGE );
|
|
+ }else{
|
|
+ /* There are inequality constraints. */
|
|
+ assert( pOp->p2==(int)(pOp-aOp)+2 );
|
|
+ assert( aOp[pOp->p2-1].opcode==OP_SeekGE );
|
|
+ }
|
|
+#endif
|
|
+
|
|
+ assert( pOp->p1>0 );
|
|
+ pC = p->apCsr[pOp[1].p1];
|
|
+ assert( pC!=0 );
|
|
+ assert( pC->eCurType==CURTYPE_BTREE );
|
|
+ assert( !pC->isTable );
|
|
+ if( !sqlite3BtreeCursorIsValidNN(pC->uc.pCursor) ){
|
|
+#ifdef SQLITE_DEBUG
|
|
+ if( db->flags&SQLITE_VdbeTrace ){
|
|
+ printf("... cursor not valid - fall through\n");
|
|
+ }
|
|
+#endif
|
|
+ break;
|
|
+ }
|
|
+ nStep = pOp->p1;
|
|
+ assert( nStep>=1 );
|
|
+ r.pKeyInfo = pC->pKeyInfo;
|
|
+ r.nField = (u16)pOp[1].p4.i;
|
|
+ r.default_rc = 0;
|
|
+ r.aMem = &aMem[pOp[1].p3];
|
|
+#ifdef SQLITE_DEBUG
|
|
+ {
|
|
+ int i;
|
|
+ for(i=0; i<r.nField; i++){
|
|
+ assert( memIsValid(&r.aMem[i]) );
|
|
+ REGISTER_TRACE(pOp[1].p3+i, &aMem[pOp[1].p3+i]);
|
|
+ }
|
|
+ }
|
|
+#endif
|
|
+ res = 0; /* Not needed. Only used to silence a warning. */
|
|
+ while(1){
|
|
+ rc = sqlite3VdbeIdxKeyCompare(db, pC, &r, &res);
|
|
+ if( rc ) goto abort_due_to_error;
|
|
+ if( res>0 && pOp->p5==0 ){
|
|
+ seekscan_search_fail:
|
|
+ /* Jump to SeekGE.P2, ending the loop */
|
|
+#ifdef SQLITE_DEBUG
|
|
+ if( db->flags&SQLITE_VdbeTrace ){
|
|
+ printf("... %d steps and then skip\n", pOp->p1 - nStep);
|
|
+ }
|
|
+#endif
|
|
+ VdbeBranchTaken(1,3);
|
|
+ pOp++;
|
|
+ goto jump_to_p2;
|
|
+ }
|
|
+ if( res>=0 ){
|
|
+ /* Jump to This.P2, bypassing the OP_SeekGE opcode */
|
|
+#ifdef SQLITE_DEBUG
|
|
+ if( db->flags&SQLITE_VdbeTrace ){
|
|
+ printf("... %d steps and then success\n", pOp->p1 - nStep);
|
|
+ }
|
|
+#endif
|
|
+ VdbeBranchTaken(2,3);
|
|
+ goto jump_to_p2;
|
|
+ break;
|
|
+ }
|
|
+ if( nStep<=0 ){
|
|
+#ifdef SQLITE_DEBUG
|
|
+ if( db->flags&SQLITE_VdbeTrace ){
|
|
+ printf("... fall through after %d steps\n", pOp->p1);
|
|
+ }
|
|
+#endif
|
|
+ VdbeBranchTaken(0,3);
|
|
+ break;
|
|
+ }
|
|
+ nStep--;
|
|
+ rc = sqlite3BtreeNext(pC->uc.pCursor, 0);
|
|
+ if( rc ){
|
|
+ if( rc==SQLITE_DONE ){
|
|
+ rc = SQLITE_OK;
|
|
+ goto seekscan_search_fail;
|
|
+ }else{
|
|
+ goto abort_due_to_error;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ break;
|
|
+}
|
|
+
|
|
+
|
|
+/* Opcode: SeekHit P1 P2 P3 * *
|
|
+** Synopsis: set P2<=seekHit<=P3
|
|
+**
|
|
+** Increase or decrease the seekHit value for cursor P1, if necessary,
|
|
+** so that it is no less than P2 and no greater than P3.
|
|
**
|
|
-** Set the seekHit flag on cursor P1 to the value in P2.
|
|
-* The seekHit flag is used by the IfNoHope opcode.
|
|
+** The seekHit integer represents the maximum of terms in an index for which
|
|
+** there is known to be at least one match. If the seekHit value is smaller
|
|
+** than the total number of equality terms in an index lookup, then the
|
|
+** OP_IfNoHope opcode might run to see if the IN loop can be abandoned
|
|
+** early, thus saving work. This is part of the IN-early-out optimization.
|
|
**
|
|
-** P1 must be a valid b-tree cursor. P2 must be a boolean value,
|
|
-** either 0 or 1.
|
|
+** P1 must be a valid b-tree cursor.
|
|
*/
|
|
-case OP_SeekHit: {
|
|
+case OP_SeekHit: { /* ncycle */
|
|
VdbeCursor *pC;
|
|
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
|
pC = p->apCsr[pOp->p1];
|
|
assert( pC!=0 );
|
|
- assert( pOp->p2==0 || pOp->p2==1 );
|
|
- pC->seekHit = pOp->p2 & 1;
|
|
+ assert( pOp->p3>=pOp->p2 );
|
|
+ if( pC->seekHit<pOp->p2 ){
|
|
+#ifdef SQLITE_DEBUG
|
|
+ if( db->flags&SQLITE_VdbeTrace ){
|
|
+ printf("seekHit changes from %d to %d\n", pC->seekHit, pOp->p2);
|
|
+ }
|
|
+#endif
|
|
+ pC->seekHit = pOp->p2;
|
|
+ }else if( pC->seekHit>pOp->p3 ){
|
|
+#ifdef SQLITE_DEBUG
|
|
+ if( db->flags&SQLITE_VdbeTrace ){
|
|
+ printf("seekHit changes from %d to %d\n", pC->seekHit, pOp->p3);
|
|
+ }
|
|
+#endif
|
|
+ pC->seekHit = pOp->p3;
|
|
+ }
|
|
break;
|
|
}
|
|
|
|
/* Opcode: IfNotOpen P1 P2 * * *
|
|
** Synopsis: if( !csr[P1] ) goto P2
|
|
**
|
|
-** If cursor P1 is not open, jump to instruction P2. Otherwise, fall through.
|
|
+** If cursor P1 is not open or if P1 is set to a NULL row using the
|
|
+** OP_NullRow opcode, then jump to instruction P2. Otherwise, fall through.
|
|
*/
|
|
case OP_IfNotOpen: { /* jump */
|
|
+ VdbeCursor *pCur;
|
|
+
|
|
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
|
- VdbeBranchTaken(p->apCsr[pOp->p1]==0, 2);
|
|
- if( !p->apCsr[pOp->p1] ){
|
|
+ pCur = p->apCsr[pOp->p1];
|
|
+ VdbeBranchTaken(pCur==0 || pCur->nullRow, 2);
|
|
+ if( pCur==0 || pCur->nullRow ){
|
|
goto jump_to_p2_and_check_for_interrupt;
|
|
}
|
|
break;
|
|
@@ -89263,9 +95295,9 @@ case OP_IfNotOpen: { /* jump */
|
|
** If P4==0 then register P3 holds a blob constructed by MakeRecord. If
|
|
** P4>0 then register P3 is the first of P4 registers that form an unpacked
|
|
** record.
|
|
-**
|
|
+**
|
|
** Cursor P1 is on an index btree. If the record identified by P3 and P4
|
|
-** is not the prefix of any entry in P1 then a jump is made to P2. If P1
|
|
+** is not the prefix of any entry in P1 then a jump is made to P2. If P1
|
|
** does contain an entry whose prefix matches the P3/P4 record then control
|
|
** falls through to the next instruction and P1 is left pointing at the
|
|
** matching entry.
|
|
@@ -89280,16 +95312,20 @@ case OP_IfNotOpen: { /* jump */
|
|
** Synopsis: key=r[P3@P4]
|
|
**
|
|
** Register P3 is the first of P4 registers that form an unpacked
|
|
-** record.
|
|
+** record. Cursor P1 is an index btree. P2 is a jump destination.
|
|
+** In other words, the operands to this opcode are the same as the
|
|
+** operands to OP_NotFound and OP_IdxGT.
|
|
**
|
|
-** Cursor P1 is on an index btree. If the seekHit flag is set on P1, then
|
|
-** this opcode is a no-op. But if the seekHit flag of P1 is clear, then
|
|
-** check to see if there is any entry in P1 that matches the
|
|
-** prefix identified by P3 and P4. If no entry matches the prefix,
|
|
-** jump to P2. Otherwise fall through.
|
|
+** This opcode is an optimization attempt only. If this opcode always
|
|
+** falls through, the correct answer is still obtained, but extra works
|
|
+** is performed.
|
|
**
|
|
-** This opcode behaves like OP_NotFound if the seekHit
|
|
-** flag is clear and it behaves like OP_Noop if the seekHit flag is set.
|
|
+** 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
|
|
+** is less than P4, attempt to find out if a match is possible by running
|
|
+** OP_NotFound.
|
|
**
|
|
** This opcode is used in IN clause processing for a multi-column key.
|
|
** If an IN clause is attached to an element of the key other than the
|
|
@@ -89309,7 +95345,7 @@ case OP_IfNotOpen: { /* jump */
|
|
** If P4==0 then register P3 holds a blob constructed by MakeRecord. If
|
|
** P4>0 then register P3 is the first of P4 registers that form an unpacked
|
|
** record.
|
|
-**
|
|
+**
|
|
** Cursor P1 is on an index btree. If the record identified by P3 and P4
|
|
** contains any NULL value, jump immediately to P2. If all terms of the
|
|
** record are not-NULL then a check is done to determine if any row in the
|
|
@@ -89326,23 +95362,26 @@ case OP_IfNotOpen: { /* jump */
|
|
**
|
|
** See also: NotFound, Found, NotExists
|
|
*/
|
|
-case OP_IfNoHope: { /* jump, in3 */
|
|
+case OP_IfNoHope: { /* jump, in3, ncycle */
|
|
VdbeCursor *pC;
|
|
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
|
pC = p->apCsr[pOp->p1];
|
|
assert( pC!=0 );
|
|
- if( pC->seekHit ) break;
|
|
+#ifdef SQLITE_DEBUG
|
|
+ if( db->flags&SQLITE_VdbeTrace ){
|
|
+ printf("seekHit is %d\n", pC->seekHit);
|
|
+ }
|
|
+#endif
|
|
+ if( pC->seekHit>=pOp->p4.i ) break;
|
|
/* Fall through into OP_NotFound */
|
|
+ /* no break */ deliberate_fall_through
|
|
}
|
|
-case OP_NoConflict: /* jump, in3 */
|
|
-case OP_NotFound: /* jump, in3 */
|
|
-case OP_Found: { /* jump, in3 */
|
|
+case OP_NoConflict: /* jump, in3, ncycle */
|
|
+case OP_NotFound: /* jump, in3, ncycle */
|
|
+case OP_Found: { /* jump, in3, ncycle */
|
|
int alreadyExists;
|
|
- int takeJump;
|
|
int ii;
|
|
VdbeCursor *pC;
|
|
- int res;
|
|
- UnpackedRecord *pFree;
|
|
UnpackedRecord *pIdxKey;
|
|
UnpackedRecord r;
|
|
|
|
@@ -89357,14 +95396,15 @@ case OP_Found: { /* jump, in3 */
|
|
#ifdef SQLITE_DEBUG
|
|
pC->seekOp = pOp->opcode;
|
|
#endif
|
|
- pIn3 = &aMem[pOp->p3];
|
|
+ r.aMem = &aMem[pOp->p3];
|
|
assert( pC->eCurType==CURTYPE_BTREE );
|
|
assert( pC->uc.pCursor!=0 );
|
|
assert( pC->isTable==0 );
|
|
- if( pOp->p4.i>0 ){
|
|
+ r.nField = (u16)pOp->p4.i;
|
|
+ if( r.nField>0 ){
|
|
+ /* Key values in an array of registers */
|
|
r.pKeyInfo = pC->pKeyInfo;
|
|
- r.nField = (u16)pOp->p4.i;
|
|
- r.aMem = pIn3;
|
|
+ r.default_rc = 0;
|
|
#ifdef SQLITE_DEBUG
|
|
for(ii=0; ii<r.nField; ii++){
|
|
assert( memIsValid(&r.aMem[ii]) );
|
|
@@ -89372,37 +95412,25 @@ case OP_Found: { /* jump, in3 */
|
|
if( ii ) REGISTER_TRACE(pOp->p3+ii, &r.aMem[ii]);
|
|
}
|
|
#endif
|
|
- pIdxKey = &r;
|
|
- pFree = 0;
|
|
+ rc = sqlite3BtreeIndexMoveto(pC->uc.pCursor, &r, &pC->seekResult);
|
|
}else{
|
|
- assert( pIn3->flags & MEM_Blob );
|
|
- rc = ExpandBlob(pIn3);
|
|
+ /* Composite key generated by OP_MakeRecord */
|
|
+ assert( r.aMem->flags & MEM_Blob );
|
|
+ assert( pOp->opcode!=OP_NoConflict );
|
|
+ rc = ExpandBlob(r.aMem);
|
|
assert( rc==SQLITE_OK || rc==SQLITE_NOMEM );
|
|
if( rc ) goto no_mem;
|
|
- pFree = pIdxKey = sqlite3VdbeAllocUnpackedRecord(pC->pKeyInfo);
|
|
+ pIdxKey = sqlite3VdbeAllocUnpackedRecord(pC->pKeyInfo);
|
|
if( pIdxKey==0 ) goto no_mem;
|
|
- sqlite3VdbeRecordUnpack(pC->pKeyInfo, pIn3->n, pIn3->z, pIdxKey);
|
|
- }
|
|
- pIdxKey->default_rc = 0;
|
|
- takeJump = 0;
|
|
- if( pOp->opcode==OP_NoConflict ){
|
|
- /* For the OP_NoConflict opcode, take the jump if any of the
|
|
- ** input fields are NULL, since any key with a NULL will not
|
|
- ** conflict */
|
|
- for(ii=0; ii<pIdxKey->nField; ii++){
|
|
- if( pIdxKey->aMem[ii].flags & MEM_Null ){
|
|
- takeJump = 1;
|
|
- break;
|
|
- }
|
|
- }
|
|
+ sqlite3VdbeRecordUnpack(pC->pKeyInfo, r.aMem->n, r.aMem->z, pIdxKey);
|
|
+ pIdxKey->default_rc = 0;
|
|
+ rc = sqlite3BtreeIndexMoveto(pC->uc.pCursor, pIdxKey, &pC->seekResult);
|
|
+ sqlite3DbFreeNN(db, pIdxKey);
|
|
}
|
|
- rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, pIdxKey, 0, 0, &res);
|
|
- if( pFree ) sqlite3DbFreeNN(db, pFree);
|
|
if( rc!=SQLITE_OK ){
|
|
goto abort_due_to_error;
|
|
}
|
|
- pC->seekResult = res;
|
|
- alreadyExists = (res==0);
|
|
+ alreadyExists = (pC->seekResult==0);
|
|
pC->nullRow = 1-alreadyExists;
|
|
pC->deferredMoveto = 0;
|
|
pC->cacheStatus = CACHE_STALE;
|
|
@@ -89410,8 +95438,25 @@ case OP_Found: { /* jump, in3 */
|
|
VdbeBranchTaken(alreadyExists!=0,2);
|
|
if( alreadyExists ) goto jump_to_p2;
|
|
}else{
|
|
- VdbeBranchTaken(takeJump||alreadyExists==0,2);
|
|
- if( takeJump || !alreadyExists ) goto jump_to_p2;
|
|
+ if( !alreadyExists ){
|
|
+ VdbeBranchTaken(1,2);
|
|
+ goto jump_to_p2;
|
|
+ }
|
|
+ if( pOp->opcode==OP_NoConflict ){
|
|
+ /* For the OP_NoConflict opcode, take the jump if any of the
|
|
+ ** input fields are NULL, since any key with a NULL will not
|
|
+ ** conflict */
|
|
+ for(ii=0; ii<r.nField; ii++){
|
|
+ if( r.aMem[ii].flags & MEM_Null ){
|
|
+ VdbeBranchTaken(1,2);
|
|
+ goto jump_to_p2;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ VdbeBranchTaken(0,2);
|
|
+ if( pOp->opcode==OP_IfNoHope ){
|
|
+ pC->seekHit = pOp->p4.i;
|
|
+ }
|
|
}
|
|
break;
|
|
}
|
|
@@ -89421,9 +95466,9 @@ case OP_Found: { /* jump, in3 */
|
|
**
|
|
** P1 is the index of a cursor open on an SQL table btree (with integer
|
|
** keys). If register P3 does not contain an integer or if P1 does not
|
|
-** contain a record with rowid P3 then jump immediately to P2.
|
|
+** contain a record with rowid P3 then jump immediately to P2.
|
|
** Or, if P2 is 0, raise an SQLITE_CORRUPT error. If P1 does contain
|
|
-** a record with rowid P3 then
|
|
+** a record with rowid P3 then
|
|
** leave the cursor pointing at that record and fall through to the next
|
|
** instruction.
|
|
**
|
|
@@ -89446,7 +95491,7 @@ case OP_Found: { /* jump, in3 */
|
|
** P1 is the index of a cursor open on an SQL table btree (with integer
|
|
** keys). P3 is an integer rowid. If P1 does not contain a record with
|
|
** rowid P3 then jump immediately to P2. Or, if P2 is 0, raise an
|
|
-** SQLITE_CORRUPT error. If P1 does contain a record with rowid P3 then
|
|
+** SQLITE_CORRUPT error. If P1 does contain a record with rowid P3 then
|
|
** leave the cursor pointing at that record and fall through to the next
|
|
** instruction.
|
|
**
|
|
@@ -89463,7 +95508,7 @@ case OP_Found: { /* jump, in3 */
|
|
**
|
|
** See also: Found, NotFound, NoConflict, SeekRowid
|
|
*/
|
|
-case OP_SeekRowid: { /* jump, in3 */
|
|
+case OP_SeekRowid: { /* jump, in3, ncycle */
|
|
VdbeCursor *pC;
|
|
BtCursor *pCrsr;
|
|
int res;
|
|
@@ -89487,7 +95532,8 @@ case OP_SeekRowid: { /* jump, in3 */
|
|
goto notExistsWithKey;
|
|
}
|
|
/* Fall through into OP_NotExists */
|
|
-case OP_NotExists: /* jump, in3 */
|
|
+ /* no break */ deliberate_fall_through
|
|
+case OP_NotExists: /* jump, in3, ncycle */
|
|
pIn3 = &aMem[pOp->p3];
|
|
assert( (pIn3->flags & MEM_Int)!=0 || pOp->opcode==OP_SeekRowid );
|
|
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
|
@@ -89503,7 +95549,7 @@ case OP_NotExists: /* jump, in3 */
|
|
pCrsr = pC->uc.pCursor;
|
|
assert( pCrsr!=0 );
|
|
res = 0;
|
|
- rc = sqlite3BtreeMovetoUnpacked(pCrsr, 0, iKey, 0, &res);
|
|
+ rc = sqlite3BtreeTableMoveto(pCrsr, iKey, 0, &res);
|
|
assert( rc==SQLITE_OK || res==0 );
|
|
pC->movetoTarget = iKey; /* Used by OP_Delete */
|
|
pC->nullRow = 0;
|
|
@@ -89529,7 +95575,7 @@ case OP_NotExists: /* jump, in3 */
|
|
** Find the next available sequence number for cursor P1.
|
|
** Write the sequence number into register P2.
|
|
** The sequence number on the cursor is incremented after this
|
|
-** instruction.
|
|
+** instruction.
|
|
*/
|
|
case OP_Sequence: { /* out2 */
|
|
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
|
@@ -89549,9 +95595,9 @@ case OP_Sequence: { /* out2 */
|
|
** table that cursor P1 points to. The new record number is written
|
|
** written to register P2.
|
|
**
|
|
-** If P3>0 then P3 is a register in the root frame of this VDBE that holds
|
|
+** If P3>0 then P3 is a register in the root frame of this VDBE that holds
|
|
** the largest previously generated record number. No new record numbers are
|
|
-** allowed to be less than this value. When this value reaches its maximum,
|
|
+** allowed to be less than this value. When this value reaches its maximum,
|
|
** an SQLITE_FULL error is generated. The P3 register is updated with the '
|
|
** generated record number. This P3 mechanism is used to help implement the
|
|
** AUTOINCREMENT feature.
|
|
@@ -89561,8 +95607,10 @@ case OP_NewRowid: { /* out2 */
|
|
VdbeCursor *pC; /* Cursor of table to get the new rowid */
|
|
int res; /* Result of an sqlite3BtreeLast() */
|
|
int cnt; /* Counter to limit the number of searches */
|
|
+#ifndef SQLITE_OMIT_AUTOINCREMENT
|
|
Mem *pMem; /* Register holding largest rowid for AUTOINCREMENT */
|
|
VdbeFrame *pFrame; /* Root frame of VDBE */
|
|
+#endif
|
|
|
|
v = 0;
|
|
res = 0;
|
|
@@ -89658,7 +95706,7 @@ case OP_NewRowid: { /* out2 */
|
|
do{
|
|
sqlite3_randomness(sizeof(v), &v);
|
|
v &= (MAX_ROWID>>1); v++; /* Ensure that v is greater than zero */
|
|
- }while( ((rc = sqlite3BtreeMovetoUnpacked(pC->uc.pCursor, 0, (u64)v,
|
|
+ }while( ((rc = sqlite3BtreeTableMoveto(pC->uc.pCursor, (u64)v,
|
|
0, &res))==SQLITE_OK)
|
|
&& (res==0)
|
|
&& (++cnt<100));
|
|
@@ -89700,8 +95748,8 @@ case OP_NewRowid: { /* out2 */
|
|
** is part of an INSERT operation. The difference is only important to
|
|
** the update hook.
|
|
**
|
|
-** Parameter P4 may point to a Table structure, or may be NULL. If it is
|
|
-** not NULL, then the update-hook (sqlite3.xUpdateCallback) is invoked
|
|
+** Parameter P4 may point to a Table structure, or may be NULL. If it is
|
|
+** not NULL, then the update-hook (sqlite3.xUpdateCallback) is invoked
|
|
** following a successful insert.
|
|
**
|
|
** (WARNING/TODO: If P1 is a pseudo-cursor and P2 is dynamically
|
|
@@ -89748,14 +95796,14 @@ case OP_Insert: {
|
|
assert( (pOp->p5 & OPFLAG_ISNOOP) || HasRowid(pTab) );
|
|
}else{
|
|
pTab = 0;
|
|
- zDb = 0; /* Not needed. Silence a compiler warning. */
|
|
+ zDb = 0;
|
|
}
|
|
|
|
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
|
|
/* Invoke the pre-update hook, if any */
|
|
if( pTab ){
|
|
if( db->xPreUpdateCallback && !(pOp->p5 & OPFLAG_ISUPDATE) ){
|
|
- sqlite3VdbePreUpdateHook(p, pC, SQLITE_INSERT, zDb, pTab, x.nKey,pOp->p2);
|
|
+ sqlite3VdbePreUpdateHook(p,pC,SQLITE_INSERT,zDb,pTab,x.nKey,pOp->p2,-1);
|
|
}
|
|
if( db->xUpdateCallback==0 || pTab->aCol==0 ){
|
|
/* Prevent post-update hook from running in cases when it should not */
|
|
@@ -89765,9 +95813,12 @@ case OP_Insert: {
|
|
if( pOp->p5 & OPFLAG_ISNOOP ) break;
|
|
#endif
|
|
|
|
- if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
|
|
- if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = x.nKey;
|
|
- assert( pData->flags & (MEM_Blob|MEM_Str) );
|
|
+ assert( (pOp->p5 & OPFLAG_LASTROWID)==0 || (pOp->p5 & OPFLAG_NCHANGE)!=0 );
|
|
+ if( pOp->p5 & OPFLAG_NCHANGE ){
|
|
+ p->nChange++;
|
|
+ if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = x.nKey;
|
|
+ }
|
|
+ assert( (pData->flags & (MEM_Blob|MEM_Str))!=0 || pData->n==0 );
|
|
x.pData = pData->z;
|
|
x.nData = pData->n;
|
|
seekResult = ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0);
|
|
@@ -89777,8 +95828,10 @@ case OP_Insert: {
|
|
x.nZero = 0;
|
|
}
|
|
x.pKey = 0;
|
|
+ assert( BTREE_PREFORMAT==OPFLAG_PREFORMAT );
|
|
rc = sqlite3BtreeInsert(pC->uc.pCursor, &x,
|
|
- (pOp->p5 & (OPFLAG_APPEND|OPFLAG_SAVEPOSITION)), seekResult
|
|
+ (pOp->p5 & (OPFLAG_APPEND|OPFLAG_SAVEPOSITION|OPFLAG_PREFORMAT)),
|
|
+ seekResult
|
|
);
|
|
pC->deferredMoveto = 0;
|
|
pC->cacheStatus = CACHE_STALE;
|
|
@@ -89795,6 +95848,33 @@ case OP_Insert: {
|
|
break;
|
|
}
|
|
|
|
+/* Opcode: RowCell P1 P2 P3 * *
|
|
+**
|
|
+** P1 and P2 are both open cursors. Both must be opened on the same type
|
|
+** of table - intkey or index. This opcode is used as part of copying
|
|
+** the current row from P2 into P1. If the cursors are opened on intkey
|
|
+** tables, register P3 contains the rowid to use with the new record in
|
|
+** P1. If they are opened on index tables, P3 is not used.
|
|
+**
|
|
+** This opcode must be followed by either an Insert or InsertIdx opcode
|
|
+** with the OPFLAG_PREFORMAT flag set to complete the insert operation.
|
|
+*/
|
|
+case OP_RowCell: {
|
|
+ VdbeCursor *pDest; /* Cursor to write to */
|
|
+ VdbeCursor *pSrc; /* Cursor to read from */
|
|
+ i64 iKey; /* Rowid value to insert with */
|
|
+ assert( pOp[1].opcode==OP_Insert || pOp[1].opcode==OP_IdxInsert );
|
|
+ assert( pOp[1].opcode==OP_Insert || pOp->p3==0 );
|
|
+ assert( pOp[1].opcode==OP_IdxInsert || pOp->p3>0 );
|
|
+ assert( pOp[1].p5 & OPFLAG_PREFORMAT );
|
|
+ pDest = p->apCsr[pOp->p1];
|
|
+ pSrc = p->apCsr[pOp->p2];
|
|
+ iKey = pOp->p3 ? aMem[pOp->p3].u.i : 0;
|
|
+ rc = sqlite3BtreeTransferRow(pDest->uc.pCursor, pSrc->uc.pCursor, iKey);
|
|
+ if( rc!=SQLITE_OK ) goto abort_due_to_error;
|
|
+ break;
|
|
+};
|
|
+
|
|
/* Opcode: Delete P1 P2 P3 P4 P5
|
|
**
|
|
** Delete the record at which the P1 cursor is currently pointing.
|
|
@@ -89803,7 +95883,7 @@ case OP_Insert: {
|
|
** the cursor will be left pointing at either the next or the previous
|
|
** record in the table. If it is left pointing at the next record, then
|
|
** the next Next instruction will be a no-op. As a result, in this case
|
|
-** it is ok to delete a record from within a Next loop. If
|
|
+** it is ok to delete a record from within a Next loop. If
|
|
** OPFLAG_SAVEPOSITION bit of P5 is clear, then the cursor will be
|
|
** left in an undefined state.
|
|
**
|
|
@@ -89819,11 +95899,11 @@ case OP_Insert: {
|
|
** P1 must not be pseudo-table. It has to be a real table with
|
|
** multiple rows.
|
|
**
|
|
-** If P4 is not NULL then it points to a Table object. In this case either
|
|
+** If P4 is not NULL then it points to a Table object. In this case either
|
|
** the update or pre-update hook, or both, may be invoked. The P1 cursor must
|
|
-** have been positioned using OP_NotFound prior to invoking this opcode in
|
|
-** this case. Specifically, if one is configured, the pre-update hook is
|
|
-** invoked if P4 is not NULL. The update-hook is invoked if one is configured,
|
|
+** have been positioned using OP_NotFound prior to invoking this opcode in
|
|
+** this case. Specifically, if one is configured, the pre-update hook is
|
|
+** invoked if P4 is not NULL. The update-hook is invoked if one is configured,
|
|
** P4 is not NULL, and the OPFLAG_NCHANGE flag is set in P2.
|
|
**
|
|
** If the OPFLAG_ISUPDATE flag is set in P2, then P3 contains the address
|
|
@@ -89862,7 +95942,7 @@ case OP_Delete: {
|
|
/* If the update-hook or pre-update-hook will be invoked, set zDb to
|
|
** the name of the db to pass as to it. Also set local pTab to a copy
|
|
** of p4.pTab. Finally, if p5 is true, indicating that this cursor was
|
|
- ** last moved with OP_Next or OP_Prev, not Seek or NotFound, set
|
|
+ ** last moved with OP_Next or OP_Prev, not Seek or NotFound, set
|
|
** VdbeCursor.movetoTarget to the current rowid. */
|
|
if( pOp->p4type==P4_TABLE && HAS_UPDATE_HOOK(db) ){
|
|
assert( pC->iDb>=0 );
|
|
@@ -89873,27 +95953,28 @@ case OP_Delete: {
|
|
pC->movetoTarget = sqlite3BtreeIntegerKey(pC->uc.pCursor);
|
|
}
|
|
}else{
|
|
- zDb = 0; /* Not needed. Silence a compiler warning. */
|
|
- pTab = 0; /* Not needed. Silence a compiler warning. */
|
|
+ zDb = 0;
|
|
+ pTab = 0;
|
|
}
|
|
|
|
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
|
|
/* Invoke the pre-update-hook if required. */
|
|
- if( db->xPreUpdateCallback && pOp->p4.pTab ){
|
|
- assert( !(opflags & OPFLAG_ISUPDATE)
|
|
- || HasRowid(pTab)==0
|
|
- || (aMem[pOp->p3].flags & MEM_Int)
|
|
+ assert( db->xPreUpdateCallback==0 || pTab==pOp->p4.pTab );
|
|
+ if( db->xPreUpdateCallback && pTab ){
|
|
+ assert( !(opflags & OPFLAG_ISUPDATE)
|
|
+ || HasRowid(pTab)==0
|
|
+ || (aMem[pOp->p3].flags & MEM_Int)
|
|
);
|
|
sqlite3VdbePreUpdateHook(p, pC,
|
|
- (opflags & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_DELETE,
|
|
+ (opflags & OPFLAG_ISUPDATE) ? SQLITE_UPDATE : SQLITE_DELETE,
|
|
zDb, pTab, pC->movetoTarget,
|
|
- pOp->p3
|
|
+ pOp->p3, -1
|
|
);
|
|
}
|
|
if( opflags & OPFLAG_ISNOOP ) break;
|
|
#endif
|
|
-
|
|
- /* Only flags that can be set are SAVEPOISTION and AUXDELETE */
|
|
+
|
|
+ /* Only flags that can be set are SAVEPOISTION and AUXDELETE */
|
|
assert( (pOp->p5 & ~(OPFLAG_SAVEPOSITION|OPFLAG_AUXDELETE))==0 );
|
|
assert( OPFLAG_SAVEPOSITION==BTREE_SAVEPOSITION );
|
|
assert( OPFLAG_AUXDELETE==BTREE_AUXDELETE );
|
|
@@ -89920,7 +96001,7 @@ case OP_Delete: {
|
|
/* Invoke the update-hook if required. */
|
|
if( opflags & OPFLAG_NCHANGE ){
|
|
p->nChange++;
|
|
- if( db->xUpdateCallback && HasRowid(pTab) ){
|
|
+ if( db->xUpdateCallback && ALWAYS(pTab!=0) && HasRowid(pTab) ){
|
|
db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE, zDb, pTab->zName,
|
|
pC->movetoTarget);
|
|
assert( pC->iDb>=0 );
|
|
@@ -89946,7 +96027,7 @@ case OP_ResetCount: {
|
|
** Synopsis: if key(P1)!=trim(r[P3],P4) goto P2
|
|
**
|
|
** P1 is a sorter cursor. This instruction compares a prefix of the
|
|
-** record blob in register P3 against a prefix of the entry that
|
|
+** record blob in register P3 against a prefix of the entry that
|
|
** the sorter cursor currently points to. Only the first P4 fields
|
|
** of r[P3] and the sorter record are compared.
|
|
**
|
|
@@ -90004,10 +96085,10 @@ case OP_SorterData: {
|
|
/* Opcode: RowData P1 P2 P3 * *
|
|
** Synopsis: r[P2]=data
|
|
**
|
|
-** Write into register P2 the complete row content for the row at
|
|
+** Write into register P2 the complete row content for the row at
|
|
** which cursor P1 is currently pointing.
|
|
-** There is no interpretation of the data.
|
|
-** It is just copied onto the P2 register exactly as
|
|
+** There is no interpretation of the data.
|
|
+** It is just copied onto the P2 register exactly as
|
|
** it is found in the database file.
|
|
**
|
|
** If cursor P1 is an index, then the content is the key of the row.
|
|
@@ -90055,17 +96136,13 @@ case OP_RowData: {
|
|
*/
|
|
assert( pC->deferredMoveto==0 );
|
|
assert( sqlite3BtreeCursorIsValid(pCrsr) );
|
|
-#if 0 /* Not required due to the previous to assert() statements */
|
|
- rc = sqlite3VdbeCursorMoveto(pC);
|
|
- if( rc!=SQLITE_OK ) goto abort_due_to_error;
|
|
-#endif
|
|
|
|
n = sqlite3BtreePayloadSize(pCrsr);
|
|
if( n>(u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){
|
|
goto too_big;
|
|
}
|
|
testcase( n==0 );
|
|
- rc = sqlite3VdbeMemFromBtree(pCrsr, 0, n, pOut);
|
|
+ rc = sqlite3VdbeMemFromBtreeZeroOffset(pCrsr, n, pOut);
|
|
if( rc ) goto abort_due_to_error;
|
|
if( !pOp->p3 ) Deephemeralize(pOut);
|
|
UPDATE_MAX_BLOBSIZE(pOut);
|
|
@@ -90074,7 +96151,7 @@ case OP_RowData: {
|
|
}
|
|
|
|
/* Opcode: Rowid P1 P2 * * *
|
|
-** Synopsis: r[P2]=rowid
|
|
+** Synopsis: r[P2]=PX rowid of P1
|
|
**
|
|
** Store in register P2 an integer which is the key of the table entry that
|
|
** P1 is currently point to.
|
|
@@ -90083,7 +96160,7 @@ case OP_RowData: {
|
|
** be a separate OP_VRowid opcode for use with virtual tables, but this
|
|
** one opcode now works for both table types.
|
|
*/
|
|
-case OP_Rowid: { /* out2 */
|
|
+case OP_Rowid: { /* out2, ncycle */
|
|
VdbeCursor *pC;
|
|
i64 v;
|
|
sqlite3_vtab *pVtab;
|
|
@@ -90129,13 +96206,25 @@ case OP_Rowid: { /* out2 */
|
|
** Move the cursor P1 to a null row. Any OP_Column operations
|
|
** that occur while the cursor is on the null row will always
|
|
** write a NULL.
|
|
+**
|
|
+** If cursor P1 is not previously opened, open it now to a special
|
|
+** pseudo-cursor that always returns NULL for every column.
|
|
*/
|
|
case OP_NullRow: {
|
|
VdbeCursor *pC;
|
|
|
|
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
|
pC = p->apCsr[pOp->p1];
|
|
- assert( pC!=0 );
|
|
+ if( pC==0 ){
|
|
+ /* If the cursor is not already open, create a special kind of
|
|
+ ** pseudo-cursor that always gives null rows. */
|
|
+ pC = allocateCursor(p, pOp->p1, 1, CURTYPE_PSEUDO);
|
|
+ if( pC==0 ) goto no_mem;
|
|
+ pC->seekResult = 0;
|
|
+ pC->isTable = 1;
|
|
+ pC->noReuse = 1;
|
|
+ pC->uc.pCursor = sqlite3BtreeFakeValidCursor();
|
|
+ }
|
|
pC->nullRow = 1;
|
|
pC->cacheStatus = CACHE_STALE;
|
|
if( pC->eCurType==CURTYPE_BTREE ){
|
|
@@ -90160,7 +96249,7 @@ case OP_NullRow: {
|
|
*/
|
|
/* Opcode: Last P1 P2 * * *
|
|
**
|
|
-** The next use of the Rowid or Column or Prev instruction for P1
|
|
+** The next use of the Rowid or Column or Prev instruction for P1
|
|
** will refer to the last entry in the database table or index.
|
|
** If the table or index is empty and P2>0, then jump immediately to P2.
|
|
** If P2 is 0 or if the table or index is not empty, fall through
|
|
@@ -90170,8 +96259,8 @@ case OP_NullRow: {
|
|
** from the end toward the beginning. In other words, the cursor is
|
|
** configured to use Prev, not Next.
|
|
*/
|
|
-case OP_SeekEnd:
|
|
-case OP_Last: { /* jump */
|
|
+case OP_SeekEnd: /* ncycle */
|
|
+case OP_Last: { /* jump, ncycle */
|
|
VdbeCursor *pC;
|
|
BtCursor *pCrsr;
|
|
int res;
|
|
@@ -90262,26 +96351,32 @@ case OP_Sort: { /* jump */
|
|
#endif
|
|
p->aCounter[SQLITE_STMTSTATUS_SORT]++;
|
|
/* Fall through into OP_Rewind */
|
|
+ /* no break */ deliberate_fall_through
|
|
}
|
|
/* Opcode: Rewind P1 P2 * * *
|
|
**
|
|
-** The next use of the Rowid or Column or Next instruction for P1
|
|
+** The next use of the Rowid or Column or Next instruction for P1
|
|
** will refer to the first entry in the database table or index.
|
|
** If the table or index is empty, jump immediately to P2.
|
|
-** If the table or index is not empty, fall through to the following
|
|
+** If the table or index is not empty, fall through to the following
|
|
** instruction.
|
|
**
|
|
+** If P2 is zero, that is an assertion that the P1 table is never
|
|
+** empty and hence the jump will never be taken.
|
|
+**
|
|
** This opcode leaves the cursor configured to move in forward order,
|
|
** from the beginning toward the end. In other words, the cursor is
|
|
** configured to use Next, not Prev.
|
|
*/
|
|
-case OP_Rewind: { /* jump */
|
|
+case OP_Rewind: { /* jump, ncycle */
|
|
VdbeCursor *pC;
|
|
BtCursor *pCrsr;
|
|
int res;
|
|
|
|
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
|
assert( pOp->p5==0 );
|
|
+ assert( pOp->p2>=0 && pOp->p2<p->nOp );
|
|
+
|
|
pC = p->apCsr[pOp->p1];
|
|
assert( pC!=0 );
|
|
assert( isSorter(pC)==(pOp->opcode==OP_SorterSort) );
|
|
@@ -90301,13 +96396,14 @@ case OP_Rewind: { /* jump */
|
|
}
|
|
if( rc ) goto abort_due_to_error;
|
|
pC->nullRow = (u8)res;
|
|
- assert( pOp->p2>0 && pOp->p2<p->nOp );
|
|
- VdbeBranchTaken(res!=0,2);
|
|
- if( res ) goto jump_to_p2;
|
|
+ if( pOp->p2>0 ){
|
|
+ VdbeBranchTaken(res!=0,2);
|
|
+ if( res ) goto jump_to_p2;
|
|
+ }
|
|
break;
|
|
}
|
|
|
|
-/* Opcode: Next P1 P2 P3 P4 P5
|
|
+/* Opcode: Next P1 P2 P3 * P5
|
|
**
|
|
** Advance cursor P1 so that it points to the next key/data pair in its
|
|
** table or index. If there are no more key/value pairs then fall through
|
|
@@ -90326,15 +96422,12 @@ case OP_Rewind: { /* jump */
|
|
** omitted if that index had been unique. P3 is usually 0. P3 is
|
|
** always either 0 or 1.
|
|
**
|
|
-** P4 is always of type P4_ADVANCE. The function pointer points to
|
|
-** sqlite3BtreeNext().
|
|
-**
|
|
** If P5 is positive and the jump is taken, then event counter
|
|
** number P5-1 in the prepared statement is incremented.
|
|
**
|
|
** See also: Prev
|
|
*/
|
|
-/* Opcode: Prev P1 P2 P3 P4 P5
|
|
+/* Opcode: Prev P1 P2 P3 * P5
|
|
**
|
|
** Back up cursor P1 so that it points to the previous key/data pair in its
|
|
** table or index. If there is no previous key/value pairs then fall through
|
|
@@ -90354,9 +96447,6 @@ case OP_Rewind: { /* jump */
|
|
** omitted if that index had been unique. P3 is usually 0. P3 is
|
|
** always either 0 or 1.
|
|
**
|
|
-** P4 is always of type P4_ADVANCE. The function pointer points to
|
|
-** sqlite3BtreePrevious().
|
|
-**
|
|
** If P5 is positive and the jump is taken, then event counter
|
|
** number P5-1 in the prepared statement is incremented.
|
|
*/
|
|
@@ -90374,30 +96464,37 @@ case OP_SorterNext: { /* jump */
|
|
assert( isSorter(pC) );
|
|
rc = sqlite3VdbeSorterNext(db, pC);
|
|
goto next_tail;
|
|
-case OP_Prev: /* jump */
|
|
-case OP_Next: /* jump */
|
|
+
|
|
+case OP_Prev: /* jump, ncycle */
|
|
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
|
- assert( pOp->p5<ArraySize(p->aCounter) );
|
|
+ assert( pOp->p5==0
|
|
+ || pOp->p5==SQLITE_STMTSTATUS_FULLSCAN_STEP
|
|
+ || pOp->p5==SQLITE_STMTSTATUS_AUTOINDEX);
|
|
pC = p->apCsr[pOp->p1];
|
|
assert( pC!=0 );
|
|
assert( pC->deferredMoveto==0 );
|
|
assert( pC->eCurType==CURTYPE_BTREE );
|
|
- assert( pOp->opcode!=OP_Next || pOp->p4.xAdvance==sqlite3BtreeNext );
|
|
- assert( pOp->opcode!=OP_Prev || pOp->p4.xAdvance==sqlite3BtreePrevious );
|
|
+ assert( pC->seekOp==OP_SeekLT || pC->seekOp==OP_SeekLE
|
|
+ || pC->seekOp==OP_Last || pC->seekOp==OP_IfNoHope
|
|
+ || pC->seekOp==OP_NullRow);
|
|
+ rc = sqlite3BtreePrevious(pC->uc.pCursor, pOp->p3);
|
|
+ goto next_tail;
|
|
|
|
- /* The Next opcode is only used after SeekGT, SeekGE, Rewind, and Found.
|
|
- ** The Prev opcode is only used after SeekLT, SeekLE, and Last. */
|
|
- assert( pOp->opcode!=OP_Next
|
|
- || pC->seekOp==OP_SeekGT || pC->seekOp==OP_SeekGE
|
|
+case OP_Next: /* jump, ncycle */
|
|
+ assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
|
+ assert( pOp->p5==0
|
|
+ || pOp->p5==SQLITE_STMTSTATUS_FULLSCAN_STEP
|
|
+ || pOp->p5==SQLITE_STMTSTATUS_AUTOINDEX);
|
|
+ pC = p->apCsr[pOp->p1];
|
|
+ assert( pC!=0 );
|
|
+ assert( pC->deferredMoveto==0 );
|
|
+ assert( pC->eCurType==CURTYPE_BTREE );
|
|
+ assert( pC->seekOp==OP_SeekGT || pC->seekOp==OP_SeekGE
|
|
|| pC->seekOp==OP_Rewind || pC->seekOp==OP_Found
|
|
|| pC->seekOp==OP_NullRow|| pC->seekOp==OP_SeekRowid
|
|
|| pC->seekOp==OP_IfNoHope);
|
|
- assert( pOp->opcode!=OP_Prev
|
|
- || pC->seekOp==OP_SeekLT || pC->seekOp==OP_SeekLE
|
|
- || pC->seekOp==OP_Last || pC->seekOp==OP_IfNoHope
|
|
- || pC->seekOp==OP_NullRow);
|
|
+ rc = sqlite3BtreeNext(pC->uc.pCursor, pOp->p3);
|
|
|
|
- rc = pOp->p4.xAdvance(pC->uc.pCursor, pOp->p3);
|
|
next_tail:
|
|
pC->cacheStatus = CACHE_STALE;
|
|
VdbeBranchTaken(rc==SQLITE_OK,2);
|
|
@@ -90438,11 +96535,41 @@ case OP_Next: /* jump */
|
|
** run faster by avoiding an unnecessary seek on cursor P1. However,
|
|
** the OPFLAG_USESEEKRESULT flag must only be set if there have been no prior
|
|
** seeks on the cursor or if the most recent seek used a key equivalent
|
|
-** to P2.
|
|
+** to P2.
|
|
**
|
|
** This instruction only works for indices. The equivalent instruction
|
|
** for tables is OP_Insert.
|
|
*/
|
|
+case OP_IdxInsert: { /* in2 */
|
|
+ VdbeCursor *pC;
|
|
+ BtreePayload x;
|
|
+
|
|
+ assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
|
+ pC = p->apCsr[pOp->p1];
|
|
+ sqlite3VdbeIncrWriteCounter(p, pC);
|
|
+ assert( pC!=0 );
|
|
+ assert( !isSorter(pC) );
|
|
+ pIn2 = &aMem[pOp->p2];
|
|
+ assert( (pIn2->flags & MEM_Blob) || (pOp->p5 & OPFLAG_PREFORMAT) );
|
|
+ if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
|
|
+ assert( pC->eCurType==CURTYPE_BTREE );
|
|
+ assert( pC->isTable==0 );
|
|
+ rc = ExpandBlob(pIn2);
|
|
+ if( rc ) goto abort_due_to_error;
|
|
+ x.nKey = pIn2->n;
|
|
+ x.pKey = pIn2->z;
|
|
+ x.aMem = aMem + pOp->p3;
|
|
+ x.nMem = (u16)pOp->p4.i;
|
|
+ rc = sqlite3BtreeInsert(pC->uc.pCursor, &x,
|
|
+ (pOp->p5 & (OPFLAG_APPEND|OPFLAG_SAVEPOSITION|OPFLAG_PREFORMAT)),
|
|
+ ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0)
|
|
+ );
|
|
+ assert( pC->deferredMoveto==0 );
|
|
+ pC->cacheStatus = CACHE_STALE;
|
|
+ if( rc) goto abort_due_to_error;
|
|
+ break;
|
|
+}
|
|
+
|
|
/* Opcode: SorterInsert P1 P2 * * *
|
|
** Synopsis: key=r[P2]
|
|
**
|
|
@@ -90450,47 +96577,38 @@ case OP_Next: /* jump */
|
|
** MakeRecord instructions. This opcode writes that key
|
|
** into the sorter P1. Data for the entry is nil.
|
|
*/
|
|
-case OP_SorterInsert: /* in2 */
|
|
-case OP_IdxInsert: { /* in2 */
|
|
+case OP_SorterInsert: { /* in2 */
|
|
VdbeCursor *pC;
|
|
- BtreePayload x;
|
|
|
|
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
|
pC = p->apCsr[pOp->p1];
|
|
sqlite3VdbeIncrWriteCounter(p, pC);
|
|
assert( pC!=0 );
|
|
- assert( isSorter(pC)==(pOp->opcode==OP_SorterInsert) );
|
|
+ assert( isSorter(pC) );
|
|
pIn2 = &aMem[pOp->p2];
|
|
assert( pIn2->flags & MEM_Blob );
|
|
- if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++;
|
|
- assert( pC->eCurType==CURTYPE_BTREE || pOp->opcode==OP_SorterInsert );
|
|
assert( pC->isTable==0 );
|
|
rc = ExpandBlob(pIn2);
|
|
if( rc ) goto abort_due_to_error;
|
|
- if( pOp->opcode==OP_SorterInsert ){
|
|
- rc = sqlite3VdbeSorterWrite(pC, pIn2);
|
|
- }else{
|
|
- x.nKey = pIn2->n;
|
|
- x.pKey = pIn2->z;
|
|
- x.aMem = aMem + pOp->p3;
|
|
- x.nMem = (u16)pOp->p4.i;
|
|
- rc = sqlite3BtreeInsert(pC->uc.pCursor, &x,
|
|
- (pOp->p5 & (OPFLAG_APPEND|OPFLAG_SAVEPOSITION)),
|
|
- ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0)
|
|
- );
|
|
- assert( pC->deferredMoveto==0 );
|
|
- pC->cacheStatus = CACHE_STALE;
|
|
- }
|
|
+ rc = sqlite3VdbeSorterWrite(pC, pIn2);
|
|
if( rc) goto abort_due_to_error;
|
|
break;
|
|
}
|
|
|
|
-/* Opcode: IdxDelete P1 P2 P3 * *
|
|
+/* Opcode: IdxDelete P1 P2 P3 * P5
|
|
** Synopsis: key=r[P2@P3]
|
|
**
|
|
** The content of P3 registers starting at register P2 form
|
|
-** an unpacked index key. This opcode removes that entry from the
|
|
+** an unpacked index key. This opcode removes that entry from the
|
|
** index opened by cursor P1.
|
|
+**
|
|
+** If P5 is not zero, then raise an SQLITE_CORRUPT_INDEX error
|
|
+** if no matching index entry is found. This happens when running
|
|
+** an UPDATE or DELETE statement and the index entry to be updated
|
|
+** or deleted is not found. For some uses of IdxDelete
|
|
+** (example: the EXCEPT operator) it does not matter that no matching
|
|
+** entry is found. For those cases, P5 is zero. Also, do not raise
|
|
+** this (self-correcting and non-critical) error if in writable_schema mode.
|
|
*/
|
|
case OP_IdxDelete: {
|
|
VdbeCursor *pC;
|
|
@@ -90507,16 +96625,18 @@ case OP_IdxDelete: {
|
|
sqlite3VdbeIncrWriteCounter(p, pC);
|
|
pCrsr = pC->uc.pCursor;
|
|
assert( pCrsr!=0 );
|
|
- assert( pOp->p5==0 );
|
|
r.pKeyInfo = pC->pKeyInfo;
|
|
r.nField = (u16)pOp->p3;
|
|
r.default_rc = 0;
|
|
r.aMem = &aMem[pOp->p2];
|
|
- rc = sqlite3BtreeMovetoUnpacked(pCrsr, &r, 0, 0, &res);
|
|
+ rc = sqlite3BtreeIndexMoveto(pCrsr, &r, &res);
|
|
if( rc ) goto abort_due_to_error;
|
|
if( res==0 ){
|
|
rc = sqlite3BtreeDelete(pCrsr, BTREE_AUXDELETE);
|
|
if( rc ) goto abort_due_to_error;
|
|
+ }else if( pOp->p5 && !sqlite3WritableSchema(db) ){
|
|
+ rc = sqlite3ReportError(SQLITE_CORRUPT_INDEX, __LINE__, "index corruption");
|
|
+ goto abort_due_to_error;
|
|
}
|
|
assert( pC->deferredMoveto==0 );
|
|
pC->cacheStatus = CACHE_STALE;
|
|
@@ -90537,8 +96657,8 @@ case OP_IdxDelete: {
|
|
**
|
|
** P4 may be an array of integers (type P4_INTARRAY) containing
|
|
** one entry for each column in the P3 table. If array entry a(i)
|
|
-** is non-zero, then reading column a(i)-1 from cursor P3 is
|
|
-** equivalent to performing the deferred seek and then reading column i
|
|
+** is non-zero, then reading column a(i)-1 from cursor P3 is
|
|
+** equivalent to performing the deferred seek and then reading column i
|
|
** from P1. This information is stored in P3 and used to redirect
|
|
** reads against P3 over to P1, thus possibly avoiding the need to
|
|
** seek and read cursor P3.
|
|
@@ -90552,8 +96672,8 @@ case OP_IdxDelete: {
|
|
**
|
|
** See also: Rowid, MakeRecord.
|
|
*/
|
|
-case OP_DeferredSeek:
|
|
-case OP_IdxRowid: { /* out2 */
|
|
+case OP_DeferredSeek: /* ncycle */
|
|
+case OP_IdxRowid: { /* out2, ncycle */
|
|
VdbeCursor *pC; /* The P1 index cursor */
|
|
VdbeCursor *pTabCur; /* The P2 table cursor (OP_DeferredSeek only) */
|
|
i64 rowid; /* Rowid that P1 current points to */
|
|
@@ -90561,9 +96681,9 @@ case OP_IdxRowid: { /* out2 */
|
|
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
|
pC = p->apCsr[pOp->p1];
|
|
assert( pC!=0 );
|
|
- assert( pC->eCurType==CURTYPE_BTREE );
|
|
+ assert( pC->eCurType==CURTYPE_BTREE || IsNullCursor(pC) );
|
|
assert( pC->uc.pCursor!=0 );
|
|
- assert( pC->isTable==0 );
|
|
+ assert( pC->isTable==0 || IsNullCursor(pC) );
|
|
assert( pC->deferredMoveto==0 );
|
|
assert( !pC->nullRow || pOp->opcode==OP_IdxRowid );
|
|
|
|
@@ -90571,10 +96691,10 @@ case OP_IdxRowid: { /* out2 */
|
|
** of sqlite3VdbeCursorRestore() and sqlite3VdbeIdxRowid(). */
|
|
rc = sqlite3VdbeCursorRestore(pC);
|
|
|
|
- /* sqlite3VbeCursorRestore() can only fail if the record has been deleted
|
|
- ** out from under the cursor. That will never happens for an IdxRowid
|
|
- ** or Seek opcode */
|
|
- if( NEVER(rc!=SQLITE_OK) ) goto abort_due_to_error;
|
|
+ /* sqlite3VdbeCursorRestore() may fail if the cursor has been disturbed
|
|
+ ** since it was last positioned and an error (e.g. OOM or an IO error)
|
|
+ ** occurs while trying to reposition it. */
|
|
+ if( rc!=SQLITE_OK ) goto abort_due_to_error;
|
|
|
|
if( !pC->nullRow ){
|
|
rowid = 0; /* Not needed. Only used to silence a warning. */
|
|
@@ -90592,8 +96712,11 @@ case OP_IdxRowid: { /* out2 */
|
|
pTabCur->nullRow = 0;
|
|
pTabCur->movetoTarget = rowid;
|
|
pTabCur->deferredMoveto = 1;
|
|
+ pTabCur->cacheStatus = CACHE_STALE;
|
|
assert( pOp->p4type==P4_INTARRAY || pOp->p4.ai==0 );
|
|
- pTabCur->aAltMap = pOp->p4.ai;
|
|
+ assert( !pTabCur->isEphemeral );
|
|
+ pTabCur->ub.aAltMap = pOp->p4.ai;
|
|
+ assert( !pC->isEphemeral );
|
|
pTabCur->pAltCursor = pC;
|
|
}else{
|
|
pOut = out2Prerelease(p, pOp);
|
|
@@ -90607,13 +96730,13 @@ case OP_IdxRowid: { /* out2 */
|
|
}
|
|
|
|
/* Opcode: FinishSeek P1 * * * *
|
|
-**
|
|
+**
|
|
** If cursor P1 was previously moved via OP_DeferredSeek, complete that
|
|
** seek operation now, without further delay. If the cursor seek has
|
|
** already occurred, this instruction is a no-op.
|
|
*/
|
|
-case OP_FinishSeek: {
|
|
- VdbeCursor *pC; /* The P1 index cursor */
|
|
+case OP_FinishSeek: { /* ncycle */
|
|
+ VdbeCursor *pC; /* The P1 index cursor */
|
|
|
|
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
|
pC = p->apCsr[pOp->p1];
|
|
@@ -90624,32 +96747,32 @@ case OP_FinishSeek: {
|
|
break;
|
|
}
|
|
|
|
-/* Opcode: IdxGE P1 P2 P3 P4 P5
|
|
+/* Opcode: IdxGE P1 P2 P3 P4 *
|
|
** Synopsis: key=r[P3@P4]
|
|
**
|
|
-** The P4 register values beginning with P3 form an unpacked index
|
|
-** key that omits the PRIMARY KEY. Compare this key value against the index
|
|
-** that P1 is currently pointing to, ignoring the PRIMARY KEY or ROWID
|
|
+** The P4 register values beginning with P3 form an unpacked index
|
|
+** key that omits the PRIMARY KEY. Compare this key value against the index
|
|
+** that P1 is currently pointing to, ignoring the PRIMARY KEY or ROWID
|
|
** fields at the end.
|
|
**
|
|
** If the P1 index entry is greater than or equal to the key value
|
|
** then jump to P2. Otherwise fall through to the next instruction.
|
|
*/
|
|
-/* Opcode: IdxGT P1 P2 P3 P4 P5
|
|
+/* Opcode: IdxGT P1 P2 P3 P4 *
|
|
** Synopsis: key=r[P3@P4]
|
|
**
|
|
-** The P4 register values beginning with P3 form an unpacked index
|
|
-** key that omits the PRIMARY KEY. Compare this key value against the index
|
|
-** that P1 is currently pointing to, ignoring the PRIMARY KEY or ROWID
|
|
+** The P4 register values beginning with P3 form an unpacked index
|
|
+** key that omits the PRIMARY KEY. Compare this key value against the index
|
|
+** that P1 is currently pointing to, ignoring the PRIMARY KEY or ROWID
|
|
** fields at the end.
|
|
**
|
|
** If the P1 index entry is greater than the key value
|
|
** then jump to P2. Otherwise fall through to the next instruction.
|
|
*/
|
|
-/* Opcode: IdxLT P1 P2 P3 P4 P5
|
|
+/* Opcode: IdxLT P1 P2 P3 P4 *
|
|
** Synopsis: key=r[P3@P4]
|
|
**
|
|
-** The P4 register values beginning with P3 form an unpacked index
|
|
+** The P4 register values beginning with P3 form an unpacked index
|
|
** key that omits the PRIMARY KEY or ROWID. Compare this key value against
|
|
** the index that P1 is currently pointing to, ignoring the PRIMARY KEY or
|
|
** ROWID on the P1 index.
|
|
@@ -90657,10 +96780,10 @@ case OP_FinishSeek: {
|
|
** If the P1 index entry is less than the key value then jump to P2.
|
|
** Otherwise fall through to the next instruction.
|
|
*/
|
|
-/* Opcode: IdxLE P1 P2 P3 P4 P5
|
|
+/* Opcode: IdxLE P1 P2 P3 P4 *
|
|
** Synopsis: key=r[P3@P4]
|
|
**
|
|
-** The P4 register values beginning with P3 form an unpacked index
|
|
+** The P4 register values beginning with P3 form an unpacked index
|
|
** key that omits the PRIMARY KEY or ROWID. Compare this key value against
|
|
** the index that P1 is currently pointing to, ignoring the PRIMARY KEY or
|
|
** ROWID on the P1 index.
|
|
@@ -90668,10 +96791,10 @@ case OP_FinishSeek: {
|
|
** If the P1 index entry is less than or equal to the key value then jump
|
|
** to P2. Otherwise fall through to the next instruction.
|
|
*/
|
|
-case OP_IdxLE: /* jump */
|
|
-case OP_IdxGT: /* jump */
|
|
-case OP_IdxLT: /* jump */
|
|
-case OP_IdxGE: { /* jump */
|
|
+case OP_IdxLE: /* jump, ncycle */
|
|
+case OP_IdxGT: /* jump, ncycle */
|
|
+case OP_IdxLT: /* jump, ncycle */
|
|
+case OP_IdxGE: { /* jump, ncycle */
|
|
VdbeCursor *pC;
|
|
int res;
|
|
UnpackedRecord r;
|
|
@@ -90683,7 +96806,6 @@ case OP_IdxGE: { /* jump */
|
|
assert( pC->eCurType==CURTYPE_BTREE );
|
|
assert( pC->uc.pCursor!=0);
|
|
assert( pC->deferredMoveto==0 );
|
|
- assert( pOp->p5==0 || pOp->p5==1 );
|
|
assert( pOp->p4type==P4_INT32 );
|
|
r.pKeyInfo = pC->pKeyInfo;
|
|
r.nField = (u16)pOp->p4.i;
|
|
@@ -90704,8 +96826,31 @@ case OP_IdxGE: { /* jump */
|
|
}
|
|
}
|
|
#endif
|
|
- res = 0; /* Not needed. Only used to silence a warning. */
|
|
- rc = sqlite3VdbeIdxKeyCompare(db, pC, &r, &res);
|
|
+
|
|
+ /* Inlined version of sqlite3VdbeIdxKeyCompare() */
|
|
+ {
|
|
+ i64 nCellKey = 0;
|
|
+ BtCursor *pCur;
|
|
+ Mem m;
|
|
+
|
|
+ assert( pC->eCurType==CURTYPE_BTREE );
|
|
+ pCur = pC->uc.pCursor;
|
|
+ assert( sqlite3BtreeCursorIsValid(pCur) );
|
|
+ nCellKey = sqlite3BtreePayloadSize(pCur);
|
|
+ /* nCellKey will always be between 0 and 0xffffffff because of the way
|
|
+ ** that btreeParseCellPtr() and sqlite3GetVarint32() are implemented */
|
|
+ if( nCellKey<=0 || nCellKey>0x7fffffff ){
|
|
+ rc = SQLITE_CORRUPT_BKPT;
|
|
+ goto abort_due_to_error;
|
|
+ }
|
|
+ sqlite3VdbeMemInit(&m, db, 0);
|
|
+ rc = sqlite3VdbeMemFromBtreeZeroOffset(pCur, (u32)nCellKey, &m);
|
|
+ if( rc ) goto abort_due_to_error;
|
|
+ res = sqlite3VdbeRecordCompareWithSkip(m.n, m.z, &r, 0);
|
|
+ sqlite3VdbeMemReleaseMalloc(&m);
|
|
+ }
|
|
+ /* End of inlined sqlite3VdbeIdxKeyCompare() */
|
|
+
|
|
assert( (OP_IdxLE&1)==(OP_IdxLT&1) && (OP_IdxGE&1)==(OP_IdxGT&1) );
|
|
if( (pOp->opcode&1)==(OP_IdxLT&1) ){
|
|
assert( pOp->opcode==OP_IdxLE || pOp->opcode==OP_IdxLT );
|
|
@@ -90715,7 +96860,7 @@ case OP_IdxGE: { /* jump */
|
|
res++;
|
|
}
|
|
VdbeBranchTaken(res>0,2);
|
|
- if( rc ) goto abort_due_to_error;
|
|
+ assert( rc==SQLITE_OK );
|
|
if( res>0 ) goto jump_to_p2;
|
|
break;
|
|
}
|
|
@@ -90734,15 +96879,15 @@ case OP_IdxGE: { /* jump */
|
|
** root pages contiguous at the beginning of the database. The former
|
|
** value of the root page that moved - its value before the move occurred -
|
|
** is stored in register P2. If no page movement was required (because the
|
|
-** table being dropped was already the last one in the database) then a
|
|
-** zero is stored in register P2. If AUTOVACUUM is disabled then a zero
|
|
+** table being dropped was already the last one in the database) then a
|
|
+** zero is stored in register P2. If AUTOVACUUM is disabled then a zero
|
|
** is stored in register P2.
|
|
**
|
|
** This opcode throws an error if there are any active reader VMs when
|
|
-** it is invoked. This is done to avoid the difficulty associated with
|
|
-** updating existing cursors when a root page is moved in an AUTOVACUUM
|
|
-** database. This error is thrown even if the database is not an AUTOVACUUM
|
|
-** db in order to avoid introducing an incompatibility between autovacuum
|
|
+** it is invoked. This is done to avoid the difficulty associated with
|
|
+** updating existing cursors when a root page is moved in an AUTOVACUUM
|
|
+** database. This error is thrown even if the database is not an AUTOVACUUM
|
|
+** db in order to avoid introducing an incompatibility between autovacuum
|
|
** and non-autovacuum modes.
|
|
**
|
|
** See also: Clear
|
|
@@ -90790,24 +96935,21 @@ case OP_Destroy: { /* out2 */
|
|
** P2==1 then the table to be clear is in the auxiliary database file
|
|
** that is used to store tables create using CREATE TEMPORARY TABLE.
|
|
**
|
|
-** If the P3 value is non-zero, then the table referred to must be an
|
|
-** intkey table (an SQL table, not an index). In this case the row change
|
|
-** count is incremented by the number of rows in the table being cleared.
|
|
-** If P3 is greater than zero, then the value stored in register P3 is
|
|
-** also incremented by the number of rows in the table being cleared.
|
|
+** If the P3 value is non-zero, then the row change count is incremented
|
|
+** by the number of rows in the table being cleared. If P3 is greater
|
|
+** than zero, then the value stored in register P3 is also incremented
|
|
+** by the number of rows in the table being cleared.
|
|
**
|
|
** See also: Destroy
|
|
*/
|
|
case OP_Clear: {
|
|
- int nChange;
|
|
-
|
|
+ i64 nChange;
|
|
+
|
|
sqlite3VdbeIncrWriteCounter(p, 0);
|
|
nChange = 0;
|
|
assert( p->readOnly==0 );
|
|
assert( DbMaskTest(p->btreeMask, pOp->p2) );
|
|
- rc = sqlite3BtreeClearTable(
|
|
- db->aDb[pOp->p2].pBt, pOp->p1, (pOp->p3 ? &nChange : 0)
|
|
- );
|
|
+ rc = sqlite3BtreeClearTable(db->aDb[pOp->p2].pBt, (u32)pOp->p1, &nChange);
|
|
if( pOp->p3 ){
|
|
p->nChange += nChange;
|
|
if( pOp->p3>0 ){
|
|
@@ -90830,7 +96972,7 @@ case OP_Clear: {
|
|
*/
|
|
case OP_ResetSorter: {
|
|
VdbeCursor *pC;
|
|
-
|
|
+
|
|
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
|
pC = p->apCsr[pOp->p1];
|
|
assert( pC!=0 );
|
|
@@ -90855,7 +96997,7 @@ case OP_ResetSorter: {
|
|
** The root page number of the new b-tree is stored in register P2.
|
|
*/
|
|
case OP_CreateBtree: { /* out2 */
|
|
- int pgno;
|
|
+ Pgno pgno;
|
|
Db *pDb;
|
|
|
|
sqlite3VdbeIncrWriteCounter(p, 0);
|
|
@@ -90888,7 +97030,7 @@ case OP_SqlExec: {
|
|
|
|
/* Opcode: ParseSchema P1 * * P4 *
|
|
**
|
|
-** Read and parse all entries from the SQLITE_MASTER table of database P1
|
|
+** Read and parse all entries from the schema table of database P1
|
|
** that match the WHERE clause P4. If P4 is a NULL pointer, then the
|
|
** entire schema for P1 is reparsed.
|
|
**
|
|
@@ -90897,12 +97039,12 @@ case OP_SqlExec: {
|
|
*/
|
|
case OP_ParseSchema: {
|
|
int iDb;
|
|
- const char *zMaster;
|
|
+ const char *zSchema;
|
|
char *zSql;
|
|
InitData initData;
|
|
|
|
/* Any prepared statement that invokes this opcode will hold mutexes
|
|
- ** on every btree. This is a prerequisite for invoking
|
|
+ ** on every btree. This is a prerequisite for invoking
|
|
** sqlite3InitCallback().
|
|
*/
|
|
#ifdef SQLITE_DEBUG
|
|
@@ -90913,26 +97055,29 @@ case OP_ParseSchema: {
|
|
|
|
iDb = pOp->p1;
|
|
assert( iDb>=0 && iDb<db->nDb );
|
|
- assert( DbHasProperty(db, iDb, DB_SchemaLoaded) );
|
|
+ assert( DbHasProperty(db, iDb, DB_SchemaLoaded)
|
|
+ || db->mallocFailed
|
|
+ || (CORRUPT_DB && (db->flags & SQLITE_NoSchemaError)!=0) );
|
|
|
|
#ifndef SQLITE_OMIT_ALTERTABLE
|
|
if( pOp->p4.z==0 ){
|
|
sqlite3SchemaClear(db->aDb[iDb].pSchema);
|
|
db->mDbFlags &= ~DBFLAG_SchemaKnownOk;
|
|
- rc = sqlite3InitOne(db, iDb, &p->zErrMsg, INITFLAG_AlterTable);
|
|
+ rc = sqlite3InitOne(db, iDb, &p->zErrMsg, pOp->p5);
|
|
db->mDbFlags |= DBFLAG_SchemaChange;
|
|
p->expired = 0;
|
|
}else
|
|
#endif
|
|
{
|
|
- zMaster = MASTER_NAME;
|
|
+ zSchema = LEGACY_SCHEMA_TABLE;
|
|
initData.db = db;
|
|
initData.iDb = iDb;
|
|
initData.pzErrMsg = &p->zErrMsg;
|
|
initData.mInitFlags = 0;
|
|
+ initData.mxPage = sqlite3BtreeLastPage(db->aDb[iDb].pBt);
|
|
zSql = sqlite3MPrintf(db,
|
|
"SELECT*FROM\"%w\".%s WHERE %s ORDER BY rowid",
|
|
- db->aDb[iDb].zDbSName, zMaster, pOp->p4.z);
|
|
+ db->aDb[iDb].zDbSName, zSchema, pOp->p4.z);
|
|
if( zSql==0 ){
|
|
rc = SQLITE_NOMEM_BKPT;
|
|
}else{
|
|
@@ -90946,7 +97091,7 @@ case OP_ParseSchema: {
|
|
if( rc==SQLITE_OK && initData.nInitRow==0 ){
|
|
/* The OP_ParseSchema opcode with a non-NULL P4 argument should parse
|
|
** at least one SQL statement. Any less than that indicates that
|
|
- ** the sqlite_master table is corrupt. */
|
|
+ ** the sqlite_schema table is corrupt. */
|
|
rc = SQLITE_CORRUPT_BKPT;
|
|
}
|
|
sqlite3DbFreeNN(db, zSql);
|
|
@@ -90960,7 +97105,7 @@ case OP_ParseSchema: {
|
|
}
|
|
goto abort_due_to_error;
|
|
}
|
|
- break;
|
|
+ break;
|
|
}
|
|
|
|
#if !defined(SQLITE_OMIT_ANALYZE)
|
|
@@ -90974,7 +97119,7 @@ case OP_LoadAnalysis: {
|
|
assert( pOp->p1>=0 && pOp->p1<db->nDb );
|
|
rc = sqlite3AnalysisLoad(db, pOp->p1);
|
|
if( rc ) goto abort_due_to_error;
|
|
- break;
|
|
+ break;
|
|
}
|
|
#endif /* !defined(SQLITE_OMIT_ANALYZE) */
|
|
|
|
@@ -90982,7 +97127,7 @@ case OP_LoadAnalysis: {
|
|
**
|
|
** Remove the internal (in-memory) data structures that describe
|
|
** the table named P4 in database P1. This is called after a table
|
|
-** is dropped from disk (using the Destroy opcode) in order to keep
|
|
+** is dropped from disk (using the Destroy opcode) in order to keep
|
|
** the internal representation of the
|
|
** schema consistent with what is on disk.
|
|
*/
|
|
@@ -91010,7 +97155,7 @@ case OP_DropIndex: {
|
|
**
|
|
** Remove the internal (in-memory) data structures that describe
|
|
** the trigger named P4 in database P1. This is called after a trigger
|
|
-** is dropped from disk (using the Destroy opcode) in order to keep
|
|
+** is dropped from disk (using the Destroy opcode) in order to keep
|
|
** the internal representation of the
|
|
** schema consistent with what is on disk.
|
|
*/
|
|
@@ -91030,7 +97175,7 @@ case OP_DropTrigger: {
|
|
**
|
|
** The register P3 contains one less than the maximum number of allowed errors.
|
|
** At most reg(P3) errors will be reported.
|
|
-** In other words, the analysis stops as soon as reg(P1) errors are
|
|
+** In other words, the analysis stops as soon as reg(P1) errors are
|
|
** seen. Reg(P1) is updated with the number of errors remaining.
|
|
**
|
|
** The root page numbers of all tables in the database are integers
|
|
@@ -91043,7 +97188,7 @@ case OP_DropTrigger: {
|
|
*/
|
|
case OP_IntegrityCk: {
|
|
int nRoot; /* Number of tables to check. (Number of root pages.) */
|
|
- int *aRoot; /* Array of rootpage numbers for tables to be checked */
|
|
+ Pgno *aRoot; /* Array of rootpage numbers for tables to be checked */
|
|
int nErr; /* Number of errors reported */
|
|
char *z; /* Text of the error report */
|
|
Mem *pnErr; /* Register keeping track of errors remaining */
|
|
@@ -91052,7 +97197,7 @@ case OP_IntegrityCk: {
|
|
nRoot = pOp->p2;
|
|
aRoot = pOp->p4.ai;
|
|
assert( nRoot>0 );
|
|
- assert( aRoot[0]==nRoot );
|
|
+ assert( aRoot[0]==(Pgno)nRoot );
|
|
assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
|
|
pnErr = &aMem[pOp->p3];
|
|
assert( (pnErr->flags & MEM_Int)!=0 );
|
|
@@ -91060,13 +97205,14 @@ case OP_IntegrityCk: {
|
|
pIn1 = &aMem[pOp->p1];
|
|
assert( pOp->p5<db->nDb );
|
|
assert( DbMaskTest(p->btreeMask, pOp->p5) );
|
|
- z = sqlite3BtreeIntegrityCheck(db, db->aDb[pOp->p5].pBt, &aRoot[1], nRoot,
|
|
- (int)pnErr->u.i+1, &nErr);
|
|
+ rc = sqlite3BtreeIntegrityCheck(db, db->aDb[pOp->p5].pBt, &aRoot[1], nRoot,
|
|
+ (int)pnErr->u.i+1, &nErr, &z);
|
|
sqlite3VdbeMemSetNull(pIn1);
|
|
if( nErr==0 ){
|
|
assert( z==0 );
|
|
- }else if( z==0 ){
|
|
- goto no_mem;
|
|
+ }else if( rc ){
|
|
+ sqlite3_free(z);
|
|
+ goto abort_due_to_error;
|
|
}else{
|
|
pnErr->u.i -= nErr-1;
|
|
sqlite3VdbeMemSetStr(pIn1, z, -1, SQLITE_UTF8, sqlite3_free);
|
|
@@ -91110,7 +97256,7 @@ case OP_RowSetRead: { /* jump, in1, out3 */
|
|
|
|
pIn1 = &aMem[pOp->p1];
|
|
assert( (pIn1->flags & MEM_Blob)==0 || sqlite3VdbeMemIsRowSet(pIn1) );
|
|
- if( (pIn1->flags & MEM_Blob)==0
|
|
+ if( (pIn1->flags & MEM_Blob)==0
|
|
|| sqlite3RowSetNext((RowSet*)pIn1->z, &val)==0
|
|
){
|
|
/* The boolean index is empty */
|
|
@@ -91182,13 +97328,13 @@ case OP_RowSetTest: { /* jump, in1, in3 */
|
|
|
|
/* Opcode: Program P1 P2 P3 P4 P5
|
|
**
|
|
-** Execute the trigger program passed as P4 (type P4_SUBPROGRAM).
|
|
+** Execute the trigger program passed as P4 (type P4_SUBPROGRAM).
|
|
**
|
|
-** P1 contains the address of the memory cell that contains the first memory
|
|
-** cell in an array of values used as arguments to the sub-program. P2
|
|
-** contains the address to jump to if the sub-program throws an IGNORE
|
|
-** exception using the RAISE() function. Register P3 contains the address
|
|
-** of a memory cell in this (the parent) VM that is used to allocate the
|
|
+** P1 contains the address of the memory cell that contains the first memory
|
|
+** cell in an array of values used as arguments to the sub-program. P2
|
|
+** contains the address to jump to if the sub-program throws an IGNORE
|
|
+** exception using the RAISE() function. Register P3 contains the address
|
|
+** of a memory cell in this (the parent) VM that is used to allocate the
|
|
** memory required by the sub-vdbe at runtime.
|
|
**
|
|
** P4 is a pointer to the VM containing the trigger program.
|
|
@@ -91208,17 +97354,17 @@ case OP_Program: { /* jump */
|
|
pProgram = pOp->p4.pProgram;
|
|
pRt = &aMem[pOp->p3];
|
|
assert( pProgram->nOp>0 );
|
|
-
|
|
- /* If the p5 flag is clear, then recursive invocation of triggers is
|
|
+
|
|
+ /* If the p5 flag is clear, then recursive invocation of triggers is
|
|
** disabled for backwards compatibility (p5 is set if this sub-program
|
|
** is really a trigger, not a foreign key action, and the flag set
|
|
** and cleared by the "PRAGMA recursive_triggers" command is clear).
|
|
- **
|
|
- ** It is recursive invocation of triggers, at the SQL level, that is
|
|
- ** disabled. In some cases a single trigger may generate more than one
|
|
- ** SubProgram (if the trigger may be executed with more than one different
|
|
+ **
|
|
+ ** It is recursive invocation of triggers, at the SQL level, that is
|
|
+ ** disabled. In some cases a single trigger may generate more than one
|
|
+ ** SubProgram (if the trigger may be executed with more than one different
|
|
** ON CONFLICT algorithm). SubProgram structures associated with a
|
|
- ** single trigger all have the same value for the SubProgram.token
|
|
+ ** single trigger all have the same value for the SubProgram.token
|
|
** variable. */
|
|
if( pOp->p5 ){
|
|
t = pProgram->token;
|
|
@@ -91234,10 +97380,10 @@ case OP_Program: { /* jump */
|
|
|
|
/* Register pRt is used to store the memory required to save the state
|
|
** of the current program, and the memory required at runtime to execute
|
|
- ** the trigger program. If this trigger has been fired before, then pRt
|
|
+ ** the trigger program. If this trigger has been fired before, then pRt
|
|
** is already allocated. Otherwise, it must be initialized. */
|
|
if( (pRt->flags&MEM_Blob)==0 ){
|
|
- /* SubProgram.nMem is set to the number of memory cells used by the
|
|
+ /* SubProgram.nMem is set to the number of memory cells used by the
|
|
** program stored in SubProgram.aOp. As well as these, one memory
|
|
** cell is required for each cursor used by the program. Set local
|
|
** variable nMem (and later, VdbeFrame.nChildMem) to this value.
|
|
@@ -91270,9 +97416,6 @@ case OP_Program: { /* jump */
|
|
pFrame->aOp = p->aOp;
|
|
pFrame->nOp = p->nOp;
|
|
pFrame->token = pProgram->token;
|
|
-#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
|
|
- pFrame->anExec = p->anExec;
|
|
-#endif
|
|
#ifdef SQLITE_DEBUG
|
|
pFrame->iFrameMagic = SQLITE_FRAME_MAGIC;
|
|
#endif
|
|
@@ -91285,7 +97428,7 @@ case OP_Program: { /* jump */
|
|
}else{
|
|
pFrame = (VdbeFrame*)pRt->z;
|
|
assert( pRt->xDel==sqlite3VdbeFrameMemDel );
|
|
- assert( pProgram->nMem+pProgram->nCsr==pFrame->nChildMem
|
|
+ assert( pProgram->nMem+pProgram->nCsr==pFrame->nChildMem
|
|
|| (pProgram->nCsr==0 && pProgram->nMem+1==pFrame->nChildMem) );
|
|
assert( pProgram->nCsr==pFrame->nChildCsr );
|
|
assert( (int)(pOp - aOp)==pFrame->pc );
|
|
@@ -91309,9 +97452,6 @@ case OP_Program: { /* jump */
|
|
memset(pFrame->aOnce, 0, (pProgram->nOp + 7)/8);
|
|
p->aOp = aOp = pProgram->aOp;
|
|
p->nOp = pProgram->nOp;
|
|
-#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
|
|
- p->anExec = 0;
|
|
-#endif
|
|
#ifdef SQLITE_DEBUG
|
|
/* Verify that second and subsequent executions of the same trigger do not
|
|
** try to reuse register values from the first use. */
|
|
@@ -91319,7 +97459,7 @@ case OP_Program: { /* jump */
|
|
int i;
|
|
for(i=0; i<p->nMem; i++){
|
|
aMem[i].pScopyFrom = 0; /* Prevent false-positive AboutToChange() errs */
|
|
- aMem[i].flags |= MEM_Undefined; /* Cause a fault if this reg is reused */
|
|
+ MemSetTypeFlag(&aMem[i], MEM_Undefined); /* Fault if this reg is reused */
|
|
}
|
|
}
|
|
#endif
|
|
@@ -91329,10 +97469,10 @@ case OP_Program: { /* jump */
|
|
|
|
/* Opcode: Param P1 P2 * * *
|
|
**
|
|
-** This opcode is only ever present in sub-programs called via the
|
|
-** OP_Program instruction. Copy a value currently stored in a memory
|
|
-** cell of the calling (parent) frame to cell P2 in the current frames
|
|
-** address space. This is used by trigger programs to access the new.*
|
|
+** This opcode is only ever present in sub-programs called via the
|
|
+** OP_Program instruction. Copy a value currently stored in a memory
|
|
+** cell of the calling (parent) frame to cell P2 in the current frames
|
|
+** address space. This is used by trigger programs to access the new.*
|
|
** and old.* values.
|
|
**
|
|
** The address of the cell in the parent frame is determined by adding
|
|
@@ -91344,7 +97484,7 @@ case OP_Param: { /* out2 */
|
|
Mem *pIn;
|
|
pOut = out2Prerelease(p, pOp);
|
|
pFrame = p->pFrame;
|
|
- pIn = &pFrame->aMem[pOp->p1 + pFrame->aOp[pFrame->pc].p1];
|
|
+ pIn = &pFrame->aMem[pOp->p1 + pFrame->aOp[pFrame->pc].p1];
|
|
sqlite3VdbeMemShallowCopy(pOut, pIn, MEM_Ephem);
|
|
break;
|
|
}
|
|
@@ -91356,8 +97496,8 @@ case OP_Param: { /* out2 */
|
|
** Synopsis: fkctr[P1]+=P2
|
|
**
|
|
** Increment a "constraint counter" by P2 (P2 may be negative or positive).
|
|
-** If P1 is non-zero, the database constraint counter is incremented
|
|
-** (deferred foreign key constraints). Otherwise, if P1 is zero, the
|
|
+** If P1 is non-zero, the database constraint counter is incremented
|
|
+** (deferred foreign key constraints). Otherwise, if P1 is zero, the
|
|
** statement counter is incremented (immediate foreign key constraints).
|
|
*/
|
|
case OP_FkCounter: {
|
|
@@ -91375,7 +97515,7 @@ case OP_FkCounter: {
|
|
** Synopsis: if fkctr[P1]==0 goto P2
|
|
**
|
|
** This opcode tests if a foreign key constraint-counter is currently zero.
|
|
-** If so, jump to instruction P2. Otherwise, fall through to the next
|
|
+** If so, jump to instruction P2. Otherwise, fall through to the next
|
|
** instruction.
|
|
**
|
|
** If P1 is non-zero, then the jump is taken if the database constraint-counter
|
|
@@ -91401,7 +97541,7 @@ case OP_FkIfZero: { /* jump */
|
|
**
|
|
** P1 is a register in the root frame of this VM (the root frame is
|
|
** different from the current frame if this instruction is being executed
|
|
-** within a sub-program). Set the value of register P1 to the maximum of
|
|
+** within a sub-program). Set the value of register P1 to the maximum of
|
|
** its current value and the value in register P2.
|
|
**
|
|
** This instruction throws an error if the memory cell is not initially
|
|
@@ -91451,7 +97591,7 @@ case OP_IfPos: { /* jump, in1 */
|
|
** Synopsis: if r[P1]>0 then r[P2]=r[P1]+max(0,r[P3]) else r[P2]=(-1)
|
|
**
|
|
** This opcode performs a commonly used computation associated with
|
|
-** LIMIT and OFFSET process. r[P1] holds the limit counter. r[P3]
|
|
+** LIMIT and OFFSET processing. r[P1] holds the limit counter. r[P3]
|
|
** holds the offset counter. The opcode computes the combined value
|
|
** of the LIMIT and OFFSET and stores that value in r[P2]. The r[P2]
|
|
** value computed is the total number of rows that will need to be
|
|
@@ -91461,7 +97601,7 @@ case OP_IfPos: { /* jump, in1 */
|
|
** and r[P2] is set to be the value of the LIMIT, r[P1].
|
|
**
|
|
** if r[P1] is zero or negative, that means there is no LIMIT
|
|
-** and r[P2] is set to -1.
|
|
+** and r[P2] is set to -1.
|
|
**
|
|
** Otherwise, r[P2] is set to the sum of r[P1] and r[P3].
|
|
*/
|
|
@@ -91493,7 +97633,7 @@ case OP_OffsetLimit: { /* in1, out2, in3 */
|
|
**
|
|
** Register P1 must contain an integer. If the content of register P1 is
|
|
** initially greater than zero, then decrement the value in register P1.
|
|
-** If it is non-zero (negative or positive) and then also jump to P2.
|
|
+** If it is non-zero (negative or positive) and then also jump to P2.
|
|
** If register P1 is initially zero, leave it unchanged and fall through.
|
|
*/
|
|
case OP_IfNotZero: { /* jump, in1 */
|
|
@@ -91527,7 +97667,7 @@ case OP_DecrJumpZero: { /* jump, in1 */
|
|
** Synopsis: accum=r[P3] step(r[P2@P5])
|
|
**
|
|
** Execute the xStep function for an aggregate.
|
|
-** The function has P5 arguments. P4 is a pointer to the
|
|
+** The function has P5 arguments. P4 is a pointer to the
|
|
** FuncDef structure that specifies the function. Register P3 is the
|
|
** accumulator.
|
|
**
|
|
@@ -91538,7 +97678,7 @@ case OP_DecrJumpZero: { /* jump, in1 */
|
|
** Synopsis: accum=r[P3] inverse(r[P2@P5])
|
|
**
|
|
** Execute the xInverse function for an aggregate.
|
|
-** The function has P5 arguments. P4 is a pointer to the
|
|
+** The function has P5 arguments. P4 is a pointer to the
|
|
** FuncDef structure that specifies the function. Register P3 is the
|
|
** accumulator.
|
|
**
|
|
@@ -91549,7 +97689,7 @@ case OP_DecrJumpZero: { /* jump, in1 */
|
|
** Synopsis: accum=r[P3] step(r[P2@P5])
|
|
**
|
|
** Execute the xStep (if P1==0) or xInverse (if P1!=0) function for an
|
|
-** aggregate. The function has P5 arguments. P4 is a pointer to the
|
|
+** aggregate. The function has P5 arguments. P4 is a pointer to the
|
|
** FuncDef structure that specifies the function. Register P3 is the
|
|
** accumulator.
|
|
**
|
|
@@ -91583,6 +97723,7 @@ case OP_AggStep: {
|
|
pCtx->pVdbe = p;
|
|
pCtx->skipFlag = 0;
|
|
pCtx->isError = 0;
|
|
+ pCtx->enc = encoding;
|
|
pCtx->argc = n;
|
|
pOp->p4type = P4_FUNCCTX;
|
|
pOp->p4.pCtx = pCtx;
|
|
@@ -91592,6 +97733,7 @@ case OP_AggStep: {
|
|
|
|
pOp->opcode = OP_AggStep1;
|
|
/* Fall through into OP_AggStep */
|
|
+ /* no break */ deliberate_fall_through
|
|
}
|
|
case OP_AggStep1: {
|
|
int i;
|
|
@@ -91665,7 +97807,7 @@ case OP_AggStep1: {
|
|
** Synopsis: accum=r[P1] N=P2
|
|
**
|
|
** P1 is the memory location that is the accumulator for an aggregate
|
|
-** or window function. Execute the finalizer function
|
|
+** or window function. Execute the finalizer function
|
|
** for an aggregate and store the result in P1.
|
|
**
|
|
** P2 is the number of arguments that the step function takes and
|
|
@@ -91704,16 +97846,13 @@ case OP_AggFinal: {
|
|
{
|
|
rc = sqlite3VdbeMemFinalize(pMem, pOp->p4.pFunc);
|
|
}
|
|
-
|
|
+
|
|
if( rc ){
|
|
sqlite3VdbeError(p, "%s", sqlite3_value_text(pMem));
|
|
goto abort_due_to_error;
|
|
}
|
|
sqlite3VdbeChangeEncoding(pMem, encoding);
|
|
UPDATE_MAX_BLOBSIZE(pMem);
|
|
- if( sqlite3VdbeMemTooBig(pMem) ){
|
|
- goto too_big;
|
|
- }
|
|
break;
|
|
}
|
|
|
|
@@ -91750,9 +97889,9 @@ case OP_Checkpoint: {
|
|
}
|
|
for(i=0, pMem = &aMem[pOp->p3]; i<3; i++, pMem++){
|
|
sqlite3VdbeMemSetInt64(pMem, (i64)aRes[i]);
|
|
- }
|
|
+ }
|
|
break;
|
|
-};
|
|
+};
|
|
#endif
|
|
|
|
#ifndef SQLITE_OMIT_PRAGMA
|
|
@@ -91778,9 +97917,9 @@ case OP_JournalMode: { /* out2 */
|
|
|
|
pOut = out2Prerelease(p, pOp);
|
|
eNew = pOp->p3;
|
|
- assert( eNew==PAGER_JOURNALMODE_DELETE
|
|
- || eNew==PAGER_JOURNALMODE_TRUNCATE
|
|
- || eNew==PAGER_JOURNALMODE_PERSIST
|
|
+ assert( eNew==PAGER_JOURNALMODE_DELETE
|
|
+ || eNew==PAGER_JOURNALMODE_TRUNCATE
|
|
+ || eNew==PAGER_JOURNALMODE_PERSIST
|
|
|| eNew==PAGER_JOURNALMODE_OFF
|
|
|| eNew==PAGER_JOURNALMODE_MEMORY
|
|
|| eNew==PAGER_JOURNALMODE_WAL
|
|
@@ -91793,13 +97932,14 @@ case OP_JournalMode: { /* out2 */
|
|
pPager = sqlite3BtreePager(pBt);
|
|
eOld = sqlite3PagerGetJournalMode(pPager);
|
|
if( eNew==PAGER_JOURNALMODE_QUERY ) eNew = eOld;
|
|
+ assert( sqlite3BtreeHoldsMutex(pBt) );
|
|
if( !sqlite3PagerOkToChangeJournalMode(pPager) ) eNew = eOld;
|
|
|
|
#ifndef SQLITE_OMIT_WAL
|
|
zFilename = sqlite3PagerFilename(pPager, 1);
|
|
|
|
/* Do not allow a transition to journal_mode=WAL for a database
|
|
- ** in temporary storage or if the VFS does not support shared memory
|
|
+ ** in temporary storage or if the VFS does not support shared memory
|
|
*/
|
|
if( eNew==PAGER_JOURNALMODE_WAL
|
|
&& (sqlite3Strlen30(zFilename)==0 /* Temp file */
|
|
@@ -91819,12 +97959,12 @@ case OP_JournalMode: { /* out2 */
|
|
);
|
|
goto abort_due_to_error;
|
|
}else{
|
|
-
|
|
+
|
|
if( eOld==PAGER_JOURNALMODE_WAL ){
|
|
/* If leaving WAL mode, close the log file. If successful, the call
|
|
- ** to PagerCloseWal() checkpoints and deletes the write-ahead-log
|
|
- ** file. An EXCLUSIVE lock may still be held on the database file
|
|
- ** after a successful return.
|
|
+ ** to PagerCloseWal() checkpoints and deletes the write-ahead-log
|
|
+ ** file. An EXCLUSIVE lock may still be held on the database file
|
|
+ ** after a successful return.
|
|
*/
|
|
rc = sqlite3PagerCloseWal(pPager, db);
|
|
if( rc==SQLITE_OK ){
|
|
@@ -91835,11 +97975,11 @@ case OP_JournalMode: { /* out2 */
|
|
** as an intermediate */
|
|
sqlite3PagerSetJournalMode(pPager, PAGER_JOURNALMODE_OFF);
|
|
}
|
|
-
|
|
+
|
|
/* Open a transaction on the database file. Regardless of the journal
|
|
** mode, this transaction always uses a rollback journal.
|
|
*/
|
|
- assert( sqlite3BtreeIsInTrans(pBt)==0 );
|
|
+ assert( sqlite3BtreeTxnState(pBt)!=SQLITE_TXN_WRITE );
|
|
if( rc==SQLITE_OK ){
|
|
rc = sqlite3BtreeSetVersion(pBt, (eNew==PAGER_JOURNALMODE_WAL ? 2 : 1));
|
|
}
|
|
@@ -91910,7 +98050,7 @@ case OP_IncrVacuum: { /* jump */
|
|
** is executed using sqlite3_step() it will either automatically
|
|
** reprepare itself (if it was originally created using sqlite3_prepare_v2())
|
|
** or it will fail with SQLITE_SCHEMA.
|
|
-**
|
|
+**
|
|
** If P1 is 0, then all SQL statements become expired. If P1 is non-zero,
|
|
** then only the currently executing statement is expired.
|
|
**
|
|
@@ -91965,7 +98105,7 @@ case OP_CursorUnlock: {
|
|
** Synopsis: iDb=P1 root=P2 write=P3
|
|
**
|
|
** Obtain a lock on a particular table. This instruction is only used when
|
|
-** the shared-cache feature is enabled.
|
|
+** the shared-cache feature is enabled.
|
|
**
|
|
** P1 is the index of the database in sqlite3.aDb[] of the database
|
|
** on which the lock is acquired. A readlock is obtained if P3==0 or
|
|
@@ -91979,7 +98119,7 @@ case OP_CursorUnlock: {
|
|
case OP_TableLock: {
|
|
u8 isWriteLock = (u8)pOp->p3;
|
|
if( isWriteLock || 0==(db->flags&SQLITE_ReadUncommit) ){
|
|
- int p1 = pOp->p1;
|
|
+ int p1 = pOp->p1;
|
|
assert( p1>=0 && p1<db->nDb );
|
|
assert( DbMaskTest(p->btreeMask, p1) );
|
|
assert( isWriteLock==0 || isWriteLock==1 );
|
|
@@ -91999,7 +98139,7 @@ case OP_TableLock: {
|
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
|
/* Opcode: VBegin * * * P4 *
|
|
**
|
|
-** P4 may be a pointer to an sqlite3_vtab structure. If so, call the
|
|
+** P4 may be a pointer to an sqlite3_vtab structure. If so, call the
|
|
** xBegin method for that table.
|
|
**
|
|
** Also, whether or not P4 is set, check that this is not being called from
|
|
@@ -92019,7 +98159,7 @@ case OP_VBegin: {
|
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
|
/* Opcode: VCreate P1 P2 * * *
|
|
**
|
|
-** P2 is a register that holds the name of a virtual table in database
|
|
+** P2 is a register that holds the name of a virtual table in database
|
|
** P1. Call the xCreate method for that table.
|
|
*/
|
|
case OP_VCreate: {
|
|
@@ -92068,7 +98208,7 @@ case OP_VDestroy: {
|
|
** P1 is a cursor number. This opcode opens a cursor to the virtual
|
|
** table and stores that cursor in P1.
|
|
*/
|
|
-case OP_VOpen: {
|
|
+case OP_VOpen: { /* ncycle */
|
|
VdbeCursor *pCur;
|
|
sqlite3_vtab_cursor *pVCur;
|
|
sqlite3_vtab *pVtab;
|
|
@@ -92091,7 +98231,7 @@ case OP_VOpen: {
|
|
pVCur->pVtab = pVtab;
|
|
|
|
/* Initialize vdbe cursor object */
|
|
- pCur = allocateCursor(p, pOp->p1, 0, -1, CURTYPE_VTAB);
|
|
+ pCur = allocateCursor(p, pOp->p1, 0, CURTYPE_VTAB);
|
|
if( pCur ){
|
|
pCur->uc.pVCur = pVCur;
|
|
pVtab->nRef++;
|
|
@@ -92104,6 +98244,34 @@ case OP_VOpen: {
|
|
}
|
|
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
|
|
|
+#ifndef SQLITE_OMIT_VIRTUALTABLE
|
|
+/* Opcode: VInitIn P1 P2 P3 * *
|
|
+** Synopsis: r[P2]=ValueList(P1,P3)
|
|
+**
|
|
+** Set register P2 to be a pointer to a ValueList object for cursor P1
|
|
+** with cache register P3 and output register P3+1. This ValueList object
|
|
+** can be used as the first argument to sqlite3_vtab_in_first() and
|
|
+** sqlite3_vtab_in_next() to extract all of the values stored in the P1
|
|
+** cursor. Register P3 is used to hold the values returned by
|
|
+** sqlite3_vtab_in_first() and sqlite3_vtab_in_next().
|
|
+*/
|
|
+case OP_VInitIn: { /* out2, ncycle */
|
|
+ VdbeCursor *pC; /* The cursor containing the RHS values */
|
|
+ ValueList *pRhs; /* New ValueList object to put in reg[P2] */
|
|
+
|
|
+ pC = p->apCsr[pOp->p1];
|
|
+ pRhs = sqlite3_malloc64( sizeof(*pRhs) );
|
|
+ if( pRhs==0 ) goto no_mem;
|
|
+ pRhs->pCsr = pC->uc.pCursor;
|
|
+ pRhs->pOut = &aMem[pOp->p3];
|
|
+ pOut = out2Prerelease(p, pOp);
|
|
+ pOut->flags = MEM_Null;
|
|
+ sqlite3VdbeMemSetPointer(pOut, pRhs, "ValueList", sqlite3VdbeValueListFree);
|
|
+ break;
|
|
+}
|
|
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
|
+
|
|
+
|
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
|
/* Opcode: VFilter P1 P2 P3 P4 *
|
|
** Synopsis: iplan=r[P3] zplan='P4'
|
|
@@ -92124,7 +98292,7 @@ case OP_VOpen: {
|
|
**
|
|
** A jump is made to P2 if the result set after filtering would be empty.
|
|
*/
|
|
-case OP_VFilter: { /* jump */
|
|
+case OP_VFilter: { /* jump, ncycle */
|
|
int nArg;
|
|
int iQuery;
|
|
const sqlite3_module *pModule;
|
|
@@ -92142,6 +98310,7 @@ case OP_VFilter: { /* jump */
|
|
pCur = p->apCsr[pOp->p1];
|
|
assert( memIsValid(pQuery) );
|
|
REGISTER_TRACE(pOp->p3, pQuery);
|
|
+ assert( pCur!=0 );
|
|
assert( pCur->eCurType==CURTYPE_VTAB );
|
|
pVCur = pCur->uc.pVCur;
|
|
pVtab = pVCur->pVtab;
|
|
@@ -92153,7 +98322,6 @@ case OP_VFilter: { /* jump */
|
|
iQuery = (int)pQuery->u.i;
|
|
|
|
/* Invoke the xFilter method */
|
|
- res = 0;
|
|
apArg = p->apArg;
|
|
for(i = 0; i<nArg; i++){
|
|
apArg[i] = &pArgc[i+1];
|
|
@@ -92184,14 +98352,14 @@ case OP_VFilter: { /* jump */
|
|
** bits (OPFLAG_LENGTHARG or OPFLAG_TYPEOFARG) but those bits are
|
|
** unused by OP_VColumn.
|
|
*/
|
|
-case OP_VColumn: {
|
|
+case OP_VColumn: { /* ncycle */
|
|
sqlite3_vtab *pVtab;
|
|
const sqlite3_module *pModule;
|
|
Mem *pDest;
|
|
sqlite3_context sContext;
|
|
|
|
VdbeCursor *pCur = p->apCsr[pOp->p1];
|
|
- assert( pCur->eCurType==CURTYPE_VTAB );
|
|
+ assert( pCur!=0 );
|
|
assert( pOp->p3>0 && pOp->p3<=(p->nMem+1 - p->nCursor) );
|
|
pDest = &aMem[pOp->p3];
|
|
memAboutToChange(p, pDest);
|
|
@@ -92199,11 +98367,13 @@ case OP_VColumn: {
|
|
sqlite3VdbeMemSetNull(pDest);
|
|
break;
|
|
}
|
|
+ assert( pCur->eCurType==CURTYPE_VTAB );
|
|
pVtab = pCur->uc.pVCur->pVtab;
|
|
pModule = pVtab->pModule;
|
|
assert( pModule->xColumn );
|
|
memset(&sContext, 0, sizeof(sContext));
|
|
sContext.pOut = pDest;
|
|
+ sContext.enc = encoding;
|
|
assert( pOp->p5==OPFLAG_NOCHNG || pOp->p5==0 );
|
|
if( pOp->p5 & OPFLAG_NOCHNG ){
|
|
sqlite3VdbeMemSetNull(pDest);
|
|
@@ -92222,9 +98392,6 @@ case OP_VColumn: {
|
|
REGISTER_TRACE(pOp->p3, pDest);
|
|
UPDATE_MAX_BLOBSIZE(pDest);
|
|
|
|
- if( sqlite3VdbeMemTooBig(pDest) ){
|
|
- goto too_big;
|
|
- }
|
|
if( rc ) goto abort_due_to_error;
|
|
break;
|
|
}
|
|
@@ -92237,14 +98404,14 @@ case OP_VColumn: {
|
|
** jump to instruction P2. Or, if the virtual table has reached
|
|
** the end of its result set, then fall through to the next instruction.
|
|
*/
|
|
-case OP_VNext: { /* jump */
|
|
+case OP_VNext: { /* jump, ncycle */
|
|
sqlite3_vtab *pVtab;
|
|
const sqlite3_module *pModule;
|
|
int res;
|
|
VdbeCursor *pCur;
|
|
|
|
- res = 0;
|
|
pCur = p->apCsr[pOp->p1];
|
|
+ assert( pCur!=0 );
|
|
assert( pCur->eCurType==CURTYPE_VTAB );
|
|
if( pCur->nullRow ){
|
|
break;
|
|
@@ -92255,7 +98422,7 @@ case OP_VNext: { /* jump */
|
|
|
|
/* Invoke the xNext() method of the module. There is no way for the
|
|
** underlying implementation to return an error if one occurs during
|
|
- ** xNext(). Instead, if an error occurs, true is returned (indicating that
|
|
+ ** xNext(). Instead, if an error occurs, true is returned (indicating that
|
|
** data is available) and the error code returned when xColumn or
|
|
** some other method is next invoked on the save virtual table cursor.
|
|
*/
|
|
@@ -92283,7 +98450,7 @@ case OP_VRename: {
|
|
sqlite3_vtab *pVtab;
|
|
Mem *pName;
|
|
int isLegacy;
|
|
-
|
|
+
|
|
isLegacy = (db->flags & SQLITE_LegacyAlter);
|
|
db->flags |= SQLITE_LegacyAlter;
|
|
pVtab = pOp->p4.pVtab->pVtab;
|
|
@@ -92313,23 +98480,23 @@ case OP_VRename: {
|
|
**
|
|
** P4 is a pointer to a virtual table object, an sqlite3_vtab structure.
|
|
** This opcode invokes the corresponding xUpdate method. P2 values
|
|
-** are contiguous memory cells starting at P3 to pass to the xUpdate
|
|
-** invocation. The value in register (P3+P2-1) corresponds to the
|
|
+** are contiguous memory cells starting at P3 to pass to the xUpdate
|
|
+** invocation. The value in register (P3+P2-1) corresponds to the
|
|
** p2th element of the argv array passed to xUpdate.
|
|
**
|
|
** The xUpdate method will do a DELETE or an INSERT or both.
|
|
** The argv[0] element (which corresponds to memory cell P3)
|
|
-** is the rowid of a row to delete. If argv[0] is NULL then no
|
|
-** deletion occurs. The argv[1] element is the rowid of the new
|
|
-** row. This can be NULL to have the virtual table select the new
|
|
-** rowid for itself. The subsequent elements in the array are
|
|
+** is the rowid of a row to delete. If argv[0] is NULL then no
|
|
+** deletion occurs. The argv[1] element is the rowid of the new
|
|
+** row. This can be NULL to have the virtual table select the new
|
|
+** rowid for itself. The subsequent elements in the array are
|
|
** the values of columns in the new row.
|
|
**
|
|
** If P2==1 then no insert is performed. argv[0] is the rowid of
|
|
** a row to delete.
|
|
**
|
|
** P1 is a boolean flag. If it is set to true and the xUpdate call
|
|
-** is successful, then the value returned by sqlite3_last_insert_rowid()
|
|
+** is successful, then the value returned by sqlite3_last_insert_rowid()
|
|
** is set to the value of the rowid for the row just inserted.
|
|
**
|
|
** P5 is the error actions (OE_Replace, OE_Fail, OE_Ignore, etc) to
|
|
@@ -92340,11 +98507,11 @@ case OP_VUpdate: {
|
|
const sqlite3_module *pModule;
|
|
int nArg;
|
|
int i;
|
|
- sqlite_int64 rowid;
|
|
+ sqlite_int64 rowid = 0;
|
|
Mem **apArg;
|
|
Mem *pX;
|
|
|
|
- assert( pOp->p2==1 || pOp->p5==OE_Fail || pOp->p5==OE_Rollback
|
|
+ assert( pOp->p2==1 || pOp->p5==OE_Fail || pOp->p5==OE_Rollback
|
|
|| pOp->p5==OE_Abort || pOp->p5==OE_Ignore || pOp->p5==OE_Replace
|
|
);
|
|
assert( p->readOnly==0 );
|
|
@@ -92430,7 +98597,7 @@ case OP_MaxPgcnt: { /* out2 */
|
|
#endif
|
|
|
|
/* Opcode: Function P1 P2 P3 P4 *
|
|
-** Synopsis: r[P3]=func(r[P2@P5])
|
|
+** Synopsis: r[P3]=func(r[P2@NP])
|
|
**
|
|
** Invoke a user function (P4 is a pointer to an sqlite3_context object that
|
|
** contains a pointer to the function to be run) with arguments taken
|
|
@@ -92439,7 +98606,7 @@ case OP_MaxPgcnt: { /* out2 */
|
|
** The result of the function is stored
|
|
** in register P3. Register P3 must not be one of the function inputs.
|
|
**
|
|
-** P1 is a 32-bit bitmask indicating whether or not each argument to the
|
|
+** P1 is a 32-bit bitmask indicating whether or not each argument to the
|
|
** function was determined to be constant at compile time. If the first
|
|
** argument was constant then bit 0 of P1 is set. This is used to determine
|
|
** whether meta data associated with a user function argument using the
|
|
@@ -92449,7 +98616,7 @@ case OP_MaxPgcnt: { /* out2 */
|
|
** See also: AggStep, AggFinal, PureFunc
|
|
*/
|
|
/* Opcode: PureFunc P1 P2 P3 P4 *
|
|
-** Synopsis: r[P3]=func(r[P2@P5])
|
|
+** Synopsis: r[P3]=func(r[P2@NP])
|
|
**
|
|
** Invoke a user function (P4 is a pointer to an sqlite3_context object that
|
|
** contains a pointer to the function to be run) with arguments taken
|
|
@@ -92458,7 +98625,7 @@ case OP_MaxPgcnt: { /* out2 */
|
|
** The result of the function is stored
|
|
** in register P3. Register P3 must not be one of the function inputs.
|
|
**
|
|
-** P1 is a 32-bit bitmask indicating whether or not each argument to the
|
|
+** P1 is a 32-bit bitmask indicating whether or not each argument to the
|
|
** function was determined to be constant at compile time. If the first
|
|
** argument was constant then bit 0 of P1 is set. This is used to determine
|
|
** whether meta data associated with a user function argument using the
|
|
@@ -92491,6 +98658,7 @@ case OP_Function: { /* group */
|
|
if( pCtx->pOut != pOut ){
|
|
pCtx->pVdbe = p;
|
|
pCtx->pOut = pOut;
|
|
+ pCtx->enc = encoding;
|
|
for(i=pCtx->argc-1; i>=0; i--) pCtx->argv[i] = &aMem[pOp->p2+i];
|
|
}
|
|
assert( pCtx->pVdbe==p );
|
|
@@ -92517,17 +98685,98 @@ case OP_Function: { /* group */
|
|
if( rc ) goto abort_due_to_error;
|
|
}
|
|
|
|
- /* Copy the result of the function into register P3 */
|
|
- if( pOut->flags & (MEM_Str|MEM_Blob) ){
|
|
- sqlite3VdbeChangeEncoding(pOut, encoding);
|
|
- if( sqlite3VdbeMemTooBig(pOut) ) goto too_big;
|
|
- }
|
|
+ assert( (pOut->flags&MEM_Str)==0
|
|
+ || pOut->enc==encoding
|
|
+ || db->mallocFailed );
|
|
+ assert( !sqlite3VdbeMemTooBig(pOut) );
|
|
|
|
REGISTER_TRACE(pOp->p3, pOut);
|
|
UPDATE_MAX_BLOBSIZE(pOut);
|
|
break;
|
|
}
|
|
|
|
+/* Opcode: ClrSubtype P1 * * * *
|
|
+** Synopsis: r[P1].subtype = 0
|
|
+**
|
|
+** Clear the subtype from register P1.
|
|
+*/
|
|
+case OP_ClrSubtype: { /* in1 */
|
|
+ pIn1 = &aMem[pOp->p1];
|
|
+ pIn1->flags &= ~MEM_Subtype;
|
|
+ break;
|
|
+}
|
|
+
|
|
+/* Opcode: FilterAdd P1 * P3 P4 *
|
|
+** Synopsis: filter(P1) += key(P3@P4)
|
|
+**
|
|
+** Compute a hash on the P4 registers starting with r[P3] and
|
|
+** add that hash to the bloom filter contained in r[P1].
|
|
+*/
|
|
+case OP_FilterAdd: {
|
|
+ u64 h;
|
|
+
|
|
+ assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) );
|
|
+ pIn1 = &aMem[pOp->p1];
|
|
+ assert( pIn1->flags & MEM_Blob );
|
|
+ assert( pIn1->n>0 );
|
|
+ h = filterHash(aMem, pOp);
|
|
+#ifdef SQLITE_DEBUG
|
|
+ if( db->flags&SQLITE_VdbeTrace ){
|
|
+ int ii;
|
|
+ for(ii=pOp->p3; ii<pOp->p3+pOp->p4.i; ii++){
|
|
+ registerTrace(ii, &aMem[ii]);
|
|
+ }
|
|
+ printf("hash: %llu modulo %d -> %u\n", h, pIn1->n, (int)(h%pIn1->n));
|
|
+ }
|
|
+#endif
|
|
+ h %= pIn1->n;
|
|
+ pIn1->z[h/8] |= 1<<(h&7);
|
|
+ break;
|
|
+}
|
|
+
|
|
+/* Opcode: Filter P1 P2 P3 P4 *
|
|
+** Synopsis: if key(P3@P4) not in filter(P1) goto P2
|
|
+**
|
|
+** Compute a hash on the key contained in the P4 registers starting
|
|
+** with r[P3]. Check to see if that hash is found in the
|
|
+** bloom filter hosted by register P1. If it is not present then
|
|
+** maybe jump to P2. Otherwise fall through.
|
|
+**
|
|
+** False negatives are harmless. It is always safe to fall through,
|
|
+** even if the value is in the bloom filter. A false negative causes
|
|
+** more CPU cycles to be used, but it should still yield the correct
|
|
+** answer. However, an incorrect answer may well arise from a
|
|
+** false positive - if the jump is taken when it should fall through.
|
|
+*/
|
|
+case OP_Filter: { /* jump */
|
|
+ u64 h;
|
|
+
|
|
+ assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) );
|
|
+ pIn1 = &aMem[pOp->p1];
|
|
+ assert( (pIn1->flags & MEM_Blob)!=0 );
|
|
+ assert( pIn1->n >= 1 );
|
|
+ h = filterHash(aMem, pOp);
|
|
+#ifdef SQLITE_DEBUG
|
|
+ if( db->flags&SQLITE_VdbeTrace ){
|
|
+ int ii;
|
|
+ for(ii=pOp->p3; ii<pOp->p3+pOp->p4.i; ii++){
|
|
+ registerTrace(ii, &aMem[ii]);
|
|
+ }
|
|
+ printf("hash: %llu modulo %d -> %u\n", h, pIn1->n, (int)(h%pIn1->n));
|
|
+ }
|
|
+#endif
|
|
+ h %= pIn1->n;
|
|
+ if( (pIn1->z[h/8] & (1<<(h&7)))==0 ){
|
|
+ VdbeBranchTaken(1, 2);
|
|
+ p->aCounter[SQLITE_STMTSTATUS_FILTER_HIT]++;
|
|
+ goto jump_to_p2;
|
|
+ }else{
|
|
+ p->aCounter[SQLITE_STMTSTATUS_FILTER_MISS]++;
|
|
+ VdbeBranchTaken(0, 2);
|
|
+ }
|
|
+ break;
|
|
+}
|
|
+
|
|
/* Opcode: Trace P1 P2 * P4 *
|
|
**
|
|
** Write P4 on the statement trace output if statement tracing is
|
|
@@ -92576,23 +98825,22 @@ case OP_Init: { /* jump */
|
|
|
|
#ifndef SQLITE_OMIT_TRACE
|
|
if( (db->mTrace & (SQLITE_TRACE_STMT|SQLITE_TRACE_LEGACY))!=0
|
|
- && !p->doingRerun
|
|
+ && p->minWriteFileFormat!=254 /* tag-20220401a */
|
|
&& (zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0
|
|
){
|
|
#ifndef SQLITE_OMIT_DEPRECATED
|
|
if( db->mTrace & SQLITE_TRACE_LEGACY ){
|
|
- void (*x)(void*,const char*) = (void(*)(void*,const char*))db->xTrace;
|
|
char *z = sqlite3VdbeExpandSql(p, zTrace);
|
|
- x(db->pTraceArg, z);
|
|
+ db->trace.xLegacy(db->pTraceArg, z);
|
|
sqlite3_free(z);
|
|
}else
|
|
#endif
|
|
if( db->nVdbeExec>1 ){
|
|
char *z = sqlite3MPrintf(db, "-- %s", zTrace);
|
|
- (void)db->xTrace(SQLITE_TRACE_STMT, db->pTraceArg, p, z);
|
|
+ (void)db->trace.xV2(SQLITE_TRACE_STMT, db->pTraceArg, p, z);
|
|
sqlite3DbFree(db, z);
|
|
}else{
|
|
- (void)db->xTrace(SQLITE_TRACE_STMT, db->pTraceArg, p, zTrace);
|
|
+ (void)db->trace.xV2(SQLITE_TRACE_STMT, db->pTraceArg, p, zTrace);
|
|
}
|
|
}
|
|
#ifdef SQLITE_USE_FCNTL_TRACE
|
|
@@ -92739,12 +98987,12 @@ default: { /* This is really OP_Noop, OP_Explain */
|
|
*****************************************************************************/
|
|
}
|
|
|
|
-#ifdef VDBE_PROFILE
|
|
- {
|
|
- u64 endTime = sqlite3NProfileCnt ? sqlite3NProfileCnt : sqlite3Hwtime();
|
|
- if( endTime>start ) pOrigOp->cycles += endTime - start;
|
|
- pOrigOp->cnt++;
|
|
- }
|
|
+#if defined(VDBE_PROFILE)
|
|
+ *pnCycle += sqlite3NProfileCnt ? sqlite3NProfileCnt : sqlite3Hwtime();
|
|
+ pnCycle = 0;
|
|
+#elif defined(SQLITE_ENABLE_STMT_SCANSTATUS)
|
|
+ *pnCycle += sqlite3Hwtime();
|
|
+ pnCycle = 0;
|
|
#endif
|
|
|
|
/* The following code adds nothing to the actual functionality
|
|
@@ -92780,18 +99028,37 @@ default: { /* This is really OP_Noop, OP_Explain */
|
|
** an error of some kind.
|
|
*/
|
|
abort_due_to_error:
|
|
- if( db->mallocFailed ) rc = SQLITE_NOMEM_BKPT;
|
|
+ if( db->mallocFailed ){
|
|
+ rc = SQLITE_NOMEM_BKPT;
|
|
+ }else if( rc==SQLITE_IOERR_CORRUPTFS ){
|
|
+ rc = SQLITE_CORRUPT_BKPT;
|
|
+ }
|
|
assert( rc );
|
|
+#ifdef SQLITE_DEBUG
|
|
+ if( db->flags & SQLITE_VdbeTrace ){
|
|
+ const char *zTrace = p->zSql;
|
|
+ if( zTrace==0 ){
|
|
+ if( aOp[0].opcode==OP_Trace ){
|
|
+ zTrace = aOp[0].p4.z;
|
|
+ }
|
|
+ if( zTrace==0 ) zTrace = "???";
|
|
+ }
|
|
+ printf("ABORT-due-to-error (rc=%d): %s\n", rc, zTrace);
|
|
+ }
|
|
+#endif
|
|
if( p->zErrMsg==0 && rc!=SQLITE_IOERR_NOMEM ){
|
|
sqlite3VdbeError(p, "%s", sqlite3ErrStr(rc));
|
|
}
|
|
p->rc = rc;
|
|
sqlite3SystemError(db, rc);
|
|
testcase( sqlite3GlobalConfig.xLog!=0 );
|
|
- sqlite3_log(rc, "statement aborts at %d: [%s] %s",
|
|
+ sqlite3_log(rc, "statement aborts at %d: [%s] %s",
|
|
(int)(pOp - aOp), p->zSql, p->zErrMsg);
|
|
- sqlite3VdbeHalt(p);
|
|
+ if( p->eVdbeState==VDBE_RUN_STATE ) sqlite3VdbeHalt(p);
|
|
if( rc==SQLITE_IOERR_NOMEM ) sqlite3OomFault(db);
|
|
+ if( rc==SQLITE_CORRUPT && db->autoCommit==0 ){
|
|
+ db->flags |= SQLITE_CorruptRdOnly;
|
|
+ }
|
|
rc = SQLITE_ERROR;
|
|
if( resetSchemaOnFault>0 ){
|
|
sqlite3ResetOneSchema(db, resetSchemaOnFault-1);
|
|
@@ -92801,20 +99068,34 @@ default: { /* This is really OP_Noop, OP_Explain */
|
|
** release the mutexes on btrees that were acquired at the
|
|
** top. */
|
|
vdbe_return:
|
|
+#if defined(VDBE_PROFILE)
|
|
+ if( pnCycle ){
|
|
+ *pnCycle += sqlite3NProfileCnt ? sqlite3NProfileCnt : sqlite3Hwtime();
|
|
+ pnCycle = 0;
|
|
+ }
|
|
+#elif defined(SQLITE_ENABLE_STMT_SCANSTATUS)
|
|
+ if( pnCycle ){
|
|
+ *pnCycle += sqlite3Hwtime();
|
|
+ pnCycle = 0;
|
|
+ }
|
|
+#endif
|
|
+
|
|
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
|
|
while( nVmStep>=nProgressLimit && db->xProgress!=0 ){
|
|
nProgressLimit += db->nProgressOps;
|
|
if( db->xProgress(db->pProgressArg) ){
|
|
- nProgressLimit = 0xffffffff;
|
|
+ nProgressLimit = LARGEST_UINT64;
|
|
rc = SQLITE_INTERRUPT;
|
|
goto abort_due_to_error;
|
|
}
|
|
}
|
|
#endif
|
|
p->aCounter[SQLITE_STMTSTATUS_VM_STEP] += (int)nVmStep;
|
|
- sqlite3VdbeLeave(p);
|
|
- assert( rc!=SQLITE_OK || nExtraDelete==0
|
|
- || sqlite3_strlike("DELETE%",p->zSql,0)!=0
|
|
+ if( DbMaskNonZero(p->lockMask) ){
|
|
+ sqlite3VdbeLeave(p);
|
|
+ }
|
|
+ assert( rc!=SQLITE_OK || nExtraDelete==0
|
|
+ || sqlite3_strlike("DELETE%",p->zSql,0)!=0
|
|
);
|
|
return rc;
|
|
|
|
@@ -92838,10 +99119,8 @@ default: { /* This is really OP_Noop, OP_Explain */
|
|
** flag.
|
|
*/
|
|
abort_due_to_interrupt:
|
|
- assert( db->u1.isInterrupted );
|
|
- rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_INTERRUPT;
|
|
- p->rc = rc;
|
|
- sqlite3VdbeError(p, "%s", sqlite3ErrStr(rc));
|
|
+ assert( AtomicLoad(&db->u1.isInterrupted) );
|
|
+ rc = SQLITE_INTERRUPT;
|
|
goto abort_due_to_error;
|
|
}
|
|
|
|
@@ -92898,7 +99177,7 @@ struct Incrblob {
|
|
** sqlite3DbFree().
|
|
**
|
|
** If an error does occur, then the b-tree cursor is closed. All subsequent
|
|
-** calls to sqlite3_blob_read(), blob_write() or blob_reopen() will
|
|
+** calls to sqlite3_blob_read(), blob_write() or blob_reopen() will
|
|
** immediately return SQLITE_ABORT.
|
|
*/
|
|
static int blobSeekToRow(Incrblob *p, sqlite3_int64 iRow, char **pzErr){
|
|
@@ -92906,7 +99185,7 @@ static int blobSeekToRow(Incrblob *p, sqlite3_int64 iRow, char **pzErr){
|
|
char *zErr = 0; /* Error message */
|
|
Vdbe *v = (Vdbe *)p->pStmt;
|
|
|
|
- /* Set the value of register r[1] in the SQL statement to integer iRow.
|
|
+ /* 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;
|
|
@@ -92925,7 +99204,10 @@ static int blobSeekToRow(Incrblob *p, sqlite3_int64 iRow, char **pzErr){
|
|
}
|
|
if( rc==SQLITE_ROW ){
|
|
VdbeCursor *pC = v->apCsr[0];
|
|
- u32 type = pC->nHdrParsed>p->iCol ? pC->aType[p->iCol] : 0;
|
|
+ u32 type;
|
|
+ assert( pC!=0 );
|
|
+ assert( pC->eCurType==CURTYPE_BTREE );
|
|
+ type = pC->nHdrParsed>p->iCol ? pC->aType[p->iCol] : 0;
|
|
testcase( pC->nHdrParsed==p->iCol );
|
|
testcase( pC->nHdrParsed==p->iCol+1 );
|
|
if( type<12 ){
|
|
@@ -92999,10 +99281,9 @@ SQLITE_API int sqlite3_blob_open(
|
|
sqlite3_mutex_enter(db->mutex);
|
|
|
|
pBlob = (Incrblob *)sqlite3DbMallocZero(db, sizeof(Incrblob));
|
|
- do {
|
|
- memset(&sParse, 0, sizeof(Parse));
|
|
+ while(1){
|
|
+ sqlite3ParseObjectInit(&sParse,db);
|
|
if( !pBlob ) goto blob_open_out;
|
|
- sParse.db = db;
|
|
sqlite3DbFree(db, zErr);
|
|
zErr = 0;
|
|
|
|
@@ -93017,7 +99298,7 @@ SQLITE_API int sqlite3_blob_open(
|
|
sqlite3ErrorMsg(&sParse, "cannot open table without rowid: %s", zTable);
|
|
}
|
|
#ifndef SQLITE_OMIT_VIEW
|
|
- if( pTab && pTab->pSelect ){
|
|
+ if( pTab && IsView(pTab) ){
|
|
pTab = 0;
|
|
sqlite3ErrorMsg(&sParse, "cannot open view: %s", zTable);
|
|
}
|
|
@@ -93037,7 +99318,7 @@ SQLITE_API int sqlite3_blob_open(
|
|
|
|
/* Now search pTab for the exact column. */
|
|
for(iCol=0; iCol<pTab->nCol; iCol++) {
|
|
- if( sqlite3StrICmp(pTab->aCol[iCol].zName, zColumn)==0 ){
|
|
+ if( sqlite3StrICmp(pTab->aCol[iCol].zCnName, zColumn)==0 ){
|
|
break;
|
|
}
|
|
}
|
|
@@ -93050,7 +99331,7 @@ SQLITE_API int sqlite3_blob_open(
|
|
}
|
|
|
|
/* If the value is being opened for writing, check that the
|
|
- ** column is not indexed, and that it is not part of a foreign key.
|
|
+ ** column is not indexed, and that it is not part of a foreign key.
|
|
*/
|
|
if( wrFlag ){
|
|
const char *zFault = 0;
|
|
@@ -93059,10 +99340,11 @@ SQLITE_API int sqlite3_blob_open(
|
|
if( db->flags&SQLITE_ForeignKeys ){
|
|
/* Check that the column is not part of an FK child key definition. It
|
|
** is not necessary to check if it is part of a parent key, as parent
|
|
- ** key columns must be indexed. The check below will pick up this
|
|
+ ** key columns must be indexed. The check below will pick up this
|
|
** case. */
|
|
FKey *pFKey;
|
|
- for(pFKey=pTab->pFKey; pFKey; pFKey=pFKey->pNextFrom){
|
|
+ assert( IsOrdinaryTable(pTab) );
|
|
+ for(pFKey=pTab->u.tab.pFKey; pFKey; pFKey=pFKey->pNextFrom){
|
|
int j;
|
|
for(j=0; j<pFKey->nCol; j++){
|
|
if( pFKey->aCol[j].iFrom==iCol ){
|
|
@@ -93093,8 +99375,8 @@ SQLITE_API int sqlite3_blob_open(
|
|
pBlob->pStmt = (sqlite3_stmt *)sqlite3VdbeCreate(&sParse);
|
|
assert( pBlob->pStmt || db->mallocFailed );
|
|
if( pBlob->pStmt ){
|
|
-
|
|
- /* This VDBE program seeks a btree cursor to the identified
|
|
+
|
|
+ /* This VDBE program seeks a btree cursor to the identified
|
|
** db/table/row entry. The reason for using a vdbe program instead
|
|
** of writing code to use the b-tree layer directly is that the
|
|
** vdbe program will take advantage of the various transaction,
|
|
@@ -93102,11 +99384,11 @@ SQLITE_API int sqlite3_blob_open(
|
|
**
|
|
** After seeking the cursor, the vdbe executes an OP_ResultRow.
|
|
** Code external to the Vdbe then "borrows" the b-tree cursor and
|
|
- ** uses it to implement the blob_read(), blob_write() and
|
|
+ ** uses it to implement the blob_read(), blob_write() and
|
|
** blob_bytes() functions.
|
|
**
|
|
** The sqlite3_blob_close() function finalizes the vdbe program,
|
|
- ** which closes the b-tree cursor and (possibly) commits the
|
|
+ ** which closes the b-tree cursor and (possibly) commits the
|
|
** transaction.
|
|
*/
|
|
static const int iLn = VDBE_OFFSET_LINENO(2);
|
|
@@ -93123,7 +99405,7 @@ SQLITE_API int sqlite3_blob_open(
|
|
int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
|
VdbeOp *aOp;
|
|
|
|
- sqlite3VdbeAddOp4Int(v, OP_Transaction, iDb, wrFlag,
|
|
+ sqlite3VdbeAddOp4Int(v, OP_Transaction, iDb, wrFlag,
|
|
pTab->pSchema->schema_cookie,
|
|
pTab->pSchema->iGeneration);
|
|
sqlite3VdbeChangeP5(v, 1);
|
|
@@ -93131,7 +99413,7 @@ SQLITE_API int sqlite3_blob_open(
|
|
aOp = sqlite3VdbeAddOpList(v, ArraySize(openBlob), openBlob, iLn);
|
|
|
|
/* Make sure a mutex is held on the table to be accessed */
|
|
- sqlite3VdbeUsesBtree(v, iDb);
|
|
+ sqlite3VdbeUsesBtree(v, iDb);
|
|
|
|
if( db->mallocFailed==0 ){
|
|
assert( aOp!=0 );
|
|
@@ -93147,17 +99429,17 @@ SQLITE_API int sqlite3_blob_open(
|
|
if( db->mallocFailed==0 ){
|
|
#endif
|
|
|
|
- /* Remove either the OP_OpenWrite or OpenRead. Set the P2
|
|
+ /* Remove either the OP_OpenWrite or OpenRead. Set the P2
|
|
** parameter of the other to pTab->tnum. */
|
|
if( wrFlag ) aOp[1].opcode = OP_OpenWrite;
|
|
aOp[1].p2 = pTab->tnum;
|
|
- aOp[1].p3 = iDb;
|
|
+ aOp[1].p3 = iDb;
|
|
|
|
/* Configure the number of columns. Configure the cursor to
|
|
** think that the table has one more column than it really
|
|
** does. An OP_Column to retrieve this imaginary column will
|
|
** always return an SQL NULL. This is useful because it means
|
|
- ** we can invoke OP_Column to fill in the vdbe cursors type
|
|
+ ** we can invoke OP_Column to fill in the vdbe cursors type
|
|
** and offset cache without causing any IO.
|
|
*/
|
|
aOp[1].p4type = P4_INT32;
|
|
@@ -93170,7 +99452,7 @@ SQLITE_API int sqlite3_blob_open(
|
|
sqlite3VdbeMakeReady(v, &sParse);
|
|
}
|
|
}
|
|
-
|
|
+
|
|
pBlob->iCol = iCol;
|
|
pBlob->db = db;
|
|
sqlite3BtreeLeaveAll(db);
|
|
@@ -93178,7 +99460,9 @@ SQLITE_API int sqlite3_blob_open(
|
|
goto blob_open_out;
|
|
}
|
|
rc = blobSeekToRow(pBlob, iRow, &zErr);
|
|
- } while( (++nAttempt)<SQLITE_MAX_SCHEMA_RETRY && rc==SQLITE_SCHEMA );
|
|
+ if( (++nAttempt)>=SQLITE_MAX_SCHEMA_RETRY || rc!=SQLITE_SCHEMA ) break;
|
|
+ sqlite3ParseObjectReset(&sParse);
|
|
+ }
|
|
|
|
blob_open_out:
|
|
if( rc==SQLITE_OK && db->mallocFailed==0 ){
|
|
@@ -93189,7 +99473,7 @@ SQLITE_API int sqlite3_blob_open(
|
|
}
|
|
sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr);
|
|
sqlite3DbFree(db, zErr);
|
|
- sqlite3ParserReset(&sParse);
|
|
+ sqlite3ParseObjectReset(&sParse);
|
|
rc = sqlite3ApiExit(db, rc);
|
|
sqlite3_mutex_leave(db->mutex);
|
|
return rc;
|
|
@@ -93221,10 +99505,10 @@ SQLITE_API int sqlite3_blob_close(sqlite3_blob *pBlob){
|
|
** Perform a read or write operation on a blob
|
|
*/
|
|
static int blobReadWrite(
|
|
- sqlite3_blob *pBlob,
|
|
- void *z,
|
|
- int n,
|
|
- int iOffset,
|
|
+ sqlite3_blob *pBlob,
|
|
+ void *z,
|
|
+ int n,
|
|
+ int iOffset,
|
|
int (*xCall)(BtCursor*, u32, u32, void*)
|
|
){
|
|
int rc;
|
|
@@ -93254,14 +99538,14 @@ static int blobReadWrite(
|
|
|
|
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
|
|
if( xCall==sqlite3BtreePutData && db->xPreUpdateCallback ){
|
|
- /* If a pre-update hook is registered and this is a write cursor,
|
|
- ** invoke it here.
|
|
- **
|
|
+ /* If a pre-update hook is registered and this is a write cursor,
|
|
+ ** invoke it here.
|
|
+ **
|
|
** TODO: The preupdate-hook is passed SQLITE_DELETE, even though this
|
|
** operation should really be an SQLITE_UPDATE. This is probably
|
|
- ** incorrect, but is convenient because at this point the new.* values
|
|
- ** are not easily obtainable. And for the sessions module, an
|
|
- ** SQLITE_UPDATE where the PK columns do not change is handled in the
|
|
+ ** incorrect, but is convenient because at this point the new.* values
|
|
+ ** are not easily obtainable. And for the sessions module, an
|
|
+ ** SQLITE_UPDATE where the PK columns do not change is handled in the
|
|
** same way as an SQLITE_DELETE (the SQLITE_DELETE code is actually
|
|
** slightly more efficient). Since you cannot write to a PK column
|
|
** using the incremental-blob API, this works. For the sessions module
|
|
@@ -93269,8 +99553,10 @@ static int blobReadWrite(
|
|
*/
|
|
sqlite3_int64 iKey;
|
|
iKey = sqlite3BtreeIntegerKey(p->pCsr);
|
|
+ assert( v->apCsr[0]!=0 );
|
|
+ assert( v->apCsr[0]->eCurType==CURTYPE_BTREE );
|
|
sqlite3VdbePreUpdateHook(
|
|
- v, v->apCsr[0], SQLITE_DELETE, p->zDb, p->pTab, iKey, -1
|
|
+ v, v->apCsr[0], SQLITE_DELETE, p->zDb, p->pTab, iKey, -1, p->iCol
|
|
);
|
|
}
|
|
#endif
|
|
@@ -93321,8 +99607,8 @@ SQLITE_API int sqlite3_blob_bytes(sqlite3_blob *pBlob){
|
|
**
|
|
** If an error occurs, or if the specified row does not exist or does not
|
|
** contain a blob or text value, then an error code is returned and the
|
|
-** database handle error code and message set. If this happens, then all
|
|
-** subsequent calls to sqlite3_blob_xxx() functions (except blob_close())
|
|
+** database handle error code and message set. If this happens, then all
|
|
+** subsequent calls to sqlite3_blob_xxx() functions (except blob_close())
|
|
** immediately return SQLITE_ABORT.
|
|
*/
|
|
SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){
|
|
@@ -93341,6 +99627,7 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){
|
|
rc = SQLITE_ABORT;
|
|
}else{
|
|
char *zErr;
|
|
+ ((Vdbe*)p->pStmt)->rc = SQLITE_OK;
|
|
rc = blobSeekToRow(p, iRow, &zErr);
|
|
if( rc!=SQLITE_OK ){
|
|
sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr);
|
|
@@ -93416,7 +99703,7 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){
|
|
** is like Close() followed by Init() only
|
|
** much faster.
|
|
**
|
|
-** The interfaces above must be called in a particular order. Write() can
|
|
+** The interfaces above must be called in a particular order. Write() can
|
|
** only occur in between Init()/Reset() and Rewind(). Next(), Rowkey(), and
|
|
** Compare() can only occur in between Rewind() and Close()/Reset(). i.e.
|
|
**
|
|
@@ -93424,16 +99711,16 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){
|
|
** for each record: Write()
|
|
** Rewind()
|
|
** Rowkey()/Compare()
|
|
-** Next()
|
|
+** Next()
|
|
** Close()
|
|
**
|
|
** Algorithm:
|
|
**
|
|
-** Records passed to the sorter via calls to Write() are initially held
|
|
+** Records passed to the sorter via calls to Write() are initially held
|
|
** unsorted in main memory. Assuming the amount of memory used never exceeds
|
|
** a threshold, when Rewind() is called the set of records is sorted using
|
|
** an in-memory merge sort. In this case, no temporary files are required
|
|
-** and subsequent calls to Rowkey(), Next() and Compare() read records
|
|
+** and subsequent calls to Rowkey(), Next() and Compare() read records
|
|
** directly from main memory.
|
|
**
|
|
** If the amount of space used to store records in main memory exceeds the
|
|
@@ -93443,10 +99730,10 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){
|
|
** of PMAs may be created by merging existing PMAs together - for example
|
|
** merging two or more level-0 PMAs together creates a level-1 PMA.
|
|
**
|
|
-** The threshold for the amount of main memory to use before flushing
|
|
+** 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
|
|
+** page-cache of the main database. Specifically, the threshold is set to
|
|
+** the value returned by "PRAGMA main.page_size" multipled by
|
|
** that returned by "PRAGMA main.cache_size", in bytes.
|
|
**
|
|
** If the sorter is running in single-threaded mode, then all PMAs generated
|
|
@@ -93463,7 +99750,7 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){
|
|
** than zero, and (b) worker threads have been enabled at runtime by calling
|
|
** "PRAGMA threads=N" with some value of N greater than 0.
|
|
**
|
|
-** When Rewind() is called, any data remaining in memory is flushed to a
|
|
+** When Rewind() is called, any data remaining in memory is flushed to a
|
|
** final PMA. So at this point the data is stored in some number of sorted
|
|
** PMAs within temporary files on disk.
|
|
**
|
|
@@ -93475,16 +99762,16 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){
|
|
**
|
|
** Or, if running in multi-threaded mode, then a background thread is
|
|
** launched to merge the existing PMAs. Once the background thread has
|
|
-** merged T bytes of data into a single sorted PMA, the main thread
|
|
+** merged T bytes of data into a single sorted PMA, the main thread
|
|
** begins reading keys from that PMA while the background thread proceeds
|
|
** with merging the next T bytes of data. And so on.
|
|
**
|
|
-** Parameter T is set to half the value of the memory threshold used
|
|
+** Parameter T is set to half the value of the memory threshold used
|
|
** by Write() above to determine when to create a new PMA.
|
|
**
|
|
-** If there are more than SORTER_MAX_MERGE_COUNT PMAs in total when
|
|
-** Rewind() is called, then a hierarchy of incremental-merges is used.
|
|
-** First, T bytes of data from the first SORTER_MAX_MERGE_COUNT PMAs on
|
|
+** If there are more than SORTER_MAX_MERGE_COUNT PMAs in total when
|
|
+** Rewind() is called, then a hierarchy of incremental-merges is used.
|
|
+** First, T bytes of data from the first SORTER_MAX_MERGE_COUNT PMAs on
|
|
** disk are merged together. Then T bytes of data from the second set, and
|
|
** so on, such that no operation ever merges more than SORTER_MAX_MERGE_COUNT
|
|
** PMAs at a time. This done is to improve locality.
|
|
@@ -93499,7 +99786,7 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){
|
|
/* #include "sqliteInt.h" */
|
|
/* #include "vdbeInt.h" */
|
|
|
|
-/*
|
|
+/*
|
|
** If SQLITE_DEBUG_SORTER_THREADS is defined, this module outputs various
|
|
** messages to stderr that may be helpful in understanding the performance
|
|
** characteristics of the sorter in multi-threaded mode.
|
|
@@ -93528,7 +99815,7 @@ typedef struct SorterList SorterList; /* In-memory list of records */
|
|
typedef struct IncrMerger IncrMerger; /* Read & merge multiple PMAs */
|
|
|
|
/*
|
|
-** A container for a temp file handle and the current amount of data
|
|
+** A container for a temp file handle and the current amount of data
|
|
** stored in the file.
|
|
*/
|
|
struct SorterFile {
|
|
@@ -93568,17 +99855,17 @@ struct SorterList {
|
|
** the MergeEngine.nTree variable.
|
|
**
|
|
** The final (N/2) elements of aTree[] contain the results of comparing
|
|
-** pairs of PMA keys together. Element i contains the result of
|
|
+** pairs of PMA keys together. Element i contains the result of
|
|
** comparing aReadr[2*i-N] and aReadr[2*i-N+1]. Whichever key is smaller, the
|
|
-** aTree element is set to the index of it.
|
|
+** aTree element is set to the index of it.
|
|
**
|
|
** For the purposes of this comparison, EOF is considered greater than any
|
|
** other key value. If the keys are equal (only possible with two EOF
|
|
** values), it doesn't matter which index is stored.
|
|
**
|
|
-** The (N/4) elements of aTree[] that precede the final (N/2) described
|
|
+** The (N/4) elements of aTree[] that precede the final (N/2) described
|
|
** above contains the index of the smallest of each block of 4 PmaReaders
|
|
-** And so on. So that aTree[1] contains the index of the PmaReader that
|
|
+** And so on. So that aTree[1] contains the index of the PmaReader that
|
|
** currently points to the smallest key value. aTree[0] is unused.
|
|
**
|
|
** Example:
|
|
@@ -93594,7 +99881,7 @@ struct SorterList {
|
|
**
|
|
** aTree[] = { X, 5 0, 5 0, 3, 5, 6 }
|
|
**
|
|
-** The current element is "Apple" (the value of the key indicated by
|
|
+** The current element is "Apple" (the value of the key indicated by
|
|
** PmaReader 5). When the Next() operation is invoked, PmaReader 5 will
|
|
** be advanced to the next key in its segment. Say the next key is
|
|
** "Eggplant":
|
|
@@ -93635,8 +99922,8 @@ struct MergeEngine {
|
|
** each thread requries its own UnpackedRecord object to unpack records in
|
|
** as part of comparison operations.
|
|
**
|
|
-** Before a background thread is launched, variable bDone is set to 0. Then,
|
|
-** right before it exits, the thread itself sets bDone to 1. This is used for
|
|
+** Before a background thread is launched, variable bDone is set to 0. Then,
|
|
+** right before it exits, the thread itself sets bDone to 1. This is used for
|
|
** two purposes:
|
|
**
|
|
** 1. When flushing the contents of memory to a level-0 PMA on disk, to
|
|
@@ -93667,7 +99954,7 @@ struct SortSubtask {
|
|
|
|
|
|
/*
|
|
-** Main sorter structure. A single instance of this is allocated for each
|
|
+** Main sorter structure. A single instance of this is allocated for each
|
|
** sorter cursor created by the VDBE.
|
|
**
|
|
** mxKeysize:
|
|
@@ -93723,21 +100010,21 @@ struct PmaReader {
|
|
};
|
|
|
|
/*
|
|
-** Normally, a PmaReader object iterates through an existing PMA stored
|
|
+** Normally, a PmaReader object iterates through an existing PMA stored
|
|
** within a temp file. However, if the PmaReader.pIncr variable points to
|
|
** an object of the following type, it may be used to iterate/merge through
|
|
** multiple PMAs simultaneously.
|
|
**
|
|
-** There are two types of IncrMerger object - single (bUseThread==0) and
|
|
-** multi-threaded (bUseThread==1).
|
|
+** There are two types of IncrMerger object - single (bUseThread==0) and
|
|
+** multi-threaded (bUseThread==1).
|
|
**
|
|
-** A multi-threaded IncrMerger object uses two temporary files - aFile[0]
|
|
-** and aFile[1]. Neither file is allowed to grow to more than mxSz bytes in
|
|
-** size. When the IncrMerger is initialized, it reads enough data from
|
|
-** pMerger to populate aFile[0]. It then sets variables within the
|
|
-** corresponding PmaReader object to read from that file and kicks off
|
|
-** a background thread to populate aFile[1] with the next mxSz bytes of
|
|
-** sorted record data from pMerger.
|
|
+** A multi-threaded IncrMerger object uses two temporary files - aFile[0]
|
|
+** and aFile[1]. Neither file is allowed to grow to more than mxSz bytes in
|
|
+** size. When the IncrMerger is initialized, it reads enough data from
|
|
+** pMerger to populate aFile[0]. It then sets variables within the
|
|
+** corresponding PmaReader object to read from that file and kicks off
|
|
+** a background thread to populate aFile[1] with the next mxSz bytes of
|
|
+** sorted record data from pMerger.
|
|
**
|
|
** When the PmaReader reaches the end of aFile[0], it blocks until the
|
|
** background thread has finished populating aFile[1]. It then exchanges
|
|
@@ -93748,7 +100035,7 @@ struct PmaReader {
|
|
**
|
|
** A single-threaded IncrMerger does not open any temporary files of its
|
|
** own. Instead, it has exclusive access to mxSz bytes of space beginning
|
|
-** at offset iStartOff of file pTask->file2. And instead of using a
|
|
+** at offset iStartOff of file pTask->file2. And instead of using a
|
|
** background thread to prepare data for the PmaReader, with a single
|
|
** threaded IncrMerger the allocate part of pTask->file2 is "refilled" with
|
|
** keys from pMerger by the calling thread whenever the PmaReader runs out
|
|
@@ -93860,7 +100147,7 @@ static int vdbePmaReadBlob(
|
|
|
|
assert( p->aBuffer );
|
|
|
|
- /* If there is no more data to be read from the buffer, read the next
|
|
+ /* If there is no more data to be read from the buffer, read the next
|
|
** p->nBuffer bytes of data from the file into it. Or, if there are less
|
|
** than p->nBuffer bytes remaining in the PMA, read all remaining data. */
|
|
iBuf = p->iReadOff % p->nBuffer;
|
|
@@ -93881,11 +100168,11 @@ static int vdbePmaReadBlob(
|
|
assert( rc!=SQLITE_IOERR_SHORT_READ );
|
|
if( rc!=SQLITE_OK ) return rc;
|
|
}
|
|
- nAvail = p->nBuffer - iBuf;
|
|
+ nAvail = p->nBuffer - iBuf;
|
|
|
|
if( nByte<=nAvail ){
|
|
/* The requested data is available in the in-memory buffer. In this
|
|
- ** case there is no need to make a copy of the data, just return a
|
|
+ ** case there is no need to make a copy of the data, just return a
|
|
** pointer into the buffer to the caller. */
|
|
*ppOut = &p->aBuffer[iBuf];
|
|
p->iReadOff += nByte;
|
|
@@ -93964,7 +100251,7 @@ static int vdbePmaReadVarint(PmaReader *p, u64 *pnOut){
|
|
|
|
/*
|
|
** Attempt to memory map file pFile. If successful, set *pp to point to the
|
|
-** new mapping and return SQLITE_OK. If the mapping is not attempted
|
|
+** new mapping and return SQLITE_OK. If the mapping is not attempted
|
|
** (because the file is too large or the VFS layer is configured not to use
|
|
** mmap), return SQLITE_OK and set *pp to NULL.
|
|
**
|
|
@@ -93985,7 +100272,7 @@ static int vdbeSorterMapFile(SortSubtask *pTask, SorterFile *pFile, u8 **pp){
|
|
|
|
/*
|
|
** Attach PmaReader pReadr to file pFile (if it is not already attached to
|
|
-** that file) and seek it to offset iOff within the file. Return SQLITE_OK
|
|
+** that file) and seek it to offset iOff within the file. Return SQLITE_OK
|
|
** if successful, or an SQLite error code if an error occurs.
|
|
*/
|
|
static int vdbePmaReaderSeek(
|
|
@@ -94075,11 +100362,11 @@ static int vdbePmaReaderNext(PmaReader *pReadr){
|
|
|
|
/*
|
|
** Initialize PmaReader pReadr to scan through the PMA stored in file pFile
|
|
-** starting at offset iStart and ending at offset iEof-1. This function
|
|
-** leaves the PmaReader pointing to the first key in the PMA (or EOF if the
|
|
+** starting at offset iStart and ending at offset iEof-1. This function
|
|
+** leaves the PmaReader pointing to the first key in the PMA (or EOF if the
|
|
** PMA is empty).
|
|
**
|
|
-** If the pnByte parameter is NULL, then it is assumed that the file
|
|
+** If the pnByte parameter is NULL, then it is assumed that the file
|
|
** contains a single PMA, and that that PMA omits the initial length varint.
|
|
*/
|
|
static int vdbePmaReaderInit(
|
|
@@ -94112,7 +100399,7 @@ static int vdbePmaReaderInit(
|
|
|
|
/*
|
|
** A version of vdbeSorterCompare() that assumes that it has already been
|
|
-** determined that the first field of key1 is equal to the first field of
|
|
+** determined that the first field of key1 is equal to the first field of
|
|
** key2.
|
|
*/
|
|
static int vdbeSorterCompareTail(
|
|
@@ -94130,7 +100417,7 @@ static int vdbeSorterCompareTail(
|
|
}
|
|
|
|
/*
|
|
-** Compare key1 (buffer pKey1, size nKey1 bytes) with key2 (buffer pKey2,
|
|
+** Compare key1 (buffer pKey1, size nKey1 bytes) with key2 (buffer pKey2,
|
|
** size nKey2 bytes). Use (pTask->pKeyInfo) for the collation sequences
|
|
** used by the comparison. Return the result of the comparison.
|
|
**
|
|
@@ -94176,8 +100463,8 @@ static int vdbeSorterCompareText(
|
|
int n2;
|
|
int res;
|
|
|
|
- getVarint32(&p1[1], n1);
|
|
- getVarint32(&p2[1], n2);
|
|
+ getVarint32NR(&p1[1], n1);
|
|
+ getVarint32NR(&p2[1], n2);
|
|
res = memcmp(v1, v2, (MIN(n1, n2) - 13)/2);
|
|
if( res==0 ){
|
|
res = n1 - n2;
|
|
@@ -94276,7 +100563,7 @@ static int vdbeSorterCompareInt(
|
|
** is non-zero and the sorter is able to guarantee a stable sort, nField
|
|
** is used instead. This is used when sorting records for a CREATE INDEX
|
|
** statement. In this case, keys are always delivered to the sorter in
|
|
-** order of the primary key, which happens to be make up the final part
|
|
+** order of the primary key, which happens to be make up the final part
|
|
** of the records being sorted. So if the sort is stable, there is never
|
|
** any reason to compare PK fields and they can be ignored for a small
|
|
** performance boost.
|
|
@@ -94321,7 +100608,8 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit(
|
|
}
|
|
#endif
|
|
|
|
- assert( pCsr->pKeyInfo && pCsr->pBtx==0 );
|
|
+ assert( pCsr->pKeyInfo );
|
|
+ assert( !pCsr->isEphemeral );
|
|
assert( pCsr->eCurType==CURTYPE_SORTER );
|
|
szKeyInfo = sizeof(KeyInfo) + (pCsr->pKeyInfo->nKeyField-1)*sizeof(CollSeq*);
|
|
sz = sizeof(VdbeSorter) + nWorker * sizeof(SortSubtask);
|
|
@@ -94331,13 +100619,16 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit(
|
|
if( pSorter==0 ){
|
|
rc = SQLITE_NOMEM_BKPT;
|
|
}else{
|
|
+ Btree *pBt = db->aDb[0].pBt;
|
|
pSorter->pKeyInfo = pKeyInfo = (KeyInfo*)((u8*)pSorter + sz);
|
|
memcpy(pKeyInfo, pCsr->pKeyInfo, szKeyInfo);
|
|
pKeyInfo->db = 0;
|
|
if( nField && nWorker==0 ){
|
|
pKeyInfo->nKeyField = nField;
|
|
}
|
|
- pSorter->pgsz = pgsz = sqlite3BtreeGetPageSize(db->aDb[0].pBt);
|
|
+ sqlite3BtreeEnter(pBt);
|
|
+ pSorter->pgsz = pgsz = sqlite3BtreeGetPageSize(pBt);
|
|
+ sqlite3BtreeLeave(pBt);
|
|
pSorter->nTask = nWorker + 1;
|
|
pSorter->iPrev = (u8)(nWorker - 1);
|
|
pSorter->bUseThreads = (pSorter->nTask>1);
|
|
@@ -94373,7 +100664,7 @@ SQLITE_PRIVATE int sqlite3VdbeSorterInit(
|
|
}
|
|
}
|
|
|
|
- if( pKeyInfo->nAllField<13
|
|
+ if( pKeyInfo->nAllField<13
|
|
&& (pKeyInfo->aColl[0]==0 || pKeyInfo->aColl[0]==db->pDfltColl)
|
|
&& (pKeyInfo->aSortFlags[0] & KEYINFO_ORDER_BIGNULL)==0
|
|
){
|
|
@@ -94398,7 +100689,7 @@ static void vdbeSorterRecordFree(sqlite3 *db, SorterRecord *pRecord){
|
|
}
|
|
|
|
/*
|
|
-** Free all resources owned by the object indicated by argument pTask. All
|
|
+** Free all resources owned by the object indicated by argument pTask. All
|
|
** fields of *pTask are zeroed before returning.
|
|
*/
|
|
static void vdbeSortSubtaskCleanup(sqlite3 *db, SortSubtask *pTask){
|
|
@@ -94431,8 +100722,9 @@ static void vdbeSorterWorkDebug(SortSubtask *pTask, const char *zEvent){
|
|
fprintf(stderr, "%lld:%d %s\n", t, iTask, zEvent);
|
|
}
|
|
static void vdbeSorterRewindDebug(const char *zEvent){
|
|
- i64 t;
|
|
- sqlite3OsCurrentTimeInt64(sqlite3_vfs_find(0), &t);
|
|
+ i64 t = 0;
|
|
+ sqlite3_vfs *pVfs = sqlite3_vfs_find(0);
|
|
+ if( ALWAYS(pVfs) ) sqlite3OsCurrentTimeInt64(pVfs, &t);
|
|
fprintf(stderr, "%lld:X %s\n", t, zEvent);
|
|
}
|
|
static void vdbeSorterPopulateDebug(
|
|
@@ -94497,7 +100789,7 @@ static int vdbeSorterCreateThread(
|
|
}
|
|
|
|
/*
|
|
-** Join all outstanding threads launched by SorterWrite() to create
|
|
+** Join all outstanding threads launched by SorterWrite() to create
|
|
** level-0 PMAs.
|
|
*/
|
|
static int vdbeSorterJoinAll(VdbeSorter *pSorter, int rcin){
|
|
@@ -94506,10 +100798,10 @@ static int vdbeSorterJoinAll(VdbeSorter *pSorter, int rcin){
|
|
|
|
/* This function is always called by the main user thread.
|
|
**
|
|
- ** If this function is being called after SorterRewind() has been called,
|
|
+ ** If this function is being called after SorterRewind() has been called,
|
|
** it is possible that thread pSorter->aTask[pSorter->nTask-1].pThread
|
|
** is currently attempt to join one of the other threads. To avoid a race
|
|
- ** condition where this thread also attempts to join the same object, join
|
|
+ ** condition where this thread also attempts to join the same object, join
|
|
** thread pSorter->aTask[pSorter->nTask-1].pThread first. */
|
|
for(i=pSorter->nTask-1; i>=0; i--){
|
|
SortSubtask *pTask = &pSorter->aTask[i];
|
|
@@ -94646,7 +100938,7 @@ static void vdbeSorterExtendFile(sqlite3 *db, sqlite3_file *pFd, i64 nByte){
|
|
sqlite3OsFileControlHint(pFd, SQLITE_FCNTL_CHUNK_SIZE, &chunksize);
|
|
sqlite3OsFileControlHint(pFd, SQLITE_FCNTL_SIZE_HINT, &nByte);
|
|
sqlite3OsFetch(pFd, 0, (int)nByte, &p);
|
|
- sqlite3OsUnfetch(pFd, 0, p);
|
|
+ if( p ) sqlite3OsUnfetch(pFd, 0, p);
|
|
}
|
|
}
|
|
#else
|
|
@@ -94681,8 +100973,8 @@ static int vdbeSorterOpenTempFile(
|
|
}
|
|
|
|
/*
|
|
-** If it has not already been allocated, allocate the UnpackedRecord
|
|
-** structure at pTask->pUnpacked. Return SQLITE_OK if successful (or
|
|
+** If it has not already been allocated, allocate the UnpackedRecord
|
|
+** structure at pTask->pUnpacked. Return SQLITE_OK if successful (or
|
|
** if no allocation was required), or SQLITE_NOMEM otherwise.
|
|
*/
|
|
static int vdbeSortAllocUnpacked(SortSubtask *pTask){
|
|
@@ -94745,14 +101037,14 @@ static SorterCompare vdbeSorterGetCompare(VdbeSorter *p){
|
|
if( p->typeMask==SORTER_TYPE_INTEGER ){
|
|
return vdbeSorterCompareInt;
|
|
}else if( p->typeMask==SORTER_TYPE_TEXT ){
|
|
- return vdbeSorterCompareText;
|
|
+ return vdbeSorterCompareText;
|
|
}
|
|
return vdbeSorterCompare;
|
|
}
|
|
|
|
/*
|
|
-** Sort the linked list of records headed at pTask->pList. Return
|
|
-** SQLITE_OK if successful, or an SQLite error code (i.e. SQLITE_NOMEM) if
|
|
+** Sort the linked list of records headed at pTask->pList. Return
|
|
+** SQLITE_OK if successful, or an SQLite error code (i.e. SQLITE_NOMEM) if
|
|
** an error occurs.
|
|
*/
|
|
static int vdbeSorterSort(SortSubtask *pTask, SorterList *pList){
|
|
@@ -94797,8 +101089,8 @@ static int vdbeSorterSort(SortSubtask *pTask, SorterList *pList){
|
|
}
|
|
pList->pList = p;
|
|
|
|
- assert( pTask->pUnpacked->errCode==SQLITE_OK
|
|
- || pTask->pUnpacked->errCode==SQLITE_NOMEM
|
|
+ assert( pTask->pUnpacked->errCode==SQLITE_OK
|
|
+ || pTask->pUnpacked->errCode==SQLITE_NOMEM
|
|
);
|
|
return pTask->pUnpacked->errCode;
|
|
}
|
|
@@ -94839,8 +101131,8 @@ static void vdbePmaWriteBlob(PmaWriter *p, u8 *pData, int nData){
|
|
memcpy(&p->aBuffer[p->iBufEnd], &pData[nData-nRem], nCopy);
|
|
p->iBufEnd += nCopy;
|
|
if( p->iBufEnd==p->nBuffer ){
|
|
- p->eFWErr = sqlite3OsWrite(p->pFd,
|
|
- &p->aBuffer[p->iBufStart], p->iBufEnd - p->iBufStart,
|
|
+ p->eFWErr = sqlite3OsWrite(p->pFd,
|
|
+ &p->aBuffer[p->iBufStart], p->iBufEnd - p->iBufStart,
|
|
p->iWriteOff + p->iBufStart
|
|
);
|
|
p->iBufStart = p->iBufEnd = 0;
|
|
@@ -94855,7 +101147,7 @@ static void vdbePmaWriteBlob(PmaWriter *p, u8 *pData, int nData){
|
|
/*
|
|
** Flush any buffered data to disk and clean up the PMA-writer object.
|
|
** The results of using the PMA-writer after this call are undefined.
|
|
-** Return SQLITE_OK if flushing the buffered data succeeds or is not
|
|
+** Return SQLITE_OK if flushing the buffered data succeeds or is not
|
|
** required. Otherwise, return an SQLite error code.
|
|
**
|
|
** Before returning, set *piEof to the offset immediately following the
|
|
@@ -94864,8 +101156,8 @@ static void vdbePmaWriteBlob(PmaWriter *p, u8 *pData, int nData){
|
|
static int vdbePmaWriterFinish(PmaWriter *p, i64 *piEof){
|
|
int rc;
|
|
if( p->eFWErr==0 && ALWAYS(p->aBuffer) && p->iBufEnd>p->iBufStart ){
|
|
- p->eFWErr = sqlite3OsWrite(p->pFd,
|
|
- &p->aBuffer[p->iBufStart], p->iBufEnd - p->iBufStart,
|
|
+ p->eFWErr = sqlite3OsWrite(p->pFd,
|
|
+ &p->aBuffer[p->iBufStart], p->iBufEnd - p->iBufStart,
|
|
p->iWriteOff + p->iBufStart
|
|
);
|
|
}
|
|
@@ -94877,11 +101169,11 @@ static int vdbePmaWriterFinish(PmaWriter *p, i64 *piEof){
|
|
}
|
|
|
|
/*
|
|
-** Write value iVal encoded as a varint to the PMA. Return
|
|
+** Write value iVal encoded as a varint to the PMA. Return
|
|
** SQLITE_OK if successful, or an SQLite error code if an error occurs.
|
|
*/
|
|
static void vdbePmaWriteVarint(PmaWriter *p, u64 iVal){
|
|
- int nByte;
|
|
+ int nByte;
|
|
u8 aByte[10];
|
|
nByte = sqlite3PutVarint(aByte, iVal);
|
|
vdbePmaWriteBlob(p, aByte, nByte);
|
|
@@ -94889,7 +101181,7 @@ static void vdbePmaWriteVarint(PmaWriter *p, u64 iVal){
|
|
|
|
/*
|
|
** Write the current contents of in-memory linked-list pList to a level-0
|
|
-** PMA in the temp file belonging to sub-task pTask. Return SQLITE_OK if
|
|
+** PMA in the temp file belonging to sub-task pTask. Return SQLITE_OK if
|
|
** successful, or an SQLite error code otherwise.
|
|
**
|
|
** The format of a PMA is:
|
|
@@ -94897,8 +101189,8 @@ static void vdbePmaWriteVarint(PmaWriter *p, u64 iVal){
|
|
** * A varint. This varint contains the total number of bytes of content
|
|
** in the PMA (not including the varint itself).
|
|
**
|
|
-** * One or more records packed end-to-end in order of ascending keys.
|
|
-** Each record consists of a varint followed by a blob of data (the
|
|
+** * One or more records packed end-to-end in order of ascending keys.
|
|
+** Each record consists of a varint followed by a blob of data (the
|
|
** key). The varint is the number of bytes in the blob of data.
|
|
*/
|
|
static int vdbeSorterListToPMA(SortSubtask *pTask, SorterList *pList){
|
|
@@ -94907,7 +101199,7 @@ static int vdbeSorterListToPMA(SortSubtask *pTask, SorterList *pList){
|
|
PmaWriter writer; /* Object used to write to the file */
|
|
|
|
#ifdef SQLITE_DEBUG
|
|
- /* Set iSz to the expected size of file pTask->file after writing the PMA.
|
|
+ /* Set iSz to the expected size of file pTask->file after writing the PMA.
|
|
** This is used by an assert() statement at the end of this function. */
|
|
i64 iSz = pList->szPMA + sqlite3VarintLen(pList->szPMA) + pTask->file.iEof;
|
|
#endif
|
|
@@ -95060,7 +101352,7 @@ static int vdbeSorterFlushPMA(VdbeSorter *pSorter){
|
|
SortSubtask *pTask = 0; /* Thread context used to create new PMA */
|
|
int nWorker = (pSorter->nTask-1);
|
|
|
|
- /* Set the flag to indicate that at least one PMA has been written.
|
|
+ /* Set the flag to indicate that at least one PMA has been written.
|
|
** Or will be, anyhow. */
|
|
pSorter->bUsePMA = 1;
|
|
|
|
@@ -95070,7 +101362,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 prefered as they use background threads - the final
|
|
** sub-task uses the main thread. */
|
|
for(i=0; i<nWorker; i++){
|
|
int iTest = (pSorter->iPrev + i + 1) % nWorker;
|
|
@@ -95134,7 +101426,7 @@ SQLITE_PRIVATE int sqlite3VdbeSorterWrite(
|
|
|
|
assert( pCsr->eCurType==CURTYPE_SORTER );
|
|
pSorter = pCsr->uc.pSorter;
|
|
- getVarint32((const u8*)&pVal->z[1], t);
|
|
+ getVarint32NR((const u8*)&pVal->z[1], t);
|
|
if( t>0 && t<10 && t!=7 ){
|
|
pSorter->typeMask &= SORTER_TYPE_INTEGER;
|
|
}else if( t>10 && (t & 0x01) ){
|
|
@@ -95151,14 +101443,14 @@ SQLITE_PRIVATE int sqlite3VdbeSorterWrite(
|
|
** If using the single large allocation mode (pSorter->aMemory!=0), then
|
|
** flush the contents of memory to a new PMA if (a) at least one value is
|
|
** already in memory and (b) the new value will not fit in memory.
|
|
- **
|
|
+ **
|
|
** Or, if using separate allocations for each record, flush the contents
|
|
** of memory to a PMA if either of the following are true:
|
|
**
|
|
- ** * The total memory allocated for the in-memory list is greater
|
|
+ ** * The total memory allocated for the in-memory list is greater
|
|
** than (page-size * cache-size), or
|
|
**
|
|
- ** * The total memory allocated for the in-memory list is greater
|
|
+ ** * The total memory allocated for the in-memory list is greater
|
|
** than (page-size * 10) and sqlite3HeapNearlyFull() returns true.
|
|
*/
|
|
nReq = pVal->n + sizeof(SorterRecord);
|
|
@@ -95297,11 +101589,11 @@ static int vdbeIncrBgPopulate(IncrMerger *pIncr){
|
|
** aFile[0] such that the PmaReader should start rereading it from the
|
|
** beginning.
|
|
**
|
|
-** For single-threaded objects, this is accomplished by literally reading
|
|
-** keys from pIncr->pMerger and repopulating aFile[0].
|
|
+** For single-threaded objects, this is accomplished by literally reading
|
|
+** keys from pIncr->pMerger and repopulating aFile[0].
|
|
**
|
|
-** For multi-threaded objects, all that is required is to wait until the
|
|
-** background thread is finished (if it is not already) and then swap
|
|
+** For multi-threaded objects, all that is required is to wait until the
|
|
+** background thread is finished (if it is not already) and then swap
|
|
** aFile[0] and aFile[1] in place. If the contents of pMerger have not
|
|
** been exhausted, this function also launches a new background thread
|
|
** to populate the new aFile[1].
|
|
@@ -95364,6 +101656,7 @@ static int vdbeIncrMergerNew(
|
|
vdbeMergeEngineFree(pMerger);
|
|
rc = SQLITE_NOMEM_BKPT;
|
|
}
|
|
+ assert( *ppOut!=0 || rc!=SQLITE_OK );
|
|
return rc;
|
|
}
|
|
|
|
@@ -95441,7 +101734,7 @@ static void vdbeMergeEngineCompare(
|
|
#define INCRINIT_TASK 1
|
|
#define INCRINIT_ROOT 2
|
|
|
|
-/*
|
|
+/*
|
|
** Forward reference required as the vdbeIncrMergeInit() and
|
|
** vdbePmaReaderIncrInit() routines are called mutually recursively when
|
|
** building a merge tree.
|
|
@@ -95450,7 +101743,7 @@ static int vdbePmaReaderIncrInit(PmaReader *pReadr, int eMode);
|
|
|
|
/*
|
|
** Initialize the MergeEngine object passed as the second argument. Once this
|
|
-** function returns, the first key of merged data may be read from the
|
|
+** function returns, the first key of merged data may be read from the
|
|
** MergeEngine object in the usual fashion.
|
|
**
|
|
** If argument eMode is INCRINIT_ROOT, then it is assumed that any IncrMerge
|
|
@@ -95460,8 +101753,8 @@ static int vdbePmaReaderIncrInit(PmaReader *pReadr, int eMode);
|
|
** required is to call vdbePmaReaderNext() on each PmaReader to point it at
|
|
** its first key.
|
|
**
|
|
-** Otherwise, if eMode is any value other than INCRINIT_ROOT, then use
|
|
-** vdbePmaReaderIncrMergeInit() to initialize each PmaReader that feeds data
|
|
+** Otherwise, if eMode is any value other than INCRINIT_ROOT, then use
|
|
+** vdbePmaReaderIncrMergeInit() to initialize each PmaReader that feeds data
|
|
** to pMerger.
|
|
**
|
|
** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
|
|
@@ -95516,19 +101809,19 @@ static int vdbeMergeEngineInit(
|
|
** object at (pReadr->pIncr).
|
|
**
|
|
** If argument eMode is set to INCRINIT_NORMAL, then all PmaReaders
|
|
-** in the sub-tree headed by pReadr are also initialized. Data is then
|
|
-** loaded into the buffers belonging to pReadr and it is set to point to
|
|
+** in the sub-tree headed by pReadr are also initialized. Data is then
|
|
+** loaded into the buffers belonging to pReadr and it is set to point to
|
|
** the first key in its range.
|
|
**
|
|
** If argument eMode is set to INCRINIT_TASK, then pReadr is guaranteed
|
|
** to be a multi-threaded PmaReader and this function is being called in a
|
|
-** background thread. In this case all PmaReaders in the sub-tree are
|
|
+** background thread. In this case all PmaReaders in the sub-tree are
|
|
** initialized as for INCRINIT_NORMAL and the aFile[1] buffer belonging to
|
|
** pReadr is populated. However, pReadr itself is not set up to point
|
|
** to its first key. A call to vdbePmaReaderNext() is still required to do
|
|
-** that.
|
|
+** that.
|
|
**
|
|
-** The reason this function does not call vdbePmaReaderNext() immediately
|
|
+** The reason this function does not call vdbePmaReaderNext() immediately
|
|
** in the INCRINIT_TASK case is that vdbePmaReaderNext() assumes that it has
|
|
** to block on thread (pTask->thread) before accessing aFile[1]. But, since
|
|
** this entire function is being run by thread (pTask->thread), that will
|
|
@@ -95584,12 +101877,12 @@ static int vdbePmaReaderIncrMergeInit(PmaReader *pReadr, int eMode){
|
|
if( rc==SQLITE_OK && pIncr->bUseThread ){
|
|
/* Use the current thread to populate aFile[1], even though this
|
|
** PmaReader is multi-threaded. If this is an INCRINIT_TASK object,
|
|
- ** then this function is already running in background thread
|
|
- ** pIncr->pTask->thread.
|
|
+ ** then this function is already running in background thread
|
|
+ ** pIncr->pTask->thread.
|
|
**
|
|
- ** If this is the INCRINIT_ROOT object, then it is running in the
|
|
+ ** If this is the INCRINIT_ROOT object, then it is running in the
|
|
** main VDBE thread. But that is Ok, as that thread cannot return
|
|
- ** control to the VDBE or proceed with anything useful until the
|
|
+ ** control to the VDBE or proceed with anything useful until the
|
|
** first results are ready from this merger object anyway.
|
|
*/
|
|
assert( eMode==INCRINIT_ROOT || eMode==INCRINIT_TASK );
|
|
@@ -95606,7 +101899,7 @@ static int vdbePmaReaderIncrMergeInit(PmaReader *pReadr, int eMode){
|
|
|
|
#if SQLITE_MAX_WORKER_THREADS>0
|
|
/*
|
|
-** The main routine for vdbePmaReaderIncrMergeInit() operations run in
|
|
+** The main routine for vdbePmaReaderIncrMergeInit() operations run in
|
|
** background threads.
|
|
*/
|
|
static void *vdbePmaReaderBgIncrInit(void *pCtx){
|
|
@@ -95624,8 +101917,8 @@ static void *vdbePmaReaderBgIncrInit(void *pCtx){
|
|
** (if pReadr->pIncr==0), then this function is a no-op. Otherwise, it invokes
|
|
** the vdbePmaReaderIncrMergeInit() function with the parameters passed to
|
|
** this routine to initialize the incremental merge.
|
|
-**
|
|
-** If the IncrMerger object is multi-threaded (IncrMerger.bUseThread==1),
|
|
+**
|
|
+** If the IncrMerger object is multi-threaded (IncrMerger.bUseThread==1),
|
|
** then a background thread is launched to call vdbePmaReaderIncrMergeInit().
|
|
** Or, if the IncrMerger is single threaded, the same function is called
|
|
** using the current thread.
|
|
@@ -95655,7 +101948,7 @@ static int vdbePmaReaderIncrInit(PmaReader *pReadr, int eMode){
|
|
** to NULL and return an SQLite error code.
|
|
**
|
|
** When this function is called, *piOffset is set to the offset of the
|
|
-** first PMA to read from pTask->file. Assuming no error occurs, it is
|
|
+** first PMA to read from pTask->file. Assuming no error occurs, it is
|
|
** set to the offset immediately following the last byte of the last
|
|
** PMA before returning. If an error does occur, then the final value of
|
|
** *piOffset is undefined.
|
|
@@ -95765,12 +102058,12 @@ static int vdbeSorterAddToTree(
|
|
/*
|
|
** This function is called as part of a SorterRewind() operation on a sorter
|
|
** that has already written two or more level-0 PMAs to one or more temp
|
|
-** files. It builds a tree of MergeEngine/IncrMerger/PmaReader objects that
|
|
+** files. It builds a tree of MergeEngine/IncrMerger/PmaReader objects that
|
|
** can be used to incrementally merge all PMAs on disk.
|
|
**
|
|
** If successful, SQLITE_OK is returned and *ppOut set to point to the
|
|
** MergeEngine object at the root of the tree before returning. Or, if an
|
|
-** error occurs, an SQLite error code is returned and the final value
|
|
+** error occurs, an SQLite error code is returned and the final value
|
|
** of *ppOut is undefined.
|
|
*/
|
|
static int vdbeSorterMergeTreeBuild(
|
|
@@ -95782,8 +102075,8 @@ static int vdbeSorterMergeTreeBuild(
|
|
int iTask;
|
|
|
|
#if SQLITE_MAX_WORKER_THREADS>0
|
|
- /* If the sorter uses more than one task, then create the top-level
|
|
- ** MergeEngine here. This MergeEngine will read data from exactly
|
|
+ /* If the sorter uses more than one task, then create the top-level
|
|
+ ** MergeEngine here. This MergeEngine will read data from exactly
|
|
** one PmaReader per sub-task. */
|
|
assert( pSorter->bUseThreads || pSorter->nTask==1 );
|
|
if( pSorter->nTask>1 ){
|
|
@@ -95892,7 +102185,7 @@ static int vdbeSorterSetupMerge(VdbeSorter *pSorter){
|
|
}
|
|
for(iTask=0; rc==SQLITE_OK && iTask<pSorter->nTask; iTask++){
|
|
/* Check that:
|
|
- **
|
|
+ **
|
|
** a) The incremental merge object is configured to use the
|
|
** right task, and
|
|
** b) If it is using task (nTask-1), it is configured to run
|
|
@@ -95955,7 +102248,7 @@ SQLITE_PRIVATE int sqlite3VdbeSorterRewind(const VdbeCursor *pCsr, int *pbEof){
|
|
return rc;
|
|
}
|
|
|
|
- /* Write the current in-memory list to a PMA. When the VdbeSorterWrite()
|
|
+ /* Write the current in-memory list to a PMA. When the VdbeSorterWrite()
|
|
** function flushes the contents of memory to disk, it immediately always
|
|
** creates a new list consisting of a single key immediately afterwards.
|
|
** So the list is never empty at this point. */
|
|
@@ -95967,7 +102260,7 @@ SQLITE_PRIVATE int sqlite3VdbeSorterRewind(const VdbeCursor *pCsr, int *pbEof){
|
|
|
|
vdbeSorterRewindDebug("rewind");
|
|
|
|
- /* Assuming no errors have occurred, set up a merger structure to
|
|
+ /* Assuming no errors have occurred, set up a merger structure to
|
|
** incrementally read and merge all remaining PMAs. */
|
|
assert( pSorter->pReader==0 );
|
|
if( rc==SQLITE_OK ){
|
|
@@ -96021,7 +102314,7 @@ SQLITE_PRIVATE int sqlite3VdbeSorterNext(sqlite3 *db, const VdbeCursor *pCsr){
|
|
}
|
|
|
|
/*
|
|
-** Return a pointer to a buffer owned by the sorter that contains the
|
|
+** Return a pointer to a buffer owned by the sorter that contains the
|
|
** current key.
|
|
*/
|
|
static void *vdbeSorterRowkey(
|
|
@@ -96121,6 +102414,437 @@ SQLITE_PRIVATE int sqlite3VdbeSorterCompare(
|
|
}
|
|
|
|
/************** End of vdbesort.c ********************************************/
|
|
+/************** Begin file vdbevtab.c ****************************************/
|
|
+/*
|
|
+** 2020-03-23
|
|
+**
|
|
+** The author disclaims copyright to this source code. In place of
|
|
+** a legal notice, here is a blessing:
|
|
+**
|
|
+** May you do good and not evil.
|
|
+** May you find forgiveness for yourself and forgive others.
|
|
+** May you share freely, never taking more than you give.
|
|
+**
|
|
+*************************************************************************
|
|
+**
|
|
+** This file implements virtual-tables for examining the bytecode content
|
|
+** of a prepared statement.
|
|
+*/
|
|
+/* #include "sqliteInt.h" */
|
|
+#if defined(SQLITE_ENABLE_BYTECODE_VTAB) && !defined(SQLITE_OMIT_VIRTUALTABLE)
|
|
+/* #include "vdbeInt.h" */
|
|
+
|
|
+/* An instance of the bytecode() table-valued function.
|
|
+*/
|
|
+typedef struct bytecodevtab bytecodevtab;
|
|
+struct bytecodevtab {
|
|
+ sqlite3_vtab base; /* Base class - must be first */
|
|
+ sqlite3 *db; /* Database connection */
|
|
+ int bTablesUsed; /* 2 for tables_used(). 0 for bytecode(). */
|
|
+};
|
|
+
|
|
+/* A cursor for scanning through the bytecode
|
|
+*/
|
|
+typedef struct bytecodevtab_cursor bytecodevtab_cursor;
|
|
+struct bytecodevtab_cursor {
|
|
+ sqlite3_vtab_cursor base; /* Base class - must be first */
|
|
+ sqlite3_stmt *pStmt; /* The statement whose bytecode is displayed */
|
|
+ int iRowid; /* The rowid of the output table */
|
|
+ int iAddr; /* Address */
|
|
+ int needFinalize; /* Cursors owns pStmt and must finalize it */
|
|
+ int showSubprograms; /* Provide a listing of subprograms */
|
|
+ Op *aOp; /* Operand array */
|
|
+ char *zP4; /* Rendered P4 value */
|
|
+ const char *zType; /* tables_used.type */
|
|
+ const char *zSchema; /* tables_used.schema */
|
|
+ const char *zName; /* tables_used.name */
|
|
+ Mem sub; /* Subprograms */
|
|
+};
|
|
+
|
|
+/*
|
|
+** Create a new bytecode() table-valued function.
|
|
+*/
|
|
+static int bytecodevtabConnect(
|
|
+ sqlite3 *db,
|
|
+ void *pAux,
|
|
+ int argc, const char *const*argv,
|
|
+ sqlite3_vtab **ppVtab,
|
|
+ char **pzErr
|
|
+){
|
|
+ bytecodevtab *pNew;
|
|
+ int rc;
|
|
+ int isTabUsed = pAux!=0;
|
|
+ const char *azSchema[2] = {
|
|
+ /* bytecode() schema */
|
|
+ "CREATE TABLE x("
|
|
+ "addr INT,"
|
|
+ "opcode TEXT,"
|
|
+ "p1 INT,"
|
|
+ "p2 INT,"
|
|
+ "p3 INT,"
|
|
+ "p4 TEXT,"
|
|
+ "p5 INT,"
|
|
+ "comment TEXT,"
|
|
+ "subprog TEXT,"
|
|
+ "stmt HIDDEN"
|
|
+ ");",
|
|
+
|
|
+ /* Tables_used() schema */
|
|
+ "CREATE TABLE x("
|
|
+ "type TEXT,"
|
|
+ "schema TEXT,"
|
|
+ "name TEXT,"
|
|
+ "wr INT,"
|
|
+ "subprog TEXT,"
|
|
+ "stmt HIDDEN"
|
|
+ ");"
|
|
+ };
|
|
+
|
|
+ (void)argc;
|
|
+ (void)argv;
|
|
+ (void)pzErr;
|
|
+ rc = sqlite3_declare_vtab(db, azSchema[isTabUsed]);
|
|
+ if( rc==SQLITE_OK ){
|
|
+ pNew = sqlite3_malloc( sizeof(*pNew) );
|
|
+ *ppVtab = (sqlite3_vtab*)pNew;
|
|
+ if( pNew==0 ) return SQLITE_NOMEM;
|
|
+ memset(pNew, 0, sizeof(*pNew));
|
|
+ pNew->db = db;
|
|
+ pNew->bTablesUsed = isTabUsed*2;
|
|
+ }
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/*
|
|
+** This method is the destructor for bytecodevtab objects.
|
|
+*/
|
|
+static int bytecodevtabDisconnect(sqlite3_vtab *pVtab){
|
|
+ bytecodevtab *p = (bytecodevtab*)pVtab;
|
|
+ sqlite3_free(p);
|
|
+ return SQLITE_OK;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Constructor for a new bytecodevtab_cursor object.
|
|
+*/
|
|
+static int bytecodevtabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
|
|
+ bytecodevtab *pVTab = (bytecodevtab*)p;
|
|
+ bytecodevtab_cursor *pCur;
|
|
+ pCur = sqlite3_malloc( sizeof(*pCur) );
|
|
+ if( pCur==0 ) return SQLITE_NOMEM;
|
|
+ memset(pCur, 0, sizeof(*pCur));
|
|
+ sqlite3VdbeMemInit(&pCur->sub, pVTab->db, 1);
|
|
+ *ppCursor = &pCur->base;
|
|
+ return SQLITE_OK;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Clear all internal content from a bytecodevtab cursor.
|
|
+*/
|
|
+static void bytecodevtabCursorClear(bytecodevtab_cursor *pCur){
|
|
+ sqlite3_free(pCur->zP4);
|
|
+ pCur->zP4 = 0;
|
|
+ sqlite3VdbeMemRelease(&pCur->sub);
|
|
+ sqlite3VdbeMemSetNull(&pCur->sub);
|
|
+ if( pCur->needFinalize ){
|
|
+ sqlite3_finalize(pCur->pStmt);
|
|
+ }
|
|
+ pCur->pStmt = 0;
|
|
+ pCur->needFinalize = 0;
|
|
+ pCur->zType = 0;
|
|
+ pCur->zSchema = 0;
|
|
+ pCur->zName = 0;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Destructor for a bytecodevtab_cursor.
|
|
+*/
|
|
+static int bytecodevtabClose(sqlite3_vtab_cursor *cur){
|
|
+ bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur;
|
|
+ bytecodevtabCursorClear(pCur);
|
|
+ sqlite3_free(pCur);
|
|
+ return SQLITE_OK;
|
|
+}
|
|
+
|
|
+
|
|
+/*
|
|
+** Advance a bytecodevtab_cursor to its next row of output.
|
|
+*/
|
|
+static int bytecodevtabNext(sqlite3_vtab_cursor *cur){
|
|
+ bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur;
|
|
+ bytecodevtab *pTab = (bytecodevtab*)cur->pVtab;
|
|
+ int rc;
|
|
+ if( pCur->zP4 ){
|
|
+ sqlite3_free(pCur->zP4);
|
|
+ pCur->zP4 = 0;
|
|
+ }
|
|
+ if( pCur->zName ){
|
|
+ pCur->zName = 0;
|
|
+ pCur->zType = 0;
|
|
+ pCur->zSchema = 0;
|
|
+ }
|
|
+ rc = sqlite3VdbeNextOpcode(
|
|
+ (Vdbe*)pCur->pStmt,
|
|
+ pCur->showSubprograms ? &pCur->sub : 0,
|
|
+ pTab->bTablesUsed,
|
|
+ &pCur->iRowid,
|
|
+ &pCur->iAddr,
|
|
+ &pCur->aOp);
|
|
+ if( rc!=SQLITE_OK ){
|
|
+ sqlite3VdbeMemSetNull(&pCur->sub);
|
|
+ pCur->aOp = 0;
|
|
+ }
|
|
+ return SQLITE_OK;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Return TRUE if the cursor has been moved off of the last
|
|
+** row of output.
|
|
+*/
|
|
+static int bytecodevtabEof(sqlite3_vtab_cursor *cur){
|
|
+ bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur;
|
|
+ return pCur->aOp==0;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Return values of columns for the row at which the bytecodevtab_cursor
|
|
+** is currently pointing.
|
|
+*/
|
|
+static int bytecodevtabColumn(
|
|
+ sqlite3_vtab_cursor *cur, /* The cursor */
|
|
+ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
|
|
+ int i /* Which column to return */
|
|
+){
|
|
+ bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur;
|
|
+ bytecodevtab *pVTab = (bytecodevtab*)cur->pVtab;
|
|
+ Op *pOp = pCur->aOp + pCur->iAddr;
|
|
+ if( pVTab->bTablesUsed ){
|
|
+ if( i==4 ){
|
|
+ i = 8;
|
|
+ }else{
|
|
+ if( i<=2 && pCur->zType==0 ){
|
|
+ Schema *pSchema;
|
|
+ HashElem *k;
|
|
+ int iDb = pOp->p3;
|
|
+ Pgno iRoot = (Pgno)pOp->p2;
|
|
+ sqlite3 *db = pVTab->db;
|
|
+ pSchema = db->aDb[iDb].pSchema;
|
|
+ pCur->zSchema = db->aDb[iDb].zDbSName;
|
|
+ for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){
|
|
+ Table *pTab = (Table*)sqliteHashData(k);
|
|
+ if( !IsVirtual(pTab) && pTab->tnum==iRoot ){
|
|
+ pCur->zName = pTab->zName;
|
|
+ pCur->zType = "table";
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ if( pCur->zName==0 ){
|
|
+ for(k=sqliteHashFirst(&pSchema->idxHash); k; k=sqliteHashNext(k)){
|
|
+ Index *pIdx = (Index*)sqliteHashData(k);
|
|
+ if( pIdx->tnum==iRoot ){
|
|
+ pCur->zName = pIdx->zName;
|
|
+ pCur->zType = "index";
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ i += 10;
|
|
+ }
|
|
+ }
|
|
+ switch( i ){
|
|
+ case 0: /* addr */
|
|
+ sqlite3_result_int(ctx, pCur->iAddr);
|
|
+ break;
|
|
+ case 1: /* opcode */
|
|
+ sqlite3_result_text(ctx, (char*)sqlite3OpcodeName(pOp->opcode),
|
|
+ -1, SQLITE_STATIC);
|
|
+ break;
|
|
+ case 2: /* p1 */
|
|
+ sqlite3_result_int(ctx, pOp->p1);
|
|
+ break;
|
|
+ case 3: /* p2 */
|
|
+ sqlite3_result_int(ctx, pOp->p2);
|
|
+ break;
|
|
+ case 4: /* p3 */
|
|
+ sqlite3_result_int(ctx, pOp->p3);
|
|
+ break;
|
|
+ case 5: /* p4 */
|
|
+ case 7: /* comment */
|
|
+ if( pCur->zP4==0 ){
|
|
+ pCur->zP4 = sqlite3VdbeDisplayP4(pVTab->db, pOp);
|
|
+ }
|
|
+ if( i==5 ){
|
|
+ sqlite3_result_text(ctx, pCur->zP4, -1, SQLITE_STATIC);
|
|
+ }else{
|
|
+#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
|
|
+ char *zCom = sqlite3VdbeDisplayComment(pVTab->db, pOp, pCur->zP4);
|
|
+ sqlite3_result_text(ctx, zCom, -1, sqlite3_free);
|
|
+#endif
|
|
+ }
|
|
+ break;
|
|
+ case 6: /* p5 */
|
|
+ sqlite3_result_int(ctx, pOp->p5);
|
|
+ break;
|
|
+ case 8: { /* subprog */
|
|
+ Op *aOp = pCur->aOp;
|
|
+ assert( aOp[0].opcode==OP_Init );
|
|
+ assert( aOp[0].p4.z==0 || strncmp(aOp[0].p4.z,"-" "- ",3)==0 );
|
|
+ if( pCur->iRowid==pCur->iAddr+1 ){
|
|
+ break; /* Result is NULL for the main program */
|
|
+ }else if( aOp[0].p4.z!=0 ){
|
|
+ sqlite3_result_text(ctx, aOp[0].p4.z+3, -1, SQLITE_STATIC);
|
|
+ }else{
|
|
+ sqlite3_result_text(ctx, "(FK)", 4, SQLITE_STATIC);
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+ case 10: /* tables_used.type */
|
|
+ sqlite3_result_text(ctx, pCur->zType, -1, SQLITE_STATIC);
|
|
+ break;
|
|
+ case 11: /* tables_used.schema */
|
|
+ sqlite3_result_text(ctx, pCur->zSchema, -1, SQLITE_STATIC);
|
|
+ break;
|
|
+ case 12: /* tables_used.name */
|
|
+ sqlite3_result_text(ctx, pCur->zName, -1, SQLITE_STATIC);
|
|
+ break;
|
|
+ case 13: /* tables_used.wr */
|
|
+ sqlite3_result_int(ctx, pOp->opcode==OP_OpenWrite);
|
|
+ break;
|
|
+ }
|
|
+ return SQLITE_OK;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Return the rowid for the current row. In this implementation, the
|
|
+** rowid is the same as the output value.
|
|
+*/
|
|
+static int bytecodevtabRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
|
|
+ bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur;
|
|
+ *pRowid = pCur->iRowid;
|
|
+ return SQLITE_OK;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Initialize a cursor.
|
|
+**
|
|
+** idxNum==0 means show all subprograms
|
|
+** idxNum==1 means show only the main bytecode and omit subprograms.
|
|
+*/
|
|
+static int bytecodevtabFilter(
|
|
+ sqlite3_vtab_cursor *pVtabCursor,
|
|
+ int idxNum, const char *idxStr,
|
|
+ int argc, sqlite3_value **argv
|
|
+){
|
|
+ bytecodevtab_cursor *pCur = (bytecodevtab_cursor *)pVtabCursor;
|
|
+ bytecodevtab *pVTab = (bytecodevtab *)pVtabCursor->pVtab;
|
|
+ int rc = SQLITE_OK;
|
|
+ (void)idxStr;
|
|
+
|
|
+ bytecodevtabCursorClear(pCur);
|
|
+ pCur->iRowid = 0;
|
|
+ pCur->iAddr = 0;
|
|
+ pCur->showSubprograms = idxNum==0;
|
|
+ assert( argc==1 );
|
|
+ if( sqlite3_value_type(argv[0])==SQLITE_TEXT ){
|
|
+ const char *zSql = (const char*)sqlite3_value_text(argv[0]);
|
|
+ if( zSql==0 ){
|
|
+ rc = SQLITE_NOMEM;
|
|
+ }else{
|
|
+ rc = sqlite3_prepare_v2(pVTab->db, zSql, -1, &pCur->pStmt, 0);
|
|
+ pCur->needFinalize = 1;
|
|
+ }
|
|
+ }else{
|
|
+ pCur->pStmt = (sqlite3_stmt*)sqlite3_value_pointer(argv[0],"stmt-pointer");
|
|
+ }
|
|
+ if( pCur->pStmt==0 ){
|
|
+ pVTab->base.zErrMsg = sqlite3_mprintf(
|
|
+ "argument to %s() is not a valid SQL statement",
|
|
+ pVTab->bTablesUsed ? "tables_used" : "bytecode"
|
|
+ );
|
|
+ rc = SQLITE_ERROR;
|
|
+ }else{
|
|
+ bytecodevtabNext(pVtabCursor);
|
|
+ }
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/*
|
|
+** We must have a single stmt=? constraint that will be passed through
|
|
+** into the xFilter method. If there is no valid stmt=? constraint,
|
|
+** then return an SQLITE_CONSTRAINT error.
|
|
+*/
|
|
+static int bytecodevtabBestIndex(
|
|
+ sqlite3_vtab *tab,
|
|
+ sqlite3_index_info *pIdxInfo
|
|
+){
|
|
+ int i;
|
|
+ int rc = SQLITE_CONSTRAINT;
|
|
+ struct sqlite3_index_constraint *p;
|
|
+ bytecodevtab *pVTab = (bytecodevtab*)tab;
|
|
+ int iBaseCol = pVTab->bTablesUsed ? 4 : 8;
|
|
+ pIdxInfo->estimatedCost = (double)100;
|
|
+ pIdxInfo->estimatedRows = 100;
|
|
+ pIdxInfo->idxNum = 0;
|
|
+ for(i=0, p=pIdxInfo->aConstraint; i<pIdxInfo->nConstraint; i++, p++){
|
|
+ if( p->usable==0 ) continue;
|
|
+ if( p->op==SQLITE_INDEX_CONSTRAINT_EQ && p->iColumn==iBaseCol+1 ){
|
|
+ rc = SQLITE_OK;
|
|
+ pIdxInfo->aConstraintUsage[i].omit = 1;
|
|
+ pIdxInfo->aConstraintUsage[i].argvIndex = 1;
|
|
+ }
|
|
+ if( p->op==SQLITE_INDEX_CONSTRAINT_ISNULL && p->iColumn==iBaseCol ){
|
|
+ pIdxInfo->aConstraintUsage[i].omit = 1;
|
|
+ pIdxInfo->idxNum = 1;
|
|
+ }
|
|
+ }
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/*
|
|
+** This following structure defines all the methods for the
|
|
+** virtual table.
|
|
+*/
|
|
+static sqlite3_module bytecodevtabModule = {
|
|
+ /* iVersion */ 0,
|
|
+ /* xCreate */ 0,
|
|
+ /* xConnect */ bytecodevtabConnect,
|
|
+ /* xBestIndex */ bytecodevtabBestIndex,
|
|
+ /* xDisconnect */ bytecodevtabDisconnect,
|
|
+ /* xDestroy */ 0,
|
|
+ /* xOpen */ bytecodevtabOpen,
|
|
+ /* xClose */ bytecodevtabClose,
|
|
+ /* xFilter */ bytecodevtabFilter,
|
|
+ /* xNext */ bytecodevtabNext,
|
|
+ /* xEof */ bytecodevtabEof,
|
|
+ /* xColumn */ bytecodevtabColumn,
|
|
+ /* xRowid */ bytecodevtabRowid,
|
|
+ /* xUpdate */ 0,
|
|
+ /* xBegin */ 0,
|
|
+ /* xSync */ 0,
|
|
+ /* xCommit */ 0,
|
|
+ /* xRollback */ 0,
|
|
+ /* xFindMethod */ 0,
|
|
+ /* xRename */ 0,
|
|
+ /* xSavepoint */ 0,
|
|
+ /* xRelease */ 0,
|
|
+ /* xRollbackTo */ 0,
|
|
+ /* xShadowName */ 0
|
|
+};
|
|
+
|
|
+
|
|
+SQLITE_PRIVATE int sqlite3VdbeBytecodeVtabInit(sqlite3 *db){
|
|
+ int rc;
|
|
+ rc = sqlite3_create_module(db, "bytecode", &bytecodevtabModule, 0);
|
|
+ if( rc==SQLITE_OK ){
|
|
+ rc = sqlite3_create_module(db, "tables_used", &bytecodevtabModule, &db);
|
|
+ }
|
|
+ return rc;
|
|
+}
|
|
+#elif defined(SQLITE_ENABLE_BYTECODE_VTAB)
|
|
+SQLITE_PRIVATE int sqlite3VdbeBytecodeVtabInit(sqlite3 *db){ return SQLITE_OK; }
|
|
+#endif /* SQLITE_ENABLE_BYTECODE_VTAB */
|
|
+
|
|
+/************** End of vdbevtab.c ********************************************/
|
|
/************** Begin file memjournal.c **************************************/
|
|
/*
|
|
** 2008 October 7
|
|
@@ -96194,7 +102918,6 @@ struct MemJournal {
|
|
int nChunkSize; /* In-memory chunk-size */
|
|
|
|
int nSpill; /* Bytes of data before flushing */
|
|
- int nSize; /* Bytes of data currently in memory */
|
|
FileChunk *pFirst; /* Head of in-memory chunk-list */
|
|
FilePoint endpoint; /* Pointer to the end of the file */
|
|
FilePoint readpoint; /* Pointer to the end of the last xRead() */
|
|
@@ -96226,7 +102949,7 @@ static int memjrnlRead(
|
|
assert( p->readpoint.iOffset==0 || p->readpoint.pChunk!=0 );
|
|
if( p->readpoint.iOffset!=iOfst || iOfst==0 ){
|
|
sqlite3_int64 iOff = 0;
|
|
- for(pChunk=p->pFirst;
|
|
+ for(pChunk=p->pFirst;
|
|
ALWAYS(pChunk) && (iOff+p->nChunkSize)<=iOfst;
|
|
pChunk=pChunk->pNext
|
|
){
|
|
@@ -96255,14 +102978,13 @@ static int memjrnlRead(
|
|
/*
|
|
** Free the list of FileChunk structures headed at MemJournal.pFirst.
|
|
*/
|
|
-static void memjrnlFreeChunks(MemJournal *p){
|
|
+static void memjrnlFreeChunks(FileChunk *pFirst){
|
|
FileChunk *pIter;
|
|
FileChunk *pNext;
|
|
- for(pIter=p->pFirst; pIter; pIter=pNext){
|
|
+ for(pIter=pFirst; pIter; pIter=pNext){
|
|
pNext = pIter->pNext;
|
|
sqlite3_free(pIter);
|
|
- }
|
|
- p->pFirst = 0;
|
|
+ }
|
|
}
|
|
|
|
/*
|
|
@@ -96289,7 +103011,7 @@ static int memjrnlCreateFile(MemJournal *p){
|
|
}
|
|
if( rc==SQLITE_OK ){
|
|
/* No error has occurred. Free the in-memory buffers. */
|
|
- memjrnlFreeChunks(©);
|
|
+ memjrnlFreeChunks(copy.pFirst);
|
|
}
|
|
}
|
|
if( rc!=SQLITE_OK ){
|
|
@@ -96304,6 +103026,9 @@ static int memjrnlCreateFile(MemJournal *p){
|
|
}
|
|
|
|
|
|
+/* Forward reference */
|
|
+static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size);
|
|
+
|
|
/*
|
|
** Write data to the file.
|
|
*/
|
|
@@ -96333,23 +103058,21 @@ static int memjrnlWrite(
|
|
** access writes are not required. The only exception to this is when
|
|
** the in-memory journal is being used by a connection using the
|
|
** atomic-write optimization. In this case the first 28 bytes of the
|
|
- ** journal file may be written as part of committing the transaction. */
|
|
- assert( iOfst==p->endpoint.iOffset || iOfst==0 );
|
|
-#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \
|
|
- || defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
|
|
+ ** journal file may be written as part of committing the transaction. */
|
|
+ assert( iOfst<=p->endpoint.iOffset );
|
|
+ if( iOfst>0 && iOfst!=p->endpoint.iOffset ){
|
|
+ memjrnlTruncate(pJfd, iOfst);
|
|
+ }
|
|
if( iOfst==0 && p->pFirst ){
|
|
assert( p->nChunkSize>iAmt );
|
|
memcpy((u8*)p->pFirst->zChunk, zBuf, iAmt);
|
|
- }else
|
|
-#else
|
|
- assert( iOfst>0 || p->pFirst==0 );
|
|
-#endif
|
|
- {
|
|
+ }else{
|
|
while( nWrite>0 ){
|
|
FileChunk *pChunk = p->endpoint.pChunk;
|
|
int iChunkOffset = (int)(p->endpoint.iOffset%p->nChunkSize);
|
|
int iSpace = MIN(nWrite, p->nChunkSize - iChunkOffset);
|
|
|
|
+ assert( pChunk!=0 || iChunkOffset==0 );
|
|
if( iChunkOffset==0 ){
|
|
/* New chunk is required to extend the file. */
|
|
FileChunk *pNew = sqlite3_malloc(fileChunkSize(p->nChunkSize));
|
|
@@ -96364,15 +103087,15 @@ static int memjrnlWrite(
|
|
assert( !p->pFirst );
|
|
p->pFirst = pNew;
|
|
}
|
|
- p->endpoint.pChunk = pNew;
|
|
+ pChunk = p->endpoint.pChunk = pNew;
|
|
}
|
|
|
|
- memcpy((u8*)p->endpoint.pChunk->zChunk + iChunkOffset, zWrite, iSpace);
|
|
+ assert( pChunk!=0 );
|
|
+ memcpy((u8*)pChunk->zChunk + iChunkOffset, zWrite, iSpace);
|
|
zWrite += iSpace;
|
|
nWrite -= iSpace;
|
|
p->endpoint.iOffset += iSpace;
|
|
}
|
|
- p->nSize = iAmt + iOfst;
|
|
}
|
|
}
|
|
|
|
@@ -96380,19 +103103,29 @@ static int memjrnlWrite(
|
|
}
|
|
|
|
/*
|
|
-** Truncate the file.
|
|
-**
|
|
-** If the journal file is already on disk, truncate it there. Or, if it
|
|
-** is still in main memory but is being truncated to zero bytes in size,
|
|
-** ignore
|
|
+** Truncate the in-memory file.
|
|
*/
|
|
static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){
|
|
MemJournal *p = (MemJournal *)pJfd;
|
|
- if( ALWAYS(size==0) ){
|
|
- memjrnlFreeChunks(p);
|
|
- p->nSize = 0;
|
|
- p->endpoint.pChunk = 0;
|
|
- p->endpoint.iOffset = 0;
|
|
+ assert( p->endpoint.pChunk==0 || p->endpoint.pChunk->pNext==0 );
|
|
+ if( size<p->endpoint.iOffset ){
|
|
+ FileChunk *pIter = 0;
|
|
+ if( size==0 ){
|
|
+ memjrnlFreeChunks(p->pFirst);
|
|
+ p->pFirst = 0;
|
|
+ }else{
|
|
+ i64 iOff = p->nChunkSize;
|
|
+ for(pIter=p->pFirst; ALWAYS(pIter) && iOff<size; pIter=pIter->pNext){
|
|
+ iOff += p->nChunkSize;
|
|
+ }
|
|
+ if( ALWAYS(pIter) ){
|
|
+ memjrnlFreeChunks(pIter->pNext);
|
|
+ pIter->pNext = 0;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ p->endpoint.pChunk = pIter;
|
|
+ p->endpoint.iOffset = size;
|
|
p->readpoint.pChunk = 0;
|
|
p->readpoint.iOffset = 0;
|
|
}
|
|
@@ -96404,15 +103137,15 @@ static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){
|
|
*/
|
|
static int memjrnlClose(sqlite3_file *pJfd){
|
|
MemJournal *p = (MemJournal *)pJfd;
|
|
- memjrnlFreeChunks(p);
|
|
+ memjrnlFreeChunks(p->pFirst);
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
/*
|
|
** Sync the file.
|
|
**
|
|
-** If the real file has been created, call its xSync method. Otherwise,
|
|
-** syncing an in-memory journal is a no-op.
|
|
+** If the real file has been created, call its xSync method. Otherwise,
|
|
+** syncing an in-memory journal is a no-op.
|
|
*/
|
|
static int memjrnlSync(sqlite3_file *pJfd, int flags){
|
|
UNUSED_PARAMETER2(pJfd, flags);
|
|
@@ -96453,11 +103186,11 @@ static const struct sqlite3_io_methods MemJournalMethods = {
|
|
0 /* xUnfetch */
|
|
};
|
|
|
|
-/*
|
|
-** Open a journal file.
|
|
+/*
|
|
+** Open a journal file.
|
|
**
|
|
-** The behaviour of the journal file depends on the value of parameter
|
|
-** nSpill. If nSpill is 0, then the journal file is always create and
|
|
+** The behaviour of the journal file depends on the value of parameter
|
|
+** nSpill. If nSpill is 0, then the journal file is always create and
|
|
** accessed using the underlying VFS. If nSpill is less than zero, then
|
|
** all content is always stored in main-memory. Finally, if nSpill is a
|
|
** positive value, then the journal file is initially created in-memory
|
|
@@ -96474,6 +103207,8 @@ SQLITE_PRIVATE int sqlite3JournalOpen(
|
|
){
|
|
MemJournal *p = (MemJournal*)pJfd;
|
|
|
|
+ assert( zName || nSpill<0 || (flags & SQLITE_OPEN_EXCLUSIVE) );
|
|
+
|
|
/* Zero the file-handle object. If nSpill was passed zero, initialize
|
|
** it using the sqlite3OsOpen() function of the underlying VFS. In this
|
|
** case none of the code in this module is executed as a result of calls
|
|
@@ -96490,7 +103225,7 @@ SQLITE_PRIVATE int sqlite3JournalOpen(
|
|
assert( MEMJOURNAL_DFLT_FILECHUNKSIZE==fileChunkSize(p->nChunkSize) );
|
|
}
|
|
|
|
- p->pMethod = (const sqlite3_io_methods*)&MemJournalMethods;
|
|
+ pJfd->pMethods = (const sqlite3_io_methods*)&MemJournalMethods;
|
|
p->nSpill = nSpill;
|
|
p->flags = flags;
|
|
p->zJournal = zName;
|
|
@@ -96508,15 +103243,15 @@ SQLITE_PRIVATE void sqlite3MemJournalOpen(sqlite3_file *pJfd){
|
|
#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \
|
|
|| defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
|
|
/*
|
|
-** If the argument p points to a MemJournal structure that is not an
|
|
+** If the argument p points to a MemJournal structure that is not an
|
|
** in-memory-only journal file (i.e. is one that was opened with a +ve
|
|
-** nSpill parameter or as SQLITE_OPEN_MAIN_JOURNAL), and the underlying
|
|
+** nSpill parameter or as SQLITE_OPEN_MAIN_JOURNAL), and the underlying
|
|
** file has not yet been created, create it now.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3JournalCreate(sqlite3_file *pJfd){
|
|
int rc = SQLITE_OK;
|
|
MemJournal *p = (MemJournal*)pJfd;
|
|
- if( p->pMethod==&MemJournalMethods && (
|
|
+ if( pJfd->pMethods==&MemJournalMethods && (
|
|
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
|
|
p->nSpill>0
|
|
#else
|
|
@@ -96544,7 +103279,7 @@ SQLITE_PRIVATE int sqlite3JournalIsInMemory(sqlite3_file *p){
|
|
return p->pMethods==&MemJournalMethods;
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** Return the number of bytes required to store a JournalFile that uses vfs
|
|
** pVfs to create the underlying on-disk files.
|
|
*/
|
|
@@ -96578,7 +103313,7 @@ SQLITE_PRIVATE int sqlite3JournalSize(sqlite3_vfs *pVfs){
|
|
** Walk all expressions linked into the list of Window objects passed
|
|
** as the second argument.
|
|
*/
|
|
-static int walkWindowList(Walker *pWalker, Window *pList){
|
|
+static int walkWindowList(Walker *pWalker, Window *pList, int bOneOnly){
|
|
Window *pWin;
|
|
for(pWin=pList; pWin; pWin=pWin->pNextWin){
|
|
int rc;
|
|
@@ -96588,15 +103323,11 @@ static int walkWindowList(Walker *pWalker, Window *pList){
|
|
if( rc ) return WRC_Abort;
|
|
rc = sqlite3WalkExpr(pWalker, pWin->pFilter);
|
|
if( rc ) return WRC_Abort;
|
|
-
|
|
- /* The next two are purely for calls to sqlite3RenameExprUnmap()
|
|
- ** within sqlite3WindowOffsetExpr(). Because of constraints imposed
|
|
- ** by sqlite3WindowOffsetExpr(), they can never fail. The results do
|
|
- ** not matter anyhow. */
|
|
rc = sqlite3WalkExpr(pWalker, pWin->pStart);
|
|
- if( NEVER(rc) ) return WRC_Abort;
|
|
+ if( rc ) return WRC_Abort;
|
|
rc = sqlite3WalkExpr(pWalker, pWin->pEnd);
|
|
- if( NEVER(rc) ) return WRC_Abort;
|
|
+ if( rc ) return WRC_Abort;
|
|
+ if( bOneOnly ) break;
|
|
}
|
|
return WRC_Continue;
|
|
}
|
|
@@ -96635,7 +103366,7 @@ static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){
|
|
assert( !ExprHasProperty(pExpr, EP_WinFunc) );
|
|
pExpr = pExpr->pRight;
|
|
continue;
|
|
- }else if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
|
+ }else if( ExprUseXSelect(pExpr) ){
|
|
assert( !ExprHasProperty(pExpr, EP_WinFunc) );
|
|
if( sqlite3WalkSelect(pWalker, pExpr->x.pSelect) ) return WRC_Abort;
|
|
}else{
|
|
@@ -96644,7 +103375,7 @@ static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){
|
|
}
|
|
#ifndef SQLITE_OMIT_WINDOWFUNC
|
|
if( ExprHasProperty(pExpr, EP_WinFunc) ){
|
|
- if( walkWindowList(pWalker, pExpr->y.pWin) ) return WRC_Abort;
|
|
+ if( walkWindowList(pWalker, pExpr->y.pWin, 1) ) return WRC_Abort;
|
|
}
|
|
#endif
|
|
}
|
|
@@ -96672,6 +103403,16 @@ SQLITE_PRIVATE int sqlite3WalkExprList(Walker *pWalker, ExprList *p){
|
|
return WRC_Continue;
|
|
}
|
|
|
|
+/*
|
|
+** This is a no-op callback for Walker->xSelectCallback2. If this
|
|
+** callback is set, then the Select->pWinDefn list is traversed.
|
|
+*/
|
|
+SQLITE_PRIVATE void sqlite3WalkWinDefnDummyCallback(Walker *pWalker, Select *p){
|
|
+ UNUSED_PARAMETER(pWalker);
|
|
+ UNUSED_PARAMETER(p);
|
|
+ /* No-op */
|
|
+}
|
|
+
|
|
/*
|
|
** Walk all expressions associated with SELECT statement p. Do
|
|
** not invoke the SELECT callback on p, but do (of course) invoke
|
|
@@ -96685,13 +103426,18 @@ SQLITE_PRIVATE int sqlite3WalkSelectExpr(Walker *pWalker, Select *p){
|
|
if( sqlite3WalkExpr(pWalker, p->pHaving) ) return WRC_Abort;
|
|
if( sqlite3WalkExprList(pWalker, p->pOrderBy) ) return WRC_Abort;
|
|
if( sqlite3WalkExpr(pWalker, p->pLimit) ) return WRC_Abort;
|
|
-#if !defined(SQLITE_OMIT_WINDOWFUNC) && !defined(SQLITE_OMIT_ALTERTABLE)
|
|
- {
|
|
- Parse *pParse = pWalker->pParse;
|
|
- if( pParse && IN_RENAME_OBJECT ){
|
|
+#if !defined(SQLITE_OMIT_WINDOWFUNC)
|
|
+ if( p->pWinDefn ){
|
|
+ Parse *pParse;
|
|
+ if( pWalker->xSelectCallback2==sqlite3WalkWinDefnDummyCallback
|
|
+ || ((pParse = pWalker->pParse)!=0 && IN_RENAME_OBJECT)
|
|
+#ifndef SQLITE_OMIT_CTE
|
|
+ || pWalker->xSelectCallback2==sqlite3SelectPopWith
|
|
+#endif
|
|
+ ){
|
|
/* The following may return WRC_Abort if there are unresolvable
|
|
** symbols (e.g. a table that does not exist) in a window definition. */
|
|
- int rc = walkWindowList(pWalker, p->pWinDefn);
|
|
+ int rc = walkWindowList(pWalker, p->pWinDefn, 0);
|
|
return rc;
|
|
}
|
|
}
|
|
@@ -96703,33 +103449,34 @@ SQLITE_PRIVATE int sqlite3WalkSelectExpr(Walker *pWalker, Select *p){
|
|
** Walk the parse trees associated with all subqueries in the
|
|
** FROM clause of SELECT statement p. Do not invoke the select
|
|
** callback on p, but do invoke it on each FROM clause subquery
|
|
-** and on any subqueries further down in the tree. Return
|
|
+** and on any subqueries further down in the tree. Return
|
|
** WRC_Abort or WRC_Continue;
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3WalkSelectFrom(Walker *pWalker, Select *p){
|
|
SrcList *pSrc;
|
|
int i;
|
|
- struct SrcList_item *pItem;
|
|
+ SrcItem *pItem;
|
|
|
|
pSrc = p->pSrc;
|
|
- assert( pSrc!=0 );
|
|
- for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){
|
|
- if( pItem->pSelect && sqlite3WalkSelect(pWalker, pItem->pSelect) ){
|
|
- return WRC_Abort;
|
|
- }
|
|
- if( pItem->fg.isTabFunc
|
|
- && sqlite3WalkExprList(pWalker, pItem->u1.pFuncArg)
|
|
- ){
|
|
- return WRC_Abort;
|
|
+ if( ALWAYS(pSrc) ){
|
|
+ for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){
|
|
+ if( pItem->pSelect && sqlite3WalkSelect(pWalker, pItem->pSelect) ){
|
|
+ return WRC_Abort;
|
|
+ }
|
|
+ if( pItem->fg.isTabFunc
|
|
+ && sqlite3WalkExprList(pWalker, pItem->u1.pFuncArg)
|
|
+ ){
|
|
+ return WRC_Abort;
|
|
+ }
|
|
}
|
|
}
|
|
return WRC_Continue;
|
|
-}
|
|
+}
|
|
|
|
/*
|
|
** Call sqlite3WalkExpr() for every expression in Select statement p.
|
|
** Invoke sqlite3WalkSelect() for subqueries in the FROM clause and
|
|
-** on the compound select chain, p->pPrior.
|
|
+** on the compound select chain, p->pPrior.
|
|
**
|
|
** If it is not NULL, the xSelectCallback() callback is invoked before
|
|
** the walk of the expressions and FROM clause. The xSelectCallback2()
|
|
@@ -96763,6 +103510,43 @@ SQLITE_PRIVATE int sqlite3WalkSelect(Walker *pWalker, Select *p){
|
|
return WRC_Continue;
|
|
}
|
|
|
|
+/* Increase the walkerDepth when entering a subquery, and
|
|
+** descrease when leaving the subquery.
|
|
+*/
|
|
+SQLITE_PRIVATE int sqlite3WalkerDepthIncrease(Walker *pWalker, Select *pSelect){
|
|
+ UNUSED_PARAMETER(pSelect);
|
|
+ pWalker->walkerDepth++;
|
|
+ return WRC_Continue;
|
|
+}
|
|
+SQLITE_PRIVATE void sqlite3WalkerDepthDecrease(Walker *pWalker, Select *pSelect){
|
|
+ UNUSED_PARAMETER(pSelect);
|
|
+ pWalker->walkerDepth--;
|
|
+}
|
|
+
|
|
+
|
|
+/*
|
|
+** No-op routine for the parse-tree walker.
|
|
+**
|
|
+** When this routine is the Walker.xExprCallback then expression trees
|
|
+** are walked without any actions being taken at each node. Presumably,
|
|
+** when this routine is used for Walker.xExprCallback then
|
|
+** Walker.xSelectCallback is set to do something useful for every
|
|
+** subquery in the parser tree.
|
|
+*/
|
|
+SQLITE_PRIVATE int sqlite3ExprWalkNoop(Walker *NotUsed, Expr *NotUsed2){
|
|
+ UNUSED_PARAMETER2(NotUsed, NotUsed2);
|
|
+ return WRC_Continue;
|
|
+}
|
|
+
|
|
+/*
|
|
+** No-op routine for the parse-tree walker for SELECT statements.
|
|
+** subquery in the parser tree.
|
|
+*/
|
|
+SQLITE_PRIVATE int sqlite3SelectWalkNoop(Walker *NotUsed, Select *NotUsed2){
|
|
+ UNUSED_PARAMETER2(NotUsed, NotUsed2);
|
|
+ return WRC_Continue;
|
|
+}
|
|
+
|
|
/************** End of walker.c **********************************************/
|
|
/************** Begin file resolve.c *****************************************/
|
|
/*
|
|
@@ -96783,6 +103567,11 @@ SQLITE_PRIVATE int sqlite3WalkSelect(Walker *pWalker, Select *p){
|
|
*/
|
|
/* #include "sqliteInt.h" */
|
|
|
|
+/*
|
|
+** Magic table number to mean the EXCLUDED table in an UPSERT statement.
|
|
+*/
|
|
+#define EXCLUDED_TABLE_NUMBER 2
|
|
+
|
|
/*
|
|
** Walk the expression tree pExpr and increase the aggregate function
|
|
** depth (the Expr.op2 field) by N on every TK_AGG_FUNCTION node.
|
|
@@ -96791,6 +103580,8 @@ SQLITE_PRIVATE int sqlite3WalkSelect(Walker *pWalker, Select *p){
|
|
**
|
|
** incrAggFunctionDepth(pExpr,n) is the main routine. incrAggDepth(..)
|
|
** is a helper function - a callback for the tree walker.
|
|
+**
|
|
+** See also the sqlite3WindowExtraAggFuncDepth() routine in window.c
|
|
*/
|
|
static int incrAggDepth(Walker *pWalker, Expr *pExpr){
|
|
if( pExpr->op==TK_AGG_FUNCTION ) pExpr->op2 += pWalker->u.n;
|
|
@@ -96830,7 +103621,6 @@ static void resolveAlias(
|
|
ExprList *pEList, /* A result set */
|
|
int iCol, /* A column in the result set. 0..pEList->nExpr-1 */
|
|
Expr *pExpr, /* Transform this into an alias to the result set */
|
|
- const char *zType, /* "GROUP" or "ORDER" or "" */
|
|
int nSubquery /* Number of subqueries that the label is moving */
|
|
){
|
|
Expr *pOrig; /* The iCol-th column of the result set */
|
|
@@ -96842,54 +103632,26 @@ static void resolveAlias(
|
|
assert( pOrig!=0 );
|
|
db = pParse->db;
|
|
pDup = sqlite3ExprDup(db, pOrig, 0);
|
|
- if( pDup!=0 ){
|
|
- if( zType[0]!='G' ) incrAggFunctionDepth(pDup, nSubquery);
|
|
+ if( db->mallocFailed ){
|
|
+ sqlite3ExprDelete(db, pDup);
|
|
+ pDup = 0;
|
|
+ }else{
|
|
+ Expr temp;
|
|
+ incrAggFunctionDepth(pDup, nSubquery);
|
|
if( pExpr->op==TK_COLLATE ){
|
|
+ assert( !ExprHasProperty(pExpr, EP_IntValue) );
|
|
pDup = sqlite3ExprAddCollateString(pParse, pDup, pExpr->u.zToken);
|
|
}
|
|
-
|
|
- /* Before calling sqlite3ExprDelete(), set the EP_Static flag. This
|
|
- ** prevents ExprDelete() from deleting the Expr structure itself,
|
|
- ** allowing it to be repopulated by the memcpy() on the following line.
|
|
- ** The pExpr->u.zToken might point into memory that will be freed by the
|
|
- ** sqlite3DbFree(db, pDup) on the last line of this block, so be sure to
|
|
- ** make a copy of the token before doing the sqlite3DbFree().
|
|
- */
|
|
- ExprSetProperty(pExpr, EP_Static);
|
|
- sqlite3ExprDelete(db, pExpr);
|
|
- memcpy(pExpr, pDup, sizeof(*pExpr));
|
|
- if( !ExprHasProperty(pExpr, EP_IntValue) && pExpr->u.zToken!=0 ){
|
|
- assert( (pExpr->flags & (EP_Reduced|EP_TokenOnly))==0 );
|
|
- pExpr->u.zToken = sqlite3DbStrDup(db, pExpr->u.zToken);
|
|
- pExpr->flags |= EP_MemToken;
|
|
- }
|
|
+ memcpy(&temp, pDup, sizeof(Expr));
|
|
+ memcpy(pDup, pExpr, sizeof(Expr));
|
|
+ memcpy(pExpr, &temp, sizeof(Expr));
|
|
if( ExprHasProperty(pExpr, EP_WinFunc) ){
|
|
- if( pExpr->y.pWin!=0 ){
|
|
+ if( ALWAYS(pExpr->y.pWin!=0) ){
|
|
pExpr->y.pWin->pOwner = pExpr;
|
|
- }else{
|
|
- assert( db->mallocFailed );
|
|
}
|
|
}
|
|
- sqlite3DbFree(db, pDup);
|
|
- }
|
|
- ExprSetProperty(pExpr, EP_Alias);
|
|
-}
|
|
-
|
|
-
|
|
-/*
|
|
-** Return TRUE if the name zCol occurs anywhere in the USING clause.
|
|
-**
|
|
-** Return FALSE if the USING clause is NULL or if it does not contain
|
|
-** zCol.
|
|
-*/
|
|
-static int nameInUsingClause(IdList *pUsing, const char *zCol){
|
|
- if( pUsing ){
|
|
- int k;
|
|
- for(k=0; k<pUsing->nId; k++){
|
|
- if( sqlite3StrICmp(pUsing->a[k].zName, zCol)==0 ) return 1;
|
|
- }
|
|
+ sqlite3ExprDeferredDelete(pParse, pDup);
|
|
}
|
|
- return 0;
|
|
}
|
|
|
|
/*
|
|
@@ -96907,7 +103669,7 @@ SQLITE_PRIVATE int sqlite3MatchEName(
|
|
){
|
|
int n;
|
|
const char *zSpan;
|
|
- if( NEVER(pItem->eEName!=ENAME_TAB) ) return 0;
|
|
+ if( pItem->fg.eEName!=ENAME_TAB ) return 0;
|
|
zSpan = pItem->zEName;
|
|
for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){}
|
|
if( zDb && (sqlite3StrNICmp(zSpan, zDb, n)!=0 || zDb[n]!=0) ){
|
|
@@ -96942,9 +103704,84 @@ static int areDoubleQuotedStringsEnabled(sqlite3 *db, NameContext *pTopNC){
|
|
}
|
|
}
|
|
|
|
+/*
|
|
+** The argument is guaranteed to be a non-NULL Expr node of type TK_COLUMN.
|
|
+** return the appropriate colUsed mask.
|
|
+*/
|
|
+SQLITE_PRIVATE Bitmask sqlite3ExprColUsed(Expr *pExpr){
|
|
+ int n;
|
|
+ Table *pExTab;
|
|
+
|
|
+ n = pExpr->iColumn;
|
|
+ assert( ExprUseYTab(pExpr) );
|
|
+ pExTab = pExpr->y.pTab;
|
|
+ assert( pExTab!=0 );
|
|
+ if( (pExTab->tabFlags & TF_HasGenerated)!=0
|
|
+ && (pExTab->aCol[n].colFlags & COLFLAG_GENERATED)!=0
|
|
+ ){
|
|
+ testcase( pExTab->nCol==BMS-1 );
|
|
+ testcase( pExTab->nCol==BMS );
|
|
+ return pExTab->nCol>=BMS ? ALLBITS : MASKBIT(pExTab->nCol)-1;
|
|
+ }else{
|
|
+ testcase( n==BMS-1 );
|
|
+ testcase( n==BMS );
|
|
+ if( n>=BMS ) n = BMS-1;
|
|
+ return ((Bitmask)1)<<n;
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+** Create a new expression term for the column specified by pMatch and
|
|
+** iColumn. Append this new expression term to the FULL JOIN Match set
|
|
+** in *ppList. Create a new *ppList if this is the first term in the
|
|
+** set.
|
|
+*/
|
|
+static void extendFJMatch(
|
|
+ Parse *pParse, /* Parsing context */
|
|
+ ExprList **ppList, /* ExprList to extend */
|
|
+ SrcItem *pMatch, /* Source table containing the column */
|
|
+ i16 iColumn /* The column number */
|
|
+){
|
|
+ Expr *pNew = sqlite3ExprAlloc(pParse->db, TK_COLUMN, 0, 0);
|
|
+ if( pNew ){
|
|
+ pNew->iTable = pMatch->iCursor;
|
|
+ pNew->iColumn = iColumn;
|
|
+ pNew->y.pTab = pMatch->pTab;
|
|
+ assert( (pMatch->fg.jointype & (JT_LEFT|JT_LTORJ))!=0 );
|
|
+ ExprSetProperty(pNew, EP_CanBeNull);
|
|
+ *ppList = sqlite3ExprListAppend(pParse, *ppList, pNew);
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+** Return TRUE (non-zero) if zTab is a valid name for the schema table pTab.
|
|
+*/
|
|
+static SQLITE_NOINLINE int isValidSchemaTableName(
|
|
+ const char *zTab, /* Name as it appears in the SQL */
|
|
+ Table *pTab, /* The schema table we are trying to match */
|
|
+ Schema *pSchema /* non-NULL if a database qualifier is present */
|
|
+){
|
|
+ const char *zLegacy;
|
|
+ assert( pTab!=0 );
|
|
+ assert( pTab->tnum==1 );
|
|
+ if( sqlite3StrNICmp(zTab, "sqlite_", 7)!=0 ) return 0;
|
|
+ zLegacy = pTab->zName;
|
|
+ if( strcmp(zLegacy+7, &LEGACY_TEMP_SCHEMA_TABLE[7])==0 ){
|
|
+ if( sqlite3StrICmp(zTab+7, &PREFERRED_TEMP_SCHEMA_TABLE[7])==0 ){
|
|
+ return 1;
|
|
+ }
|
|
+ if( pSchema==0 ) return 0;
|
|
+ if( sqlite3StrICmp(zTab+7, &LEGACY_SCHEMA_TABLE[7])==0 ) return 1;
|
|
+ if( sqlite3StrICmp(zTab+7, &PREFERRED_SCHEMA_TABLE[7])==0 ) return 1;
|
|
+ }else{
|
|
+ if( sqlite3StrICmp(zTab+7, &PREFERRED_SCHEMA_TABLE[7])==0 ) return 1;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
/*
|
|
** Given the name of a column of the form X.Y.Z or Y.Z or just Z, look up
|
|
-** that name in the set of source tables in pSrcList and make the pExpr
|
|
+** that name in the set of source tables in pSrcList and make the pExpr
|
|
** expression node refer back to that source column. The following changes
|
|
** are made to pExpr:
|
|
**
|
|
@@ -96982,16 +103819,18 @@ static int lookupName(
|
|
int cntTab = 0; /* Number of matching table names */
|
|
int nSubquery = 0; /* How many levels of subquery */
|
|
sqlite3 *db = pParse->db; /* The database connection */
|
|
- struct SrcList_item *pItem; /* Use for looping over pSrcList items */
|
|
- struct SrcList_item *pMatch = 0; /* The matching pSrcList item */
|
|
+ SrcItem *pItem; /* Use for looping over pSrcList items */
|
|
+ SrcItem *pMatch = 0; /* The matching pSrcList item */
|
|
NameContext *pTopNC = pNC; /* First namecontext in the list */
|
|
Schema *pSchema = 0; /* Schema of the expression */
|
|
int eNewExprOp = TK_COLUMN; /* New value for pExpr->op on success */
|
|
- Table *pTab = 0; /* Table hold the row */
|
|
+ Table *pTab = 0; /* Table holding the row */
|
|
Column *pCol; /* A column of pTab */
|
|
+ ExprList *pFJMatch = 0; /* Matches for FULL JOIN .. USING */
|
|
|
|
assert( pNC ); /* the name context cannot be NULL. */
|
|
assert( zCol ); /* The Z in X.Y.Z cannot be NULL */
|
|
+ assert( zDb==0 || zTab!=0 );
|
|
assert( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) );
|
|
|
|
/* Initialize the node to no-match */
|
|
@@ -97019,6 +103858,12 @@ static int lookupName(
|
|
break;
|
|
}
|
|
}
|
|
+ if( i==db->nDb && sqlite3StrICmp("main", zDb)==0 ){
|
|
+ /* This branch is taken when the main database has been renamed
|
|
+ ** using SQLITE_DBCONFIG_MAINDBNAME. */
|
|
+ pSchema = db->aDb[0].pSchema;
|
|
+ zDb = db->aDb[0].zDbSName;
|
|
+ }
|
|
}
|
|
}
|
|
|
|
@@ -97030,63 +103875,129 @@ static int lookupName(
|
|
|
|
if( pSrcList ){
|
|
for(i=0, pItem=pSrcList->a; i<pSrcList->nSrc; i++, pItem++){
|
|
+ u8 hCol;
|
|
pTab = pItem->pTab;
|
|
assert( pTab!=0 && pTab->zName!=0 );
|
|
- assert( pTab->nCol>0 );
|
|
- if( pItem->pSelect && (pItem->pSelect->selFlags & SF_NestedFrom)!=0 ){
|
|
+ assert( pTab->nCol>0 || pParse->nErr );
|
|
+ assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem->pSelect) );
|
|
+ if( pItem->fg.isNestedFrom ){
|
|
+ /* In this case, pItem is a subquery that has been formed from a
|
|
+ ** parenthesized subset of the FROM clause terms. Example:
|
|
+ ** .... FROM t1 LEFT JOIN (t2 RIGHT JOIN t3 USING(x)) USING(y) ...
|
|
+ ** \_________________________/
|
|
+ ** This pItem -------------^
|
|
+ */
|
|
int hit = 0;
|
|
+ assert( pItem->pSelect!=0 );
|
|
pEList = pItem->pSelect->pEList;
|
|
+ assert( pEList!=0 );
|
|
+ assert( pEList->nExpr==pTab->nCol );
|
|
for(j=0; j<pEList->nExpr; j++){
|
|
- if( sqlite3MatchEName(&pEList->a[j], zCol, zTab, zDb) ){
|
|
- cnt++;
|
|
- cntTab = 2;
|
|
- pMatch = pItem;
|
|
- pExpr->iColumn = j;
|
|
- hit = 1;
|
|
+ if( !sqlite3MatchEName(&pEList->a[j], zCol, zTab, zDb) ){
|
|
+ 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);
|
|
+ }
|
|
+ }
|
|
+ cnt++;
|
|
+ cntTab = 2;
|
|
+ pMatch = pItem;
|
|
+ pExpr->iColumn = j;
|
|
+ pEList->a[j].fg.bUsed = 1;
|
|
+ hit = 1;
|
|
+ if( pEList->a[j].fg.bUsingTerm ) break;
|
|
}
|
|
if( hit || zTab==0 ) continue;
|
|
}
|
|
- if( zDb && pTab->pSchema!=pSchema ){
|
|
- continue;
|
|
- }
|
|
+ assert( zDb==0 || zTab!=0 );
|
|
if( zTab ){
|
|
- const char *zTabName = pItem->zAlias ? pItem->zAlias : pTab->zName;
|
|
- assert( zTabName!=0 );
|
|
- if( sqlite3StrICmp(zTabName, zTab)!=0 ){
|
|
- continue;
|
|
+ if( zDb ){
|
|
+ if( pTab->pSchema!=pSchema ) continue;
|
|
+ if( pSchema==0 && strcmp(zDb,"*")!=0 ) continue;
|
|
+ }
|
|
+ if( pItem->zAlias!=0 ){
|
|
+ if( sqlite3StrICmp(zTab, pItem->zAlias)!=0 ){
|
|
+ continue;
|
|
+ }
|
|
+ }else if( sqlite3StrICmp(zTab, pTab->zName)!=0 ){
|
|
+ if( pTab->tnum!=1 ) continue;
|
|
+ if( !isValidSchemaTableName(zTab, pTab, pSchema) ) continue;
|
|
}
|
|
+ assert( ExprUseYTab(pExpr) );
|
|
if( IN_RENAME_OBJECT && pItem->zAlias ){
|
|
sqlite3RenameTokenRemap(pParse, 0, (void*)&pExpr->y.pTab);
|
|
}
|
|
}
|
|
- if( 0==(cntTab++) ){
|
|
- pMatch = pItem;
|
|
- }
|
|
+ hCol = sqlite3StrIHash(zCol);
|
|
for(j=0, pCol=pTab->aCol; j<pTab->nCol; j++, pCol++){
|
|
- if( sqlite3StrICmp(pCol->zName, zCol)==0 ){
|
|
- /* If there has been exactly one prior match and this match
|
|
- ** is for the right-hand table of a NATURAL JOIN or is in a
|
|
- ** USING clause, then skip this match.
|
|
- */
|
|
- if( cnt==1 ){
|
|
- if( pItem->fg.jointype & JT_NATURAL ) continue;
|
|
- if( nameInUsingClause(pItem->pUsing, zCol) ) continue;
|
|
+ if( pCol->hName==hCol
|
|
+ && sqlite3StrICmp(pCol->zCnName, zCol)==0
|
|
+ ){
|
|
+ if( cnt>0 ){
|
|
+ if( pItem->fg.isUsing==0
|
|
+ || sqlite3IdListIndex(pItem->u3.pUsing, zCol)<0
|
|
+ ){
|
|
+ /* Two or more tables have the same column name which is
|
|
+ ** not joined by USING. This is an error. Signal as much
|
|
+ ** by clearing pFJMatch and letting cnt go above 1. */
|
|
+ sqlite3ExprListDelete(db, pFJMatch);
|
|
+ pFJMatch = 0;
|
|
+ }else
|
|
+ if( (pItem->fg.jointype & JT_RIGHT)==0 ){
|
|
+ /* An INNER or LEFT JOIN. Use the left-most table */
|
|
+ continue;
|
|
+ }else
|
|
+ if( (pItem->fg.jointype & JT_LEFT)==0 ){
|
|
+ /* A RIGHT JOIN. Use the right-most table */
|
|
+ cnt = 0;
|
|
+ sqlite3ExprListDelete(db, pFJMatch);
|
|
+ pFJMatch = 0;
|
|
+ }else{
|
|
+ /* For a FULL JOIN, we must construct a coalesce() func */
|
|
+ extendFJMatch(pParse, &pFJMatch, pMatch, pExpr->iColumn);
|
|
+ }
|
|
}
|
|
cnt++;
|
|
pMatch = pItem;
|
|
/* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */
|
|
pExpr->iColumn = j==pTab->iPKey ? -1 : (i16)j;
|
|
+ if( pItem->fg.isNestedFrom ){
|
|
+ sqlite3SrcItemColumnUsed(pItem, j);
|
|
+ }
|
|
break;
|
|
}
|
|
}
|
|
+ if( 0==cnt && VisibleRowid(pTab) ){
|
|
+ cntTab++;
|
|
+ pMatch = pItem;
|
|
+ }
|
|
}
|
|
if( pMatch ){
|
|
pExpr->iTable = pMatch->iCursor;
|
|
+ assert( ExprUseYTab(pExpr) );
|
|
pExpr->y.pTab = pMatch->pTab;
|
|
- /* RIGHT JOIN not (yet) supported */
|
|
- assert( (pMatch->fg.jointype & JT_RIGHT)==0 );
|
|
- if( (pMatch->fg.jointype & JT_LEFT)!=0 ){
|
|
+ if( (pMatch->fg.jointype & (JT_LEFT|JT_LTORJ))!=0 ){
|
|
ExprSetProperty(pExpr, EP_CanBeNull);
|
|
}
|
|
pSchema = pExpr->y.pTab->pSchema;
|
|
@@ -97094,41 +104005,52 @@ static int lookupName(
|
|
} /* if( pSrcList ) */
|
|
|
|
#if !defined(SQLITE_OMIT_TRIGGER) || !defined(SQLITE_OMIT_UPSERT)
|
|
- /* If we have not already resolved the name, then maybe
|
|
+ /* If we have not already resolved the name, then maybe
|
|
** it is a new.* or old.* trigger argument reference. Or
|
|
- ** maybe it is an excluded.* from an upsert.
|
|
+ ** maybe it is an excluded.* from an upsert. Or maybe it is
|
|
+ ** a reference in the RETURNING clause to a table being modified.
|
|
*/
|
|
- if( zDb==0 && zTab!=0 && cntTab==0 ){
|
|
+ if( cnt==0 && zDb==0 ){
|
|
pTab = 0;
|
|
#ifndef SQLITE_OMIT_TRIGGER
|
|
if( pParse->pTriggerTab!=0 ){
|
|
int op = pParse->eTriggerOp;
|
|
assert( op==TK_DELETE || op==TK_UPDATE || op==TK_INSERT );
|
|
- if( op!=TK_DELETE && sqlite3StrICmp("new",zTab) == 0 ){
|
|
+ if( pParse->bReturning ){
|
|
+ if( (pNC->ncFlags & NC_UBaseReg)!=0
|
|
+ && (zTab==0 || sqlite3StrICmp(zTab,pParse->pTriggerTab->zName)==0)
|
|
+ ){
|
|
+ pExpr->iTable = op!=TK_DELETE;
|
|
+ pTab = pParse->pTriggerTab;
|
|
+ }
|
|
+ }else if( op!=TK_DELETE && zTab && sqlite3StrICmp("new",zTab) == 0 ){
|
|
pExpr->iTable = 1;
|
|
pTab = pParse->pTriggerTab;
|
|
- }else if( op!=TK_INSERT && sqlite3StrICmp("old",zTab)==0 ){
|
|
+ }else if( op!=TK_INSERT && zTab && sqlite3StrICmp("old",zTab)==0 ){
|
|
pExpr->iTable = 0;
|
|
pTab = pParse->pTriggerTab;
|
|
}
|
|
}
|
|
#endif /* SQLITE_OMIT_TRIGGER */
|
|
#ifndef SQLITE_OMIT_UPSERT
|
|
- if( (pNC->ncFlags & NC_UUpsert)!=0 ){
|
|
+ if( (pNC->ncFlags & NC_UUpsert)!=0 && zTab!=0 ){
|
|
Upsert *pUpsert = pNC->uNC.pUpsert;
|
|
if( pUpsert && sqlite3StrICmp("excluded",zTab)==0 ){
|
|
pTab = pUpsert->pUpsertSrc->a[0].pTab;
|
|
- pExpr->iTable = 2;
|
|
+ pExpr->iTable = EXCLUDED_TABLE_NUMBER;
|
|
}
|
|
}
|
|
#endif /* SQLITE_OMIT_UPSERT */
|
|
|
|
- if( pTab ){
|
|
+ if( pTab ){
|
|
int iCol;
|
|
+ u8 hCol = sqlite3StrIHash(zCol);
|
|
pSchema = pTab->pSchema;
|
|
cntTab++;
|
|
for(iCol=0, pCol=pTab->aCol; iCol<pTab->nCol; iCol++, pCol++){
|
|
- if( sqlite3StrICmp(pCol->zName, zCol)==0 ){
|
|
+ if( pCol->hName==hCol
|
|
+ && sqlite3StrICmp(pCol->zCnName, zCol)==0
|
|
+ ){
|
|
if( iCol==pTab->iPKey ){
|
|
iCol = -1;
|
|
}
|
|
@@ -97141,37 +104063,48 @@ static int lookupName(
|
|
}
|
|
if( iCol<pTab->nCol ){
|
|
cnt++;
|
|
+ pMatch = 0;
|
|
#ifndef SQLITE_OMIT_UPSERT
|
|
- if( pExpr->iTable==2 ){
|
|
+ if( pExpr->iTable==EXCLUDED_TABLE_NUMBER ){
|
|
testcase( iCol==(-1) );
|
|
+ assert( ExprUseYTab(pExpr) );
|
|
if( IN_RENAME_OBJECT ){
|
|
pExpr->iColumn = iCol;
|
|
pExpr->y.pTab = pTab;
|
|
eNewExprOp = TK_COLUMN;
|
|
}else{
|
|
- pExpr->iTable = pNC->uNC.pUpsert->regData + iCol;
|
|
+ pExpr->iTable = pNC->uNC.pUpsert->regData +
|
|
+ sqlite3TableColumnToStorage(pTab, iCol);
|
|
eNewExprOp = TK_REGISTER;
|
|
- ExprSetProperty(pExpr, EP_Alias);
|
|
}
|
|
}else
|
|
#endif /* SQLITE_OMIT_UPSERT */
|
|
{
|
|
-#ifndef SQLITE_OMIT_TRIGGER
|
|
- if( iCol<0 ){
|
|
- pExpr->affExpr = SQLITE_AFF_INTEGER;
|
|
- }else if( pExpr->iTable==0 ){
|
|
- testcase( iCol==31 );
|
|
- testcase( iCol==32 );
|
|
- pParse->oldmask |= (iCol>=32 ? 0xffffffff : (((u32)1)<<iCol));
|
|
- }else{
|
|
- testcase( iCol==31 );
|
|
- testcase( iCol==32 );
|
|
- pParse->newmask |= (iCol>=32 ? 0xffffffff : (((u32)1)<<iCol));
|
|
- }
|
|
+ assert( ExprUseYTab(pExpr) );
|
|
pExpr->y.pTab = pTab;
|
|
- pExpr->iColumn = (i16)iCol;
|
|
- eNewExprOp = TK_TRIGGER;
|
|
+ if( pParse->bReturning ){
|
|
+ eNewExprOp = TK_REGISTER;
|
|
+ pExpr->op2 = TK_COLUMN;
|
|
+ pExpr->iColumn = iCol;
|
|
+ pExpr->iTable = pNC->uNC.iBaseReg + (pTab->nCol+1)*pExpr->iTable +
|
|
+ sqlite3TableColumnToStorage(pTab, iCol) + 1;
|
|
+ }else{
|
|
+ pExpr->iColumn = (i16)iCol;
|
|
+ eNewExprOp = TK_TRIGGER;
|
|
+#ifndef SQLITE_OMIT_TRIGGER
|
|
+ if( iCol<0 ){
|
|
+ pExpr->affExpr = SQLITE_AFF_INTEGER;
|
|
+ }else if( pExpr->iTable==0 ){
|
|
+ testcase( iCol==31 );
|
|
+ testcase( iCol==32 );
|
|
+ pParse->oldmask |= (iCol>=32 ? 0xffffffff : (((u32)1)<<iCol));
|
|
+ }else{
|
|
+ testcase( iCol==31 );
|
|
+ testcase( iCol==32 );
|
|
+ pParse->newmask |= (iCol>=32 ? 0xffffffff : (((u32)1)<<iCol));
|
|
+ }
|
|
#endif /* SQLITE_OMIT_TRIGGER */
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
@@ -97186,7 +104119,7 @@ static int lookupName(
|
|
&& pMatch
|
|
&& (pNC->ncFlags & (NC_IdxExpr|NC_GenCol))==0
|
|
&& sqlite3IsRowid(zCol)
|
|
- && VisibleRowid(pMatch->pTab)
|
|
+ && ALWAYS(VisibleRowid(pMatch->pTab))
|
|
){
|
|
cnt = 1;
|
|
pExpr->iColumn = -1;
|
|
@@ -97211,21 +104144,21 @@ static int lookupName(
|
|
** is supported for backwards compatibility only. Hence, we issue a warning
|
|
** on sqlite3_log() whenever the capability is used.
|
|
*/
|
|
- if( (pNC->ncFlags & NC_UEList)!=0
|
|
- && cnt==0
|
|
+ if( cnt==0
|
|
+ && (pNC->ncFlags & NC_UEList)!=0
|
|
&& zTab==0
|
|
){
|
|
pEList = pNC->uNC.pEList;
|
|
assert( pEList!=0 );
|
|
for(j=0; j<pEList->nExpr; j++){
|
|
char *zAs = pEList->a[j].zEName;
|
|
- if( pEList->a[j].eEName==ENAME_NAME
|
|
+ if( pEList->a[j].fg.eEName==ENAME_NAME
|
|
&& sqlite3_stricmp(zAs, zCol)==0
|
|
){
|
|
Expr *pOrig;
|
|
assert( pExpr->pLeft==0 && pExpr->pRight==0 );
|
|
- assert( pExpr->x.pList==0 );
|
|
- assert( pExpr->x.pSelect==0 );
|
|
+ assert( ExprUseXList(pExpr)==0 || pExpr->x.pList==0 );
|
|
+ assert( ExprUseXSelect(pExpr)==0 || pExpr->x.pSelect==0 );
|
|
pOrig = pEList->a[j].pExpr;
|
|
if( (pNC->ncFlags&NC_AllowAgg)==0 && ExprHasProperty(pOrig, EP_Agg) ){
|
|
sqlite3ErrorMsg(pParse, "misuse of aliased aggregate %s", zAs);
|
|
@@ -97241,7 +104174,7 @@ static int lookupName(
|
|
sqlite3ErrorMsg(pParse, "row value misused");
|
|
return WRC_Abort;
|
|
}
|
|
- resolveAlias(pParse, pEList, j, pExpr, "", nSubquery);
|
|
+ resolveAlias(pParse, pEList, j, pExpr, nSubquery);
|
|
cnt = 1;
|
|
pMatch = 0;
|
|
assert( zTab==0 && zDb==0 );
|
|
@@ -97250,7 +104183,7 @@ static int lookupName(
|
|
}
|
|
goto lookupname_end;
|
|
}
|
|
- }
|
|
+ }
|
|
}
|
|
|
|
/* Advance to the next name context. The loop will exit when either
|
|
@@ -97297,7 +104230,7 @@ static int lookupName(
|
|
sqlite3VdbeAddDblquoteStr(db, pParse->pVdbe, zCol);
|
|
#endif
|
|
pExpr->op = TK_STRING;
|
|
- pExpr->y.pTab = 0;
|
|
+ memset(&pExpr->y, 0, sizeof(pExpr->y));
|
|
return WRC_Prune;
|
|
}
|
|
if( sqlite3ExprIdToTrueFalse(pExpr) ){
|
|
@@ -97306,11 +104239,37 @@ static int lookupName(
|
|
}
|
|
|
|
/*
|
|
- ** cnt==0 means there was not match. cnt>1 means there were two or
|
|
- ** more matches. Either way, we have an error.
|
|
+ ** cnt==0 means there was not match.
|
|
+ ** cnt>1 means there were two or more matches.
|
|
+ **
|
|
+ ** cnt==0 is always an error. cnt>1 is often an error, but might
|
|
+ ** be multiple matches for a NATURAL LEFT JOIN or a LEFT JOIN USING.
|
|
*/
|
|
+ assert( pFJMatch==0 || cnt>0 );
|
|
+ assert( !ExprHasProperty(pExpr, EP_xIsSelect|EP_IntValue) );
|
|
if( cnt!=1 ){
|
|
const char *zErr;
|
|
+ if( pFJMatch ){
|
|
+ if( pFJMatch->nExpr==cnt-1 ){
|
|
+ if( ExprHasProperty(pExpr,EP_Leaf) ){
|
|
+ ExprClearProperty(pExpr,EP_Leaf);
|
|
+ }else{
|
|
+ sqlite3ExprDelete(db, pExpr->pLeft);
|
|
+ pExpr->pLeft = 0;
|
|
+ sqlite3ExprDelete(db, pExpr->pRight);
|
|
+ pExpr->pRight = 0;
|
|
+ }
|
|
+ extendFJMatch(pParse, &pFJMatch, pMatch, pExpr->iColumn);
|
|
+ pExpr->op = TK_FUNCTION;
|
|
+ pExpr->u.zToken = "coalesce";
|
|
+ pExpr->x.pList = pFJMatch;
|
|
+ cnt = 1;
|
|
+ goto lookupname_end;
|
|
+ }else{
|
|
+ sqlite3ExprListDelete(db, pFJMatch);
|
|
+ pFJMatch = 0;
|
|
+ }
|
|
+ }
|
|
zErr = cnt==0 ? "no such column" : "ambiguous column name";
|
|
if( zDb ){
|
|
sqlite3ErrorMsg(pParse, "%s: %s.%s.%s", zErr, zDb, zTab, zCol);
|
|
@@ -97319,8 +104278,19 @@ static int lookupName(
|
|
}else{
|
|
sqlite3ErrorMsg(pParse, "%s: %s", zErr, zCol);
|
|
}
|
|
+ sqlite3RecordErrorOffsetOfExpr(pParse->db, pExpr);
|
|
pParse->checkSchema = 1;
|
|
- pTopNC->nErr++;
|
|
+ pTopNC->nNcErr++;
|
|
+ }
|
|
+ assert( pFJMatch==0 );
|
|
+
|
|
+ /* Remove all substructure from pExpr */
|
|
+ if( !ExprHasProperty(pExpr,(EP_TokenOnly|EP_Leaf)) ){
|
|
+ sqlite3ExprDelete(db, pExpr->pLeft);
|
|
+ pExpr->pLeft = 0;
|
|
+ sqlite3ExprDelete(db, pExpr->pRight);
|
|
+ pExpr->pRight = 0;
|
|
+ ExprSetProperty(pExpr, EP_Leaf);
|
|
}
|
|
|
|
/* If a column from a table in pSrcList is referenced, then record
|
|
@@ -97338,38 +104308,20 @@ static int lookupName(
|
|
** of the table.
|
|
*/
|
|
if( pExpr->iColumn>=0 && pMatch!=0 ){
|
|
- int n = pExpr->iColumn;
|
|
- Table *pExTab = pExpr->y.pTab;
|
|
- assert( pExTab!=0 );
|
|
- assert( pMatch->iCursor==pExpr->iTable );
|
|
- if( (pExTab->tabFlags & TF_HasGenerated)!=0
|
|
- && (pExTab->aCol[n].colFlags & COLFLAG_GENERATED)!=0
|
|
- ){
|
|
- testcase( pExTab->nCol==BMS-1 );
|
|
- testcase( pExTab->nCol==BMS );
|
|
- pMatch->colUsed = pExTab->nCol>=BMS ? ALLBITS : MASKBIT(pExTab->nCol)-1;
|
|
- }else{
|
|
- testcase( n==BMS-1 );
|
|
- testcase( n==BMS );
|
|
- if( n>=BMS ) n = BMS-1;
|
|
- pMatch->colUsed |= ((Bitmask)1)<<n;
|
|
- }
|
|
+ pMatch->colUsed |= sqlite3ExprColUsed(pExpr);
|
|
}
|
|
|
|
- /* Clean up and return
|
|
- */
|
|
- sqlite3ExprDelete(db, pExpr->pLeft);
|
|
- pExpr->pLeft = 0;
|
|
- sqlite3ExprDelete(db, pExpr->pRight);
|
|
- pExpr->pRight = 0;
|
|
pExpr->op = eNewExprOp;
|
|
- ExprSetProperty(pExpr, EP_Leaf);
|
|
lookupname_end:
|
|
if( cnt==1 ){
|
|
assert( pNC!=0 );
|
|
- if( !ExprHasProperty(pExpr, EP_Alias) ){
|
|
+#ifndef SQLITE_OMIT_AUTHORIZATION
|
|
+ if( pParse->db->xAuth
|
|
+ && (pExpr->op==TK_COLUMN || pExpr->op==TK_TRIGGER)
|
|
+ ){
|
|
sqlite3AuthRead(pParse, pExpr, pSchema, pNC->pSrcList);
|
|
}
|
|
+#endif
|
|
/* Increment the nRef value on all name contexts from TopNC up to
|
|
** the point where the name matched. */
|
|
for(;;){
|
|
@@ -97391,8 +104343,10 @@ static int lookupName(
|
|
SQLITE_PRIVATE Expr *sqlite3CreateColumnExpr(sqlite3 *db, SrcList *pSrc, int iSrc, int iCol){
|
|
Expr *p = sqlite3ExprAlloc(db, TK_COLUMN, 0, 0);
|
|
if( p ){
|
|
- struct SrcList_item *pItem = &pSrc->a[iSrc];
|
|
- Table *pTab = p->y.pTab = pItem->pTab;
|
|
+ SrcItem *pItem = &pSrc->a[iSrc];
|
|
+ Table *pTab;
|
|
+ assert( ExprUseYTab(p) );
|
|
+ pTab = p->y.pTab = pItem->pTab;
|
|
p->iTable = pItem->iCursor;
|
|
if( p->y.pTab->iPKey==iCol ){
|
|
p->iColumn = -1;
|
|
@@ -97420,7 +104374,7 @@ SQLITE_PRIVATE Expr *sqlite3CreateColumnExpr(sqlite3 *db, SrcList *pSrc, int iSr
|
|
**
|
|
** static void notValid(
|
|
** Parse *pParse, // Leave error message here
|
|
-** NameContext *pNC, // The name context
|
|
+** NameContext *pNC, // The name context
|
|
** const char *zMsg, // Type of error
|
|
** int validMask, // Set of contexts for which prohibited
|
|
** Expr *pExpr // Invalidate this expression on error
|
|
@@ -97434,7 +104388,8 @@ static void notValidImpl(
|
|
Parse *pParse, /* Leave error message here */
|
|
NameContext *pNC, /* The name context */
|
|
const char *zMsg, /* Type of error */
|
|
- Expr *pExpr /* Invalidate this expression on error */
|
|
+ Expr *pExpr, /* Invalidate this expression on error */
|
|
+ Expr *pError /* Associate error with this expression */
|
|
){
|
|
const char *zIn = "partial index WHERE clauses";
|
|
if( pNC->ncFlags & NC_IdxExpr ) zIn = "index expressions";
|
|
@@ -97446,10 +104401,11 @@ static void notValidImpl(
|
|
#endif
|
|
sqlite3ErrorMsg(pParse, "%s prohibited in %s", zMsg, zIn);
|
|
if( pExpr ) pExpr->op = TK_NULL;
|
|
+ sqlite3RecordErrorOffsetOfExpr(pParse->db, pError);
|
|
}
|
|
-#define sqlite3ResolveNotValid(P,N,M,X,E) \
|
|
+#define sqlite3ResolveNotValid(P,N,M,X,E,R) \
|
|
assert( ((X)&~(NC_IsCheck|NC_PartIdx|NC_IdxExpr|NC_GenCol))==0 ); \
|
|
- if( ((N)->ncFlags & (X))!=0 ) notValidImpl(P,N,M,E);
|
|
+ if( ((N)->ncFlags & (X))!=0 ) notValidImpl(P,N,M,E,R);
|
|
|
|
/*
|
|
** Expression p should encode a floating point value between 1.0 and 0.0.
|
|
@@ -97459,6 +104415,7 @@ static void notValidImpl(
|
|
static int exprProbability(Expr *p){
|
|
double r = -1.0;
|
|
if( p->op!=TK_FLOAT ) return -1;
|
|
+ assert( !ExprHasProperty(p, EP_IntValue) );
|
|
sqlite3AtoF(p->u.zToken, &r, sqlite3Strlen30(p->u.zToken), SQLITE_UTF8);
|
|
assert( r>=0.0 );
|
|
if( r>1.0 ) return -1;
|
|
@@ -97496,33 +104453,70 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
|
#endif
|
|
switch( pExpr->op ){
|
|
|
|
-#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY)
|
|
/* The special operator TK_ROW means use the rowid for the first
|
|
** column in the FROM clause. This is used by the LIMIT and ORDER BY
|
|
- ** clause processing on UPDATE and DELETE statements.
|
|
+ ** clause processing on UPDATE and DELETE statements, and by
|
|
+ ** UPDATE ... FROM statement processing.
|
|
*/
|
|
case TK_ROW: {
|
|
SrcList *pSrcList = pNC->pSrcList;
|
|
- struct SrcList_item *pItem;
|
|
- assert( pSrcList && pSrcList->nSrc==1 );
|
|
+ SrcItem *pItem;
|
|
+ assert( pSrcList && pSrcList->nSrc>=1 );
|
|
pItem = pSrcList->a;
|
|
- assert( HasRowid(pItem->pTab) && pItem->pTab->pSelect==0 );
|
|
pExpr->op = TK_COLUMN;
|
|
+ assert( ExprUseYTab(pExpr) );
|
|
pExpr->y.pTab = pItem->pTab;
|
|
pExpr->iTable = pItem->iCursor;
|
|
- pExpr->iColumn = -1;
|
|
+ pExpr->iColumn--;
|
|
pExpr->affExpr = SQLITE_AFF_INTEGER;
|
|
break;
|
|
}
|
|
-#endif /* defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT)
|
|
- && !defined(SQLITE_OMIT_SUBQUERY) */
|
|
+
|
|
+ /* An optimization: Attempt to convert
|
|
+ **
|
|
+ ** "expr IS NOT NULL" --> "TRUE"
|
|
+ ** "expr IS NULL" --> "FALSE"
|
|
+ **
|
|
+ ** if we can prove that "expr" is never NULL. Call this the
|
|
+ ** "NOT NULL strength reduction optimization".
|
|
+ **
|
|
+ ** If this optimization occurs, also restore the NameContext ref-counts
|
|
+ ** to the state they where in before the "column" LHS expression was
|
|
+ ** resolved. This prevents "column" from being counted as having been
|
|
+ ** referenced, which might prevent a SELECT from being erroneously
|
|
+ ** marked as correlated.
|
|
+ */
|
|
+ case TK_NOTNULL:
|
|
+ case TK_ISNULL: {
|
|
+ int anRef[8];
|
|
+ NameContext *p;
|
|
+ int i;
|
|
+ for(i=0, p=pNC; p && i<ArraySize(anRef); p=p->pNext, i++){
|
|
+ anRef[i] = p->nRef;
|
|
+ }
|
|
+ sqlite3WalkExpr(pWalker, pExpr->pLeft);
|
|
+ if( 0==sqlite3ExprCanBeNull(pExpr->pLeft) && !IN_RENAME_OBJECT ){
|
|
+ testcase( ExprHasProperty(pExpr, EP_OuterON) );
|
|
+ assert( !ExprHasProperty(pExpr, EP_IntValue) );
|
|
+ pExpr->u.iValue = (pExpr->op==TK_NOTNULL);
|
|
+ pExpr->flags |= EP_IntValue;
|
|
+ pExpr->op = TK_INTEGER;
|
|
+
|
|
+ for(i=0, p=pNC; p && i<ArraySize(anRef); p=p->pNext, i++){
|
|
+ p->nRef = anRef[i];
|
|
+ }
|
|
+ sqlite3ExprDelete(pParse->db, pExpr->pLeft);
|
|
+ pExpr->pLeft = 0;
|
|
+ }
|
|
+ return WRC_Prune;
|
|
+ }
|
|
|
|
/* A column name: ID
|
|
** Or table name and column name: ID.ID
|
|
** Or a database, table and column: ID.ID.ID
|
|
**
|
|
** The TK_ID and TK_OUT cases are combined so that there will only
|
|
- ** be one call to lookupName(). Then the compiler will in-line
|
|
+ ** be one call to lookupName(). Then the compiler will in-line
|
|
** lookupName() for a size reduction and performance increase.
|
|
*/
|
|
case TK_ID:
|
|
@@ -97535,24 +104529,28 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
|
if( pExpr->op==TK_ID ){
|
|
zDb = 0;
|
|
zTable = 0;
|
|
+ assert( !ExprHasProperty(pExpr, EP_IntValue) );
|
|
zColumn = pExpr->u.zToken;
|
|
}else{
|
|
Expr *pLeft = pExpr->pLeft;
|
|
testcase( pNC->ncFlags & NC_IdxExpr );
|
|
testcase( pNC->ncFlags & NC_GenCol );
|
|
sqlite3ResolveNotValid(pParse, pNC, "the \".\" operator",
|
|
- NC_IdxExpr|NC_GenCol, 0);
|
|
+ NC_IdxExpr|NC_GenCol, 0, pExpr);
|
|
pRight = pExpr->pRight;
|
|
if( pRight->op==TK_ID ){
|
|
zDb = 0;
|
|
}else{
|
|
assert( pRight->op==TK_DOT );
|
|
+ assert( !ExprHasProperty(pRight, EP_IntValue) );
|
|
zDb = pLeft->u.zToken;
|
|
pLeft = pRight->pLeft;
|
|
pRight = pRight->pRight;
|
|
}
|
|
+ assert( ExprUseUToken(pLeft) && ExprUseUToken(pRight) );
|
|
zTable = pLeft->u.zToken;
|
|
zColumn = pRight->u.zToken;
|
|
+ assert( ExprUseYTab(pExpr) );
|
|
if( IN_RENAME_OBJECT ){
|
|
sqlite3RenameTokenRemap(pParse, (void*)pExpr, (void*)pRight);
|
|
sqlite3RenameTokenRemap(pParse, (void*)&pExpr->y.pTab, (void*)pLeft);
|
|
@@ -97569,7 +104567,6 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
|
int no_such_func = 0; /* True if no such function exists */
|
|
int wrong_num_args = 0; /* True if wrong number of arguments */
|
|
int is_agg = 0; /* True if is an aggregate function */
|
|
- int nId; /* Number of characters in function name */
|
|
const char *zId; /* The function name. */
|
|
FuncDef *pDef; /* Information about the function */
|
|
u8 enc = ENC(pParse->db); /* The database encoding */
|
|
@@ -97577,9 +104574,8 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
|
#ifndef SQLITE_OMIT_WINDOWFUNC
|
|
Window *pWin = (IsWindowFunc(pExpr) ? pExpr->y.pWin : 0);
|
|
#endif
|
|
- assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
|
|
+ assert( !ExprHasProperty(pExpr, EP_xIsSelect|EP_IntValue) );
|
|
zId = pExpr->u.zToken;
|
|
- nId = sqlite3Strlen30(zId);
|
|
pDef = sqlite3FindFunction(pParse->db, zId, n, enc, 0);
|
|
if( pDef==0 ){
|
|
pDef = sqlite3FindFunction(pParse->db, zId, -2, enc, 0);
|
|
@@ -97596,9 +104592,9 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
|
pExpr->iTable = exprProbability(pList->a[1].pExpr);
|
|
if( pExpr->iTable<0 ){
|
|
sqlite3ErrorMsg(pParse,
|
|
- "second argument to likelihood() must be a "
|
|
- "constant between 0.0 and 1.0");
|
|
- pNC->nErr++;
|
|
+ "second argument to %#T() must be a "
|
|
+ "constant between 0.0 and 1.0", pExpr);
|
|
+ pNC->nNcErr++;
|
|
}
|
|
}else{
|
|
/* EVIDENCE-OF: R-61304-29449 The unlikely(X) function is
|
|
@@ -97611,16 +104607,16 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
|
** to likelihood(X,0.9375). */
|
|
/* TUNING: unlikely() probability is 0.0625. likely() is 0.9375 */
|
|
pExpr->iTable = pDef->zName[0]=='u' ? 8388608 : 125829120;
|
|
- }
|
|
+ }
|
|
}
|
|
#ifndef SQLITE_OMIT_AUTHORIZATION
|
|
{
|
|
int auth = sqlite3AuthCheck(pParse, SQLITE_FUNCTION, 0,pDef->zName,0);
|
|
if( auth!=SQLITE_OK ){
|
|
if( auth==SQLITE_DENY ){
|
|
- sqlite3ErrorMsg(pParse, "not authorized to use function: %s",
|
|
- pDef->zName);
|
|
- pNC->nErr++;
|
|
+ sqlite3ErrorMsg(pParse, "not authorized to use function: %#T",
|
|
+ pExpr);
|
|
+ pNC->nNcErr++;
|
|
}
|
|
pExpr->op = TK_NULL;
|
|
return WRC_Prune;
|
|
@@ -97642,7 +104638,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
|
** in a CHECK constraint. SQLServer, MySQL, and PostgreSQL all
|
|
** all this. */
|
|
sqlite3ResolveNotValid(pParse, pNC, "non-deterministic functions",
|
|
- NC_IdxExpr|NC_PartIdx|NC_GenCol, 0);
|
|
+ NC_IdxExpr|NC_PartIdx|NC_GenCol, 0, pExpr);
|
|
}else{
|
|
assert( (NC_SelfRef & 0xff)==NC_SelfRef ); /* Must fit in 8 bits */
|
|
pExpr->op2 = pNC->ncFlags & NC_SelfRef;
|
|
@@ -97655,7 +104651,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
|
/* Internal-use-only functions are disallowed unless the
|
|
** SQL is being compiled using sqlite3NestedParse() or
|
|
** the SQLITE_TESTCTRL_INTERNAL_FUNCTIONS test-control has be
|
|
- ** used to activate internal functionsn for testing purposes */
|
|
+ ** used to activate internal functions for testing purposes */
|
|
no_such_func = 1;
|
|
pDef = 0;
|
|
}else
|
|
@@ -97673,11 +104669,11 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
|
|| (pDef->xValue && pDef->xInverse && pDef->xSFunc && pDef->xFinalize)
|
|
);
|
|
if( pDef && pDef->xValue==0 && pWin ){
|
|
- sqlite3ErrorMsg(pParse,
|
|
- "%.*s() may not be used as a window function", nId, zId
|
|
+ sqlite3ErrorMsg(pParse,
|
|
+ "%#T() may not be used as a window function", pExpr
|
|
);
|
|
- pNC->nErr++;
|
|
- }else if(
|
|
+ pNC->nNcErr++;
|
|
+ }else if(
|
|
(is_agg && (pNC->ncFlags & NC_AllowAgg)==0)
|
|
|| (is_agg && (pDef->funcFlags&SQLITE_FUNC_WINDOW) && !pWin)
|
|
|| (is_agg && pWin && (pNC->ncFlags & NC_AllowWin)==0)
|
|
@@ -97688,14 +104684,14 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
|
}else{
|
|
zType = "aggregate";
|
|
}
|
|
- sqlite3ErrorMsg(pParse, "misuse of %s function %.*s()",zType,nId,zId);
|
|
- pNC->nErr++;
|
|
+ sqlite3ErrorMsg(pParse, "misuse of %s function %#T()",zType,pExpr);
|
|
+ pNC->nNcErr++;
|
|
is_agg = 0;
|
|
}
|
|
#else
|
|
if( (is_agg && (pNC->ncFlags & NC_AllowAgg)==0) ){
|
|
- sqlite3ErrorMsg(pParse,"misuse of aggregate function %.*s()",nId,zId);
|
|
- pNC->nErr++;
|
|
+ sqlite3ErrorMsg(pParse,"misuse of aggregate function %#T()",pExpr);
|
|
+ pNC->nNcErr++;
|
|
is_agg = 0;
|
|
}
|
|
#endif
|
|
@@ -97704,20 +104700,20 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
|
&& pParse->explain==0
|
|
#endif
|
|
){
|
|
- sqlite3ErrorMsg(pParse, "no such function: %.*s", nId, zId);
|
|
- pNC->nErr++;
|
|
+ sqlite3ErrorMsg(pParse, "no such function: %#T", pExpr);
|
|
+ pNC->nNcErr++;
|
|
}else if( wrong_num_args ){
|
|
- sqlite3ErrorMsg(pParse,"wrong number of arguments to function %.*s()",
|
|
- nId, zId);
|
|
- pNC->nErr++;
|
|
+ sqlite3ErrorMsg(pParse,"wrong number of arguments to function %#T()",
|
|
+ pExpr);
|
|
+ pNC->nNcErr++;
|
|
}
|
|
#ifndef SQLITE_OMIT_WINDOWFUNC
|
|
else if( is_agg==0 && ExprHasProperty(pExpr, EP_WinFunc) ){
|
|
- sqlite3ErrorMsg(pParse,
|
|
- "FILTER may not be used with non-aggregate %.*s()",
|
|
- nId, zId
|
|
+ sqlite3ErrorMsg(pParse,
|
|
+ "FILTER may not be used with non-aggregate %#T()",
|
|
+ pExpr
|
|
);
|
|
- pNC->nErr++;
|
|
+ pNC->nNcErr++;
|
|
}
|
|
#endif
|
|
if( is_agg ){
|
|
@@ -97741,9 +104737,10 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
|
#ifndef SQLITE_OMIT_WINDOWFUNC
|
|
if( pWin ){
|
|
Select *pSel = pNC->pWinSelect;
|
|
- assert( pWin==pExpr->y.pWin );
|
|
+ assert( pWin==0 || (ExprUseYWin(pExpr) && pWin==pExpr->y.pWin) );
|
|
if( IN_RENAME_OBJECT==0 ){
|
|
sqlite3WindowUpdate(pParse, pSel ? pSel->pWinDefn : 0, pWin, pDef);
|
|
+ if( pParse->db->mallocFailed ) break;
|
|
}
|
|
sqlite3WalkExprList(pWalker, pWin->pPartition);
|
|
sqlite3WalkExprList(pWalker, pWin->pOrderBy);
|
|
@@ -97753,7 +104750,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
|
}else
|
|
#endif /* SQLITE_OMIT_WINDOWFUNC */
|
|
{
|
|
- NameContext *pNC2 = pNC;
|
|
+ NameContext *pNC2; /* For looping up thru outer contexts */
|
|
pExpr->op = TK_AGG_FUNCTION;
|
|
pExpr->op2 = 0;
|
|
#ifndef SQLITE_OMIT_WINDOWFUNC
|
|
@@ -97761,22 +104758,28 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
|
sqlite3WalkExpr(pWalker, pExpr->y.pWin->pFilter);
|
|
}
|
|
#endif
|
|
- while( pNC2 && !sqlite3FunctionUsesThisSrc(pExpr, pNC2->pSrcList) ){
|
|
+ pNC2 = pNC;
|
|
+ while( pNC2
|
|
+ && sqlite3ReferencesSrcList(pParse, pExpr, pNC2->pSrcList)==0
|
|
+ ){
|
|
pExpr->op2++;
|
|
pNC2 = pNC2->pNext;
|
|
}
|
|
assert( pDef!=0 || IN_RENAME_OBJECT );
|
|
if( pNC2 && pDef ){
|
|
assert( SQLITE_FUNC_MINMAX==NC_MinMaxAgg );
|
|
+ assert( SQLITE_FUNC_ANYORDER==NC_OrderAgg );
|
|
testcase( (pDef->funcFlags & SQLITE_FUNC_MINMAX)!=0 );
|
|
- pNC2->ncFlags |= NC_HasAgg | (pDef->funcFlags & SQLITE_FUNC_MINMAX);
|
|
-
|
|
+ testcase( (pDef->funcFlags & SQLITE_FUNC_ANYORDER)!=0 );
|
|
+ pNC2->ncFlags |= NC_HasAgg
|
|
+ | ((pDef->funcFlags^SQLITE_FUNC_ANYORDER)
|
|
+ & (SQLITE_FUNC_MINMAX|SQLITE_FUNC_ANYORDER));
|
|
}
|
|
}
|
|
pNC->ncFlags |= savedAllowFlags;
|
|
}
|
|
/* FIX ME: Compute pExpr->affinity based on the expected return
|
|
- ** type of the function
|
|
+ ** type of the function
|
|
*/
|
|
return WRC_Prune;
|
|
}
|
|
@@ -97786,20 +104789,22 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
|
#endif
|
|
case TK_IN: {
|
|
testcase( pExpr->op==TK_IN );
|
|
- if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
|
+ if( ExprUseXSelect(pExpr) ){
|
|
int nRef = pNC->nRef;
|
|
testcase( pNC->ncFlags & NC_IsCheck );
|
|
testcase( pNC->ncFlags & NC_PartIdx );
|
|
testcase( pNC->ncFlags & NC_IdxExpr );
|
|
testcase( pNC->ncFlags & NC_GenCol );
|
|
- sqlite3ResolveNotValid(pParse, pNC, "subqueries",
|
|
- NC_IsCheck|NC_PartIdx|NC_IdxExpr|NC_GenCol, pExpr);
|
|
- sqlite3WalkSelect(pWalker, pExpr->x.pSelect);
|
|
+ if( pNC->ncFlags & NC_SelfRef ){
|
|
+ notValidImpl(pParse, pNC, "subqueries", pExpr, pExpr);
|
|
+ }else{
|
|
+ sqlite3WalkSelect(pWalker, pExpr->x.pSelect);
|
|
+ }
|
|
assert( pNC->nRef>=nRef );
|
|
if( nRef!=pNC->nRef ){
|
|
ExprSetProperty(pExpr, EP_VarSelect);
|
|
- pNC->ncFlags |= NC_VarSelect;
|
|
}
|
|
+ pNC->ncFlags |= NC_Subquery;
|
|
}
|
|
break;
|
|
}
|
|
@@ -97809,7 +104814,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
|
testcase( pNC->ncFlags & NC_IdxExpr );
|
|
testcase( pNC->ncFlags & NC_GenCol );
|
|
sqlite3ResolveNotValid(pParse, pNC, "parameters",
|
|
- NC_IsCheck|NC_PartIdx|NC_IdxExpr|NC_GenCol, pExpr);
|
|
+ NC_IsCheck|NC_PartIdx|NC_IdxExpr|NC_GenCol, pExpr, pExpr);
|
|
break;
|
|
}
|
|
case TK_IS:
|
|
@@ -97818,7 +104823,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
|
assert( !ExprHasProperty(pExpr, EP_Reduced) );
|
|
/* Handle special cases of "x IS TRUE", "x IS FALSE", "x IS NOT TRUE",
|
|
** and "x IS NOT FALSE". */
|
|
- if( pRight->op==TK_ID ){
|
|
+ if( ALWAYS(pRight) && (pRight->op==TK_ID || pRight->op==TK_TRUEFALSE) ){
|
|
int rc = resolveExprStep(pWalker, pRight);
|
|
if( rc==WRC_Abort ) return WRC_Abort;
|
|
if( pRight->op==TK_TRUEFALSE ){
|
|
@@ -97827,7 +104832,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
|
return WRC_Continue;
|
|
}
|
|
}
|
|
- /* Fall thru */
|
|
+ /* no break */ deliberate_fall_through
|
|
}
|
|
case TK_BETWEEN:
|
|
case TK_EQ:
|
|
@@ -97841,6 +104846,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
|
assert( pExpr->pLeft!=0 );
|
|
nLeft = sqlite3ExprVectorSize(pExpr->pLeft);
|
|
if( pExpr->op==TK_BETWEEN ){
|
|
+ assert( ExprUseXList(pExpr) );
|
|
nRight = sqlite3ExprVectorSize(pExpr->x.pList->a[0].pExpr);
|
|
if( nRight==nLeft ){
|
|
nRight = sqlite3ExprVectorSize(pExpr->x.pList->a[1].pExpr);
|
|
@@ -97860,11 +104866,13 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
|
testcase( pExpr->op==TK_ISNOT );
|
|
testcase( pExpr->op==TK_BETWEEN );
|
|
sqlite3ErrorMsg(pParse, "row value misused");
|
|
+ sqlite3RecordErrorOffsetOfExpr(pParse->db, pExpr);
|
|
}
|
|
- break;
|
|
+ break;
|
|
}
|
|
}
|
|
- return (pParse->nErr || pParse->db->mallocFailed) ? WRC_Abort : WRC_Continue;
|
|
+ assert( pParse->db->mallocFailed==0 || pParse->nErr!=0 );
|
|
+ return pParse->nErr ? WRC_Abort : WRC_Continue;
|
|
}
|
|
|
|
/*
|
|
@@ -97889,9 +104897,11 @@ static int resolveAsName(
|
|
UNUSED_PARAMETER(pParse);
|
|
|
|
if( pE->op==TK_ID ){
|
|
- char *zCol = pE->u.zToken;
|
|
+ const char *zCol;
|
|
+ assert( !ExprHasProperty(pE, EP_IntValue) );
|
|
+ zCol = pE->u.zToken;
|
|
for(i=0; i<pEList->nExpr; i++){
|
|
- if( pEList->a[i].eEName==ENAME_NAME
|
|
+ if( pEList->a[i].fg.eEName==ENAME_NAME
|
|
&& sqlite3_stricmp(pEList->a[i].zEName, zCol)==0
|
|
){
|
|
return i+1;
|
|
@@ -97940,8 +104950,8 @@ static int resolveOrderByTermToExprList(
|
|
nc.pParse = pParse;
|
|
nc.pSrcList = pSelect->pSrc;
|
|
nc.uNC.pEList = pEList;
|
|
- nc.ncFlags = NC_AllowAgg|NC_UEList;
|
|
- nc.nErr = 0;
|
|
+ nc.ncFlags = NC_AllowAgg|NC_UEList|NC_NoSelect;
|
|
+ nc.nNcErr = 0;
|
|
db = pParse->db;
|
|
savedSuppErr = db->suppressErr;
|
|
db->suppressErr = 1;
|
|
@@ -97970,11 +104980,13 @@ static void resolveOutOfRangeError(
|
|
Parse *pParse, /* The error context into which to write the error */
|
|
const char *zType, /* "ORDER" or "GROUP" */
|
|
int i, /* The index (1-based) of the term out of range */
|
|
- int mx /* Largest permissible value of i */
|
|
+ int mx, /* Largest permissible value of i */
|
|
+ Expr *pError /* Associate the error with the expression */
|
|
){
|
|
- sqlite3ErrorMsg(pParse,
|
|
+ sqlite3ErrorMsg(pParse,
|
|
"%r %s BY term out of range - should be "
|
|
"between 1 and %d", i, zType, mx);
|
|
+ sqlite3RecordErrorOffsetOfExpr(pParse->db, pError);
|
|
}
|
|
|
|
/*
|
|
@@ -98010,7 +105022,7 @@ static int resolveCompoundOrderBy(
|
|
return 1;
|
|
}
|
|
for(i=0; i<pOrderBy->nExpr; i++){
|
|
- pOrderBy->a[i].done = 0;
|
|
+ pOrderBy->a[i].fg.done = 0;
|
|
}
|
|
pSelect->pNext = 0;
|
|
while( pSelect->pPrior ){
|
|
@@ -98025,46 +105037,42 @@ static int resolveCompoundOrderBy(
|
|
for(i=0, pItem=pOrderBy->a; i<pOrderBy->nExpr; i++, pItem++){
|
|
int iCol = -1;
|
|
Expr *pE, *pDup;
|
|
- if( pItem->done ) continue;
|
|
+ if( pItem->fg.done ) continue;
|
|
pE = sqlite3ExprSkipCollateAndLikely(pItem->pExpr);
|
|
+ if( NEVER(pE==0) ) continue;
|
|
if( sqlite3ExprIsInteger(pE, &iCol) ){
|
|
if( iCol<=0 || iCol>pEList->nExpr ){
|
|
- resolveOutOfRangeError(pParse, "ORDER", i+1, pEList->nExpr);
|
|
+ resolveOutOfRangeError(pParse, "ORDER", i+1, pEList->nExpr, pE);
|
|
return 1;
|
|
}
|
|
}else{
|
|
iCol = resolveAsName(pParse, pEList, pE);
|
|
if( iCol==0 ){
|
|
/* Now test if expression pE matches one of the values returned
|
|
- ** by pSelect. In the usual case this is done by duplicating the
|
|
+ ** by pSelect. In the usual case this is done by duplicating the
|
|
** expression, resolving any symbols in it, and then comparing
|
|
** it against each expression returned by the SELECT statement.
|
|
** Once the comparisons are finished, the duplicate expression
|
|
** is deleted.
|
|
**
|
|
- ** Or, if this is running as part of an ALTER TABLE operation,
|
|
- ** resolve the symbols in the actual expression, not a duplicate.
|
|
- ** And, if one of the comparisons is successful, leave the expression
|
|
- ** as is instead of transforming it to an integer as in the usual
|
|
- ** case. This allows the code in alter.c to modify column
|
|
- ** refererences within the ORDER BY expression as required. */
|
|
- if( IN_RENAME_OBJECT ){
|
|
- pDup = pE;
|
|
- }else{
|
|
- pDup = sqlite3ExprDup(db, pE, 0);
|
|
- }
|
|
+ ** If this is running as part of an ALTER TABLE operation and
|
|
+ ** the symbols resolve successfully, also resolve the symbols in the
|
|
+ ** actual expression. This allows the code in alter.c to modify
|
|
+ ** column references within the ORDER BY expression as required. */
|
|
+ pDup = sqlite3ExprDup(db, pE, 0);
|
|
if( !db->mallocFailed ){
|
|
assert(pDup);
|
|
iCol = resolveOrderByTermToExprList(pParse, pSelect, pDup);
|
|
+ if( IN_RENAME_OBJECT && iCol>0 ){
|
|
+ resolveOrderByTermToExprList(pParse, pSelect, pE);
|
|
+ }
|
|
}
|
|
- if( !IN_RENAME_OBJECT ){
|
|
- sqlite3ExprDelete(db, pDup);
|
|
- }
|
|
+ sqlite3ExprDelete(db, pDup);
|
|
}
|
|
}
|
|
if( iCol>0 ){
|
|
/* Convert the ORDER BY term into an integer column number iCol,
|
|
- ** taking care to preserve the COLLATE clause if it exists */
|
|
+ ** taking care to preserve the COLLATE clause if it exists. */
|
|
if( !IN_RENAME_OBJECT ){
|
|
Expr *pNew = sqlite3Expr(db, TK_INTEGER, 0);
|
|
if( pNew==0 ) return 1;
|
|
@@ -98082,7 +105090,7 @@ static int resolveCompoundOrderBy(
|
|
sqlite3ExprDelete(db, pE);
|
|
pItem->u.x.iOrderByCol = (u16)iCol;
|
|
}
|
|
- pItem->done = 1;
|
|
+ pItem->fg.done = 1;
|
|
}else{
|
|
moreToDo = 1;
|
|
}
|
|
@@ -98090,7 +105098,7 @@ static int resolveCompoundOrderBy(
|
|
pSelect = pSelect->pNext;
|
|
}
|
|
for(i=0; i<pOrderBy->nExpr; i++){
|
|
- if( pOrderBy->a[i].done==0 ){
|
|
+ if( pOrderBy->a[i].fg.done==0 ){
|
|
sqlite3ErrorMsg(pParse, "%r ORDER BY term does not match any "
|
|
"column in the result set", i+1);
|
|
return 1;
|
|
@@ -98130,11 +105138,10 @@ SQLITE_PRIVATE int sqlite3ResolveOrderGroupBy(
|
|
for(i=0, pItem=pOrderBy->a; i<pOrderBy->nExpr; i++, pItem++){
|
|
if( pItem->u.x.iOrderByCol ){
|
|
if( pItem->u.x.iOrderByCol>pEList->nExpr ){
|
|
- resolveOutOfRangeError(pParse, zType, i+1, pEList->nExpr);
|
|
+ resolveOutOfRangeError(pParse, zType, i+1, pEList->nExpr, 0);
|
|
return 1;
|
|
}
|
|
- resolveAlias(pParse, pEList, pItem->u.x.iOrderByCol-1, pItem->pExpr,
|
|
- zType,0);
|
|
+ resolveAlias(pParse, pEList, pItem->u.x.iOrderByCol-1, pItem->pExpr,0);
|
|
}
|
|
}
|
|
return 0;
|
|
@@ -98200,12 +105207,13 @@ static int resolveOrderGroupBy(
|
|
Parse *pParse; /* Parsing context */
|
|
int nResult; /* Number of terms in the result set */
|
|
|
|
- if( pOrderBy==0 ) return 0;
|
|
+ assert( pOrderBy!=0 );
|
|
nResult = pSelect->pEList->nExpr;
|
|
pParse = pNC->pParse;
|
|
for(i=0, pItem=pOrderBy->a; i<pOrderBy->nExpr; i++, pItem++){
|
|
Expr *pE = pItem->pExpr;
|
|
Expr *pE2 = sqlite3ExprSkipCollateAndLikely(pE);
|
|
+ if( NEVER(pE2==0) ) continue;
|
|
if( zType[0]!='G' ){
|
|
iCol = resolveAsName(pParse, pSelect->pEList, pE2);
|
|
if( iCol>0 ){
|
|
@@ -98222,7 +105230,7 @@ static int resolveOrderGroupBy(
|
|
** number so that sqlite3ResolveOrderGroupBy() will convert the
|
|
** order-by term to a copy of the result-set expression */
|
|
if( iCol<1 || iCol>0xffff ){
|
|
- resolveOutOfRangeError(pParse, zType, i+1, nResult);
|
|
+ resolveOutOfRangeError(pParse, zType, i+1, nResult, pE2);
|
|
return 1;
|
|
}
|
|
pItem->u.x.iOrderByCol = (u16)iCol;
|
|
@@ -98260,7 +105268,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
|
|
ExprList *pGroupBy; /* The GROUP BY clause */
|
|
Select *pLeftmost; /* Left-most of SELECT of a compound */
|
|
sqlite3 *db; /* Database connection */
|
|
-
|
|
+
|
|
|
|
assert( p!=0 );
|
|
if( p->selFlags & SF_Resolved ){
|
|
@@ -98280,7 +105288,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
|
|
*/
|
|
if( (p->selFlags & SF_Expanded)==0 ){
|
|
sqlite3SelectPrep(pParse, p, pOuterNC);
|
|
- return (pParse->nErr || db->mallocFailed) ? WRC_Abort : WRC_Prune;
|
|
+ return pParse->nErr ? WRC_Abort : WRC_Prune;
|
|
}
|
|
|
|
isCompound = p->pPrior!=0;
|
|
@@ -98289,8 +105297,10 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
|
|
while( p ){
|
|
assert( (p->selFlags & SF_Expanded)!=0 );
|
|
assert( (p->selFlags & SF_Resolved)==0 );
|
|
+ assert( db->suppressErr==0 ); /* SF_Resolved not set if errors suppressed */
|
|
p->selFlags |= SF_Resolved;
|
|
|
|
+
|
|
/* Resolve the expressions in the LIMIT and OFFSET clauses. These
|
|
** are not allowed to refer to any names, so pass an empty NameContext.
|
|
*/
|
|
@@ -98314,64 +105324,58 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
|
|
pSub->pOrderBy = p->pOrderBy;
|
|
p->pOrderBy = 0;
|
|
}
|
|
-
|
|
- /* Recursively resolve names in all subqueries
|
|
+
|
|
+ /* Recursively resolve names in all subqueries in the FROM clause
|
|
*/
|
|
for(i=0; i<p->pSrc->nSrc; i++){
|
|
- struct SrcList_item *pItem = &p->pSrc->a[i];
|
|
+ SrcItem *pItem = &p->pSrc->a[i];
|
|
if( pItem->pSelect && (pItem->pSelect->selFlags & SF_Resolved)==0 ){
|
|
- NameContext *pNC; /* Used to iterate name contexts */
|
|
- int nRef = 0; /* Refcount for pOuterNC and outer contexts */
|
|
+ int nRef = pOuterNC ? pOuterNC->nRef : 0;
|
|
const char *zSavedContext = pParse->zAuthContext;
|
|
|
|
- /* Count the total number of references to pOuterNC and all of its
|
|
- ** parent contexts. After resolving references to expressions in
|
|
- ** pItem->pSelect, check if this value has changed. If so, then
|
|
- ** SELECT statement pItem->pSelect must be correlated. Set the
|
|
- ** pItem->fg.isCorrelated flag if this is the case. */
|
|
- for(pNC=pOuterNC; pNC; pNC=pNC->pNext) nRef += pNC->nRef;
|
|
-
|
|
if( pItem->zName ) pParse->zAuthContext = pItem->zName;
|
|
sqlite3ResolveSelectNames(pParse, pItem->pSelect, pOuterNC);
|
|
pParse->zAuthContext = zSavedContext;
|
|
- if( pParse->nErr || db->mallocFailed ) return WRC_Abort;
|
|
+ if( pParse->nErr ) return WRC_Abort;
|
|
+ assert( db->mallocFailed==0 );
|
|
|
|
- for(pNC=pOuterNC; pNC; pNC=pNC->pNext) nRef -= pNC->nRef;
|
|
- assert( pItem->fg.isCorrelated==0 && nRef<=0 );
|
|
- pItem->fg.isCorrelated = (nRef!=0);
|
|
+ /* If the number of references to the outer context changed when
|
|
+ ** expressions in the sub-select were resolved, the sub-select
|
|
+ ** is correlated. It is not required to check the refcount on any
|
|
+ ** but the innermost outer context object, as lookupName() increments
|
|
+ ** the refcount on all contexts between the current one and the
|
|
+ ** context containing the column when it resolves a name. */
|
|
+ if( pOuterNC ){
|
|
+ assert( pItem->fg.isCorrelated==0 && pOuterNC->nRef>=nRef );
|
|
+ pItem->fg.isCorrelated = (pOuterNC->nRef>nRef);
|
|
+ }
|
|
}
|
|
}
|
|
-
|
|
+
|
|
/* Set up the local name-context to pass to sqlite3ResolveExprNames() to
|
|
** resolve the result-set expression list.
|
|
*/
|
|
sNC.ncFlags = NC_AllowAgg|NC_AllowWin;
|
|
sNC.pSrcList = p->pSrc;
|
|
sNC.pNext = pOuterNC;
|
|
-
|
|
+
|
|
/* Resolve names in the result set. */
|
|
if( sqlite3ResolveExprListNames(&sNC, p->pEList) ) return WRC_Abort;
|
|
sNC.ncFlags &= ~NC_AllowWin;
|
|
-
|
|
- /* If there are no aggregate functions in the result-set, and no GROUP BY
|
|
+
|
|
+ /* If there are no aggregate functions in the result-set, and no GROUP BY
|
|
** expression, do not allow aggregates in any of the other expressions.
|
|
*/
|
|
assert( (p->selFlags & SF_Aggregate)==0 );
|
|
pGroupBy = p->pGroupBy;
|
|
if( pGroupBy || (sNC.ncFlags & NC_HasAgg)!=0 ){
|
|
assert( NC_MinMaxAgg==SF_MinMaxAgg );
|
|
- p->selFlags |= SF_Aggregate | (sNC.ncFlags&NC_MinMaxAgg);
|
|
+ assert( NC_OrderAgg==SF_OrderByReqd );
|
|
+ p->selFlags |= SF_Aggregate | (sNC.ncFlags&(NC_MinMaxAgg|NC_OrderAgg));
|
|
}else{
|
|
sNC.ncFlags &= ~NC_AllowAgg;
|
|
}
|
|
-
|
|
- /* If a HAVING clause is present, then there must be a GROUP BY clause.
|
|
- */
|
|
- if( p->pHaving && !pGroupBy ){
|
|
- sqlite3ErrorMsg(pParse, "a GROUP BY clause is required before HAVING");
|
|
- return WRC_Abort;
|
|
- }
|
|
-
|
|
+
|
|
/* Add the output column list to the name-context before parsing the
|
|
** other expressions in the SELECT statement. This is so that
|
|
** expressions in the WHERE clause (etc.) can refer to expressions by
|
|
@@ -98380,29 +105384,48 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
|
|
** Minor point: If this is the case, then the expression will be
|
|
** re-evaluated for each reference to it.
|
|
*/
|
|
- assert( (sNC.ncFlags & (NC_UAggInfo|NC_UUpsert))==0 );
|
|
+ assert( (sNC.ncFlags & (NC_UAggInfo|NC_UUpsert|NC_UBaseReg))==0 );
|
|
sNC.uNC.pEList = p->pEList;
|
|
sNC.ncFlags |= NC_UEList;
|
|
- if( sqlite3ResolveExprNames(&sNC, p->pHaving) ) return WRC_Abort;
|
|
+ if( p->pHaving ){
|
|
+ if( (p->selFlags & SF_Aggregate)==0 ){
|
|
+ sqlite3ErrorMsg(pParse, "HAVING clause on a non-aggregate query");
|
|
+ return WRC_Abort;
|
|
+ }
|
|
+ if( sqlite3ResolveExprNames(&sNC, p->pHaving) ) return WRC_Abort;
|
|
+ }
|
|
if( sqlite3ResolveExprNames(&sNC, p->pWhere) ) return WRC_Abort;
|
|
|
|
/* Resolve names in table-valued-function arguments */
|
|
for(i=0; i<p->pSrc->nSrc; i++){
|
|
- struct SrcList_item *pItem = &p->pSrc->a[i];
|
|
+ SrcItem *pItem = &p->pSrc->a[i];
|
|
if( pItem->fg.isTabFunc
|
|
- && sqlite3ResolveExprListNames(&sNC, pItem->u1.pFuncArg)
|
|
+ && sqlite3ResolveExprListNames(&sNC, pItem->u1.pFuncArg)
|
|
){
|
|
return WRC_Abort;
|
|
}
|
|
}
|
|
|
|
+#ifndef SQLITE_OMIT_WINDOWFUNC
|
|
+ if( IN_RENAME_OBJECT ){
|
|
+ Window *pWin;
|
|
+ for(pWin=p->pWinDefn; pWin; pWin=pWin->pNextWin){
|
|
+ if( sqlite3ResolveExprListNames(&sNC, pWin->pOrderBy)
|
|
+ || sqlite3ResolveExprListNames(&sNC, pWin->pPartition)
|
|
+ ){
|
|
+ return WRC_Abort;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+#endif
|
|
+
|
|
/* The ORDER BY and GROUP BY clauses may not refer to terms in
|
|
- ** outer queries
|
|
+ ** outer queries
|
|
*/
|
|
sNC.pNext = 0;
|
|
sNC.ncFlags |= NC_AllowAgg|NC_AllowWin;
|
|
|
|
- /* If this is a converted compound query, move the ORDER BY clause from
|
|
+ /* If this is a converted compound query, move the ORDER BY clause from
|
|
** the sub-query back to the parent query. At this point each term
|
|
** within the ORDER BY clause has been transformed to an integer value.
|
|
** These integers will be replaced by copies of the corresponding result
|
|
@@ -98423,7 +105446,8 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
|
|
** is not detected until much later, and so we need to go ahead and
|
|
** resolve those symbols on the incorrect ORDER BY for consistency.
|
|
*/
|
|
- if( isCompound<=nCompound /* Defer right-most ORDER BY of a compound */
|
|
+ if( p->pOrderBy!=0
|
|
+ && isCompound<=nCompound /* Defer right-most ORDER BY of a compound */
|
|
&& resolveOrderGroupBy(&sNC, p, p->pOrderBy, "ORDER")
|
|
){
|
|
return WRC_Abort;
|
|
@@ -98432,13 +105456,13 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
|
|
return WRC_Abort;
|
|
}
|
|
sNC.ncFlags &= ~NC_AllowWin;
|
|
-
|
|
- /* Resolve the GROUP BY clause. At the same time, make sure
|
|
+
|
|
+ /* Resolve the GROUP BY clause. At the same time, make sure
|
|
** the GROUP BY clause does not contain aggregate functions.
|
|
*/
|
|
if( pGroupBy ){
|
|
struct ExprList_item *pItem;
|
|
-
|
|
+
|
|
if( resolveOrderGroupBy(&sNC, p, pGroupBy, "GROUP") || db->mallocFailed ){
|
|
return WRC_Abort;
|
|
}
|
|
@@ -98451,19 +105475,6 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
|
|
}
|
|
}
|
|
|
|
-#ifndef SQLITE_OMIT_WINDOWFUNC
|
|
- if( IN_RENAME_OBJECT ){
|
|
- Window *pWin;
|
|
- for(pWin=p->pWinDefn; pWin; pWin=pWin->pNextWin){
|
|
- if( sqlite3ResolveExprListNames(&sNC, pWin->pOrderBy)
|
|
- || sqlite3ResolveExprListNames(&sNC, pWin->pPartition)
|
|
- ){
|
|
- return WRC_Abort;
|
|
- }
|
|
- }
|
|
- }
|
|
-#endif
|
|
-
|
|
/* If this is part of a compound SELECT, check that it has the right
|
|
** number of expressions in the select list. */
|
|
if( p->pNext && p->pEList->nExpr!=p->pNext->pEList->nExpr ){
|
|
@@ -98493,7 +105504,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
|
|
** checking on function usage and set a flag if any aggregate functions
|
|
** are seen.
|
|
**
|
|
-** To resolve table columns references we look for nodes (or subtrees) of the
|
|
+** To resolve table columns references we look for nodes (or subtrees) of the
|
|
** form X.Y.Z or Y.Z or just Z where
|
|
**
|
|
** X: The name of a database. Ex: "main" or "temp" or
|
|
@@ -98525,7 +105536,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
|
|
**
|
|
** SELECT a+b AS x, c+d AS y FROM t1 ORDER BY a+b;
|
|
**
|
|
-** Function calls are checked to make sure that the function is
|
|
+** Function calls are checked to make sure that the function is
|
|
** defined and that the correct number of arguments are specified.
|
|
** If the function is an aggregate function, then the NC_HasAgg flag is
|
|
** set and the opcode is changed from TK_FUNCTION to TK_AGG_FUNCTION.
|
|
@@ -98535,7 +105546,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
|
|
** An error message is left in pParse if anything is amiss. The number
|
|
** if errors is returned.
|
|
*/
|
|
-SQLITE_PRIVATE int sqlite3ResolveExprNames(
|
|
+SQLITE_PRIVATE int sqlite3ResolveExprNames(
|
|
NameContext *pNC, /* Namespace to resolve expressions in. */
|
|
Expr *pExpr /* The expression to be analyzed. */
|
|
){
|
|
@@ -98543,11 +105554,11 @@ SQLITE_PRIVATE int sqlite3ResolveExprNames(
|
|
Walker w;
|
|
|
|
if( pExpr==0 ) return SQLITE_OK;
|
|
- savedHasAgg = pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg|NC_HasWin);
|
|
- pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg|NC_HasWin);
|
|
+ savedHasAgg = pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg);
|
|
+ pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg);
|
|
w.pParse = pNC->pParse;
|
|
w.xExprCallback = resolveExprStep;
|
|
- w.xSelectCallback = resolveSelectStep;
|
|
+ w.xSelectCallback = (pNC->ncFlags & NC_NoSelect) ? 0 : resolveSelectStep;
|
|
w.xSelectCallback2 = 0;
|
|
w.u.pNC = pNC;
|
|
#if SQLITE_MAX_EXPR_DEPTH>0
|
|
@@ -98566,7 +105577,7 @@ SQLITE_PRIVATE int sqlite3ResolveExprNames(
|
|
testcase( pNC->ncFlags & NC_HasWin );
|
|
ExprSetProperty(pExpr, pNC->ncFlags & (NC_HasAgg|NC_HasWin) );
|
|
pNC->ncFlags |= savedHasAgg;
|
|
- return pNC->nErr>0 || w.pParse->nErr>0;
|
|
+ return pNC->nNcErr>0 || w.pParse->nErr>0;
|
|
}
|
|
|
|
/*
|
|
@@ -98574,16 +105585,47 @@ SQLITE_PRIVATE int sqlite3ResolveExprNames(
|
|
** just like sqlite3ResolveExprNames() except that it works for an expression
|
|
** list rather than a single expression.
|
|
*/
|
|
-SQLITE_PRIVATE int sqlite3ResolveExprListNames(
|
|
+SQLITE_PRIVATE int sqlite3ResolveExprListNames(
|
|
NameContext *pNC, /* Namespace to resolve expressions in. */
|
|
ExprList *pList /* The expression list to be analyzed. */
|
|
){
|
|
int i;
|
|
- if( pList ){
|
|
- for(i=0; i<pList->nExpr; i++){
|
|
- if( sqlite3ResolveExprNames(pNC, pList->a[i].pExpr) ) return WRC_Abort;
|
|
+ int savedHasAgg = 0;
|
|
+ Walker w;
|
|
+ if( pList==0 ) return WRC_Continue;
|
|
+ w.pParse = pNC->pParse;
|
|
+ w.xExprCallback = resolveExprStep;
|
|
+ w.xSelectCallback = resolveSelectStep;
|
|
+ w.xSelectCallback2 = 0;
|
|
+ w.u.pNC = pNC;
|
|
+ savedHasAgg = pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg);
|
|
+ pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg);
|
|
+ for(i=0; i<pList->nExpr; i++){
|
|
+ Expr *pExpr = pList->a[i].pExpr;
|
|
+ if( pExpr==0 ) continue;
|
|
+#if SQLITE_MAX_EXPR_DEPTH>0
|
|
+ w.pParse->nHeight += pExpr->nHeight;
|
|
+ if( sqlite3ExprCheckHeight(w.pParse, w.pParse->nHeight) ){
|
|
+ return WRC_Abort;
|
|
}
|
|
+#endif
|
|
+ sqlite3WalkExpr(&w, pExpr);
|
|
+#if SQLITE_MAX_EXPR_DEPTH>0
|
|
+ w.pParse->nHeight -= pExpr->nHeight;
|
|
+#endif
|
|
+ assert( EP_Agg==NC_HasAgg );
|
|
+ assert( EP_Win==NC_HasWin );
|
|
+ testcase( pNC->ncFlags & NC_HasAgg );
|
|
+ testcase( pNC->ncFlags & NC_HasWin );
|
|
+ if( pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg) ){
|
|
+ ExprSetProperty(pExpr, pNC->ncFlags & (NC_HasAgg|NC_HasWin) );
|
|
+ savedHasAgg |= pNC->ncFlags &
|
|
+ (NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg);
|
|
+ pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg);
|
|
+ }
|
|
+ if( w.pParse->nErr>0 ) return WRC_Abort;
|
|
}
|
|
+ pNC->ncFlags |= savedHasAgg;
|
|
return WRC_Continue;
|
|
}
|
|
|
|
@@ -98693,16 +105735,16 @@ static int exprCodeVector(Parse *pParse, Expr *p, int *piToFree);
|
|
/*
|
|
** Return the affinity character for a single column of a table.
|
|
*/
|
|
-SQLITE_PRIVATE char sqlite3TableColumnAffinity(Table *pTab, int iCol){
|
|
- assert( iCol<pTab->nCol );
|
|
- return iCol>=0 ? pTab->aCol[iCol].affinity : SQLITE_AFF_INTEGER;
|
|
+SQLITE_PRIVATE char sqlite3TableColumnAffinity(const Table *pTab, int iCol){
|
|
+ if( iCol<0 || NEVER(iCol>=pTab->nCol) ) return SQLITE_AFF_INTEGER;
|
|
+ return pTab->aCol[iCol].affinity;
|
|
}
|
|
|
|
/*
|
|
** Return the 'affinity' of the expression pExpr if any.
|
|
**
|
|
** If pExpr is a column, a reference to a column via an 'AS' alias,
|
|
-** or a sub-select with a column as the return value, then the
|
|
+** or a sub-select with a column as the return value, then the
|
|
** affinity of that column is returned. Otherwise, 0x00 is returned,
|
|
** indicating no affinity for the expression.
|
|
**
|
|
@@ -98714,40 +105756,123 @@ SQLITE_PRIVATE char sqlite3TableColumnAffinity(Table *pTab, int iCol){
|
|
** SELECT a AS b FROM t1 WHERE b;
|
|
** SELECT * FROM t1 WHERE (select a from t1);
|
|
*/
|
|
-SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr){
|
|
+SQLITE_PRIVATE char sqlite3ExprAffinity(const Expr *pExpr){
|
|
int op;
|
|
- while( ExprHasProperty(pExpr, EP_Skip) ){
|
|
- assert( pExpr->op==TK_COLLATE );
|
|
- pExpr = pExpr->pLeft;
|
|
- assert( pExpr!=0 );
|
|
- }
|
|
op = pExpr->op;
|
|
- if( op==TK_SELECT ){
|
|
- assert( pExpr->flags&EP_xIsSelect );
|
|
- return sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr);
|
|
- }
|
|
- if( op==TK_REGISTER ) op = pExpr->op2;
|
|
+ while( 1 /* exit-by-break */ ){
|
|
+ if( op==TK_COLUMN || (op==TK_AGG_COLUMN && pExpr->y.pTab!=0) ){
|
|
+ assert( ExprUseYTab(pExpr) );
|
|
+ assert( pExpr->y.pTab!=0 );
|
|
+ return sqlite3TableColumnAffinity(pExpr->y.pTab, pExpr->iColumn);
|
|
+ }
|
|
+ if( op==TK_SELECT ){
|
|
+ assert( ExprUseXSelect(pExpr) );
|
|
+ assert( pExpr->x.pSelect!=0 );
|
|
+ assert( pExpr->x.pSelect->pEList!=0 );
|
|
+ assert( pExpr->x.pSelect->pEList->a[0].pExpr!=0 );
|
|
+ return sqlite3ExprAffinity(pExpr->x.pSelect->pEList->a[0].pExpr);
|
|
+ }
|
|
#ifndef SQLITE_OMIT_CAST
|
|
- if( op==TK_CAST ){
|
|
- assert( !ExprHasProperty(pExpr, EP_IntValue) );
|
|
- return sqlite3AffinityType(pExpr->u.zToken, 0);
|
|
- }
|
|
+ if( op==TK_CAST ){
|
|
+ assert( !ExprHasProperty(pExpr, EP_IntValue) );
|
|
+ return sqlite3AffinityType(pExpr->u.zToken, 0);
|
|
+ }
|
|
#endif
|
|
- if( (op==TK_AGG_COLUMN || op==TK_COLUMN) && pExpr->y.pTab ){
|
|
- return sqlite3TableColumnAffinity(pExpr->y.pTab, pExpr->iColumn);
|
|
- }
|
|
- if( op==TK_SELECT_COLUMN ){
|
|
- assert( pExpr->pLeft->flags&EP_xIsSelect );
|
|
- return sqlite3ExprAffinity(
|
|
- pExpr->pLeft->x.pSelect->pEList->a[pExpr->iColumn].pExpr
|
|
- );
|
|
- }
|
|
- if( op==TK_VECTOR ){
|
|
- return sqlite3ExprAffinity(pExpr->x.pList->a[0].pExpr);
|
|
+ if( op==TK_SELECT_COLUMN ){
|
|
+ assert( pExpr->pLeft!=0 && ExprUseXSelect(pExpr->pLeft) );
|
|
+ assert( pExpr->iColumn < pExpr->iTable );
|
|
+ assert( pExpr->iTable==pExpr->pLeft->x.pSelect->pEList->nExpr );
|
|
+ return sqlite3ExprAffinity(
|
|
+ pExpr->pLeft->x.pSelect->pEList->a[pExpr->iColumn].pExpr
|
|
+ );
|
|
+ }
|
|
+ if( op==TK_VECTOR ){
|
|
+ assert( ExprUseXList(pExpr) );
|
|
+ return sqlite3ExprAffinity(pExpr->x.pList->a[0].pExpr);
|
|
+ }
|
|
+ if( ExprHasProperty(pExpr, EP_Skip|EP_IfNullRow) ){
|
|
+ assert( pExpr->op==TK_COLLATE
|
|
+ || pExpr->op==TK_IF_NULL_ROW
|
|
+ || (pExpr->op==TK_REGISTER && pExpr->op2==TK_IF_NULL_ROW) );
|
|
+ pExpr = pExpr->pLeft;
|
|
+ op = pExpr->op;
|
|
+ continue;
|
|
+ }
|
|
+ if( op!=TK_REGISTER || (op = pExpr->op2)==TK_REGISTER ) break;
|
|
}
|
|
return pExpr->affExpr;
|
|
}
|
|
|
|
+/*
|
|
+** Make a guess at all the possible datatypes of the result that could
|
|
+** be returned by an expression. Return a bitmask indicating the answer:
|
|
+**
|
|
+** 0x01 Numeric
|
|
+** 0x02 Text
|
|
+** 0x04 Blob
|
|
+**
|
|
+** If the expression must return NULL, then 0x00 is returned.
|
|
+*/
|
|
+SQLITE_PRIVATE int sqlite3ExprDataType(const Expr *pExpr){
|
|
+ while( pExpr ){
|
|
+ switch( pExpr->op ){
|
|
+ case TK_COLLATE:
|
|
+ case TK_IF_NULL_ROW:
|
|
+ case TK_UPLUS: {
|
|
+ pExpr = pExpr->pLeft;
|
|
+ break;
|
|
+ }
|
|
+ case TK_NULL: {
|
|
+ pExpr = 0;
|
|
+ break;
|
|
+ }
|
|
+ case TK_STRING: {
|
|
+ return 0x02;
|
|
+ }
|
|
+ case TK_BLOB: {
|
|
+ return 0x04;
|
|
+ }
|
|
+ case TK_CONCAT: {
|
|
+ return 0x06;
|
|
+ }
|
|
+ case TK_VARIABLE:
|
|
+ case TK_AGG_FUNCTION:
|
|
+ case TK_FUNCTION: {
|
|
+ return 0x07;
|
|
+ }
|
|
+ case TK_COLUMN:
|
|
+ case TK_AGG_COLUMN:
|
|
+ case TK_SELECT:
|
|
+ case TK_CAST:
|
|
+ case TK_SELECT_COLUMN:
|
|
+ case TK_VECTOR: {
|
|
+ int aff = sqlite3ExprAffinity(pExpr);
|
|
+ if( aff>=SQLITE_AFF_NUMERIC ) return 0x05;
|
|
+ if( aff==SQLITE_AFF_TEXT ) return 0x06;
|
|
+ return 0x07;
|
|
+ }
|
|
+ case TK_CASE: {
|
|
+ int res = 0;
|
|
+ int ii;
|
|
+ ExprList *pList = pExpr->x.pList;
|
|
+ assert( ExprUseXList(pExpr) && pList!=0 );
|
|
+ assert( pList->nExpr > 0);
|
|
+ for(ii=1; ii<pList->nExpr; ii+=2){
|
|
+ res |= sqlite3ExprDataType(pList->a[ii].pExpr);
|
|
+ }
|
|
+ if( pList->nExpr % 2 ){
|
|
+ res |= sqlite3ExprDataType(pList->a[pList->nExpr-1].pExpr);
|
|
+ }
|
|
+ return res;
|
|
+ }
|
|
+ default: {
|
|
+ return 0x01;
|
|
+ }
|
|
+ } /* End of switch(op) */
|
|
+ } /* End of while(pExpr) */
|
|
+ return 0x00;
|
|
+}
|
|
+
|
|
/*
|
|
** Set the collating sequence for expression pExpr to be the collating
|
|
** sequence named by pToken. Return a pointer to a new Expr node that
|
|
@@ -98757,7 +105882,7 @@ SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr){
|
|
** and the pExpr parameter is returned unchanged.
|
|
*/
|
|
SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(
|
|
- Parse *pParse, /* Parsing context */
|
|
+ const Parse *pParse, /* Parsing context */
|
|
Expr *pExpr, /* Add the "COLLATE" clause to this expression */
|
|
const Token *pCollName, /* Name of collating sequence */
|
|
int dequote /* True to dequote pCollName */
|
|
@@ -98772,7 +105897,11 @@ SQLITE_PRIVATE Expr *sqlite3ExprAddCollateToken(
|
|
}
|
|
return pExpr;
|
|
}
|
|
-SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(Parse *pParse, Expr *pExpr, const char *zC){
|
|
+SQLITE_PRIVATE Expr *sqlite3ExprAddCollateString(
|
|
+ const Parse *pParse, /* Parsing context */
|
|
+ Expr *pExpr, /* Add the "COLLATE" clause to this expression */
|
|
+ const char *zC /* The collating sequence name */
|
|
+){
|
|
Token s;
|
|
assert( zC!=0 );
|
|
sqlite3TokenInit(&s, (char*)zC);
|
|
@@ -98786,7 +105915,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr *pExpr){
|
|
while( pExpr && ExprHasProperty(pExpr, EP_Skip) ){
|
|
assert( pExpr->op==TK_COLLATE );
|
|
pExpr = pExpr->pLeft;
|
|
- }
|
|
+ }
|
|
return pExpr;
|
|
}
|
|
|
|
@@ -98798,7 +105927,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprSkipCollate(Expr *pExpr){
|
|
SQLITE_PRIVATE Expr *sqlite3ExprSkipCollateAndLikely(Expr *pExpr){
|
|
while( pExpr && ExprHasProperty(pExpr, EP_Skip|EP_Unlikely) ){
|
|
if( ExprHasProperty(pExpr, EP_Unlikely) ){
|
|
- assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
|
|
+ assert( ExprUseXList(pExpr) );
|
|
assert( pExpr->x.pList->nExpr>0 );
|
|
assert( pExpr->op==TK_FUNCTION );
|
|
pExpr = pExpr->x.pList->a[0].pExpr;
|
|
@@ -98806,7 +105935,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprSkipCollateAndLikely(Expr *pExpr){
|
|
assert( pExpr->op==TK_COLLATE );
|
|
pExpr = pExpr->pLeft;
|
|
}
|
|
- }
|
|
+ }
|
|
return pExpr;
|
|
}
|
|
|
|
@@ -98824,21 +105953,21 @@ SQLITE_PRIVATE Expr *sqlite3ExprSkipCollateAndLikely(Expr *pExpr){
|
|
** COLLATE operators take first precedence. Left operands take
|
|
** precedence over right operands.
|
|
*/
|
|
-SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
|
|
+SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, const Expr *pExpr){
|
|
sqlite3 *db = pParse->db;
|
|
CollSeq *pColl = 0;
|
|
- Expr *p = pExpr;
|
|
+ const Expr *p = pExpr;
|
|
while( p ){
|
|
int op = p->op;
|
|
if( op==TK_REGISTER ) op = p->op2;
|
|
- if( (op==TK_AGG_COLUMN || op==TK_COLUMN || op==TK_TRIGGER)
|
|
- && p->y.pTab!=0
|
|
+ if( (op==TK_AGG_COLUMN && p->y.pTab!=0)
|
|
+ || op==TK_COLUMN || op==TK_TRIGGER
|
|
){
|
|
- /* op==TK_REGISTER && p->y.pTab!=0 happens when pExpr was originally
|
|
- ** a TK_COLUMN but was previously evaluated and cached in a register */
|
|
- int j = p->iColumn;
|
|
- if( j>=0 ){
|
|
- const char *zColl = p->y.pTab->aCol[j].zColl;
|
|
+ int j;
|
|
+ assert( ExprUseYTab(p) );
|
|
+ assert( p->y.pTab!=0 );
|
|
+ if( (j = p->iColumn)>=0 ){
|
|
+ const char *zColl = sqlite3ColumnColl(&p->y.pTab->aCol[j]);
|
|
pColl = sqlite3FindCollSeq(db, ENC(db), zColl, 0);
|
|
}
|
|
break;
|
|
@@ -98848,10 +105977,12 @@ SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
|
|
continue;
|
|
}
|
|
if( op==TK_VECTOR ){
|
|
+ assert( ExprUseXList(p) );
|
|
p = p->x.pList->a[0].pExpr;
|
|
continue;
|
|
}
|
|
if( op==TK_COLLATE ){
|
|
+ assert( !ExprHasProperty(p, EP_IntValue) );
|
|
pColl = sqlite3GetCollSeq(pParse, ENC(db), 0, p->u.zToken);
|
|
break;
|
|
}
|
|
@@ -98861,13 +105992,11 @@ SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, 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
|
|
- && ALWAYS(!ExprHasProperty(p, EP_xIsSelect))
|
|
- ){
|
|
+ if( p->x.pList!=0 && !db->mallocFailed ){
|
|
int i;
|
|
- for(i=0; i<p->x.pList->nExpr; i++){
|
|
+ for(i=0; ALWAYS(i<p->x.pList->nExpr); i++){
|
|
if( ExprHasProperty(p->x.pList->a[i].pExpr, EP_Collate) ){
|
|
pNext = p->x.pList->a[i].pExpr;
|
|
break;
|
|
@@ -98880,7 +106009,7 @@ SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
|
|
break;
|
|
}
|
|
}
|
|
- if( sqlite3CheckCollSeq(pParse, pColl) ){
|
|
+ if( sqlite3CheckCollSeq(pParse, pColl) ){
|
|
pColl = 0;
|
|
}
|
|
return pColl;
|
|
@@ -98896,7 +106025,7 @@ SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
|
|
** The sqlite3ExprCollSeq() routine works the same except that it
|
|
** returns NULL if there is no defined collation.
|
|
*/
|
|
-SQLITE_PRIVATE CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, Expr *pExpr){
|
|
+SQLITE_PRIVATE CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, const Expr *pExpr){
|
|
CollSeq *p = sqlite3ExprCollSeq(pParse, pExpr);
|
|
if( p==0 ) p = pParse->db->pDfltColl;
|
|
assert( p!=0 );
|
|
@@ -98906,7 +106035,7 @@ SQLITE_PRIVATE CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, Expr *pExpr){
|
|
/*
|
|
** Return TRUE if the two expressions have equivalent collating sequences.
|
|
*/
|
|
-SQLITE_PRIVATE int sqlite3ExprCollSeqMatch(Parse *pParse, Expr *pE1, Expr *pE2){
|
|
+SQLITE_PRIVATE int sqlite3ExprCollSeqMatch(Parse *pParse, const Expr *pE1, const Expr *pE2){
|
|
CollSeq *pColl1 = sqlite3ExprNNCollSeq(pParse, pE1);
|
|
CollSeq *pColl2 = sqlite3ExprNNCollSeq(pParse, pE2);
|
|
return sqlite3StrICmp(pColl1->zName, pColl2->zName)==0;
|
|
@@ -98917,7 +106046,7 @@ SQLITE_PRIVATE int sqlite3ExprCollSeqMatch(Parse *pParse, Expr *pE1, Expr *pE2){
|
|
** type affinity of the other operand. This routine returns the
|
|
** type affinity that should be used for the comparison operator.
|
|
*/
|
|
-SQLITE_PRIVATE char sqlite3CompareAffinity(Expr *pExpr, char aff2){
|
|
+SQLITE_PRIVATE char sqlite3CompareAffinity(const Expr *pExpr, char aff2){
|
|
char aff1 = sqlite3ExprAffinity(pExpr);
|
|
if( aff1>SQLITE_AFF_NONE && aff2>SQLITE_AFF_NONE ){
|
|
/* Both sides of the comparison are columns. If one has numeric
|
|
@@ -98939,7 +106068,7 @@ SQLITE_PRIVATE char sqlite3CompareAffinity(Expr *pExpr, char aff2){
|
|
** pExpr is a comparison operator. Return the type affinity that should
|
|
** be applied to both operands prior to doing the comparison.
|
|
*/
|
|
-static char comparisonAffinity(Expr *pExpr){
|
|
+static char comparisonAffinity(const Expr *pExpr){
|
|
char aff;
|
|
assert( pExpr->op==TK_EQ || pExpr->op==TK_IN || pExpr->op==TK_LT ||
|
|
pExpr->op==TK_GT || pExpr->op==TK_GE || pExpr->op==TK_LE ||
|
|
@@ -98948,7 +106077,7 @@ static char comparisonAffinity(Expr *pExpr){
|
|
aff = sqlite3ExprAffinity(pExpr->pLeft);
|
|
if( pExpr->pRight ){
|
|
aff = sqlite3CompareAffinity(pExpr->pRight, aff);
|
|
- }else if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
|
+ }else if( ExprUseXSelect(pExpr) ){
|
|
aff = sqlite3CompareAffinity(pExpr->x.pSelect->pEList->a[0].pExpr, aff);
|
|
}else if( aff==0 ){
|
|
aff = SQLITE_AFF_BLOB;
|
|
@@ -98962,7 +106091,7 @@ static char comparisonAffinity(Expr *pExpr){
|
|
** if the index with affinity idx_affinity may be used to implement
|
|
** the comparison in pExpr.
|
|
*/
|
|
-SQLITE_PRIVATE int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity){
|
|
+SQLITE_PRIVATE int sqlite3IndexAffinityOk(const Expr *pExpr, char idx_affinity){
|
|
char aff = comparisonAffinity(pExpr);
|
|
if( aff<SQLITE_AFF_TEXT ){
|
|
return 1;
|
|
@@ -98977,7 +106106,11 @@ SQLITE_PRIVATE int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity){
|
|
** Return the P5 value that should be used for a binary comparison
|
|
** opcode (OP_Eq, OP_Ge etc.) used to compare pExpr1 and pExpr2.
|
|
*/
|
|
-static u8 binaryCompareP5(Expr *pExpr1, Expr *pExpr2, int jumpIfNull){
|
|
+static u8 binaryCompareP5(
|
|
+ const Expr *pExpr1, /* Left operand */
|
|
+ const Expr *pExpr2, /* Right operand */
|
|
+ int jumpIfNull /* Extra flags added to P5 */
|
|
+){
|
|
u8 aff = (char)sqlite3ExprAffinity(pExpr2);
|
|
aff = (u8)sqlite3CompareAffinity(pExpr1, aff) | (u8)jumpIfNull;
|
|
return aff;
|
|
@@ -98996,9 +106129,9 @@ static u8 binaryCompareP5(Expr *pExpr1, Expr *pExpr2, int jumpIfNull){
|
|
** it is not considered.
|
|
*/
|
|
SQLITE_PRIVATE CollSeq *sqlite3BinaryCompareCollSeq(
|
|
- Parse *pParse,
|
|
- Expr *pLeft,
|
|
- Expr *pRight
|
|
+ Parse *pParse,
|
|
+ const Expr *pLeft,
|
|
+ const Expr *pRight
|
|
){
|
|
CollSeq *pColl;
|
|
assert( pLeft );
|
|
@@ -99023,7 +106156,7 @@ SQLITE_PRIVATE CollSeq *sqlite3BinaryCompareCollSeq(
|
|
** is reversed in the sqlite3BinaryCompareCollSeq() call so that the
|
|
** correct collating sequence is found.
|
|
*/
|
|
-SQLITE_PRIVATE CollSeq *sqlite3ExprCompareCollSeq(Parse *pParse, Expr *p){
|
|
+SQLITE_PRIVATE CollSeq *sqlite3ExprCompareCollSeq(Parse *pParse, const Expr *p){
|
|
if( ExprHasProperty(p, EP_Commuted) ){
|
|
return sqlite3BinaryCompareCollSeq(pParse, p->pRight, p->pLeft);
|
|
}else{
|
|
@@ -99070,22 +106203,24 @@ static int codeCompare(
|
|
** But a TK_SELECT might be either a vector or a scalar. It is only
|
|
** considered a vector if it has two or more result columns.
|
|
*/
|
|
-SQLITE_PRIVATE int sqlite3ExprIsVector(Expr *pExpr){
|
|
+SQLITE_PRIVATE int sqlite3ExprIsVector(const Expr *pExpr){
|
|
return sqlite3ExprVectorSize(pExpr)>1;
|
|
}
|
|
|
|
/*
|
|
-** If the expression passed as the only argument is of type TK_VECTOR
|
|
+** If the expression passed as the only argument is of type TK_VECTOR
|
|
** return the number of expressions in the vector. Or, if the expression
|
|
** is a sub-select, return the number of columns in the sub-select. For
|
|
** any other type of expression, return 1.
|
|
*/
|
|
-SQLITE_PRIVATE int sqlite3ExprVectorSize(Expr *pExpr){
|
|
+SQLITE_PRIVATE int sqlite3ExprVectorSize(const Expr *pExpr){
|
|
u8 op = pExpr->op;
|
|
if( op==TK_REGISTER ) op = pExpr->op2;
|
|
if( op==TK_VECTOR ){
|
|
+ assert( ExprUseXList(pExpr) );
|
|
return pExpr->x.pList->nExpr;
|
|
}else if( op==TK_SELECT ){
|
|
+ assert( ExprUseXSelect(pExpr) );
|
|
return pExpr->x.pSelect->pEList->nExpr;
|
|
}else{
|
|
return 1;
|
|
@@ -99108,12 +106243,14 @@ SQLITE_PRIVATE int sqlite3ExprVectorSize(Expr *pExpr){
|
|
** been positioned.
|
|
*/
|
|
SQLITE_PRIVATE Expr *sqlite3VectorFieldSubexpr(Expr *pVector, int i){
|
|
- assert( i<sqlite3ExprVectorSize(pVector) );
|
|
+ assert( i<sqlite3ExprVectorSize(pVector) || pVector->op==TK_ERROR );
|
|
if( sqlite3ExprIsVector(pVector) ){
|
|
assert( pVector->op2==0 || pVector->op==TK_REGISTER );
|
|
if( pVector->op==TK_SELECT || pVector->op2==TK_SELECT ){
|
|
+ assert( ExprUseXSelect(pVector) );
|
|
return pVector->x.pSelect->pEList->a[i].pExpr;
|
|
}else{
|
|
+ assert( ExprUseXList(pVector) );
|
|
return pVector->x.pList->a[i].pExpr;
|
|
}
|
|
}
|
|
@@ -99125,7 +106262,7 @@ SQLITE_PRIVATE Expr *sqlite3VectorFieldSubexpr(Expr *pVector, int i){
|
|
** sqlite3ExprCode() will generate all necessary code to compute
|
|
** the iField-th column of the vector expression pVector.
|
|
**
|
|
-** It is ok for pVector to be a scalar (as long as iField==0).
|
|
+** It is ok for pVector to be a scalar (as long as iField==0).
|
|
** In that case, this routine works like sqlite3ExprDup().
|
|
**
|
|
** The caller owns the returned Expr object and is responsible for
|
|
@@ -99144,11 +106281,12 @@ SQLITE_PRIVATE Expr *sqlite3VectorFieldSubexpr(Expr *pVector, int i){
|
|
SQLITE_PRIVATE Expr *sqlite3ExprForVectorField(
|
|
Parse *pParse, /* Parsing context */
|
|
Expr *pVector, /* The vector. List of expressions or a sub-SELECT */
|
|
- int iField /* Which column of the vector to return */
|
|
+ int iField, /* Which column of the vector to return */
|
|
+ int nField /* Total number of columns in the vector */
|
|
){
|
|
Expr *pRet;
|
|
if( pVector->op==TK_SELECT ){
|
|
- assert( pVector->flags & EP_xIsSelect );
|
|
+ assert( ExprUseXSelect(pVector) );
|
|
/* The TK_SELECT_COLUMN Expr node:
|
|
**
|
|
** pLeft: pVector containing TK_SELECT. Not deleted.
|
|
@@ -99167,21 +106305,30 @@ SQLITE_PRIVATE Expr *sqlite3ExprForVectorField(
|
|
*/
|
|
pRet = sqlite3PExpr(pParse, TK_SELECT_COLUMN, 0, 0);
|
|
if( pRet ){
|
|
+ pRet->iTable = nField;
|
|
pRet->iColumn = iField;
|
|
pRet->pLeft = pVector;
|
|
}
|
|
- assert( pRet==0 || pRet->iTable==0 );
|
|
}else{
|
|
- if( pVector->op==TK_VECTOR ) pVector = pVector->x.pList->a[iField].pExpr;
|
|
+ if( pVector->op==TK_VECTOR ){
|
|
+ Expr **ppVector;
|
|
+ assert( ExprUseXList(pVector) );
|
|
+ ppVector = &pVector->x.pList->a[iField].pExpr;
|
|
+ pVector = *ppVector;
|
|
+ if( IN_RENAME_OBJECT ){
|
|
+ /* This must be a vector UPDATE inside a trigger */
|
|
+ *ppVector = 0;
|
|
+ return pVector;
|
|
+ }
|
|
+ }
|
|
pRet = sqlite3ExprDup(pParse->db, pVector, 0);
|
|
- sqlite3RenameTokenRemap(pParse, pRet, pVector);
|
|
}
|
|
return pRet;
|
|
}
|
|
|
|
/*
|
|
** If expression pExpr is of type TK_SELECT, generate code to evaluate
|
|
-** it. Return the register in which the result is stored (or, if the
|
|
+** it. Return the register in which the result is stored (or, if the
|
|
** sub-select returns more than one column, the first in an array
|
|
** of registers in which the result is stored).
|
|
**
|
|
@@ -99203,10 +106350,10 @@ static int exprCodeSubselect(Parse *pParse, Expr *pExpr){
|
|
** the register number of a register that contains the value of
|
|
** element iField of the vector.
|
|
**
|
|
-** If pVector is a TK_SELECT expression, then code for it must have
|
|
+** If pVector is a TK_SELECT expression, then code for it must have
|
|
** already been generated using the exprCodeSubselect() routine. In this
|
|
** case parameter regSelect should be the first in an array of registers
|
|
-** containing the results of the sub-select.
|
|
+** containing the results of the sub-select.
|
|
**
|
|
** If pVector is of type TK_VECTOR, then code for the requested field
|
|
** is generated. In this case (*pRegFree) may be set to the number of
|
|
@@ -99224,17 +106371,22 @@ static int exprVectorRegister(
|
|
int *pRegFree /* OUT: Temp register to free */
|
|
){
|
|
u8 op = pVector->op;
|
|
- assert( op==TK_VECTOR || op==TK_REGISTER || op==TK_SELECT );
|
|
+ assert( op==TK_VECTOR || op==TK_REGISTER || op==TK_SELECT || op==TK_ERROR );
|
|
if( op==TK_REGISTER ){
|
|
*ppExpr = sqlite3VectorFieldSubexpr(pVector, iField);
|
|
return pVector->iTable+iField;
|
|
}
|
|
if( op==TK_SELECT ){
|
|
+ assert( ExprUseXSelect(pVector) );
|
|
*ppExpr = pVector->x.pSelect->pEList->a[iField].pExpr;
|
|
return regSelect+iField;
|
|
}
|
|
- *ppExpr = pVector->x.pList->a[iField].pExpr;
|
|
- return sqlite3ExprCodeTemp(pParse, *ppExpr, pRegFree);
|
|
+ if( op==TK_VECTOR ){
|
|
+ assert( ExprUseXList(pVector) );
|
|
+ *ppExpr = pVector->x.pList->a[iField].pExpr;
|
|
+ return sqlite3ExprCodeTemp(pParse, *ppExpr, pRegFree);
|
|
+ }
|
|
+ return 0;
|
|
}
|
|
|
|
/*
|
|
@@ -99263,39 +106415,44 @@ static void codeVectorCompare(
|
|
int regLeft = 0;
|
|
int regRight = 0;
|
|
u8 opx = op;
|
|
+ int addrCmp = 0;
|
|
int addrDone = sqlite3VdbeMakeLabel(pParse);
|
|
int isCommuted = ExprHasProperty(pExpr,EP_Commuted);
|
|
|
|
+ assert( !ExprHasVVAProperty(pExpr,EP_Immutable) );
|
|
if( pParse->nErr ) return;
|
|
if( nLeft!=sqlite3ExprVectorSize(pRight) ){
|
|
sqlite3ErrorMsg(pParse, "row value misused");
|
|
return;
|
|
}
|
|
- assert( pExpr->op==TK_EQ || pExpr->op==TK_NE
|
|
- || pExpr->op==TK_IS || pExpr->op==TK_ISNOT
|
|
- || pExpr->op==TK_LT || pExpr->op==TK_GT
|
|
- || pExpr->op==TK_LE || pExpr->op==TK_GE
|
|
+ assert( pExpr->op==TK_EQ || pExpr->op==TK_NE
|
|
+ || pExpr->op==TK_IS || pExpr->op==TK_ISNOT
|
|
+ || pExpr->op==TK_LT || pExpr->op==TK_GT
|
|
+ || pExpr->op==TK_LE || pExpr->op==TK_GE
|
|
);
|
|
assert( pExpr->op==op || (pExpr->op==TK_IS && op==TK_EQ)
|
|
|| (pExpr->op==TK_ISNOT && op==TK_NE) );
|
|
assert( p5==0 || pExpr->op!=op );
|
|
assert( p5==SQLITE_NULLEQ || pExpr->op==op );
|
|
|
|
- p5 |= SQLITE_STOREP2;
|
|
- if( opx==TK_LE ) opx = TK_LT;
|
|
- if( opx==TK_GE ) opx = TK_GT;
|
|
+ if( op==TK_LE ) opx = TK_LT;
|
|
+ if( op==TK_GE ) opx = TK_GT;
|
|
+ if( op==TK_NE ) opx = TK_EQ;
|
|
|
|
regLeft = exprCodeSubselect(pParse, pLeft);
|
|
regRight = exprCodeSubselect(pParse, pRight);
|
|
|
|
+ sqlite3VdbeAddOp2(v, OP_Integer, 1, dest);
|
|
for(i=0; 1 /*Loop exits by "break"*/; i++){
|
|
int regFree1 = 0, regFree2 = 0;
|
|
- Expr *pL, *pR;
|
|
+ Expr *pL = 0, *pR = 0;
|
|
int r1, r2;
|
|
assert( i>=0 && i<nLeft );
|
|
+ if( addrCmp ) sqlite3VdbeJumpHere(v, addrCmp);
|
|
r1 = exprVectorRegister(pParse, pLeft, i, regLeft, &pL, ®Free1);
|
|
r2 = exprVectorRegister(pParse, pRight, i, regRight, &pR, ®Free2);
|
|
- codeCompare(pParse, pL, pR, opx, r1, r2, dest, p5, isCommuted);
|
|
+ addrCmp = sqlite3VdbeCurrentAddr(v);
|
|
+ codeCompare(pParse, pL, pR, opx, r1, r2, addrDone, p5, isCommuted);
|
|
testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt);
|
|
testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le);
|
|
testcase(op==OP_Gt); VdbeCoverageIf(v,op==OP_Gt);
|
|
@@ -99304,26 +106461,32 @@ static void codeVectorCompare(
|
|
testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne);
|
|
sqlite3ReleaseTempReg(pParse, regFree1);
|
|
sqlite3ReleaseTempReg(pParse, regFree2);
|
|
+ if( (opx==TK_LT || opx==TK_GT) && i<nLeft-1 ){
|
|
+ addrCmp = sqlite3VdbeAddOp0(v, OP_ElseEq);
|
|
+ testcase(opx==TK_LT); VdbeCoverageIf(v,opx==TK_LT);
|
|
+ testcase(opx==TK_GT); VdbeCoverageIf(v,opx==TK_GT);
|
|
+ }
|
|
+ if( p5==SQLITE_NULLEQ ){
|
|
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, dest);
|
|
+ }else{
|
|
+ sqlite3VdbeAddOp3(v, OP_ZeroOrNull, r1, dest, r2);
|
|
+ }
|
|
if( i==nLeft-1 ){
|
|
break;
|
|
}
|
|
if( opx==TK_EQ ){
|
|
- sqlite3VdbeAddOp2(v, OP_IfNot, dest, addrDone); VdbeCoverage(v);
|
|
- p5 |= SQLITE_KEEPNULL;
|
|
- }else if( opx==TK_NE ){
|
|
- sqlite3VdbeAddOp2(v, OP_If, dest, addrDone); VdbeCoverage(v);
|
|
- p5 |= SQLITE_KEEPNULL;
|
|
+ sqlite3VdbeAddOp2(v, OP_NotNull, dest, addrDone); VdbeCoverage(v);
|
|
}else{
|
|
assert( op==TK_LT || op==TK_GT || op==TK_LE || op==TK_GE );
|
|
- sqlite3VdbeAddOp2(v, OP_ElseNotEq, 0, addrDone);
|
|
- VdbeCoverageIf(v, op==TK_LT);
|
|
- VdbeCoverageIf(v, op==TK_GT);
|
|
- VdbeCoverageIf(v, op==TK_LE);
|
|
- VdbeCoverageIf(v, op==TK_GE);
|
|
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, addrDone);
|
|
if( i==nLeft-2 ) opx = op;
|
|
}
|
|
}
|
|
+ sqlite3VdbeJumpHere(v, addrCmp);
|
|
sqlite3VdbeResolveLabel(v, addrDone);
|
|
+ if( op==TK_NE ){
|
|
+ sqlite3VdbeAddOp2(v, OP_Not, dest, dest);
|
|
+ }
|
|
}
|
|
|
|
#if SQLITE_MAX_EXPR_DEPTH>0
|
|
@@ -99336,7 +106499,7 @@ SQLITE_PRIVATE int sqlite3ExprCheckHeight(Parse *pParse, int nHeight){
|
|
int rc = SQLITE_OK;
|
|
int mxHeight = pParse->db->aLimit[SQLITE_LIMIT_EXPR_DEPTH];
|
|
if( nHeight>mxHeight ){
|
|
- sqlite3ErrorMsg(pParse,
|
|
+ sqlite3ErrorMsg(pParse,
|
|
"Expression tree is too large (maximum depth %d)", mxHeight
|
|
);
|
|
rc = SQLITE_ERROR;
|
|
@@ -99353,14 +106516,14 @@ SQLITE_PRIVATE int sqlite3ExprCheckHeight(Parse *pParse, int nHeight){
|
|
** to by pnHeight, the second parameter, then set *pnHeight to that
|
|
** value.
|
|
*/
|
|
-static void heightOfExpr(Expr *p, int *pnHeight){
|
|
+static void heightOfExpr(const Expr *p, int *pnHeight){
|
|
if( p ){
|
|
if( p->nHeight>*pnHeight ){
|
|
*pnHeight = p->nHeight;
|
|
}
|
|
}
|
|
}
|
|
-static void heightOfExprList(ExprList *p, int *pnHeight){
|
|
+static void heightOfExprList(const ExprList *p, int *pnHeight){
|
|
if( p ){
|
|
int i;
|
|
for(i=0; i<p->nExpr; i++){
|
|
@@ -99368,8 +106531,8 @@ static void heightOfExprList(ExprList *p, int *pnHeight){
|
|
}
|
|
}
|
|
}
|
|
-static void heightOfSelect(Select *pSelect, int *pnHeight){
|
|
- Select *p;
|
|
+static void heightOfSelect(const Select *pSelect, int *pnHeight){
|
|
+ const Select *p;
|
|
for(p=pSelect; p; p=p->pPrior){
|
|
heightOfExpr(p->pWhere, pnHeight);
|
|
heightOfExpr(p->pHaving, pnHeight);
|
|
@@ -99381,20 +106544,21 @@ static void heightOfSelect(Select *pSelect, int *pnHeight){
|
|
}
|
|
|
|
/*
|
|
-** Set the Expr.nHeight variable in the structure passed as an
|
|
-** argument. An expression with no children, Expr.pList or
|
|
+** Set the Expr.nHeight variable in the structure passed as an
|
|
+** argument. An expression with no children, Expr.pList or
|
|
** Expr.pSelect member has a height of 1. Any other expression
|
|
-** has a height equal to the maximum height of any other
|
|
+** has a height equal to the maximum height of any other
|
|
** referenced Expr plus one.
|
|
**
|
|
** Also propagate EP_Propagate flags up from Expr.x.pList to Expr.flags,
|
|
** if appropriate.
|
|
*/
|
|
static void exprSetHeight(Expr *p){
|
|
- int nHeight = 0;
|
|
- heightOfExpr(p->pLeft, &nHeight);
|
|
- heightOfExpr(p->pRight, &nHeight);
|
|
- if( ExprHasProperty(p, EP_xIsSelect) ){
|
|
+ int nHeight = p->pLeft ? p->pLeft->nHeight : 0;
|
|
+ if( NEVER(p->pRight) && p->pRight->nHeight>nHeight ){
|
|
+ nHeight = p->pRight->nHeight;
|
|
+ }
|
|
+ if( ExprUseXSelect(p) ){
|
|
heightOfSelect(p->x.pSelect, &nHeight);
|
|
}else if( p->x.pList ){
|
|
heightOfExprList(p->x.pList, &nHeight);
|
|
@@ -99409,7 +106573,7 @@ static void exprSetHeight(Expr *p){
|
|
** leave an error in pParse.
|
|
**
|
|
** Also propagate all EP_Propagate flags from the Expr.x.pList into
|
|
-** Expr.flags.
|
|
+** Expr.flags.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p){
|
|
if( pParse->nErr ) return;
|
|
@@ -99421,7 +106585,7 @@ SQLITE_PRIVATE void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p){
|
|
** Return the maximum height of any expression tree referenced
|
|
** by the select statement passed as an argument.
|
|
*/
|
|
-SQLITE_PRIVATE int sqlite3SelectExprHeight(Select *p){
|
|
+SQLITE_PRIVATE int sqlite3SelectExprHeight(const Select *p){
|
|
int nHeight = 0;
|
|
heightOfSelect(p, &nHeight);
|
|
return nHeight;
|
|
@@ -99429,10 +106593,11 @@ SQLITE_PRIVATE int sqlite3SelectExprHeight(Select *p){
|
|
#else /* ABOVE: Height enforcement enabled. BELOW: Height enforcement off */
|
|
/*
|
|
** Propagate all EP_Propagate flags from the Expr.x.pList into
|
|
-** Expr.flags.
|
|
+** Expr.flags.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p){
|
|
- if( p && p->x.pList && !ExprHasProperty(p, EP_xIsSelect) ){
|
|
+ if( pParse->nErr ) return;
|
|
+ if( p && ExprUseXList(p) && p->x.pList ){
|
|
p->flags |= EP_Propagate & sqlite3ExprListFlags(p->x.pList);
|
|
}
|
|
}
|
|
@@ -99498,7 +106663,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprAlloc(
|
|
}
|
|
#if SQLITE_MAX_EXPR_DEPTH>0
|
|
pNew->nHeight = 1;
|
|
-#endif
|
|
+#endif
|
|
}
|
|
return pNew;
|
|
}
|
|
@@ -99535,15 +106700,26 @@ SQLITE_PRIVATE void sqlite3ExprAttachSubtrees(
|
|
sqlite3ExprDelete(db, pLeft);
|
|
sqlite3ExprDelete(db, pRight);
|
|
}else{
|
|
+ assert( ExprUseXList(pRoot) );
|
|
+ assert( pRoot->x.pSelect==0 );
|
|
if( pRight ){
|
|
pRoot->pRight = pRight;
|
|
pRoot->flags |= EP_Propagate & pRight->flags;
|
|
+#if SQLITE_MAX_EXPR_DEPTH>0
|
|
+ pRoot->nHeight = pRight->nHeight+1;
|
|
+ }else{
|
|
+ pRoot->nHeight = 1;
|
|
+#endif
|
|
}
|
|
if( pLeft ){
|
|
pRoot->pLeft = pLeft;
|
|
pRoot->flags |= EP_Propagate & pLeft->flags;
|
|
+#if SQLITE_MAX_EXPR_DEPTH>0
|
|
+ if( pLeft->nHeight>=pRoot->nHeight ){
|
|
+ pRoot->nHeight = pLeft->nHeight+1;
|
|
+ }
|
|
+#endif
|
|
}
|
|
- exprSetHeight(pRoot);
|
|
}
|
|
}
|
|
|
|
@@ -99590,6 +106766,63 @@ SQLITE_PRIVATE void sqlite3PExprAddSelect(Parse *pParse, Expr *pExpr, Select *pS
|
|
}
|
|
}
|
|
|
|
+/*
|
|
+** Expression list pEList is a list of vector values. This function
|
|
+** converts the contents of pEList to a VALUES(...) Select statement
|
|
+** returning 1 row for each element of the list. For example, the
|
|
+** expression list:
|
|
+**
|
|
+** ( (1,2), (3,4) (5,6) )
|
|
+**
|
|
+** is translated to the equivalent of:
|
|
+**
|
|
+** VALUES(1,2), (3,4), (5,6)
|
|
+**
|
|
+** Each of the vector values in pEList must contain exactly nElem terms.
|
|
+** If a list element that is not a vector or does not contain nElem terms,
|
|
+** an error message is left in pParse.
|
|
+**
|
|
+** This is used as part of processing IN(...) expressions with a list
|
|
+** of vectors on the RHS. e.g. "... IN ((1,2), (3,4), (5,6))".
|
|
+*/
|
|
+SQLITE_PRIVATE Select *sqlite3ExprListToValues(Parse *pParse, int nElem, ExprList *pEList){
|
|
+ int ii;
|
|
+ Select *pRet = 0;
|
|
+ assert( nElem>1 );
|
|
+ for(ii=0; ii<pEList->nExpr; ii++){
|
|
+ Select *pSel;
|
|
+ Expr *pExpr = pEList->a[ii].pExpr;
|
|
+ int nExprElem;
|
|
+ if( pExpr->op==TK_VECTOR ){
|
|
+ assert( ExprUseXList(pExpr) );
|
|
+ nExprElem = pExpr->x.pList->nExpr;
|
|
+ }else{
|
|
+ nExprElem = 1;
|
|
+ }
|
|
+ if( nExprElem!=nElem ){
|
|
+ sqlite3ErrorMsg(pParse, "IN(...) element has %d term%s - expected %d",
|
|
+ nExprElem, nExprElem>1?"s":"", nElem
|
|
+ );
|
|
+ break;
|
|
+ }
|
|
+ assert( ExprUseXList(pExpr) );
|
|
+ pSel = sqlite3SelectNew(pParse, pExpr->x.pList, 0, 0, 0, 0, 0, SF_Values,0);
|
|
+ pExpr->x.pList = 0;
|
|
+ if( pSel ){
|
|
+ if( pRet ){
|
|
+ pSel->op = TK_ALL;
|
|
+ pSel->pPrior = pRet;
|
|
+ }
|
|
+ pRet = pSel;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if( pRet && pRet->pPrior ){
|
|
+ pRet->selFlags |= SF_MultiValue;
|
|
+ }
|
|
+ sqlite3ExprListDelete(pParse->db, pEList);
|
|
+ return pRet;
|
|
+}
|
|
|
|
/*
|
|
** Join two expressions using an AND operator. If either expression is
|
|
@@ -99605,11 +106838,11 @@ SQLITE_PRIVATE Expr *sqlite3ExprAnd(Parse *pParse, Expr *pLeft, Expr *pRight){
|
|
return pRight;
|
|
}else if( pRight==0 ){
|
|
return pLeft;
|
|
- }else if( (ExprAlwaysFalse(pLeft) || ExprAlwaysFalse(pRight))
|
|
+ }else if( (ExprAlwaysFalse(pLeft) || ExprAlwaysFalse(pRight))
|
|
&& !IN_RENAME_OBJECT
|
|
){
|
|
- sqlite3ExprDelete(db, pLeft);
|
|
- sqlite3ExprDelete(db, pRight);
|
|
+ sqlite3ExprDeferredDelete(pParse, pLeft);
|
|
+ sqlite3ExprDeferredDelete(pParse, pRight);
|
|
return sqlite3Expr(db, TK_INTEGER, "0");
|
|
}else{
|
|
return sqlite3PExpr(pParse, TK_AND, pLeft, pRight);
|
|
@@ -99623,7 +106856,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprAnd(Parse *pParse, Expr *pLeft, Expr *pRight){
|
|
SQLITE_PRIVATE Expr *sqlite3ExprFunction(
|
|
Parse *pParse, /* Parsing context */
|
|
ExprList *pList, /* Argument list */
|
|
- Token *pToken, /* Name of the function */
|
|
+ const Token *pToken, /* Name of the function */
|
|
int eDistinct /* SF_Distinct or SF_ALL or 0 */
|
|
){
|
|
Expr *pNew;
|
|
@@ -99634,12 +106867,17 @@ SQLITE_PRIVATE Expr *sqlite3ExprFunction(
|
|
sqlite3ExprListDelete(db, pList); /* Avoid memory leak when malloc fails */
|
|
return 0;
|
|
}
|
|
- if( pList && pList->nExpr > pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] ){
|
|
+ assert( !ExprHasProperty(pNew, EP_InnerON|EP_OuterON) );
|
|
+ pNew->w.iOfst = (int)(pToken->z - pParse->zTail);
|
|
+ if( pList
|
|
+ && pList->nExpr > pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG]
|
|
+ && !pParse->nested
|
|
+ ){
|
|
sqlite3ErrorMsg(pParse, "too many arguments on function %T", pToken);
|
|
}
|
|
pNew->x.pList = pList;
|
|
ExprSetProperty(pNew, EP_HasFunc);
|
|
- assert( !ExprHasProperty(pNew, EP_xIsSelect) );
|
|
+ assert( ExprUseXList(pNew) );
|
|
sqlite3ExprSetHeightAndFlags(pParse, pNew);
|
|
if( eDistinct==SF_Distinct ) ExprSetProperty(pNew, EP_Distinct);
|
|
return pNew;
|
|
@@ -99658,8 +106896,8 @@ SQLITE_PRIVATE Expr *sqlite3ExprFunction(
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3ExprFunctionUsable(
|
|
Parse *pParse, /* Parsing and code generating context */
|
|
- Expr *pExpr, /* The function invocation */
|
|
- FuncDef *pDef /* The function being invoked */
|
|
+ const Expr *pExpr, /* The function invocation */
|
|
+ const FuncDef *pDef /* The function being invoked */
|
|
){
|
|
assert( !IN_RENAME_OBJECT );
|
|
assert( (pDef->funcFlags & (SQLITE_FUNC_DIRECT|SQLITE_FUNC_UNSAFE))!=0 );
|
|
@@ -99670,18 +106908,18 @@ SQLITE_PRIVATE void sqlite3ExprFunctionUsable(
|
|
/* Functions prohibited in triggers and views if:
|
|
** (1) tagged with SQLITE_DIRECTONLY
|
|
** (2) not tagged with SQLITE_INNOCUOUS (which means it
|
|
- ** is tagged with SQLITE_FUNC_UNSAFE) and
|
|
+ ** is tagged with SQLITE_FUNC_UNSAFE) and
|
|
** SQLITE_DBCONFIG_TRUSTED_SCHEMA is off (meaning
|
|
** that the schema is possibly tainted).
|
|
*/
|
|
- sqlite3ErrorMsg(pParse, "unsafe use of %s()", pDef->zName);
|
|
+ sqlite3ErrorMsg(pParse, "unsafe use of %#T()", pExpr);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Assign a variable number to an expression that encodes a wildcard
|
|
-** in the original SQL statement.
|
|
+** in the original SQL statement.
|
|
**
|
|
** Wildcards consisting of a single "?" are assigned the next sequential
|
|
** variable number.
|
|
@@ -99730,6 +106968,7 @@ SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr, u32 n
|
|
if( bOk==0 || i<1 || i>db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] ){
|
|
sqlite3ErrorMsg(pParse, "variable number must be between ?1 and ?%d",
|
|
db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]);
|
|
+ sqlite3RecordErrorOffsetOfExpr(pParse->db, pExpr);
|
|
return;
|
|
}
|
|
x = (ynVar)i;
|
|
@@ -99757,6 +106996,7 @@ SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr, u32 n
|
|
pExpr->iColumn = x;
|
|
if( x>db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] ){
|
|
sqlite3ErrorMsg(pParse, "too many SQL variables");
|
|
+ sqlite3RecordErrorOffsetOfExpr(pParse->db, pExpr);
|
|
}
|
|
}
|
|
|
|
@@ -99765,27 +107005,27 @@ SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr, u32 n
|
|
*/
|
|
static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){
|
|
assert( p!=0 );
|
|
- /* Sanity check: Assert that the IntValue is non-negative if it exists */
|
|
- assert( !ExprHasProperty(p, EP_IntValue) || p->u.iValue>=0 );
|
|
-
|
|
- assert( !ExprHasProperty(p, EP_WinFunc) || p->y.pWin!=0 || db->mallocFailed );
|
|
- assert( p->op!=TK_FUNCTION || ExprHasProperty(p, EP_TokenOnly|EP_Reduced)
|
|
- || p->y.pWin==0 || ExprHasProperty(p, EP_WinFunc) );
|
|
+ assert( db!=0 );
|
|
+ assert( !ExprUseUValue(p) || p->u.iValue>=0 );
|
|
+ assert( !ExprUseYWin(p) || !ExprUseYSub(p) );
|
|
+ assert( !ExprUseYWin(p) || p->y.pWin!=0 || db->mallocFailed );
|
|
+ assert( p->op!=TK_FUNCTION || !ExprUseYSub(p) );
|
|
#ifdef SQLITE_DEBUG
|
|
if( ExprHasProperty(p, EP_Leaf) && !ExprHasProperty(p, EP_TokenOnly) ){
|
|
assert( p->pLeft==0 );
|
|
assert( p->pRight==0 );
|
|
- assert( p->x.pSelect==0 );
|
|
+ assert( !ExprUseXSelect(p) || p->x.pSelect==0 );
|
|
+ assert( !ExprUseXList(p) || p->x.pList==0 );
|
|
}
|
|
#endif
|
|
if( !ExprHasProperty(p, (EP_TokenOnly|EP_Leaf)) ){
|
|
/* The Expr.x union is never used at the same time as Expr.pRight */
|
|
- assert( p->x.pList==0 || p->pRight==0 );
|
|
+ assert( (ExprUseXList(p) && p->x.pList==0) || p->pRight==0 );
|
|
if( p->pLeft && p->op!=TK_SELECT_COLUMN ) sqlite3ExprDeleteNN(db, p->pLeft);
|
|
if( p->pRight ){
|
|
assert( !ExprHasProperty(p, EP_WinFunc) );
|
|
sqlite3ExprDeleteNN(db, p->pRight);
|
|
- }else if( ExprHasProperty(p, EP_xIsSelect) ){
|
|
+ }else if( ExprUseXSelect(p) ){
|
|
assert( !ExprHasProperty(p, EP_WinFunc) );
|
|
sqlite3SelectDelete(db, p->x.pSelect);
|
|
}else{
|
|
@@ -99797,15 +107037,43 @@ static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){
|
|
#endif
|
|
}
|
|
}
|
|
- if( ExprHasProperty(p, EP_MemToken) ) sqlite3DbFree(db, p->u.zToken);
|
|
if( !ExprHasProperty(p, EP_Static) ){
|
|
- sqlite3DbFreeNN(db, p);
|
|
+ sqlite3DbNNFreeNN(db, p);
|
|
}
|
|
}
|
|
SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3 *db, Expr *p){
|
|
if( p ) sqlite3ExprDeleteNN(db, p);
|
|
}
|
|
|
|
+/*
|
|
+** Clear both elements of an OnOrUsing object
|
|
+*/
|
|
+SQLITE_PRIVATE void sqlite3ClearOnOrUsing(sqlite3 *db, OnOrUsing *p){
|
|
+ if( p==0 ){
|
|
+ /* Nothing to clear */
|
|
+ }else if( p->pOn ){
|
|
+ sqlite3ExprDeleteNN(db, p->pOn);
|
|
+ }else if( p->pUsing ){
|
|
+ sqlite3IdListDelete(db, p->pUsing);
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+** 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.
|
|
+**
|
|
+** The pExpr might be deleted immediately on an OOM error.
|
|
+**
|
|
+** The deferred delete is (currently) implemented by adding the
|
|
+** pExpr to the pParse->pConstExpr list with a register number of 0.
|
|
+*/
|
|
+SQLITE_PRIVATE void sqlite3ExprDeferredDelete(Parse *pParse, Expr *pExpr){
|
|
+ sqlite3ParserAddCleanup(pParse,
|
|
+ (void(*)(sqlite3*,void*))sqlite3ExprDelete,
|
|
+ pExpr);
|
|
+}
|
|
+
|
|
/* Invoke sqlite3RenameExprUnmap() and sqlite3ExprDelete() on the
|
|
** expression.
|
|
*/
|
|
@@ -99819,11 +107087,11 @@ SQLITE_PRIVATE void sqlite3ExprUnmapAndDelete(Parse *pParse, Expr *p){
|
|
}
|
|
|
|
/*
|
|
-** Return the number of bytes allocated for the expression structure
|
|
+** Return the number of bytes allocated for the expression structure
|
|
** passed as the first argument. This is always one of EXPR_FULLSIZE,
|
|
** EXPR_REDUCEDSIZE or EXPR_TOKENONLYSIZE.
|
|
*/
|
|
-static int exprStructSize(Expr *p){
|
|
+static int exprStructSize(const Expr *p){
|
|
if( ExprHasProperty(p, EP_TokenOnly) ) return EXPR_TOKENONLYSIZE;
|
|
if( ExprHasProperty(p, EP_Reduced) ) return EXPR_REDUCEDSIZE;
|
|
return EXPR_FULLSIZE;
|
|
@@ -99834,14 +107102,14 @@ static int exprStructSize(Expr *p){
|
|
** to store a copy of an expression or expression tree. They differ in
|
|
** how much of the tree is measured.
|
|
**
|
|
-** dupedExprStructSize() Size of only the Expr structure
|
|
+** dupedExprStructSize() Size of only the Expr structure
|
|
** dupedExprNodeSize() Size of Expr + space for token
|
|
** dupedExprSize() Expr + token + subtree components
|
|
**
|
|
***************************************************************************
|
|
**
|
|
-** The dupedExprStructSize() function returns two values OR-ed together:
|
|
-** (1) the space required for a copy of the Expr structure only and
|
|
+** The dupedExprStructSize() function returns two values OR-ed together:
|
|
+** (1) the space required for a copy of the Expr structure only and
|
|
** (2) the EP_xxx flags that indicate what the structure size should be.
|
|
** The return values is always one of:
|
|
**
|
|
@@ -99863,12 +107131,12 @@ static int exprStructSize(Expr *p){
|
|
** of dupedExprStructSize() contain multiple assert() statements that attempt
|
|
** to enforce this constraint.
|
|
*/
|
|
-static int dupedExprStructSize(Expr *p, int flags){
|
|
+static int dupedExprStructSize(const Expr *p, int flags){
|
|
int nSize;
|
|
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
|
|
+ if( 0==flags || p->op==TK_SELECT_COLUMN
|
|
#ifndef SQLITE_OMIT_WINDOWFUNC
|
|
|| ExprHasProperty(p, EP_WinFunc)
|
|
#endif
|
|
@@ -99876,9 +107144,8 @@ static int dupedExprStructSize(Expr *p, int flags){
|
|
nSize = EXPR_FULLSIZE;
|
|
}else{
|
|
assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) );
|
|
- assert( !ExprHasProperty(p, EP_FromJoin) );
|
|
- assert( !ExprHasProperty(p, EP_MemToken) );
|
|
- assert( !ExprHasProperty(p, EP_NoReduce) );
|
|
+ assert( !ExprHasProperty(p, EP_OuterON) );
|
|
+ assert( !ExprHasVVAProperty(p, EP_NoReduce) );
|
|
if( p->pLeft || p->x.pList ){
|
|
nSize = EXPR_REDUCEDSIZE | EP_Reduced;
|
|
}else{
|
|
@@ -99890,11 +107157,11 @@ static int dupedExprStructSize(Expr *p, int flags){
|
|
}
|
|
|
|
/*
|
|
-** This function returns the space in bytes required to store the copy
|
|
+** This function returns the space in bytes required to store the copy
|
|
** of the Expr structure and a copy of the Expr.u.zToken string (if that
|
|
** string is defined.)
|
|
*/
|
|
-static int dupedExprNodeSize(Expr *p, int flags){
|
|
+static int dupedExprNodeSize(const Expr *p, int flags){
|
|
int nByte = dupedExprStructSize(p, flags) & 0xfff;
|
|
if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){
|
|
nByte += sqlite3Strlen30NN(p->u.zToken)+1;
|
|
@@ -99903,19 +107170,19 @@ static int dupedExprNodeSize(Expr *p, int flags){
|
|
}
|
|
|
|
/*
|
|
-** Return the number of bytes required to create a duplicate of the
|
|
+** 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.
|
|
**
|
|
** 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
|
|
+** If the EXPRDUP_REDUCE flag is set, then the return value includes
|
|
+** space to duplicate all Expr nodes in the tree formed by Expr.pLeft
|
|
+** and Expr.pRight variables (but not for any structures pointed to or
|
|
** descended from the Expr.x.pList or Expr.x.pSelect variables).
|
|
*/
|
|
-static int dupedExprSize(Expr *p, int flags){
|
|
+static int dupedExprSize(const Expr *p, int flags){
|
|
int nByte = 0;
|
|
if( p ){
|
|
nByte = dupedExprNodeSize(p, flags);
|
|
@@ -99927,14 +107194,14 @@ static int dupedExprSize(Expr *p, int flags){
|
|
}
|
|
|
|
/*
|
|
-** This function is similar to sqlite3ExprDup(), except that if pzBuffer
|
|
-** is not NULL then *pzBuffer is assumed to point to a buffer large enough
|
|
+** This function is similar to sqlite3ExprDup(), except that if pzBuffer
|
|
+** is not NULL then *pzBuffer is assumed to point to a buffer large enough
|
|
** to store the copy of expression p, the copies of p->u.zToken
|
|
** (if applicable), and the copies of the p->pLeft and p->pRight expressions,
|
|
** if any. Before returning, *pzBuffer is set to the first byte past the
|
|
** portion of the buffer copied into by this function.
|
|
*/
|
|
-static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){
|
|
+static Expr *exprDup(sqlite3 *db, const Expr *p, int dupFlags, u8 **pzBuffer){
|
|
Expr *pNew; /* Value to return */
|
|
u8 *zAlloc; /* Memory space from which to build Expr object */
|
|
u32 staticFlag; /* EP_Static if space not obtained from malloc */
|
|
@@ -99948,6 +107215,7 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){
|
|
if( pzBuffer ){
|
|
zAlloc = *pzBuffer;
|
|
staticFlag = EP_Static;
|
|
+ assert( zAlloc!=0 );
|
|
}else{
|
|
zAlloc = sqlite3DbMallocRawNN(db, dupedExprSize(p, dupFlags));
|
|
staticFlag = 0;
|
|
@@ -99974,15 +107242,19 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){
|
|
}else{
|
|
u32 nSize = (u32)exprStructSize(p);
|
|
memcpy(zAlloc, p, nSize);
|
|
- if( nSize<EXPR_FULLSIZE ){
|
|
+ if( nSize<EXPR_FULLSIZE ){
|
|
memset(&zAlloc[nSize], 0, EXPR_FULLSIZE-nSize);
|
|
}
|
|
}
|
|
|
|
/* Set the EP_Reduced, EP_TokenOnly, and EP_Static flags appropriately. */
|
|
- pNew->flags &= ~(EP_Reduced|EP_TokenOnly|EP_Static|EP_MemToken);
|
|
+ pNew->flags &= ~(EP_Reduced|EP_TokenOnly|EP_Static);
|
|
pNew->flags |= nStructSize & (EP_Reduced|EP_TokenOnly);
|
|
pNew->flags |= staticFlag;
|
|
+ ExprClearVVAProperties(pNew);
|
|
+ if( dupFlags ){
|
|
+ ExprSetVVAProperty(pNew, EP_Immutable);
|
|
+ }
|
|
|
|
/* Copy the p->u.zToken string, if any. */
|
|
if( nToken ){
|
|
@@ -99992,7 +107264,7 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){
|
|
|
|
if( 0==((p->flags|pNew->flags) & (EP_TokenOnly|EP_Leaf)) ){
|
|
/* Fill in the pNew->x.pSelect or pNew->x.pList member. */
|
|
- if( ExprHasProperty(p, EP_xIsSelect) ){
|
|
+ if( ExprUseXSelect(p) ){
|
|
pNew->x.pSelect = sqlite3SelectDup(db, p->x.pSelect, dupFlags);
|
|
}else{
|
|
pNew->x.pList = sqlite3ExprListDup(db, p->x.pList, dupFlags);
|
|
@@ -100021,8 +107293,8 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){
|
|
if( !ExprHasProperty(p, EP_TokenOnly|EP_Leaf) ){
|
|
if( pNew->op==TK_SELECT_COLUMN ){
|
|
pNew->pLeft = p->pLeft;
|
|
- assert( p->iColumn==0 || p->pRight==0 );
|
|
- assert( p->pRight==0 || p->pRight==p->pLeft );
|
|
+ assert( p->pRight==0 || p->pRight==p->pLeft
|
|
+ || ExprHasProperty(p->pLeft, EP_Subquery) );
|
|
}else{
|
|
pNew->pLeft = sqlite3ExprDup(db, p->pLeft, 0);
|
|
}
|
|
@@ -100034,12 +107306,12 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){
|
|
}
|
|
|
|
/*
|
|
-** Create and return a deep copy of the object passed as the second
|
|
+** Create and return a deep copy of the object passed as the second
|
|
** argument. If an OOM condition is encountered, NULL is returned
|
|
** and the db->mallocFailed flag set.
|
|
*/
|
|
#ifndef SQLITE_OMIT_CTE
|
|
-static With *withDup(sqlite3 *db, With *p){
|
|
+SQLITE_PRIVATE With *sqlite3WithDup(sqlite3 *db, With *p){
|
|
With *pRet = 0;
|
|
if( p ){
|
|
sqlite3_int64 nByte = sizeof(*p) + sizeof(p->a[0]) * (p->nCte-1);
|
|
@@ -100051,13 +107323,14 @@ static With *withDup(sqlite3 *db, With *p){
|
|
pRet->a[i].pSelect = sqlite3SelectDup(db, p->a[i].pSelect, 0);
|
|
pRet->a[i].pCols = sqlite3ExprListDup(db, p->a[i].pCols, 0);
|
|
pRet->a[i].zName = sqlite3DbStrDup(db, p->a[i].zName);
|
|
+ pRet->a[i].eM10d = p->a[i].eM10d;
|
|
}
|
|
}
|
|
}
|
|
return pRet;
|
|
}
|
|
#else
|
|
-# define withDup(x,y) 0
|
|
+# define sqlite3WithDup(x,y) 0
|
|
#endif
|
|
|
|
#ifndef SQLITE_OMIT_WINDOWFUNC
|
|
@@ -100100,7 +107373,7 @@ static void gatherSelectWindows(Select *p){
|
|
** without effecting the originals.
|
|
**
|
|
** The expression list, ID, and source lists return by sqlite3ExprListDup(),
|
|
-** sqlite3IdListDup(), and sqlite3SrcListDup() can not be further expanded
|
|
+** sqlite3IdListDup(), and sqlite3SrcListDup() can not be further expanded
|
|
** by subsequent calls to sqlite*ListAppend() routines.
|
|
**
|
|
** Any tables that the SrcList might point to are not duplicated.
|
|
@@ -100110,48 +107383,49 @@ static void gatherSelectWindows(Select *p){
|
|
** truncated version of the usual Expr structure that will be stored as
|
|
** part of the in-memory representation of the database schema.
|
|
*/
|
|
-SQLITE_PRIVATE Expr *sqlite3ExprDup(sqlite3 *db, Expr *p, int flags){
|
|
+SQLITE_PRIVATE Expr *sqlite3ExprDup(sqlite3 *db, const Expr *p, int flags){
|
|
assert( flags==0 || flags==EXPRDUP_REDUCE );
|
|
return p ? exprDup(db, p, flags, 0) : 0;
|
|
}
|
|
-SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags){
|
|
+SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3 *db, const ExprList *p, int flags){
|
|
ExprList *pNew;
|
|
- struct ExprList_item *pItem, *pOldItem;
|
|
+ struct ExprList_item *pItem;
|
|
+ const struct ExprList_item *pOldItem;
|
|
int i;
|
|
- Expr *pPriorSelectCol = 0;
|
|
+ Expr *pPriorSelectColOld = 0;
|
|
+ Expr *pPriorSelectColNew = 0;
|
|
assert( db!=0 );
|
|
if( p==0 ) return 0;
|
|
pNew = sqlite3DbMallocRawNN(db, sqlite3DbMallocSize(db, p));
|
|
if( pNew==0 ) return 0;
|
|
pNew->nExpr = p->nExpr;
|
|
+ pNew->nAlloc = p->nAlloc;
|
|
pItem = pNew->a;
|
|
pOldItem = p->a;
|
|
for(i=0; i<p->nExpr; i++, pItem++, pOldItem++){
|
|
Expr *pOldExpr = pOldItem->pExpr;
|
|
Expr *pNewExpr;
|
|
pItem->pExpr = sqlite3ExprDup(db, pOldExpr, flags);
|
|
- if( pOldExpr
|
|
+ if( pOldExpr
|
|
&& pOldExpr->op==TK_SELECT_COLUMN
|
|
- && (pNewExpr = pItem->pExpr)!=0
|
|
+ && (pNewExpr = pItem->pExpr)!=0
|
|
){
|
|
- assert( pNewExpr->iColumn==0 || i>0 );
|
|
- if( pNewExpr->iColumn==0 ){
|
|
- assert( pOldExpr->pLeft==pOldExpr->pRight );
|
|
- pPriorSelectCol = pNewExpr->pLeft = pNewExpr->pRight;
|
|
+ if( pNewExpr->pRight ){
|
|
+ pPriorSelectColOld = pOldExpr->pRight;
|
|
+ pPriorSelectColNew = pNewExpr->pRight;
|
|
+ pNewExpr->pLeft = pNewExpr->pRight;
|
|
}else{
|
|
- assert( i>0 );
|
|
- assert( pItem[-1].pExpr!=0 );
|
|
- assert( pNewExpr->iColumn==pItem[-1].pExpr->iColumn+1 );
|
|
- assert( pPriorSelectCol==pItem[-1].pExpr->pLeft );
|
|
- pNewExpr->pLeft = pPriorSelectCol;
|
|
+ if( pOldExpr->pLeft!=pPriorSelectColOld ){
|
|
+ pPriorSelectColOld = pOldExpr->pLeft;
|
|
+ pPriorSelectColNew = sqlite3ExprDup(db, pPriorSelectColOld, flags);
|
|
+ pNewExpr->pRight = pPriorSelectColNew;
|
|
+ }
|
|
+ pNewExpr->pLeft = pPriorSelectColNew;
|
|
}
|
|
}
|
|
pItem->zEName = sqlite3DbStrDup(db, pOldItem->zEName);
|
|
- pItem->sortFlags = pOldItem->sortFlags;
|
|
- pItem->eEName = pOldItem->eEName;
|
|
- pItem->done = 0;
|
|
- pItem->bNulls = pOldItem->bNulls;
|
|
- pItem->bSorterRef = pOldItem->bSorterRef;
|
|
+ pItem->fg = pOldItem->fg;
|
|
+ pItem->fg.done = 0;
|
|
pItem->u = pOldItem->u;
|
|
}
|
|
return pNew;
|
|
@@ -100159,13 +107433,13 @@ SQLITE_PRIVATE ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags)
|
|
|
|
/*
|
|
** If cursors, triggers, views and subqueries are all omitted from
|
|
-** the build, then none of the following routines, except for
|
|
+** the build, then none of the following routines, except for
|
|
** sqlite3SelectDup(), can be called. sqlite3SelectDup() is sometimes
|
|
** called with a NULL argument.
|
|
*/
|
|
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER) \
|
|
|| !defined(SQLITE_OMIT_SUBQUERY)
|
|
-SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){
|
|
+SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3 *db, const SrcList *p, int flags){
|
|
SrcList *pNew;
|
|
int i;
|
|
int nByte;
|
|
@@ -100176,8 +107450,8 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){
|
|
if( pNew==0 ) return 0;
|
|
pNew->nSrc = pNew->nAlloc = p->nSrc;
|
|
for(i=0; i<p->nSrc; i++){
|
|
- struct SrcList_item *pNewItem = &pNew->a[i];
|
|
- struct SrcList_item *pOldItem = &p->a[i];
|
|
+ SrcItem *pNewItem = &pNew->a[i];
|
|
+ const SrcItem *pOldItem = &p->a[i];
|
|
Table *pTab;
|
|
pNewItem->pSchema = pOldItem->pSchema;
|
|
pNewItem->zDatabase = sqlite3DbStrDup(db, pOldItem->zDatabase);
|
|
@@ -100190,9 +107464,12 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){
|
|
if( pNewItem->fg.isIndexedBy ){
|
|
pNewItem->u1.zIndexedBy = sqlite3DbStrDup(db, pOldItem->u1.zIndexedBy);
|
|
}
|
|
- pNewItem->pIBIndex = pOldItem->pIBIndex;
|
|
+ pNewItem->u2 = pOldItem->u2;
|
|
+ if( pNewItem->fg.isCte ){
|
|
+ pNewItem->u2.pCteUse->nUse++;
|
|
+ }
|
|
if( pNewItem->fg.isTabFunc ){
|
|
- pNewItem->u1.pFuncArg =
|
|
+ pNewItem->u1.pFuncArg =
|
|
sqlite3ExprListDup(db, pOldItem->u1.pFuncArg, flags);
|
|
}
|
|
pTab = pNewItem->pTab = pOldItem->pTab;
|
|
@@ -100200,41 +107477,39 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){
|
|
pTab->nTabRef++;
|
|
}
|
|
pNewItem->pSelect = sqlite3SelectDup(db, pOldItem->pSelect, flags);
|
|
- pNewItem->pOn = sqlite3ExprDup(db, pOldItem->pOn, flags);
|
|
- pNewItem->pUsing = sqlite3IdListDup(db, pOldItem->pUsing);
|
|
+ if( pOldItem->fg.isUsing ){
|
|
+ assert( pNewItem->fg.isUsing );
|
|
+ pNewItem->u3.pUsing = sqlite3IdListDup(db, pOldItem->u3.pUsing);
|
|
+ }else{
|
|
+ pNewItem->u3.pOn = sqlite3ExprDup(db, pOldItem->u3.pOn, flags);
|
|
+ }
|
|
pNewItem->colUsed = pOldItem->colUsed;
|
|
}
|
|
return pNew;
|
|
}
|
|
-SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3 *db, IdList *p){
|
|
+SQLITE_PRIVATE IdList *sqlite3IdListDup(sqlite3 *db, const IdList *p){
|
|
IdList *pNew;
|
|
int i;
|
|
assert( db!=0 );
|
|
if( p==0 ) return 0;
|
|
- pNew = sqlite3DbMallocRawNN(db, sizeof(*pNew) );
|
|
+ assert( p->eU4!=EU4_EXPR );
|
|
+ pNew = sqlite3DbMallocRawNN(db, sizeof(*pNew)+(p->nId-1)*sizeof(p->a[0]) );
|
|
if( pNew==0 ) return 0;
|
|
pNew->nId = p->nId;
|
|
- pNew->a = sqlite3DbMallocRawNN(db, p->nId*sizeof(p->a[0]) );
|
|
- if( pNew->a==0 ){
|
|
- sqlite3DbFreeNN(db, pNew);
|
|
- return 0;
|
|
- }
|
|
- /* Note that because the size of the allocation for p->a[] is not
|
|
- ** necessarily a power of two, sqlite3IdListAppend() may not be called
|
|
- ** on the duplicate created by this function. */
|
|
+ pNew->eU4 = p->eU4;
|
|
for(i=0; i<p->nId; i++){
|
|
struct IdList_item *pNewItem = &pNew->a[i];
|
|
- struct IdList_item *pOldItem = &p->a[i];
|
|
+ const struct IdList_item *pOldItem = &p->a[i];
|
|
pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
|
|
- pNewItem->idx = pOldItem->idx;
|
|
+ pNewItem->u4 = pOldItem->u4;
|
|
}
|
|
return pNew;
|
|
}
|
|
-SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, Select *pDup, int flags){
|
|
+SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, const Select *pDup, int flags){
|
|
Select *pRet = 0;
|
|
Select *pNext = 0;
|
|
Select **pp = &pRet;
|
|
- Select *p;
|
|
+ const Select *p;
|
|
|
|
assert( db!=0 );
|
|
for(p=pDup; p; p=p->pPrior){
|
|
@@ -100256,13 +107531,21 @@ SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, Select *pDup, int flags){
|
|
pNew->addrOpenEphm[0] = -1;
|
|
pNew->addrOpenEphm[1] = -1;
|
|
pNew->nSelectRow = p->nSelectRow;
|
|
- pNew->pWith = withDup(db, p->pWith);
|
|
+ pNew->pWith = sqlite3WithDup(db, p->pWith);
|
|
#ifndef SQLITE_OMIT_WINDOWFUNC
|
|
pNew->pWin = 0;
|
|
pNew->pWinDefn = sqlite3WindowListDup(db, p->pWinDefn);
|
|
if( p->pWin && db->mallocFailed==0 ) gatherSelectWindows(pNew);
|
|
#endif
|
|
pNew->selId = p->selId;
|
|
+ if( db->mallocFailed ){
|
|
+ /* Any prior OOM might have left the Select object incomplete.
|
|
+ ** Delete the whole thing rather than allow an incomplete Select
|
|
+ ** to be used by the code generator. */
|
|
+ pNew->pNext = 0;
|
|
+ sqlite3SelectDelete(db, pNew);
|
|
+ break;
|
|
+ }
|
|
*pp = pNew;
|
|
pp = &pNew->pPrior;
|
|
pNext = pNew;
|
|
@@ -100271,7 +107554,7 @@ SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, Select *pDup, int flags){
|
|
return pRet;
|
|
}
|
|
#else
|
|
-SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){
|
|
+SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, const Select *p, int flags){
|
|
assert( p==0 );
|
|
return 0;
|
|
}
|
|
@@ -100293,41 +107576,64 @@ SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){
|
|
** NULL is returned. If non-NULL is returned, then it is guaranteed
|
|
** that the new entry was successfully appended.
|
|
*/
|
|
+static const struct ExprList_item zeroItem = {0};
|
|
+SQLITE_PRIVATE SQLITE_NOINLINE ExprList *sqlite3ExprListAppendNew(
|
|
+ sqlite3 *db, /* Database handle. Used for memory allocation */
|
|
+ Expr *pExpr /* Expression to be appended. Might be NULL */
|
|
+){
|
|
+ struct ExprList_item *pItem;
|
|
+ ExprList *pList;
|
|
+
|
|
+ pList = sqlite3DbMallocRawNN(db, sizeof(ExprList)+sizeof(pList->a[0])*4 );
|
|
+ if( pList==0 ){
|
|
+ sqlite3ExprDelete(db, pExpr);
|
|
+ return 0;
|
|
+ }
|
|
+ pList->nAlloc = 4;
|
|
+ pList->nExpr = 1;
|
|
+ pItem = &pList->a[0];
|
|
+ *pItem = zeroItem;
|
|
+ pItem->pExpr = pExpr;
|
|
+ return pList;
|
|
+}
|
|
+SQLITE_PRIVATE SQLITE_NOINLINE ExprList *sqlite3ExprListAppendGrow(
|
|
+ sqlite3 *db, /* Database handle. Used for memory allocation */
|
|
+ ExprList *pList, /* List to which to append. Might be NULL */
|
|
+ Expr *pExpr /* Expression to be appended. Might be NULL */
|
|
+){
|
|
+ struct ExprList_item *pItem;
|
|
+ ExprList *pNew;
|
|
+ pList->nAlloc *= 2;
|
|
+ pNew = sqlite3DbRealloc(db, pList,
|
|
+ sizeof(*pList)+(pList->nAlloc-1)*sizeof(pList->a[0]));
|
|
+ if( pNew==0 ){
|
|
+ sqlite3ExprListDelete(db, pList);
|
|
+ sqlite3ExprDelete(db, pExpr);
|
|
+ return 0;
|
|
+ }else{
|
|
+ pList = pNew;
|
|
+ }
|
|
+ pItem = &pList->a[pList->nExpr++];
|
|
+ *pItem = zeroItem;
|
|
+ pItem->pExpr = pExpr;
|
|
+ return pList;
|
|
+}
|
|
SQLITE_PRIVATE ExprList *sqlite3ExprListAppend(
|
|
Parse *pParse, /* Parsing context */
|
|
ExprList *pList, /* List to which to append. Might be NULL */
|
|
Expr *pExpr /* Expression to be appended. Might be NULL */
|
|
){
|
|
struct ExprList_item *pItem;
|
|
- sqlite3 *db = pParse->db;
|
|
- assert( db!=0 );
|
|
if( pList==0 ){
|
|
- pList = sqlite3DbMallocRawNN(db, sizeof(ExprList) );
|
|
- if( pList==0 ){
|
|
- goto no_mem;
|
|
- }
|
|
- pList->nExpr = 0;
|
|
- }else if( (pList->nExpr & (pList->nExpr-1))==0 ){
|
|
- ExprList *pNew;
|
|
- pNew = sqlite3DbRealloc(db, pList,
|
|
- sizeof(*pList)+(2*(sqlite3_int64)pList->nExpr-1)*sizeof(pList->a[0]));
|
|
- if( pNew==0 ){
|
|
- goto no_mem;
|
|
- }
|
|
- pList = pNew;
|
|
+ return sqlite3ExprListAppendNew(pParse->db,pExpr);
|
|
+ }
|
|
+ if( pList->nAlloc<pList->nExpr+1 ){
|
|
+ return sqlite3ExprListAppendGrow(pParse->db,pList,pExpr);
|
|
}
|
|
pItem = &pList->a[pList->nExpr++];
|
|
- assert( offsetof(struct ExprList_item,zEName)==sizeof(pItem->pExpr) );
|
|
- assert( offsetof(struct ExprList_item,pExpr)==0 );
|
|
- memset(&pItem->zEName,0,sizeof(*pItem)-offsetof(struct ExprList_item,zEName));
|
|
+ *pItem = zeroItem;
|
|
pItem->pExpr = pExpr;
|
|
return pList;
|
|
-
|
|
-no_mem:
|
|
- /* Avoid leaking memory if malloc has failed. */
|
|
- sqlite3ExprDelete(db, pExpr);
|
|
- sqlite3ExprListDelete(db, pList);
|
|
- return 0;
|
|
}
|
|
|
|
/*
|
|
@@ -100356,8 +107662,8 @@ SQLITE_PRIVATE ExprList *sqlite3ExprListAppendVector(
|
|
if( NEVER(pColumns==0) ) goto vector_append_error;
|
|
if( pExpr==0 ) goto vector_append_error;
|
|
|
|
- /* If the RHS is a vector, then we can immediately check to see that
|
|
- ** the size of the RHS and LHS match. But if the RHS is a SELECT,
|
|
+ /* If the RHS is a vector, then we can immediately check to see that
|
|
+ ** the size of the RHS and LHS match. But if the RHS is a SELECT,
|
|
** wildcards ("*") in the result set of the SELECT must be expanded before
|
|
** we can do the size check, so defer the size check until code generation.
|
|
*/
|
|
@@ -100368,11 +107674,9 @@ SQLITE_PRIVATE ExprList *sqlite3ExprListAppendVector(
|
|
}
|
|
|
|
for(i=0; i<pColumns->nId; i++){
|
|
- Expr *pSubExpr = sqlite3ExprForVectorField(pParse, pExpr, i);
|
|
+ Expr *pSubExpr = sqlite3ExprForVectorField(pParse, pExpr, i, pColumns->nId);
|
|
assert( pSubExpr!=0 || db->mallocFailed );
|
|
- assert( pSubExpr==0 || pSubExpr->iTable==0 );
|
|
if( pSubExpr==0 ) continue;
|
|
- pSubExpr->iTable = pColumns->nId;
|
|
pList = sqlite3ExprListAppend(pParse, pList, pSubExpr);
|
|
if( pList ){
|
|
assert( pList->nExpr==iFirst+i+1 );
|
|
@@ -100385,7 +107689,7 @@ SQLITE_PRIVATE ExprList *sqlite3ExprListAppendVector(
|
|
Expr *pFirst = pList->a[iFirst].pExpr;
|
|
assert( pFirst!=0 );
|
|
assert( pFirst->op==TK_SELECT_COLUMN );
|
|
-
|
|
+
|
|
/* Store the SELECT statement in pRight so it will be deleted when
|
|
** sqlite3ExprListDelete() is called */
|
|
pFirst->pRight = pExpr;
|
|
@@ -100411,26 +107715,26 @@ SQLITE_PRIVATE void sqlite3ExprListSetSortOrder(ExprList *p, int iSortOrder, int
|
|
assert( p->nExpr>0 );
|
|
|
|
assert( SQLITE_SO_UNDEFINED<0 && SQLITE_SO_ASC==0 && SQLITE_SO_DESC>0 );
|
|
- assert( iSortOrder==SQLITE_SO_UNDEFINED
|
|
- || iSortOrder==SQLITE_SO_ASC
|
|
- || iSortOrder==SQLITE_SO_DESC
|
|
+ assert( iSortOrder==SQLITE_SO_UNDEFINED
|
|
+ || iSortOrder==SQLITE_SO_ASC
|
|
+ || iSortOrder==SQLITE_SO_DESC
|
|
);
|
|
- assert( eNulls==SQLITE_SO_UNDEFINED
|
|
- || eNulls==SQLITE_SO_ASC
|
|
- || eNulls==SQLITE_SO_DESC
|
|
+ assert( eNulls==SQLITE_SO_UNDEFINED
|
|
+ || eNulls==SQLITE_SO_ASC
|
|
+ || eNulls==SQLITE_SO_DESC
|
|
);
|
|
|
|
pItem = &p->a[p->nExpr-1];
|
|
- assert( pItem->bNulls==0 );
|
|
+ assert( pItem->fg.bNulls==0 );
|
|
if( iSortOrder==SQLITE_SO_UNDEFINED ){
|
|
iSortOrder = SQLITE_SO_ASC;
|
|
}
|
|
- pItem->sortFlags = (u8)iSortOrder;
|
|
+ pItem->fg.sortFlags = (u8)iSortOrder;
|
|
|
|
if( eNulls!=SQLITE_SO_UNDEFINED ){
|
|
- pItem->bNulls = 1;
|
|
+ pItem->fg.bNulls = 1;
|
|
if( iSortOrder!=eNulls ){
|
|
- pItem->sortFlags |= KEYINFO_ORDER_BIGNULL;
|
|
+ pItem->fg.sortFlags |= KEYINFO_ORDER_BIGNULL;
|
|
}
|
|
}
|
|
}
|
|
@@ -100446,20 +107750,26 @@ SQLITE_PRIVATE void sqlite3ExprListSetSortOrder(ExprList *p, int iSortOrder, int
|
|
SQLITE_PRIVATE void sqlite3ExprListSetName(
|
|
Parse *pParse, /* Parsing context */
|
|
ExprList *pList, /* List to which to add the span. */
|
|
- Token *pName, /* Name to be added */
|
|
+ const Token *pName, /* Name to be added */
|
|
int dequote /* True to cause the name to be dequoted */
|
|
){
|
|
assert( pList!=0 || pParse->db->mallocFailed!=0 );
|
|
+ assert( pParse->eParseMode!=PARSE_MODE_UNMAP || dequote==0 );
|
|
if( pList ){
|
|
struct ExprList_item *pItem;
|
|
assert( pList->nExpr>0 );
|
|
pItem = &pList->a[pList->nExpr-1];
|
|
assert( pItem->zEName==0 );
|
|
- assert( pItem->eEName==ENAME_NAME );
|
|
+ assert( pItem->fg.eEName==ENAME_NAME );
|
|
pItem->zEName = sqlite3DbStrNDup(pParse->db, pName->z, pName->n);
|
|
- if( dequote ) sqlite3Dequote(pItem->zEName);
|
|
- if( IN_RENAME_OBJECT ){
|
|
- sqlite3RenameTokenMap(pParse, (void*)pItem->zEName, pName);
|
|
+ if( dequote ){
|
|
+ /* If dequote==0, then pName->z does not point to part of a DDL
|
|
+ ** statement handled by the parser. And so no token need be added
|
|
+ ** to the token-map. */
|
|
+ sqlite3Dequote(pItem->zEName);
|
|
+ if( IN_RENAME_OBJECT ){
|
|
+ sqlite3RenameTokenMap(pParse, (const void*)pItem->zEName, pName);
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
@@ -100485,7 +107795,7 @@ SQLITE_PRIVATE void sqlite3ExprListSetSpan(
|
|
assert( pList->nExpr>0 );
|
|
if( pItem->zEName==0 ){
|
|
pItem->zEName = sqlite3DbSpanDup(db, zStart, zEnd);
|
|
- pItem->eEName = ENAME_SPAN;
|
|
+ pItem->fg.eEName = ENAME_SPAN;
|
|
}
|
|
}
|
|
}
|
|
@@ -100514,12 +107824,13 @@ static SQLITE_NOINLINE void exprListDeleteNN(sqlite3 *db, ExprList *pList){
|
|
int i = pList->nExpr;
|
|
struct ExprList_item *pItem = pList->a;
|
|
assert( pList->nExpr>0 );
|
|
+ assert( db!=0 );
|
|
do{
|
|
sqlite3ExprDelete(db, pItem->pExpr);
|
|
- sqlite3DbFree(db, pItem->zEName);
|
|
+ if( pItem->zEName ) sqlite3DbNNFreeNN(db, pItem->zEName);
|
|
pItem++;
|
|
}while( --i>0 );
|
|
- sqlite3DbFreeNN(db, pList);
|
|
+ sqlite3DbNNFreeNN(db, pList);
|
|
}
|
|
SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){
|
|
if( pList ) exprListDeleteNN(db, pList);
|
|
@@ -100577,7 +107888,7 @@ SQLITE_PRIVATE u32 sqlite3IsTrueOrFalse(const char *zIn){
|
|
SQLITE_PRIVATE int sqlite3ExprIdToTrueFalse(Expr *pExpr){
|
|
u32 v;
|
|
assert( pExpr->op==TK_ID || pExpr->op==TK_STRING );
|
|
- if( !ExprHasProperty(pExpr, EP_Quoted)
|
|
+ if( !ExprHasProperty(pExpr, EP_Quoted|EP_IntValue)
|
|
&& (v = sqlite3IsTrueOrFalse(pExpr->u.zToken))!=0
|
|
){
|
|
pExpr->op = TK_TRUEFALSE;
|
|
@@ -100594,6 +107905,7 @@ SQLITE_PRIVATE int sqlite3ExprIdToTrueFalse(Expr *pExpr){
|
|
SQLITE_PRIVATE int sqlite3ExprTruthValue(const Expr *pExpr){
|
|
pExpr = sqlite3ExprSkipCollate((Expr*)pExpr);
|
|
assert( pExpr->op==TK_TRUEFALSE );
|
|
+ assert( !ExprHasProperty(pExpr, EP_IntValue) );
|
|
assert( sqlite3StrICmp(pExpr->u.zToken,"true")==0
|
|
|| sqlite3StrICmp(pExpr->u.zToken,"false")==0 );
|
|
return pExpr->u.zToken[4]==0;
|
|
@@ -100645,10 +107957,10 @@ SQLITE_PRIVATE Expr *sqlite3ExprSimplifiedAndOr(Expr *pExpr){
|
|
**
|
|
** The sqlite3ExprIsConstantOrFunction() is used for evaluating DEFAULT
|
|
** expressions in a CREATE TABLE statement. The Walker.eCode value is 5
|
|
-** when parsing an existing schema out of the sqlite_master table and 4
|
|
+** when parsing an existing schema out of the sqlite_schema table and 4
|
|
** when processing a new CREATE TABLE statement. A bound parameter raises
|
|
** an error for new statements, but is silently converted
|
|
-** to NULL for existing schemas. This allows sqlite_master tables that
|
|
+** to NULL for existing schemas. This allows sqlite_schema tables that
|
|
** contain a bound parameter because they were generated by older versions
|
|
** of SQLite to be parsed by newer versions of SQLite without raising a
|
|
** malformed schema error.
|
|
@@ -100656,9 +107968,9 @@ SQLITE_PRIVATE Expr *sqlite3ExprSimplifiedAndOr(Expr *pExpr){
|
|
static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
|
|
|
|
/* If pWalker->eCode is 2 then any term of the expression that comes from
|
|
- ** the ON or USING clauses of a left join disqualifies the expression
|
|
+ ** the ON or USING clauses of an outer join disqualifies the expression
|
|
** from being considered constant. */
|
|
- if( pWalker->eCode==2 && ExprHasProperty(pExpr, EP_FromJoin) ){
|
|
+ if( pWalker->eCode==2 && ExprHasProperty(pExpr, EP_OuterON) ){
|
|
pWalker->eCode = 0;
|
|
return WRC_Abort;
|
|
}
|
|
@@ -100683,7 +107995,7 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
|
|
if( sqlite3ExprIdToTrueFalse(pExpr) ){
|
|
return WRC_Prune;
|
|
}
|
|
- /* Fall thru */
|
|
+ /* no break */ deliberate_fall_through
|
|
case TK_COLUMN:
|
|
case TK_AGG_FUNCTION:
|
|
case TK_AGG_COLUMN:
|
|
@@ -100697,18 +108009,20 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
|
|
if( pWalker->eCode==3 && pExpr->iTable==pWalker->u.iCur ){
|
|
return WRC_Continue;
|
|
}
|
|
- /* Fall through */
|
|
+ /* no break */ deliberate_fall_through
|
|
case TK_IF_NULL_ROW:
|
|
case TK_REGISTER:
|
|
+ case TK_DOT:
|
|
testcase( pExpr->op==TK_REGISTER );
|
|
testcase( pExpr->op==TK_IF_NULL_ROW );
|
|
+ testcase( pExpr->op==TK_DOT );
|
|
pWalker->eCode = 0;
|
|
return WRC_Abort;
|
|
case TK_VARIABLE:
|
|
if( pWalker->eCode==5 ){
|
|
/* Silently convert bound parameters that appear inside of CREATE
|
|
** statements into a NULL when parsing the CREATE statement text out
|
|
- ** of the sqlite_master table */
|
|
+ ** of the sqlite_schema table */
|
|
pExpr->op = TK_NULL;
|
|
}else if( pWalker->eCode==4 ){
|
|
/* A bound parameter in a CREATE statement that originates from
|
|
@@ -100716,7 +108030,7 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
|
|
pWalker->eCode = 0;
|
|
return WRC_Abort;
|
|
}
|
|
- /* Fall through */
|
|
+ /* no break */ deliberate_fall_through
|
|
default:
|
|
testcase( pExpr->op==TK_SELECT ); /* sqlite3SelectWalkFail() disallows */
|
|
testcase( pExpr->op==TK_EXISTS ); /* sqlite3SelectWalkFail() disallows */
|
|
@@ -100759,7 +108073,7 @@ SQLITE_PRIVATE int sqlite3ExprIsConstant(Expr *p){
|
|
**
|
|
** When this routine returns true, it indicates that the expression
|
|
** can be added to the pParse->pConstExpr list and evaluated once when
|
|
-** the prepared statement starts up. See sqlite3ExprCodeAtInit().
|
|
+** the prepared statement starts up. See sqlite3ExprCodeRunJustOnce().
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3ExprIsConstantNotJoin(Expr *p){
|
|
return exprIsConst(p, 2, 0);
|
|
@@ -100775,6 +108089,42 @@ SQLITE_PRIVATE int sqlite3ExprIsTableConstant(Expr *p, int iCur){
|
|
return exprIsConst(p, 3, iCur);
|
|
}
|
|
|
|
+/*
|
|
+** Check pExpr to see if it is an invariant constraint on data source pSrc.
|
|
+** This is an optimization. False negatives will perhaps cause slower
|
|
+** queries, but false positives will yield incorrect answers. So when in
|
|
+** doubt, return 0.
|
|
+**
|
|
+** To be an invariant constraint, the following must be true:
|
|
+**
|
|
+** (1) pExpr cannot refer to any table other than pSrc->iCursor.
|
|
+**
|
|
+** (2) pExpr cannot use subqueries or non-deterministic functions.
|
|
+**
|
|
+** (3) pSrc cannot be part of the left operand for a RIGHT JOIN.
|
|
+** (Is there some way to relax this constraint?)
|
|
+**
|
|
+** (4) If pSrc is the right operand of a LEFT JOIN, then...
|
|
+** (4a) pExpr must come from an ON clause..
|
|
+ (4b) and specifically the ON clause associated with the LEFT JOIN.
|
|
+**
|
|
+** (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.
|
|
+*/
|
|
+SQLITE_PRIVATE int sqlite3ExprIsTableConstraint(Expr *pExpr, const SrcItem *pSrc){
|
|
+ if( pSrc->fg.jointype & JT_LTORJ ){
|
|
+ return 0; /* rule (3) */
|
|
+ }
|
|
+ if( pSrc->fg.jointype & JT_LEFT ){
|
|
+ if( !ExprHasProperty(pExpr, EP_OuterON) ) return 0; /* rule (4a) */
|
|
+ if( pExpr->w.iJoin!=pSrc->iCursor ) return 0; /* rule (4b) */
|
|
+ }else{
|
|
+ if( ExprHasProperty(pExpr, EP_OuterON) ) return 0; /* rule (5) */
|
|
+ }
|
|
+ return sqlite3ExprIsTableConstant(pExpr, pSrc->iCursor); /* rules (1), (2) */
|
|
+}
|
|
+
|
|
|
|
/*
|
|
** sqlite3WalkExpr() callback used by sqlite3ExprIsConstantOrGroupBy().
|
|
@@ -100796,7 +108146,7 @@ static int exprNodeIsConstantOrGroupBy(Walker *pWalker, Expr *pExpr){
|
|
}
|
|
|
|
/* Check if pExpr is a sub-select. If so, consider it variable. */
|
|
- if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
|
+ if( ExprUseXSelect(pExpr) ){
|
|
pWalker->eCode = 0;
|
|
return WRC_Abort;
|
|
}
|
|
@@ -100806,7 +108156,7 @@ static int exprNodeIsConstantOrGroupBy(Walker *pWalker, Expr *pExpr){
|
|
|
|
/*
|
|
** Walk the expression tree passed as the first argument. Return non-zero
|
|
-** if the expression consists entirely of constants or copies of terms
|
|
+** if the expression consists entirely of constants or copies of terms
|
|
** in pGroupBy that sort with the BINARY collation sequence.
|
|
**
|
|
** This routine is used to determine if a term of the HAVING clause can
|
|
@@ -100836,17 +108186,17 @@ SQLITE_PRIVATE int sqlite3ExprIsConstantOrGroupBy(Parse *pParse, Expr *p, ExprLi
|
|
|
|
/*
|
|
** Walk an expression tree for the DEFAULT field of a column definition
|
|
-** in a CREATE TABLE statement. Return non-zero if the expression is
|
|
+** in a CREATE TABLE statement. Return non-zero if the expression is
|
|
** acceptable for use as a DEFAULT. That is to say, return non-zero if
|
|
** the expression is constant or a function call with constant arguments.
|
|
** Return and 0 if there are any variables.
|
|
**
|
|
-** isInit is true when parsing from sqlite_master. isInit is false when
|
|
+** isInit is true when parsing from sqlite_schema. isInit is false when
|
|
** processing a new CREATE TABLE statement. When isInit is true, parameters
|
|
** (such as ? or $abc) in the expression are converted into NULL. When
|
|
** isInit is false, parameters raise an error. Parameters should not be
|
|
** allowed in a CREATE TABLE statement, but some legacy versions of SQLite
|
|
-** allowed it, so we need to support it when reading sqlite_master for
|
|
+** allowed it, so we need to support it when reading sqlite_schema for
|
|
** backwards compatibility.
|
|
**
|
|
** If isInit is true, set EP_FromDDL on every TK_FUNCTION node.
|
|
@@ -100884,7 +108234,7 @@ SQLITE_PRIVATE int sqlite3ExprContainsSubquery(Expr *p){
|
|
** in *pValue. If the expression is not an integer or if it is too big
|
|
** to fit in a signed 32-bit integer, return 0 and leave *pValue unchanged.
|
|
*/
|
|
-SQLITE_PRIVATE int sqlite3ExprIsInteger(Expr *p, int *pValue){
|
|
+SQLITE_PRIVATE int sqlite3ExprIsInteger(const Expr *p, int *pValue){
|
|
int rc = 0;
|
|
if( NEVER(p==0) ) return 0; /* Used to only happen following on OOM */
|
|
|
|
@@ -100903,9 +108253,9 @@ SQLITE_PRIVATE int sqlite3ExprIsInteger(Expr *p, int *pValue){
|
|
break;
|
|
}
|
|
case TK_UMINUS: {
|
|
- int v;
|
|
+ int v = 0;
|
|
if( sqlite3ExprIsInteger(p->pLeft, &v) ){
|
|
- assert( v!=(-2147483647-1) );
|
|
+ assert( ((unsigned int)v)!=0x80000000 );
|
|
*pValue = -v;
|
|
rc = 1;
|
|
}
|
|
@@ -100920,7 +108270,7 @@ SQLITE_PRIVATE int sqlite3ExprIsInteger(Expr *p, int *pValue){
|
|
** Return FALSE if there is no chance that the expression can be NULL.
|
|
**
|
|
** If the expression might be NULL or if the expression is too complex
|
|
-** to tell return TRUE.
|
|
+** to tell return TRUE.
|
|
**
|
|
** This routine is used as an optimization, to skip OP_IsNull opcodes
|
|
** when we know that a value cannot be NULL. Hence, a false positive
|
|
@@ -100932,8 +108282,10 @@ SQLITE_PRIVATE int sqlite3ExprIsInteger(Expr *p, int *pValue){
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr *p){
|
|
u8 op;
|
|
+ assert( p!=0 );
|
|
while( p->op==TK_UPLUS || p->op==TK_UMINUS ){
|
|
p = p->pLeft;
|
|
+ assert( p!=0 );
|
|
}
|
|
op = p->op;
|
|
if( op==TK_REGISTER ) op = p->op2;
|
|
@@ -100944,10 +108296,11 @@ SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr *p){
|
|
case TK_BLOB:
|
|
return 0;
|
|
case TK_COLUMN:
|
|
+ assert( ExprUseYTab(p) );
|
|
return ExprHasProperty(p, EP_CanBeNull) ||
|
|
p->y.pTab==0 || /* Reference to column of index on expression */
|
|
(p->iColumn>=0
|
|
- && ALWAYS(p->y.pTab->aCol!=0) /* Defense against OOM problems */
|
|
+ && p->y.pTab->aCol!=0 /* Possible due to prior error */
|
|
&& p->y.pTab->aCol[p->iColumn].notNull==0);
|
|
default:
|
|
return 1;
|
|
@@ -101008,20 +108361,20 @@ SQLITE_PRIVATE int sqlite3IsRowid(const char *z){
|
|
}
|
|
|
|
/*
|
|
-** pX is the RHS of an IN operator. If pX is a SELECT statement
|
|
+** pX is the RHS of an IN operator. If pX is a SELECT statement
|
|
** that can be simplified to a direct table access, then return
|
|
** a pointer to the SELECT statement. If pX is not a SELECT statement,
|
|
** or if the SELECT statement needs to be manifested into a transient
|
|
** table, then return NULL.
|
|
*/
|
|
#ifndef SQLITE_OMIT_SUBQUERY
|
|
-static Select *isCandidateForInOpt(Expr *pX){
|
|
+static Select *isCandidateForInOpt(const Expr *pX){
|
|
Select *p;
|
|
SrcList *pSrc;
|
|
ExprList *pEList;
|
|
Table *pTab;
|
|
int i;
|
|
- if( !ExprHasProperty(pX, EP_xIsSelect) ) return 0; /* Not a subquery */
|
|
+ if( !ExprUseXSelect(pX) ) return 0; /* Not a subquery */
|
|
if( ExprHasProperty(pX, EP_VarSelect) ) return 0; /* Correlated subq */
|
|
p = pX->x.pSelect;
|
|
if( p->pPrior ) return 0; /* Not a compound SELECT */
|
|
@@ -101039,7 +108392,7 @@ static Select *isCandidateForInOpt(Expr *pX){
|
|
if( pSrc->a[0].pSelect ) return 0; /* FROM is not a subquery or view */
|
|
pTab = pSrc->a[0].pTab;
|
|
assert( pTab!=0 );
|
|
- assert( pTab->pSelect==0 ); /* FROM clause is not a view */
|
|
+ assert( !IsView(pTab) ); /* FROM clause is not a view */
|
|
if( IsVirtual(pTab) ) return 0; /* FROM clause not a virtual table */
|
|
pEList = p->pEList;
|
|
assert( pEList!=0 );
|
|
@@ -101074,7 +108427,7 @@ static void sqlite3SetHasNullFlag(Vdbe *v, int iCur, int regHasNull){
|
|
|
|
#ifndef SQLITE_OMIT_SUBQUERY
|
|
/*
|
|
-** The argument is an IN operator with a list (not a subquery) on the
|
|
+** The argument is an IN operator with a list (not a subquery) on the
|
|
** right-hand side. Return TRUE if that list is constant.
|
|
*/
|
|
static int sqlite3InRhsIsConstant(Expr *pIn){
|
|
@@ -101099,7 +108452,7 @@ static int sqlite3InRhsIsConstant(Expr *pIn){
|
|
** all members of the RHS set, skipping duplicates.
|
|
**
|
|
** A cursor is opened on the b-tree object that is the RHS of the IN operator
|
|
-** and pX->iTable is set to the index of that cursor.
|
|
+** and the *piTab parameter is set to the index of that cursor.
|
|
**
|
|
** The returned value of this function indicates the b-tree type, as follows:
|
|
**
|
|
@@ -101119,7 +108472,10 @@ static int sqlite3InRhsIsConstant(Expr *pIn){
|
|
** If the RHS of the IN operator is a list or a more complex subquery, then
|
|
** 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.
|
|
+** existing table. In this case, the creation and initialization of the
|
|
+** ephmeral table might be put inside of a subroutine, the EP_Subrtn flag
|
|
+** will be set on pX and the pX->y.sub fields will be set to show where
|
|
+** the subroutine is coded.
|
|
**
|
|
** The inFlags parameter must contain, at a minimum, one of the bits
|
|
** IN_INDEX_MEMBERSHIP or IN_INDEX_LOOP but not both. If inFlags contains
|
|
@@ -101133,9 +108489,9 @@ static int sqlite3InRhsIsConstant(Expr *pIn){
|
|
** 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
|
|
-** be used unless <columns> is a single INTEGER PRIMARY KEY column or an
|
|
+** When IN_INDEX_MEMBERSHIP is used (and the b-tree will be used
|
|
+** for fast set membership tests) then an epheremal table must
|
|
+** be used unless <columns> is a single INTEGER PRIMARY KEY column or an
|
|
** index can be found with the specified <columns> as its left-most.
|
|
**
|
|
** If the IN_INDEX_NOOP_OK and IN_INDEX_MEMBERSHIP are both set and
|
|
@@ -101147,7 +108503,7 @@ static int sqlite3InRhsIsConstant(Expr *pIn){
|
|
**
|
|
** When the b-tree is being used for membership tests, the calling function
|
|
** might need to know whether or not the RHS side of the IN operator
|
|
-** contains a NULL. If prRhsHasNull is not a NULL pointer and
|
|
+** contains a NULL. If prRhsHasNull is not a NULL pointer and
|
|
** if there is any chance that the (...) might contain a NULL value at
|
|
** runtime, then a register is allocated and the register number written
|
|
** to *prRhsHasNull. If there is no chance that the (...) contains a
|
|
@@ -101180,19 +108536,20 @@ SQLITE_PRIVATE int sqlite3FindInIndex(
|
|
){
|
|
Select *p; /* SELECT to the right of IN operator */
|
|
int eType = 0; /* Type of RHS table. IN_INDEX_* */
|
|
- int iTab = pParse->nTab++; /* Cursor of the RHS table */
|
|
+ int iTab; /* Cursor of the RHS table */
|
|
int mustBeUnique; /* True if RHS must be unique */
|
|
Vdbe *v = sqlite3GetVdbe(pParse); /* Virtual machine being coded */
|
|
|
|
assert( pX->op==TK_IN );
|
|
mustBeUnique = (inFlags & IN_INDEX_LOOP)!=0;
|
|
+ iTab = pParse->nTab++;
|
|
|
|
- /* If the RHS of this IN(...) operator is a SELECT, and if it matters
|
|
+ /* If the RHS of this IN(...) operator is a SELECT, and if it matters
|
|
** whether or not the SELECT result contains NULL values, check whether
|
|
- ** or not NULL is actually possible (it may not be, for example, due
|
|
+ ** or not NULL is actually possible (it may not be, for example, due
|
|
** to NOT NULL constraints in the schema). If no NULL values are possible,
|
|
** set prRhsHasNull to 0 before continuing. */
|
|
- if( prRhsHasNull && (pX->flags & EP_xIsSelect) ){
|
|
+ if( prRhsHasNull && ExprUseXSelect(pX) ){
|
|
int i;
|
|
ExprList *pEList = pX->x.pSelect->pEList;
|
|
for(i=0; i<pEList->nExpr; i++){
|
|
@@ -101204,12 +108561,12 @@ SQLITE_PRIVATE int sqlite3FindInIndex(
|
|
}
|
|
|
|
/* Check to see if an existing table or index can be used to
|
|
- ** satisfy the query. This is preferable to generating a new
|
|
+ ** satisfy the query. This is preferable to generating a new
|
|
** ephemeral table. */
|
|
if( pParse->nErr==0 && (p = isCandidateForInOpt(pX))!=0 ){
|
|
sqlite3 *db = pParse->db; /* Database connection */
|
|
Table *pTab; /* Table <table>. */
|
|
- i16 iDb; /* Database idx for pTab */
|
|
+ int iDb; /* Database idx for pTab */
|
|
ExprList *pEList = p->pEList;
|
|
int nExpr = pEList->nExpr;
|
|
|
|
@@ -101220,6 +108577,7 @@ SQLITE_PRIVATE int sqlite3FindInIndex(
|
|
|
|
/* Code an OP_Transaction and OP_TableLock for <table>. */
|
|
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
|
+ assert( iDb>=0 && iDb<SQLITE_MAX_DB );
|
|
sqlite3CodeVerifySchema(pParse, iDb);
|
|
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
|
|
|
|
@@ -101239,7 +108597,7 @@ SQLITE_PRIVATE int sqlite3FindInIndex(
|
|
int affinity_ok = 1;
|
|
int i;
|
|
|
|
- /* Check that the affinity that will be used to perform each
|
|
+ /* Check that the affinity that will be used to perform each
|
|
** comparison is the same as the affinity of each column in table
|
|
** on the RHS of the IN operator. If it not, it is not possible to
|
|
** use any index of the RHS table. */
|
|
@@ -101284,14 +108642,14 @@ SQLITE_PRIVATE int sqlite3FindInIndex(
|
|
continue; /* This index is not unique over the IN RHS columns */
|
|
}
|
|
}
|
|
-
|
|
+
|
|
colUsed = 0; /* Columns of index used so far */
|
|
for(i=0; i<nExpr; i++){
|
|
Expr *pLhs = sqlite3VectorFieldSubexpr(pX->pLeft, i);
|
|
Expr *pRhs = pEList->a[i].pExpr;
|
|
CollSeq *pReq = sqlite3BinaryCompareCollSeq(pParse, pLhs, pRhs);
|
|
int j;
|
|
-
|
|
+
|
|
assert( pReq!=0 || pRhs->iColumn==XN_ROWID || pParse->nErr );
|
|
for(j=0; j<nExpr; j++){
|
|
if( pIdx->aiColumn[j]!=pRhs->iColumn ) continue;
|
|
@@ -101307,7 +108665,7 @@ SQLITE_PRIVATE int sqlite3FindInIndex(
|
|
colUsed |= mCol;
|
|
if( aiMap ) aiMap[i] = j;
|
|
}
|
|
-
|
|
+
|
|
assert( i==nExpr || colUsed!=(MASKBIT(nExpr)-1) );
|
|
if( colUsed==(MASKBIT(nExpr)-1) ){
|
|
/* If we reach this point, that means the index pIdx is usable */
|
|
@@ -101319,11 +108677,11 @@ SQLITE_PRIVATE int sqlite3FindInIndex(
|
|
VdbeComment((v, "%s", pIdx->zName));
|
|
assert( IN_INDEX_INDEX_DESC == IN_INDEX_INDEX_ASC+1 );
|
|
eType = IN_INDEX_INDEX_ASC + pIdx->aSortOrder[0];
|
|
-
|
|
+
|
|
if( prRhsHasNull ){
|
|
#ifdef SQLITE_ENABLE_COLUMN_USED_MASK
|
|
i64 mask = (1<<nExpr)-1;
|
|
- sqlite3VdbeAddOp4Dup8(v, OP_ColumnsUsed,
|
|
+ sqlite3VdbeAddOp4Dup8(v, OP_ColumnsUsed,
|
|
iTab, 0, 0, (u8*)&mask, P4_INT64);
|
|
#endif
|
|
*prRhsHasNull = ++pParse->nMem;
|
|
@@ -101347,9 +108705,11 @@ SQLITE_PRIVATE int sqlite3FindInIndex(
|
|
*/
|
|
if( eType==0
|
|
&& (inFlags & IN_INDEX_NOOP_OK)
|
|
- && !ExprHasProperty(pX, EP_xIsSelect)
|
|
+ && ExprUseXList(pX)
|
|
&& (!sqlite3InRhsIsConstant(pX) || pX->x.pList->nExpr<=2)
|
|
){
|
|
+ pParse->nTab--; /* Back out the allocation of the unused cursor */
|
|
+ iTab = -1; /* Cursor is not allocated */
|
|
eType = IN_INDEX_NOOP;
|
|
}
|
|
|
|
@@ -101385,17 +108745,17 @@ SQLITE_PRIVATE int sqlite3FindInIndex(
|
|
|
|
#ifndef SQLITE_OMIT_SUBQUERY
|
|
/*
|
|
-** Argument pExpr is an (?, ?...) IN(...) expression. This
|
|
-** function allocates and returns a nul-terminated string containing
|
|
+** Argument pExpr is an (?, ?...) IN(...) expression. This
|
|
+** function allocates and returns a nul-terminated string containing
|
|
** the affinities to be used for each column of the comparison.
|
|
**
|
|
** It is the responsibility of the caller to ensure that the returned
|
|
** string is eventually freed using sqlite3DbFree().
|
|
*/
|
|
-static char *exprINAffinity(Parse *pParse, Expr *pExpr){
|
|
+static char *exprINAffinity(Parse *pParse, const Expr *pExpr){
|
|
Expr *pLeft = pExpr->pLeft;
|
|
int nVal = sqlite3ExprVectorSize(pLeft);
|
|
- Select *pSelect = (pExpr->flags & EP_xIsSelect) ? pExpr->x.pSelect : 0;
|
|
+ Select *pSelect = ExprUseXSelect(pExpr) ? pExpr->x.pSelect : 0;
|
|
char *zRet;
|
|
|
|
assert( pExpr->op==TK_IN );
|
|
@@ -101419,11 +108779,11 @@ static char *exprINAffinity(Parse *pParse, Expr *pExpr){
|
|
|
|
#ifndef SQLITE_OMIT_SUBQUERY
|
|
/*
|
|
-** Load the Parse object passed as the first argument with an error
|
|
+** Load the Parse object passed as the first argument with an error
|
|
** message of the form:
|
|
**
|
|
** "sub-select returns N columns - expected M"
|
|
-*/
|
|
+*/
|
|
SQLITE_PRIVATE void sqlite3SubselectError(Parse *pParse, int nActual, int nExpect){
|
|
if( pParse->nErr==0 ){
|
|
const char *zFmt = "sub-select returns %d columns - expected %d";
|
|
@@ -101434,7 +108794,7 @@ SQLITE_PRIVATE void sqlite3SubselectError(Parse *pParse, int nActual, int nExpec
|
|
|
|
/*
|
|
** Expression pExpr is a vector that has been used in a context where
|
|
-** it is not permitted. If pExpr is a sub-select vector, this routine
|
|
+** it is not permitted. If pExpr is a sub-select vector, this routine
|
|
** loads the Parse object with a message of the form:
|
|
**
|
|
** "sub-select returns N columns - expected 1"
|
|
@@ -101442,10 +108802,10 @@ SQLITE_PRIVATE void sqlite3SubselectError(Parse *pParse, int nActual, int nExpec
|
|
** Or, if it is a regular scalar vector:
|
|
**
|
|
** "row value misused"
|
|
-*/
|
|
+*/
|
|
SQLITE_PRIVATE void sqlite3VectorErrorMsg(Parse *pParse, Expr *pExpr){
|
|
#ifndef SQLITE_OMIT_SUBQUERY
|
|
- if( pExpr->flags & EP_xIsSelect ){
|
|
+ if( ExprUseXSelect(pExpr) ){
|
|
sqlite3SubselectError(pParse, pExpr->x.pSelect->pEList->nExpr, 1);
|
|
}else
|
|
#endif
|
|
@@ -101505,27 +108865,30 @@ SQLITE_PRIVATE void sqlite3CodeRhsOfIN(
|
|
if( !ExprHasProperty(pExpr, EP_VarSelect) && pParse->iSelfTab==0 ){
|
|
/* Reuse of the RHS is allowed */
|
|
/* If this routine has already been coded, but the previous code
|
|
- ** might not have been invoked yet, so invoke it now as a subroutine.
|
|
+ ** might not have been invoked yet, so invoke it now as a subroutine.
|
|
*/
|
|
if( ExprHasProperty(pExpr, EP_Subrtn) ){
|
|
addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
|
|
- if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
|
+ if( ExprUseXSelect(pExpr) ){
|
|
ExplainQueryPlan((pParse, 0, "REUSE LIST SUBQUERY %d",
|
|
pExpr->x.pSelect->selId));
|
|
}
|
|
+ assert( ExprUseYSub(pExpr) );
|
|
sqlite3VdbeAddOp2(v, OP_Gosub, pExpr->y.sub.regReturn,
|
|
pExpr->y.sub.iAddr);
|
|
+ assert( iTab!=pExpr->iTable );
|
|
sqlite3VdbeAddOp2(v, OP_OpenDup, iTab, pExpr->iTable);
|
|
sqlite3VdbeJumpHere(v, addrOnce);
|
|
return;
|
|
}
|
|
|
|
/* Begin coding the subroutine */
|
|
+ assert( !ExprUseYWin(pExpr) );
|
|
ExprSetProperty(pExpr, EP_Subrtn);
|
|
+ assert( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) );
|
|
pExpr->y.sub.regReturn = ++pParse->nMem;
|
|
pExpr->y.sub.iAddr =
|
|
- sqlite3VdbeAddOp2(v, OP_Integer, 0, pExpr->y.sub.regReturn) + 1;
|
|
- VdbeComment((v, "return address"));
|
|
+ sqlite3VdbeAddOp2(v, OP_BeginSubrtn, 0, pExpr->y.sub.regReturn) + 1;
|
|
|
|
addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
|
|
}
|
|
@@ -101540,7 +108903,7 @@ SQLITE_PRIVATE void sqlite3CodeRhsOfIN(
|
|
pExpr->iTable = iTab;
|
|
addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pExpr->iTable, nVal);
|
|
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
|
|
- if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
|
+ if( ExprUseXSelect(pExpr) ){
|
|
VdbeComment((v, "Result of SELECT %u", pExpr->x.pSelect->selId));
|
|
}else{
|
|
VdbeComment((v, "RHS of IN operator"));
|
|
@@ -101548,7 +108911,7 @@ SQLITE_PRIVATE void sqlite3CodeRhsOfIN(
|
|
#endif
|
|
pKeyInfo = sqlite3KeyInfoAlloc(pParse->db, nVal, 1);
|
|
|
|
- if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
|
+ if( ExprUseXSelect(pExpr) ){
|
|
/* Case 1: expr IN (SELECT ...)
|
|
**
|
|
** Generate code to write the results of the select into the temporary
|
|
@@ -101563,19 +108926,23 @@ SQLITE_PRIVATE void sqlite3CodeRhsOfIN(
|
|
/* If the LHS and RHS of the IN operator do not match, that
|
|
** error will have been caught long before we reach this point. */
|
|
if( ALWAYS(pEList->nExpr==nVal) ){
|
|
+ Select *pCopy;
|
|
SelectDest dest;
|
|
int i;
|
|
+ int rc;
|
|
sqlite3SelectDestInit(&dest, SRT_Set, iTab);
|
|
dest.zAffSdst = exprINAffinity(pParse, pExpr);
|
|
pSelect->iLimit = 0;
|
|
testcase( pSelect->selFlags & SF_Distinct );
|
|
testcase( pKeyInfo==0 ); /* Caused by OOM in sqlite3KeyInfoAlloc() */
|
|
- if( sqlite3Select(pParse, pSelect, &dest) ){
|
|
- sqlite3DbFree(pParse->db, dest.zAffSdst);
|
|
+ pCopy = sqlite3SelectDup(pParse->db, pSelect, 0);
|
|
+ rc = pParse->db->mallocFailed ? 1 :sqlite3Select(pParse, pCopy, &dest);
|
|
+ sqlite3SelectDelete(pParse->db, pCopy);
|
|
+ sqlite3DbFree(pParse->db, dest.zAffSdst);
|
|
+ if( rc ){
|
|
sqlite3KeyInfoUnref(pKeyInfo);
|
|
return;
|
|
}
|
|
- sqlite3DbFree(pParse->db, dest.zAffSdst);
|
|
assert( pKeyInfo!=0 ); /* OOM will cause exit after sqlite3Select() */
|
|
assert( pEList!=0 );
|
|
assert( pEList->nExpr>0 );
|
|
@@ -101603,6 +108970,8 @@ SQLITE_PRIVATE void sqlite3CodeRhsOfIN(
|
|
affinity = sqlite3ExprAffinity(pLeft);
|
|
if( affinity<=SQLITE_AFF_NONE ){
|
|
affinity = SQLITE_AFF_BLOB;
|
|
+ }else if( affinity==SQLITE_AFF_REAL ){
|
|
+ affinity = SQLITE_AFF_NUMERIC;
|
|
}
|
|
if( pKeyInfo ){
|
|
assert( sqlite3KeyInfoIsWriteable(pKeyInfo) );
|
|
@@ -101621,6 +108990,7 @@ SQLITE_PRIVATE void sqlite3CodeRhsOfIN(
|
|
** expression we need to rerun this code each time.
|
|
*/
|
|
if( addrOnce && !sqlite3ExprIsConstant(pE2) ){
|
|
+ sqlite3VdbeChangeToNoop(v, addrOnce-1);
|
|
sqlite3VdbeChangeToNoop(v, addrOnce);
|
|
ExprClearProperty(pExpr, EP_Subrtn);
|
|
addrOnce = 0;
|
|
@@ -101638,10 +109008,15 @@ SQLITE_PRIVATE void sqlite3CodeRhsOfIN(
|
|
sqlite3VdbeChangeP4(v, addr, (void *)pKeyInfo, P4_KEYINFO);
|
|
}
|
|
if( addrOnce ){
|
|
+ sqlite3VdbeAddOp1(v, OP_NullRow, iTab);
|
|
sqlite3VdbeJumpHere(v, addrOnce);
|
|
/* Subroutine return */
|
|
- sqlite3VdbeAddOp1(v, OP_Return, pExpr->y.sub.regReturn);
|
|
- sqlite3VdbeChangeP1(v, pExpr->y.sub.iAddr-1, sqlite3VdbeCurrentAddr(v)-1);
|
|
+ assert( ExprUseYSub(pExpr) );
|
|
+ assert( sqlite3VdbeGetOp(v,pExpr->y.sub.iAddr-1)->opcode==OP_BeginSubrtn
|
|
+ || pParse->nErr );
|
|
+ sqlite3VdbeAddOp3(v, OP_Return, pExpr->y.sub.regReturn,
|
|
+ pExpr->y.sub.iAddr, 1);
|
|
+ VdbeCoverage(v);
|
|
sqlite3ClearTempRegCache(pParse);
|
|
}
|
|
}
|
|
@@ -101656,7 +109031,7 @@ SQLITE_PRIVATE void sqlite3CodeRhsOfIN(
|
|
**
|
|
** The pExpr parameter is the SELECT or EXISTS operator to be coded.
|
|
**
|
|
-** Return the register that holds the result. For a multi-column SELECT,
|
|
+** Return the register that holds the result. For a multi-column SELECT,
|
|
** the result is stored in a contiguous array of registers and the
|
|
** return value is the register of the left-most result column.
|
|
** Return 0 if an error occurs.
|
|
@@ -101669,15 +109044,37 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
|
|
SelectDest dest; /* How to deal with SELECT result */
|
|
int nReg; /* Registers to allocate */
|
|
Expr *pLimit; /* New limit expression */
|
|
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
|
|
+ int addrExplain; /* Address of OP_Explain instruction */
|
|
+#endif
|
|
|
|
Vdbe *v = pParse->pVdbe;
|
|
assert( v!=0 );
|
|
+ if( pParse->nErr ) return 0;
|
|
testcase( pExpr->op==TK_EXISTS );
|
|
testcase( pExpr->op==TK_SELECT );
|
|
assert( pExpr->op==TK_EXISTS || pExpr->op==TK_SELECT );
|
|
- assert( ExprHasProperty(pExpr, EP_xIsSelect) );
|
|
+ assert( ExprUseXSelect(pExpr) );
|
|
pSel = pExpr->x.pSelect;
|
|
|
|
+ /* If this routine has already been coded, then invoke it as a
|
|
+ ** subroutine. */
|
|
+ if( ExprHasProperty(pExpr, EP_Subrtn) ){
|
|
+ ExplainQueryPlan((pParse, 0, "REUSE SUBQUERY %d", pSel->selId));
|
|
+ assert( ExprUseYSub(pExpr) );
|
|
+ sqlite3VdbeAddOp2(v, OP_Gosub, pExpr->y.sub.regReturn,
|
|
+ pExpr->y.sub.iAddr);
|
|
+ return pExpr->iTable;
|
|
+ }
|
|
+
|
|
+ /* Begin coding the subroutine */
|
|
+ assert( !ExprUseYWin(pExpr) );
|
|
+ assert( !ExprHasProperty(pExpr, EP_Reduced|EP_TokenOnly) );
|
|
+ ExprSetProperty(pExpr, EP_Subrtn);
|
|
+ pExpr->y.sub.regReturn = ++pParse->nMem;
|
|
+ pExpr->y.sub.iAddr =
|
|
+ sqlite3VdbeAddOp2(v, OP_BeginSubrtn, 0, pExpr->y.sub.regReturn) + 1;
|
|
+
|
|
/* The evaluation of the EXISTS/SELECT must be repeated every time it
|
|
** is encountered if any of the following is true:
|
|
**
|
|
@@ -101689,25 +109086,9 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
|
|
** save the results, and reuse the same result on subsequent invocations.
|
|
*/
|
|
if( !ExprHasProperty(pExpr, EP_VarSelect) ){
|
|
- /* If this routine has already been coded, then invoke it as a
|
|
- ** subroutine. */
|
|
- if( ExprHasProperty(pExpr, EP_Subrtn) ){
|
|
- ExplainQueryPlan((pParse, 0, "REUSE SUBQUERY %d", pSel->selId));
|
|
- sqlite3VdbeAddOp2(v, OP_Gosub, pExpr->y.sub.regReturn,
|
|
- pExpr->y.sub.iAddr);
|
|
- return pExpr->iTable;
|
|
- }
|
|
-
|
|
- /* Begin coding the subroutine */
|
|
- ExprSetProperty(pExpr, EP_Subrtn);
|
|
- pExpr->y.sub.regReturn = ++pParse->nMem;
|
|
- pExpr->y.sub.iAddr =
|
|
- sqlite3VdbeAddOp2(v, OP_Integer, 0, pExpr->y.sub.regReturn) + 1;
|
|
- VdbeComment((v, "return address"));
|
|
-
|
|
addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
|
|
}
|
|
-
|
|
+
|
|
/* For a SELECT, generate code to put the values for all columns of
|
|
** the first row into an array of registers and return the index of
|
|
** the first register.
|
|
@@ -101715,11 +109096,12 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
|
|
** If this is an EXISTS, write an integer 0 (not exists) or 1 (exists)
|
|
** into a register and return that register number.
|
|
**
|
|
- ** In both cases, the query is augmented with "LIMIT 1". Any
|
|
+ ** In both cases, the query is augmented with "LIMIT 1". Any
|
|
** preexisting limit is discarded in place of the new LIMIT 1.
|
|
*/
|
|
- ExplainQueryPlan((pParse, 1, "%sSCALAR SUBQUERY %d",
|
|
+ ExplainQueryPlan2(addrExplain, (pParse, 1, "%sSCALAR SUBQUERY %d",
|
|
addrOnce?"":"CORRELATED ", pSel->selId));
|
|
+ sqlite3VdbeScanStatusCounters(v, addrExplain, addrExplain, -1);
|
|
nReg = pExpr->op==TK_SELECT ? pSel->pEList->nExpr : 1;
|
|
sqlite3SelectDestInit(&dest, 0, pParse->nMem+1);
|
|
pParse->nMem += nReg;
|
|
@@ -101744,7 +109126,7 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
|
|
pLimit = sqlite3PExpr(pParse, TK_NE,
|
|
sqlite3ExprDup(db, pSel->pLimit->pLeft, 0), pLimit);
|
|
}
|
|
- sqlite3ExprDelete(db, pSel->pLimit->pLeft);
|
|
+ sqlite3ExprDeferredDelete(pParse, pSel->pLimit->pLeft);
|
|
pSel->pLimit->pLeft = pLimit;
|
|
}else{
|
|
/* If there is no pre-existing limit add a limit of 1 */
|
|
@@ -101753,33 +109135,39 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
|
|
}
|
|
pSel->iLimit = 0;
|
|
if( sqlite3Select(pParse, pSel, &dest) ){
|
|
+ pExpr->op2 = pExpr->op;
|
|
+ pExpr->op = TK_ERROR;
|
|
return 0;
|
|
}
|
|
pExpr->iTable = rReg = dest.iSDParm;
|
|
ExprSetVVAProperty(pExpr, EP_NoReduce);
|
|
if( addrOnce ){
|
|
sqlite3VdbeJumpHere(v, addrOnce);
|
|
-
|
|
- /* Subroutine return */
|
|
- sqlite3VdbeAddOp1(v, OP_Return, pExpr->y.sub.regReturn);
|
|
- sqlite3VdbeChangeP1(v, pExpr->y.sub.iAddr-1, sqlite3VdbeCurrentAddr(v)-1);
|
|
- sqlite3ClearTempRegCache(pParse);
|
|
}
|
|
+ sqlite3VdbeScanStatusRange(v, addrExplain, addrExplain, -1);
|
|
|
|
+ /* Subroutine return */
|
|
+ assert( ExprUseYSub(pExpr) );
|
|
+ assert( sqlite3VdbeGetOp(v,pExpr->y.sub.iAddr-1)->opcode==OP_BeginSubrtn
|
|
+ || pParse->nErr );
|
|
+ sqlite3VdbeAddOp3(v, OP_Return, pExpr->y.sub.regReturn,
|
|
+ pExpr->y.sub.iAddr, 1);
|
|
+ VdbeCoverage(v);
|
|
+ sqlite3ClearTempRegCache(pParse);
|
|
return rReg;
|
|
}
|
|
#endif /* SQLITE_OMIT_SUBQUERY */
|
|
|
|
#ifndef SQLITE_OMIT_SUBQUERY
|
|
/*
|
|
-** Expr pIn is an IN(...) expression. This function checks that the
|
|
-** sub-select on the RHS of the IN() operator has the same number of
|
|
-** columns as the vector on the LHS. Or, if the RHS of the IN() is not
|
|
+** Expr pIn is an IN(...) expression. This function checks that the
|
|
+** sub-select on the RHS of the IN() operator has the same number of
|
|
+** columns as the vector on the LHS. Or, if the RHS of the IN() is not
|
|
** a sub-query, that the LHS is a vector of size 1.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3ExprCheckIN(Parse *pParse, Expr *pIn){
|
|
int nVector = sqlite3ExprVectorSize(pIn->pLeft);
|
|
- if( (pIn->flags & EP_xIsSelect) ){
|
|
+ if( ExprUseXSelect(pIn) && !pParse->db->mallocFailed ){
|
|
if( nVector!=pIn->x.pSelect->pEList->nExpr ){
|
|
sqlite3SubselectError(pParse, pIn->x.pSelect->pEList->nExpr, nVector);
|
|
return 1;
|
|
@@ -101799,18 +109187,18 @@ SQLITE_PRIVATE int sqlite3ExprCheckIN(Parse *pParse, Expr *pIn){
|
|
** x IN (SELECT ...)
|
|
** x IN (value, value, ...)
|
|
**
|
|
-** The left-hand side (LHS) is a scalar or vector expression. The
|
|
+** The left-hand side (LHS) is a scalar or vector expression. The
|
|
** right-hand side (RHS) is an array of zero or more scalar values, or a
|
|
** subquery. If the RHS is a subquery, the number of result columns must
|
|
** match the number of columns in the vector on the LHS. If the RHS is
|
|
-** a list of values, the LHS must be a scalar.
|
|
+** a list of values, the LHS must be a scalar.
|
|
**
|
|
** The IN operator is true if the LHS value is contained within the RHS.
|
|
-** The result is false if the LHS is definitely not in the RHS. The
|
|
-** result is NULL if the presence of the LHS in the RHS cannot be
|
|
+** The result is false if the LHS is definitely not in the RHS. The
|
|
+** result is NULL if the presence of the LHS in the RHS cannot be
|
|
** determined due to NULLs.
|
|
**
|
|
-** This routine generates code that jumps to destIfFalse if the LHS is not
|
|
+** This routine generates code that jumps to destIfFalse if the LHS is not
|
|
** contained within the RHS. If due to NULLs we cannot determine if the LHS
|
|
** is contained in the RHS then jump to destIfNull. If the LHS is contained
|
|
** within the RHS then fall through.
|
|
@@ -101839,9 +109227,11 @@ static void sqlite3ExprCodeIN(
|
|
int destStep6 = 0; /* Start of code for Step 6 */
|
|
int addrTruthOp; /* Address of opcode that determines the IN is true */
|
|
int destNotNull; /* Jump here if a comparison is not true in step 6 */
|
|
- int addrTop; /* Top of the step-6 loop */
|
|
+ int addrTop; /* Top of the step-6 loop */
|
|
int iTab = 0; /* Index to use */
|
|
+ u8 okConstFactor = pParse->okConstFactor;
|
|
|
|
+ assert( !ExprHasVVAProperty(pExpr,EP_Immutable) );
|
|
pLeft = pExpr->pLeft;
|
|
if( sqlite3ExprCheckIN(pParse, pExpr) ) return;
|
|
zAff = exprINAffinity(pParse, pExpr);
|
|
@@ -101864,7 +109254,7 @@ static void sqlite3ExprCodeIN(
|
|
aiMap, &iTab);
|
|
|
|
assert( pParse->nErr || nVector==1 || eType==IN_INDEX_EPH
|
|
- || eType==IN_INDEX_INDEX_ASC || eType==IN_INDEX_INDEX_DESC
|
|
+ || eType==IN_INDEX_INDEX_ASC || eType==IN_INDEX_INDEX_DESC
|
|
);
|
|
#ifdef SQLITE_DEBUG
|
|
/* Confirm that aiMap[] contains nVector integer values between 0 and
|
|
@@ -101876,16 +109266,22 @@ static void sqlite3ExprCodeIN(
|
|
}
|
|
#endif
|
|
|
|
- /* Code the LHS, the <expr> from "<expr> IN (...)". If the LHS is a
|
|
- ** vector, then it is stored in an array of nVector registers starting
|
|
+ /* Code the LHS, the <expr> from "<expr> IN (...)". If the LHS is a
|
|
+ ** vector, then it is stored in an array of nVector registers starting
|
|
** at r1.
|
|
**
|
|
** sqlite3FindInIndex() might have reordered the fields of the LHS vector
|
|
** so that the fields are in the same order as an existing index. The
|
|
** aiMap[] array contains a mapping from the original LHS field order to
|
|
** the field order that matches the RHS index.
|
|
- */
|
|
+ **
|
|
+ ** Avoid factoring the LHS of the IN(...) expression out of the loop,
|
|
+ ** even if it is constant, as OP_Affinity may be used on the register
|
|
+ ** by code generated below. */
|
|
+ assert( pParse->okConstFactor==okConstFactor );
|
|
+ pParse->okConstFactor = 0;
|
|
rLhsOrig = exprCodeVector(pParse, pLeft, &iDummy);
|
|
+ pParse->okConstFactor = okConstFactor;
|
|
for(i=0; i<nVector && aiMap[i]==i; i++){} /* Are LHS fields reordered? */
|
|
if( i==nVector ){
|
|
/* LHS fields are not reordered */
|
|
@@ -101905,27 +109301,21 @@ static void sqlite3ExprCodeIN(
|
|
** This is step (1) in the in-operator.md optimized algorithm.
|
|
*/
|
|
if( eType==IN_INDEX_NOOP ){
|
|
- ExprList *pList = pExpr->x.pList;
|
|
- CollSeq *pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft);
|
|
+ ExprList *pList;
|
|
+ CollSeq *pColl;
|
|
int labelOk = sqlite3VdbeMakeLabel(pParse);
|
|
int r2, regToFree;
|
|
int regCkNull = 0;
|
|
int ii;
|
|
- int bLhsReal; /* True if the LHS of the IN has REAL affinity */
|
|
- assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
|
|
+ assert( ExprUseXList(pExpr) );
|
|
+ pList = pExpr->x.pList;
|
|
+ pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft);
|
|
if( destIfNull!=destIfFalse ){
|
|
regCkNull = sqlite3GetTempReg(pParse);
|
|
sqlite3VdbeAddOp3(v, OP_BitAnd, rLhs, rLhs, regCkNull);
|
|
}
|
|
- bLhsReal = sqlite3ExprAffinity(pExpr->pLeft)==SQLITE_AFF_REAL;
|
|
for(ii=0; ii<pList->nExpr; ii++){
|
|
- if( bLhsReal ){
|
|
- r2 = regToFree = sqlite3GetTempReg(pParse);
|
|
- sqlite3ExprCode(pParse, pList->a[ii].pExpr, r2);
|
|
- sqlite3VdbeAddOp4(v, OP_Affinity, r2, 1, 0, "E", P4_STATIC);
|
|
- }else{
|
|
- r2 = sqlite3ExprCodeTemp(pParse, pList->a[ii].pExpr, ®ToFree);
|
|
- }
|
|
+ r2 = sqlite3ExprCodeTemp(pParse, pList->a[ii].pExpr, ®ToFree);
|
|
if( regCkNull && sqlite3ExprCanBeNull(pList->a[ii].pExpr) ){
|
|
sqlite3VdbeAddOp3(v, OP_BitAnd, regCkNull, r2, regCkNull);
|
|
}
|
|
@@ -101967,9 +109357,9 @@ static void sqlite3ExprCodeIN(
|
|
}else{
|
|
destStep2 = destStep6 = sqlite3VdbeMakeLabel(pParse);
|
|
}
|
|
- if( pParse->nErr ) goto sqlite3ExprCodeIN_finished;
|
|
for(i=0; i<nVector; i++){
|
|
Expr *p = sqlite3VectorFieldSubexpr(pExpr->pLeft, i);
|
|
+ if( pParse->nErr ) goto sqlite3ExprCodeIN_oom_error;
|
|
if( sqlite3ExprCanBeNull(p) ){
|
|
sqlite3VdbeAddOp2(v, OP_IsNull, rLhs+i, destStep2);
|
|
VdbeCoverage(v);
|
|
@@ -102009,7 +109399,7 @@ static void sqlite3ExprCodeIN(
|
|
}
|
|
|
|
/* Step 5. If we do not care about the difference between NULL and
|
|
- ** FALSE, then just return false.
|
|
+ ** FALSE, then just return false.
|
|
*/
|
|
if( destIfFalse==destIfNull ) sqlite3VdbeGoto(v, destIfFalse);
|
|
|
|
@@ -102070,7 +109460,7 @@ static void sqlite3ExprCodeIN(
|
|
** Generate an instruction that will put the floating point
|
|
** value described by z[0..n-1] into register iMem.
|
|
**
|
|
-** The z[] string will probably not be zero-terminated. But the
|
|
+** The z[] string will probably not be zero-terminated. But the
|
|
** z[n] character is guaranteed to be something that does not look
|
|
** like the continuation of the number.
|
|
*/
|
|
@@ -102107,11 +109497,12 @@ static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){
|
|
c = sqlite3DecOrHexToI64(z, &value);
|
|
if( (c==3 && !negFlag) || (c==2) || (negFlag && value==SMALLEST_INT64)){
|
|
#ifdef SQLITE_OMIT_FLOATING_POINT
|
|
- sqlite3ErrorMsg(pParse, "oversized integer: %s%s", negFlag ? "-" : "", z);
|
|
+ sqlite3ErrorMsg(pParse, "oversized integer: %s%#T", negFlag?"-":"",pExpr);
|
|
#else
|
|
#ifndef SQLITE_OMIT_HEX_INTEGER
|
|
if( sqlite3_strnicmp(z,"0x",2)==0 ){
|
|
- sqlite3ErrorMsg(pParse, "hex literal too big: %s%s", negFlag?"-":"",z);
|
|
+ sqlite3ErrorMsg(pParse, "hex literal too big: %s%#T",
|
|
+ negFlag?"-":"",pExpr);
|
|
}else
|
|
#endif
|
|
{
|
|
@@ -102155,12 +109546,14 @@ SQLITE_PRIVATE void sqlite3ExprCodeLoadIndexColumn(
|
|
** and store the result in register regOut
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3ExprCodeGeneratedColumn(
|
|
- Parse *pParse,
|
|
- Column *pCol,
|
|
- int regOut
|
|
+ Parse *pParse, /* Parsing context */
|
|
+ Table *pTab, /* Table containing the generated column */
|
|
+ Column *pCol, /* The generated column */
|
|
+ int regOut /* Put the result in this register */
|
|
){
|
|
int iAddr;
|
|
Vdbe *v = pParse->pVdbe;
|
|
+ int nErr = pParse->nErr;
|
|
assert( v!=0 );
|
|
assert( pParse->iSelfTab!=0 );
|
|
if( pParse->iSelfTab>0 ){
|
|
@@ -102168,11 +109561,12 @@ SQLITE_PRIVATE void sqlite3ExprCodeGeneratedColumn(
|
|
}else{
|
|
iAddr = 0;
|
|
}
|
|
- sqlite3ExprCode(pParse, pCol->pDflt, regOut);
|
|
+ sqlite3ExprCodeCopy(pParse, sqlite3ColumnExpr(pTab,pCol), regOut);
|
|
if( pCol->affinity>=SQLITE_AFF_TEXT ){
|
|
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 */
|
|
|
|
@@ -102188,12 +109582,11 @@ SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable(
|
|
){
|
|
Column *pCol;
|
|
assert( v!=0 );
|
|
- if( pTab==0 ){
|
|
- sqlite3VdbeAddOp3(v, OP_Column, iTabCur, iCol, regOut);
|
|
- return;
|
|
- }
|
|
+ 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));
|
|
}else{
|
|
int op;
|
|
int x;
|
|
@@ -102204,12 +109597,13 @@ SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable(
|
|
}else if( (pCol = &pTab->aCol[iCol])->colFlags & COLFLAG_VIRTUAL ){
|
|
Parse *pParse = sqlite3VdbeParser(v);
|
|
if( pCol->colFlags & COLFLAG_BUSY ){
|
|
- sqlite3ErrorMsg(pParse, "generated column loop on \"%s\"", pCol->zName);
|
|
+ sqlite3ErrorMsg(pParse, "generated column loop on \"%s\"",
|
|
+ pCol->zCnName);
|
|
}else{
|
|
int savedSelfTab = pParse->iSelfTab;
|
|
pCol->colFlags |= COLFLAG_BUSY;
|
|
pParse->iSelfTab = iTabCur+1;
|
|
- sqlite3ExprCodeGeneratedColumn(pParse, pCol, regOut);
|
|
+ sqlite3ExprCodeGeneratedColumn(pParse, pTab, pCol, regOut);
|
|
pParse->iSelfTab = savedSelfTab;
|
|
pCol->colFlags &= ~COLFLAG_BUSY;
|
|
}
|
|
@@ -102231,7 +109625,7 @@ SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable(
|
|
|
|
/*
|
|
** Generate code that will extract the iColumn-th column from
|
|
-** table pTab and store the column value in register iReg.
|
|
+** table pTab and store the column value in register iReg.
|
|
**
|
|
** There must be an open cursor to pTab in iTable when this routine
|
|
** is called. If iColumn<0 then code is generated that extracts the rowid.
|
|
@@ -102247,7 +109641,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeGetColumn(
|
|
assert( pParse->pVdbe!=0 );
|
|
sqlite3ExprCodeGetColumnOfTable(pParse->pVdbe, pTab, iTable, iColumn, iReg);
|
|
if( p5 ){
|
|
- VdbeOp *pOp = sqlite3VdbeGetOp(pParse->pVdbe,-1);
|
|
+ VdbeOp *pOp = sqlite3VdbeGetLastOp(pParse->pVdbe);
|
|
if( pOp->opcode==OP_Column ) pOp->p5 = p5;
|
|
}
|
|
return iReg;
|
|
@@ -102268,6 +109662,7 @@ SQLITE_PRIVATE void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int n
|
|
*/
|
|
static void exprToRegister(Expr *pExpr, int iReg){
|
|
Expr *p = sqlite3ExprSkipCollateAndLikely(pExpr);
|
|
+ if( NEVER(p==0) ) return;
|
|
p->op2 = p->op;
|
|
p->op = TK_REGISTER;
|
|
p->iTable = iReg;
|
|
@@ -102301,6 +109696,7 @@ static int exprCodeVector(Parse *pParse, Expr *p, int *piFreeable){
|
|
int i;
|
|
iResult = pParse->nMem+1;
|
|
pParse->nMem += nResult;
|
|
+ assert( ExprUseXList(p) );
|
|
for(i=0; i<nResult; i++){
|
|
sqlite3ExprCodeFactorable(pParse, p->x.pList->a[i].pExpr, i+iResult);
|
|
}
|
|
@@ -102309,6 +109705,16 @@ static int exprCodeVector(Parse *pParse, Expr *p, int *piFreeable){
|
|
return iResult;
|
|
}
|
|
|
|
+/*
|
|
+** If the last opcode is a OP_Copy, then set the do-not-merge flag (p5)
|
|
+** so that a subsequent copy will not be merged into this one.
|
|
+*/
|
|
+static void setDoNotMergeFlagOnCopy(Vdbe *v){
|
|
+ if( sqlite3VdbeGetLastOp(v)->opcode==OP_Copy ){
|
|
+ sqlite3VdbeChangeP5(v, 1); /* Tag trailing OP_Copy as not mergable */
|
|
+ }
|
|
+}
|
|
+
|
|
/*
|
|
** Generate code to implement special SQL functions that are implemented
|
|
** in-line rather than by using the usual callbacks.
|
|
@@ -102340,14 +109746,29 @@ static int exprCodeInlineFunction(
|
|
VdbeCoverage(v);
|
|
sqlite3ExprCode(pParse, pFarg->a[i].pExpr, target);
|
|
}
|
|
- if( sqlite3VdbeGetOp(v, -1)->opcode==OP_Copy ){
|
|
- sqlite3VdbeChangeP5(v, 1); /* Tag trailing OP_Copy as not mergable */
|
|
- }
|
|
+ setDoNotMergeFlagOnCopy(v);
|
|
sqlite3VdbeResolveLabel(v, endCoalesce);
|
|
break;
|
|
}
|
|
-
|
|
- default: {
|
|
+ case INLINEFUNC_iif: {
|
|
+ Expr caseExpr;
|
|
+ memset(&caseExpr, 0, sizeof(caseExpr));
|
|
+ caseExpr.op = TK_CASE;
|
|
+ caseExpr.x.pList = pFarg;
|
|
+ return sqlite3ExprCodeTarget(pParse, &caseExpr, target);
|
|
+ }
|
|
+#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
|
|
+ case INLINEFUNC_sqlite_offset: {
|
|
+ Expr *pArg = pFarg->a[0].pExpr;
|
|
+ if( pArg->op==TK_COLUMN && pArg->iTable>=0 ){
|
|
+ sqlite3VdbeAddOp3(v, OP_Offset, pArg->iTable, pArg->iColumn, target);
|
|
+ }else{
|
|
+ sqlite3VdbeAddOp2(v, OP_Null, 0, target);
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+#endif
|
|
+ default: {
|
|
/* The UNLIKELY() function is a no-op. The result is the value
|
|
** of the first argument.
|
|
*/
|
|
@@ -102360,10 +109781,11 @@ static int exprCodeInlineFunction(
|
|
** Test-only SQL functions that are only usable if enabled
|
|
** via SQLITE_TESTCTRL_INTERNAL_FUNCTIONS
|
|
*/
|
|
+#if !defined(SQLITE_UNTESTABLE)
|
|
case INLINEFUNC_expr_compare: {
|
|
/* Compare two expressions using sqlite3ExprCompare() */
|
|
assert( nFarg==2 );
|
|
- sqlite3VdbeAddOp2(v, OP_Integer,
|
|
+ sqlite3VdbeAddOp2(v, OP_Integer,
|
|
sqlite3ExprCompare(0,pFarg->a[0].pExpr, pFarg->a[1].pExpr,-1),
|
|
target);
|
|
break;
|
|
@@ -102372,7 +109794,7 @@ static int exprCodeInlineFunction(
|
|
case INLINEFUNC_expr_implies_expr: {
|
|
/* Compare two expressions using sqlite3ExprImpliesExpr() */
|
|
assert( nFarg==2 );
|
|
- sqlite3VdbeAddOp2(v, OP_Integer,
|
|
+ sqlite3VdbeAddOp2(v, OP_Integer,
|
|
sqlite3ExprImpliesExpr(pParse,pFarg->a[0].pExpr, pFarg->a[1].pExpr,-1),
|
|
target);
|
|
break;
|
|
@@ -102384,7 +109806,7 @@ static int exprCodeInlineFunction(
|
|
assert( nFarg==2 );
|
|
pA1 = pFarg->a[1].pExpr;
|
|
if( pA1->op==TK_COLUMN ){
|
|
- sqlite3VdbeAddOp2(v, OP_Integer,
|
|
+ sqlite3VdbeAddOp2(v, OP_Integer,
|
|
sqlite3ExprImpliesNonNullRow(pFarg->a[0].pExpr,pA1->iTable),
|
|
target);
|
|
}else{
|
|
@@ -102393,25 +109815,85 @@ static int exprCodeInlineFunction(
|
|
break;
|
|
}
|
|
|
|
-#ifdef SQLITE_DEBUG
|
|
case INLINEFUNC_affinity: {
|
|
/* The AFFINITY() function evaluates to a string that describes
|
|
** the type affinity of the argument. This is used for testing of
|
|
** the SQLite type logic.
|
|
*/
|
|
- const char *azAff[] = { "blob", "text", "numeric", "integer", "real" };
|
|
+ const char *azAff[] = { "blob", "text", "numeric", "integer",
|
|
+ "real", "flexnum" };
|
|
char aff;
|
|
assert( nFarg==1 );
|
|
aff = sqlite3ExprAffinity(pFarg->a[0].pExpr);
|
|
- sqlite3VdbeLoadString(v, target,
|
|
+ assert( aff<=SQLITE_AFF_NONE
|
|
+ || (aff>=SQLITE_AFF_BLOB && aff<=SQLITE_AFF_FLEXNUM) );
|
|
+ sqlite3VdbeLoadString(v, target,
|
|
(aff<=SQLITE_AFF_NONE) ? "none" : azAff[aff-SQLITE_AFF_BLOB]);
|
|
break;
|
|
}
|
|
-#endif
|
|
+#endif /* !defined(SQLITE_UNTESTABLE) */
|
|
}
|
|
return target;
|
|
}
|
|
|
|
+/*
|
|
+** Check to see if pExpr is one of the indexed expressions on pParse->pIdxEpr.
|
|
+** If it is, then resolve the expression by reading from the index and
|
|
+** return the register into which the value has been read. If pExpr is
|
|
+** not an indexed expression, then return negative.
|
|
+*/
|
|
+static SQLITE_NOINLINE int sqlite3IndexedExprLookup(
|
|
+ Parse *pParse, /* The parsing context */
|
|
+ Expr *pExpr, /* The expression to potentially bypass */
|
|
+ int target /* Where to store the result of the expression */
|
|
+){
|
|
+ IndexedExpr *p;
|
|
+ Vdbe *v;
|
|
+ for(p=pParse->pIdxEpr; p; p=p->pIENext){
|
|
+ u8 exprAff;
|
|
+ int iDataCur = p->iDataCur;
|
|
+ if( iDataCur<0 ) continue;
|
|
+ if( pParse->iSelfTab ){
|
|
+ if( p->iDataCur!=pParse->iSelfTab-1 ) continue;
|
|
+ iDataCur = -1;
|
|
+ }
|
|
+ if( sqlite3ExprCompare(0, pExpr, p->pExpr, iDataCur)!=0 ) continue;
|
|
+ assert( p->aff>=SQLITE_AFF_BLOB && p->aff<=SQLITE_AFF_NUMERIC );
|
|
+ exprAff = sqlite3ExprAffinity(pExpr);
|
|
+ if( (exprAff<=SQLITE_AFF_BLOB && p->aff!=SQLITE_AFF_BLOB)
|
|
+ || (exprAff==SQLITE_AFF_TEXT && p->aff!=SQLITE_AFF_TEXT)
|
|
+ || (exprAff>=SQLITE_AFF_NUMERIC && p->aff!=SQLITE_AFF_NUMERIC)
|
|
+ ){
|
|
+ /* Affinity mismatch on a generated column */
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ v = pParse->pVdbe;
|
|
+ assert( v!=0 );
|
|
+ if( p->bMaybeNullRow ){
|
|
+ /* If the index is on a NULL row due to an outer join, then we
|
|
+ ** cannot extract the value from the index. The value must be
|
|
+ ** computed using the original expression. */
|
|
+ int addr = sqlite3VdbeCurrentAddr(v);
|
|
+ sqlite3VdbeAddOp3(v, OP_IfNullRow, p->iIdxCur, addr+3, target);
|
|
+ VdbeCoverage(v);
|
|
+ sqlite3VdbeAddOp3(v, OP_Column, p->iIdxCur, p->iIdxCol, target);
|
|
+ VdbeComment((v, "%s expr-column %d", p->zIdxName, p->iIdxCol));
|
|
+ sqlite3VdbeGoto(v, 0);
|
|
+ p = pParse->pIdxEpr;
|
|
+ pParse->pIdxEpr = 0;
|
|
+ sqlite3ExprCode(pParse, pExpr, target);
|
|
+ pParse->pIdxEpr = p;
|
|
+ sqlite3VdbeJumpHere(v, addr+2);
|
|
+ }else{
|
|
+ sqlite3VdbeAddOp3(v, OP_Column, p->iIdxCur, p->iIdxCol, target);
|
|
+ VdbeComment((v, "%s expr-column %d", p->zIdxName, p->iIdxCol));
|
|
+ }
|
|
+ return target;
|
|
+ }
|
|
+ return -1; /* Not found */
|
|
+}
|
|
+
|
|
|
|
/*
|
|
** Generate code into the current Vdbe to evaluate the given
|
|
@@ -102435,30 +109917,53 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
|
|
int p5 = 0;
|
|
|
|
assert( target>0 && target<=pParse->nMem );
|
|
- if( v==0 ){
|
|
- assert( pParse->db->mallocFailed );
|
|
- return 0;
|
|
- }
|
|
+ assert( v!=0 );
|
|
|
|
expr_code_doover:
|
|
if( pExpr==0 ){
|
|
op = TK_NULL;
|
|
+ }else if( pParse->pIdxEpr!=0
|
|
+ && !ExprHasProperty(pExpr, EP_Leaf)
|
|
+ && (r1 = sqlite3IndexedExprLookup(pParse, pExpr, target))>=0
|
|
+ ){
|
|
+ return r1;
|
|
}else{
|
|
+ assert( !ExprHasVVAProperty(pExpr,EP_Immutable) );
|
|
op = pExpr->op;
|
|
}
|
|
switch( op ){
|
|
case TK_AGG_COLUMN: {
|
|
AggInfo *pAggInfo = pExpr->pAggInfo;
|
|
- struct AggInfo_col *pCol = &pAggInfo->aCol[pExpr->iAgg];
|
|
+ struct AggInfo_col *pCol;
|
|
+ assert( pAggInfo!=0 );
|
|
+ assert( pExpr->iAgg>=0 && pExpr->iAgg<pAggInfo->nColumn );
|
|
+ pCol = &pAggInfo->aCol[pExpr->iAgg];
|
|
if( !pAggInfo->directMode ){
|
|
- assert( pCol->iMem>0 );
|
|
- return pCol->iMem;
|
|
+ return AggInfoColumnReg(pAggInfo, pExpr->iAgg);
|
|
}else if( pAggInfo->useSortingIdx ){
|
|
+ Table *pTab = pCol->pTab;
|
|
sqlite3VdbeAddOp3(v, OP_Column, pAggInfo->sortingIdxPTab,
|
|
pCol->iSorterColumn, target);
|
|
+ if( pTab==0 ){
|
|
+ /* No comment added */
|
|
+ }else if( pCol->iColumn<0 ){
|
|
+ VdbeComment((v,"%s.rowid",pTab->zName));
|
|
+ }else{
|
|
+ VdbeComment((v,"%s.%s",
|
|
+ pTab->zName, pTab->aCol[pCol->iColumn].zCnName));
|
|
+ if( pTab->aCol[pCol->iColumn].affinity==SQLITE_AFF_REAL ){
|
|
+ sqlite3VdbeAddOp1(v, OP_RealAffinity, target);
|
|
+ }
|
|
+ }
|
|
+ return target;
|
|
+ }else if( pExpr->y.pTab==0 ){
|
|
+ /* This case happens when the argument to an aggregate function
|
|
+ ** is rewritten by aggregateConvertIndexedExprRefToColumn() */
|
|
+ sqlite3VdbeAddOp3(v, OP_Column, pExpr->iTable, pExpr->iColumn, target);
|
|
return target;
|
|
}
|
|
/* Otherwise, fall thru into the TK_COLUMN case */
|
|
+ /* no break */ deliberate_fall_through
|
|
}
|
|
case TK_COLUMN: {
|
|
int iTab = pExpr->iTable;
|
|
@@ -102472,19 +109977,13 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
|
|
*/
|
|
int aff;
|
|
iReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft,target);
|
|
- if( pExpr->y.pTab ){
|
|
- aff = sqlite3TableColumnAffinity(pExpr->y.pTab, pExpr->iColumn);
|
|
- }else{
|
|
- aff = pExpr->affExpr;
|
|
- }
|
|
+ assert( ExprUseYTab(pExpr) );
|
|
+ assert( pExpr->y.pTab!=0 );
|
|
+ aff = sqlite3TableColumnAffinity(pExpr->y.pTab, pExpr->iColumn);
|
|
if( aff>SQLITE_AFF_BLOB ){
|
|
- static const char zAff[] = "B\000C\000D\000E";
|
|
+ static const char zAff[] = "B\000C\000D\000E\000F";
|
|
assert( SQLITE_AFF_BLOB=='A' );
|
|
assert( SQLITE_AFF_TEXT=='B' );
|
|
- if( iReg!=target ){
|
|
- sqlite3VdbeAddOp2(v, OP_SCopy, iReg, target);
|
|
- iReg = target;
|
|
- }
|
|
sqlite3VdbeAddOp4(v, OP_Affinity, iReg, 1, 0,
|
|
&zAff[(aff-'B')*2], P4_STATIC);
|
|
}
|
|
@@ -102499,9 +109998,11 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
|
|
** immediately prior to the first column.
|
|
*/
|
|
Column *pCol;
|
|
- Table *pTab = pExpr->y.pTab;
|
|
+ Table *pTab;
|
|
int iSrc;
|
|
int iCol = pExpr->iColumn;
|
|
+ assert( ExprUseYTab(pExpr) );
|
|
+ pTab = pExpr->y.pTab;
|
|
assert( pTab!=0 );
|
|
assert( iCol>=XN_ROWID );
|
|
assert( iCol<pTab->nCol );
|
|
@@ -102515,12 +110016,12 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
|
|
if( pCol->colFlags & COLFLAG_GENERATED ){
|
|
if( pCol->colFlags & COLFLAG_BUSY ){
|
|
sqlite3ErrorMsg(pParse, "generated column loop on \"%s\"",
|
|
- pCol->zName);
|
|
+ pCol->zCnName);
|
|
return 0;
|
|
}
|
|
pCol->colFlags |= COLFLAG_BUSY;
|
|
if( pCol->colFlags & COLFLAG_NOTAVAIL ){
|
|
- sqlite3ExprCodeGeneratedColumn(pParse, pCol, iSrc);
|
|
+ sqlite3ExprCodeGeneratedColumn(pParse, pTab, pCol, iSrc);
|
|
}
|
|
pCol->colFlags &= ~(COLFLAG_BUSY|COLFLAG_NOTAVAIL);
|
|
return iSrc;
|
|
@@ -102539,12 +110040,11 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
|
|
iTab = pParse->iSelfTab - 1;
|
|
}
|
|
}
|
|
+ assert( ExprUseYTab(pExpr) );
|
|
+ assert( pExpr->y.pTab!=0 );
|
|
iReg = sqlite3ExprCodeGetColumn(pParse, pExpr->y.pTab,
|
|
pExpr->iColumn, iTab, target,
|
|
pExpr->op2);
|
|
- if( pExpr->y.pTab==0 && pExpr->affExpr==SQLITE_AFF_REAL ){
|
|
- sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg);
|
|
- }
|
|
return iReg;
|
|
}
|
|
case TK_INTEGER: {
|
|
@@ -102572,7 +110072,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
|
|
** Expr node to be passed into this function, it will be handled
|
|
** sanely and not crash. But keep the assert() to bring the problem
|
|
** to the attention of the developers. */
|
|
- assert( op==TK_NULL );
|
|
+ assert( op==TK_NULL || op==TK_ERROR || pParse->db->mallocFailed );
|
|
sqlite3VdbeAddOp2(v, OP_Null, 0, target);
|
|
return target;
|
|
}
|
|
@@ -102616,6 +110116,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
|
|
sqlite3VdbeAddOp2(v, OP_SCopy, inReg, target);
|
|
inReg = target;
|
|
}
|
|
+ assert( !ExprHasProperty(pExpr, EP_IntValue) );
|
|
sqlite3VdbeAddOp2(v, OP_Cast, target,
|
|
sqlite3AffinityType(pExpr->u.zToken, 0));
|
|
return inReg;
|
|
@@ -102638,8 +110139,9 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
|
|
}else{
|
|
r1 = sqlite3ExprCodeTemp(pParse, pLeft, ®Free1);
|
|
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pRight, ®Free2);
|
|
- codeCompare(pParse, pLeft, pExpr->pRight, op,
|
|
- r1, r2, inReg, SQLITE_STOREP2 | p5,
|
|
+ sqlite3VdbeAddOp2(v, OP_Integer, 1, inReg);
|
|
+ codeCompare(pParse, pLeft, pExpr->pRight, op, r1, r2,
|
|
+ sqlite3VdbeCurrentAddr(v)+2, p5,
|
|
ExprHasProperty(pExpr,EP_Commuted));
|
|
assert(TK_LT==OP_Lt); testcase(op==OP_Lt); VdbeCoverageIf(v,op==OP_Lt);
|
|
assert(TK_LE==OP_Le); testcase(op==OP_Le); VdbeCoverageIf(v,op==OP_Le);
|
|
@@ -102647,6 +110149,11 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
|
|
assert(TK_GE==OP_Ge); testcase(op==OP_Ge); VdbeCoverageIf(v,op==OP_Ge);
|
|
assert(TK_EQ==OP_Eq); testcase(op==OP_Eq); VdbeCoverageIf(v,op==OP_Eq);
|
|
assert(TK_NE==OP_Ne); testcase(op==OP_Ne); VdbeCoverageIf(v,op==OP_Ne);
|
|
+ if( p5==SQLITE_NULLEQ ){
|
|
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, inReg);
|
|
+ }else{
|
|
+ sqlite3VdbeAddOp3(v, OP_ZeroOrNull, r1, inReg, r2);
|
|
+ }
|
|
testcase( regFree1==0 );
|
|
testcase( regFree2==0 );
|
|
}
|
|
@@ -102662,7 +110169,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
|
|
case TK_BITOR:
|
|
case TK_SLASH:
|
|
case TK_LSHIFT:
|
|
- case TK_RSHIFT:
|
|
+ case TK_RSHIFT:
|
|
case TK_CONCAT: {
|
|
assert( TK_AND==OP_And ); testcase( op==TK_AND );
|
|
assert( TK_OR==OP_Or ); testcase( op==TK_OR );
|
|
@@ -102698,6 +110205,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
|
|
tempX.op = TK_INTEGER;
|
|
tempX.flags = EP_IntValue|EP_TokenOnly;
|
|
tempX.u.iValue = 0;
|
|
+ ExprClearVVAProperties(&tempX);
|
|
r1 = sqlite3ExprCodeTemp(pParse, &tempX, ®Free1);
|
|
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free2);
|
|
sqlite3VdbeAddOp3(v, OP_Subtract, r2, r1, target);
|
|
@@ -102743,11 +110251,14 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
|
|
}
|
|
case TK_AGG_FUNCTION: {
|
|
AggInfo *pInfo = pExpr->pAggInfo;
|
|
- if( pInfo==0 ){
|
|
+ if( pInfo==0
|
|
+ || NEVER(pExpr->iAgg<0)
|
|
+ || NEVER(pExpr->iAgg>=pInfo->nFunc)
|
|
+ ){
|
|
assert( !ExprHasProperty(pExpr, EP_IntValue) );
|
|
- sqlite3ErrorMsg(pParse, "misuse of aggregate: %s()", pExpr->u.zToken);
|
|
+ sqlite3ErrorMsg(pParse, "misuse of aggregate: %#T()", pExpr);
|
|
}else{
|
|
- return pInfo->aFunc[pExpr->iAgg].iMem;
|
|
+ return AggInfoFuncReg(pInfo, pExpr->iAgg);
|
|
}
|
|
break;
|
|
}
|
|
@@ -102769,16 +110280,13 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
|
|
#endif
|
|
|
|
if( ConstFactorOk(pParse) && sqlite3ExprIsConstantNotJoin(pExpr) ){
|
|
- /* SQL functions can be expensive. So try to move constant functions
|
|
- ** out of the inner loop, even if that means an extra OP_Copy. */
|
|
- return sqlite3ExprCodeAtInit(pParse, pExpr, -1);
|
|
- }
|
|
- assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
|
|
- if( ExprHasProperty(pExpr, EP_TokenOnly) ){
|
|
- pFarg = 0;
|
|
- }else{
|
|
- pFarg = pExpr->x.pList;
|
|
+ /* SQL functions can be expensive. So try to avoid running them
|
|
+ ** multiple times if we know they always give the same result */
|
|
+ return sqlite3ExprCodeRunJustOnce(pParse, pExpr, -1);
|
|
}
|
|
+ assert( !ExprHasProperty(pExpr, EP_TokenOnly) );
|
|
+ assert( ExprUseXList(pExpr) );
|
|
+ pFarg = pExpr->x.pList;
|
|
nFarg = pFarg ? pFarg->nExpr : 0;
|
|
assert( !ExprHasProperty(pExpr, EP_IntValue) );
|
|
zId = pExpr->u.zToken;
|
|
@@ -102789,7 +110297,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
|
|
}
|
|
#endif
|
|
if( pDef==0 || pDef->xFinalize!=0 ){
|
|
- sqlite3ErrorMsg(pParse, "unknown function: %s()", zId);
|
|
+ sqlite3ErrorMsg(pParse, "unknown function: %#T()", pExpr);
|
|
break;
|
|
}
|
|
if( pDef->funcFlags & SQLITE_FUNC_INLINE ){
|
|
@@ -102832,7 +110340,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
|
|
assert( SQLITE_FUNC_LENGTH==OPFLAG_LENGTHARG );
|
|
assert( SQLITE_FUNC_TYPEOF==OPFLAG_TYPEOFARG );
|
|
testcase( pDef->funcFlags & OPFLAG_LENGTHARG );
|
|
- pFarg->a[0].pExpr->op2 =
|
|
+ pFarg->a[0].pExpr->op2 =
|
|
pDef->funcFlags & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG);
|
|
}
|
|
}
|
|
@@ -102851,7 +110359,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
|
|
** see if it is a column in a virtual table. This is done because
|
|
** the left operand of infix functions (the operand we want to
|
|
** control overloading) ends up as the second argument to the
|
|
- ** function. The expression "A glob B" is equivalent to
|
|
+ ** function. The expression "A glob B" is equivalent to
|
|
** "glob(B,A). We want to use the A in "A glob B" to test
|
|
** for function overloading. But we use the B term in "glob(B,A)".
|
|
*/
|
|
@@ -102862,23 +110370,11 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
|
|
}
|
|
#endif
|
|
if( pDef->funcFlags & SQLITE_FUNC_NEEDCOLL ){
|
|
- if( !pColl ) pColl = db->pDfltColl;
|
|
+ if( !pColl ) pColl = db->pDfltColl;
|
|
sqlite3VdbeAddOp4(v, OP_CollSeq, 0, 0, 0, (char *)pColl, P4_COLLSEQ);
|
|
}
|
|
-#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
|
|
- if( pDef->funcFlags & SQLITE_FUNC_OFFSET ){
|
|
- Expr *pArg = pFarg->a[0].pExpr;
|
|
- if( pArg->op==TK_COLUMN ){
|
|
- sqlite3VdbeAddOp3(v, OP_Offset, pArg->iTable, pArg->iColumn, target);
|
|
- }else{
|
|
- sqlite3VdbeAddOp2(v, OP_Null, 0, target);
|
|
- }
|
|
- }else
|
|
-#endif
|
|
- {
|
|
- sqlite3VdbeAddFunctionCall(pParse, constMask, r1, target, nFarg,
|
|
- pDef, pExpr->op2);
|
|
- }
|
|
+ sqlite3VdbeAddFunctionCall(pParse, constMask, r1, target, nFarg,
|
|
+ pDef, pExpr->op2);
|
|
if( nFarg ){
|
|
if( constMask==0 ){
|
|
sqlite3ReleaseTempRange(pParse, r1, nFarg);
|
|
@@ -102894,7 +110390,12 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
|
|
int nCol;
|
|
testcase( op==TK_EXISTS );
|
|
testcase( op==TK_SELECT );
|
|
- if( op==TK_SELECT && (nCol = pExpr->x.pSelect->pEList->nExpr)!=1 ){
|
|
+ if( pParse->db->mallocFailed ){
|
|
+ return 0;
|
|
+ }else if( op==TK_SELECT
|
|
+ && ALWAYS( ExprUseXSelect(pExpr) )
|
|
+ && (nCol = pExpr->x.pSelect->pEList->nExpr)!=1
|
|
+ ){
|
|
sqlite3SubselectError(pParse, nCol, 1);
|
|
}else{
|
|
return sqlite3CodeSubselect(pParse, pExpr);
|
|
@@ -102903,17 +110404,18 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
|
|
}
|
|
case TK_SELECT_COLUMN: {
|
|
int n;
|
|
- if( pExpr->pLeft->iTable==0 ){
|
|
- pExpr->pLeft->iTable = sqlite3CodeSubselect(pParse, pExpr->pLeft);
|
|
+ Expr *pLeft = pExpr->pLeft;
|
|
+ if( pLeft->iTable==0 || pParse->withinRJSubrtn > pLeft->op2 ){
|
|
+ pLeft->iTable = sqlite3CodeSubselect(pParse, pLeft);
|
|
+ pLeft->op2 = pParse->withinRJSubrtn;
|
|
}
|
|
- assert( pExpr->iTable==0 || pExpr->pLeft->op==TK_SELECT );
|
|
- if( pExpr->iTable!=0
|
|
- && pExpr->iTable!=(n = sqlite3ExprVectorSize(pExpr->pLeft))
|
|
- ){
|
|
+ assert( pLeft->op==TK_SELECT || pLeft->op==TK_ERROR );
|
|
+ n = sqlite3ExprVectorSize(pLeft);
|
|
+ if( pExpr->iTable!=n ){
|
|
sqlite3ErrorMsg(pParse, "%d columns assigned %d values",
|
|
pExpr->iTable, n);
|
|
}
|
|
- return pExpr->pLeft->iTable + pExpr->iColumn;
|
|
+ return pLeft->iTable + pExpr->iColumn;
|
|
}
|
|
case TK_IN: {
|
|
int destIfFalse = sqlite3VdbeMakeLabel(pParse);
|
|
@@ -102944,8 +110446,27 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
|
|
exprCodeBetween(pParse, pExpr, target, 0, 0);
|
|
return target;
|
|
}
|
|
+ case TK_COLLATE: {
|
|
+ if( !ExprHasProperty(pExpr, EP_Collate) ){
|
|
+ /* A TK_COLLATE Expr node without the EP_Collate tag is a so-called
|
|
+ ** "SOFT-COLLATE" that is added to constraints that are pushed down
|
|
+ ** from outer queries into sub-queries by the push-down optimization.
|
|
+ ** 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;
|
|
+ }else{
|
|
+ pExpr = pExpr->pLeft;
|
|
+ goto expr_code_doover; /* 2018-04-28: Prevent deep recursion. */
|
|
+ }
|
|
+ }
|
|
case TK_SPAN:
|
|
- case TK_COLLATE:
|
|
case TK_UPLUS: {
|
|
pExpr = pExpr->pLeft;
|
|
goto expr_code_doover; /* 2018-04-28: Prevent deep recursion. OSSFuzz. */
|
|
@@ -102961,7 +110482,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
|
|
**
|
|
** The expression is implemented using an OP_Param opcode. The p1
|
|
** parameter is set to 0 for an old.rowid reference, or to (i+1)
|
|
- ** to reference another column of the old.* pseudo-table, where
|
|
+ ** to reference another column of the old.* pseudo-table, where
|
|
** i is the index of the column. For a new.rowid reference, p1 is
|
|
** set to (n+1), where n is the number of columns in each pseudo-table.
|
|
** For a reference to any other column in the new.* pseudo-table, p1
|
|
@@ -102975,11 +110496,16 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
|
|
**
|
|
** p1==0 -> old.rowid p1==3 -> new.rowid
|
|
** p1==1 -> old.a p1==4 -> new.a
|
|
- ** p1==2 -> old.b p1==5 -> new.b
|
|
+ ** p1==2 -> old.b p1==5 -> new.b
|
|
*/
|
|
- Table *pTab = pExpr->y.pTab;
|
|
- int iCol = pExpr->iColumn;
|
|
- int p1 = pExpr->iTable * (pTab->nCol+1) + 1
|
|
+ Table *pTab;
|
|
+ int iCol;
|
|
+ int p1;
|
|
+
|
|
+ assert( ExprUseYTab(pExpr) );
|
|
+ pTab = pExpr->y.pTab;
|
|
+ iCol = pExpr->iColumn;
|
|
+ p1 = pExpr->iTable * (pTab->nCol+1) + 1
|
|
+ sqlite3TableColumnToStorage(pTab, iCol);
|
|
|
|
assert( pExpr->iTable==0 || pExpr->iTable==1 );
|
|
@@ -102990,7 +110516,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
|
|
sqlite3VdbeAddOp2(v, OP_Param, p1, target);
|
|
VdbeComment((v, "r[%d]=%s.%s", target,
|
|
(pExpr->iTable ? "new" : "old"),
|
|
- (pExpr->iColumn<0 ? "rowid" : pExpr->y.pTab->aCol[iCol].zName)
|
|
+ (pExpr->iColumn<0 ? "rowid" : pExpr->y.pTab->aCol[iCol].zCnName)
|
|
));
|
|
|
|
#ifndef SQLITE_OMIT_FLOATING_POINT
|
|
@@ -103020,16 +110546,37 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
|
|
case TK_IF_NULL_ROW: {
|
|
int addrINR;
|
|
u8 okConstFactor = pParse->okConstFactor;
|
|
- addrINR = sqlite3VdbeAddOp1(v, OP_IfNullRow, pExpr->iTable);
|
|
- /* Temporarily disable factoring of constant expressions, since
|
|
- ** even though expressions may appear to be constant, they are not
|
|
- ** really constant because they originate from the right-hand side
|
|
- ** of a LEFT JOIN. */
|
|
- pParse->okConstFactor = 0;
|
|
+ AggInfo *pAggInfo = pExpr->pAggInfo;
|
|
+ if( pAggInfo ){
|
|
+ assert( pExpr->iAgg>=0 && pExpr->iAgg<pAggInfo->nColumn );
|
|
+ if( !pAggInfo->directMode ){
|
|
+ inReg = AggInfoColumnReg(pAggInfo, pExpr->iAgg);
|
|
+ break;
|
|
+ }
|
|
+ if( pExpr->pAggInfo->useSortingIdx ){
|
|
+ sqlite3VdbeAddOp3(v, OP_Column, pAggInfo->sortingIdxPTab,
|
|
+ pAggInfo->aCol[pExpr->iAgg].iSorterColumn,
|
|
+ target);
|
|
+ inReg = target;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ addrINR = sqlite3VdbeAddOp3(v, OP_IfNullRow, pExpr->iTable, 0, target);
|
|
+ /* The OP_IfNullRow opcode above can overwrite the result register with
|
|
+ ** NULL. So we have to ensure that the result register is not a value
|
|
+ ** that is suppose to be a constant. Two defenses are needed:
|
|
+ ** (1) Temporarily disable factoring of constant expressions
|
|
+ ** (2) Make sure the computed value really is stored in register
|
|
+ ** "target" and not someplace else.
|
|
+ */
|
|
+ pParse->okConstFactor = 0; /* note (1) above */
|
|
inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
|
|
pParse->okConstFactor = okConstFactor;
|
|
+ if( inReg!=target ){ /* note (2) above */
|
|
+ sqlite3VdbeAddOp2(v, OP_SCopy, inReg, target);
|
|
+ inReg = target;
|
|
+ }
|
|
sqlite3VdbeJumpHere(v, addrINR);
|
|
- sqlite3VdbeChangeP3(v, addrINR, inReg);
|
|
break;
|
|
}
|
|
|
|
@@ -103067,7 +110614,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
|
|
Expr *pDel = 0;
|
|
sqlite3 *db = pParse->db;
|
|
|
|
- assert( !ExprHasProperty(pExpr, EP_xIsSelect) && pExpr->x.pList );
|
|
+ assert( ExprUseXList(pExpr) && pExpr->x.pList!=0 );
|
|
assert(pExpr->x.pList->nExpr > 0);
|
|
pEList = pExpr->x.pList;
|
|
aListelem = pEList->a;
|
|
@@ -103113,17 +110660,18 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
|
|
sqlite3VdbeAddOp2(v, OP_Null, 0, target);
|
|
}
|
|
sqlite3ExprDelete(db, pDel);
|
|
+ setDoNotMergeFlagOnCopy(v);
|
|
sqlite3VdbeResolveLabel(v, endLabel);
|
|
break;
|
|
}
|
|
#ifndef SQLITE_OMIT_TRIGGER
|
|
case TK_RAISE: {
|
|
- assert( pExpr->affExpr==OE_Rollback
|
|
+ assert( pExpr->affExpr==OE_Rollback
|
|
|| pExpr->affExpr==OE_Abort
|
|
|| pExpr->affExpr==OE_Fail
|
|
|| pExpr->affExpr==OE_Ignore
|
|
);
|
|
- if( !pParse->pTriggerTab ){
|
|
+ if( !pParse->pTriggerTab && !pParse->nested ){
|
|
sqlite3ErrorMsg(pParse,
|
|
"RAISE() may only be used within a trigger-program");
|
|
return 0;
|
|
@@ -103137,8 +110685,9 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
|
|
v, OP_Halt, SQLITE_OK, OE_Ignore, 0, pExpr->u.zToken,0);
|
|
VdbeCoverage(v);
|
|
}else{
|
|
- sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_TRIGGER,
|
|
- pExpr->affExpr, pExpr->u.zToken, 0, 0);
|
|
+ sqlite3HaltConstraint(pParse,
|
|
+ pParse->pTriggerTab ? SQLITE_CONSTRAINT_TRIGGER : SQLITE_ERROR,
|
|
+ pExpr->affExpr, pExpr->u.zToken, 0, 0);
|
|
}
|
|
|
|
break;
|
|
@@ -103151,15 +110700,23 @@ SQLITE_PRIVATE int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target)
|
|
}
|
|
|
|
/*
|
|
-** Factor out the code of the given expression to initialization time.
|
|
+** Generate code that will evaluate expression pExpr just one time
|
|
+** per prepared statement execution.
|
|
+**
|
|
+** If the expression uses functions (that might throw an exception) then
|
|
+** guard them with an OP_Once opcode to ensure that the code is only executed
|
|
+** 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
|
|
-** result is not reusable. If regDest<0 then this routine is free to
|
|
-** store the value whereever it wants. The register where the expression
|
|
-** is stored is returned. When regDest<0, two identical expressions will
|
|
-** code to the same register.
|
|
-*/
|
|
-SQLITE_PRIVATE int sqlite3ExprCodeAtInit(
|
|
+** result is not reusable. If regDest<0 then this routine is free to
|
|
+** store the value whereever it wants. The register where the expression
|
|
+** is stored is returned. When regDest<0, two identical expressions might
|
|
+** code to the same register, if they do not contain function calls and hence
|
|
+** are factored out into the initialization section at the end of the
|
|
+** prepared statement.
|
|
+*/
|
|
+SQLITE_PRIVATE int sqlite3ExprCodeRunJustOnce(
|
|
Parse *pParse, /* Parsing context */
|
|
Expr *pExpr, /* The expression to code when the VDBE initializes */
|
|
int regDest /* Store the value in this register */
|
|
@@ -103171,20 +110728,37 @@ SQLITE_PRIVATE int sqlite3ExprCodeAtInit(
|
|
struct ExprList_item *pItem;
|
|
int i;
|
|
for(pItem=p->a, i=p->nExpr; i>0; pItem++, i--){
|
|
- if( pItem->reusable && sqlite3ExprCompare(0,pItem->pExpr,pExpr,-1)==0 ){
|
|
+ if( pItem->fg.reusable
|
|
+ && sqlite3ExprCompare(0,pItem->pExpr,pExpr,-1)==0
|
|
+ ){
|
|
return pItem->u.iConstExprReg;
|
|
}
|
|
}
|
|
}
|
|
pExpr = sqlite3ExprDup(pParse->db, pExpr, 0);
|
|
- p = sqlite3ExprListAppend(pParse, p, pExpr);
|
|
- if( p ){
|
|
- struct ExprList_item *pItem = &p->a[p->nExpr-1];
|
|
- pItem->reusable = regDest<0;
|
|
- if( regDest<0 ) regDest = ++pParse->nMem;
|
|
- pItem->u.iConstExprReg = regDest;
|
|
+ if( pExpr!=0 && ExprHasProperty(pExpr, EP_HasFunc) ){
|
|
+ Vdbe *v = pParse->pVdbe;
|
|
+ int addr;
|
|
+ assert( v );
|
|
+ addr = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
|
|
+ pParse->okConstFactor = 0;
|
|
+ if( !pParse->db->mallocFailed ){
|
|
+ if( regDest<0 ) regDest = ++pParse->nMem;
|
|
+ sqlite3ExprCode(pParse, pExpr, regDest);
|
|
+ }
|
|
+ pParse->okConstFactor = 1;
|
|
+ sqlite3ExprDelete(pParse->db, pExpr);
|
|
+ sqlite3VdbeJumpHere(v, addr);
|
|
+ }else{
|
|
+ p = sqlite3ExprListAppend(pParse, p, pExpr);
|
|
+ if( p ){
|
|
+ struct ExprList_item *pItem = &p->a[p->nExpr-1];
|
|
+ pItem->fg.reusable = regDest<0;
|
|
+ if( regDest<0 ) regDest = ++pParse->nMem;
|
|
+ pItem->u.iConstExprReg = regDest;
|
|
+ }
|
|
+ pParse->pConstExpr = p;
|
|
}
|
|
- pParse->pConstExpr = p;
|
|
return regDest;
|
|
}
|
|
|
|
@@ -103205,11 +110779,12 @@ SQLITE_PRIVATE int sqlite3ExprCodeTemp(Parse *pParse, Expr *pExpr, int *pReg){
|
|
int r2;
|
|
pExpr = sqlite3ExprSkipCollateAndLikely(pExpr);
|
|
if( ConstFactorOk(pParse)
|
|
+ && ALWAYS(pExpr!=0)
|
|
&& pExpr->op!=TK_REGISTER
|
|
&& sqlite3ExprIsConstantNotJoin(pExpr)
|
|
){
|
|
*pReg = 0;
|
|
- r2 = sqlite3ExprCodeAtInit(pParse, pExpr, -1);
|
|
+ r2 = sqlite3ExprCodeRunJustOnce(pParse, pExpr, -1);
|
|
}else{
|
|
int r1 = sqlite3GetTempReg(pParse);
|
|
r2 = sqlite3ExprCodeTarget(pParse, pExpr, r1);
|
|
@@ -103231,12 +110806,14 @@ SQLITE_PRIVATE int sqlite3ExprCodeTemp(Parse *pParse, Expr *pExpr, int *pReg){
|
|
SQLITE_PRIVATE void sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
|
|
int inReg;
|
|
|
|
+ assert( pExpr==0 || !ExprHasVVAProperty(pExpr,EP_Immutable) );
|
|
assert( target>0 && target<=pParse->nMem );
|
|
- inReg = sqlite3ExprCodeTarget(pParse, pExpr, target);
|
|
assert( pParse->pVdbe!=0 || pParse->db->mallocFailed );
|
|
- if( inReg!=target && pParse->pVdbe ){
|
|
+ if( pParse->pVdbe==0 ) return;
|
|
+ inReg = sqlite3ExprCodeTarget(pParse, pExpr, target);
|
|
+ if( inReg!=target ){
|
|
u8 op;
|
|
- if( ExprHasProperty(pExpr,EP_Subquery) ){
|
|
+ if( ALWAYS(pExpr) && ExprHasProperty(pExpr,EP_Subquery) ){
|
|
op = OP_Copy;
|
|
}else{
|
|
op = OP_SCopy;
|
|
@@ -103265,9 +110842,9 @@ SQLITE_PRIVATE void sqlite3ExprCodeCopy(Parse *pParse, Expr *pExpr, int target){
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3ExprCodeFactorable(Parse *pParse, Expr *pExpr, int target){
|
|
if( pParse->okConstFactor && sqlite3ExprIsConstantNotJoin(pExpr) ){
|
|
- sqlite3ExprCodeAtInit(pParse, pExpr, target);
|
|
+ sqlite3ExprCodeRunJustOnce(pParse, pExpr, target);
|
|
}else{
|
|
- sqlite3ExprCode(pParse, pExpr, target);
|
|
+ sqlite3ExprCodeCopy(pParse, pExpr, target);
|
|
}
|
|
}
|
|
|
|
@@ -103310,7 +110887,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeExprList(
|
|
for(pItem=pList->a, i=0; i<n; i++, pItem++){
|
|
Expr *pExpr = pItem->pExpr;
|
|
#ifdef SQLITE_ENABLE_SORTER_REFERENCES
|
|
- if( pItem->bSorterRef ){
|
|
+ if( pItem->fg.bSorterRef ){
|
|
i--;
|
|
n--;
|
|
}else
|
|
@@ -103325,13 +110902,13 @@ SQLITE_PRIVATE int sqlite3ExprCodeExprList(
|
|
}else if( (flags & SQLITE_ECEL_FACTOR)!=0
|
|
&& sqlite3ExprIsConstantNotJoin(pExpr)
|
|
){
|
|
- sqlite3ExprCodeAtInit(pParse, pExpr, target+i);
|
|
+ sqlite3ExprCodeRunJustOnce(pParse, pExpr, target+i);
|
|
}else{
|
|
int inReg = sqlite3ExprCodeTarget(pParse, pExpr, target+i);
|
|
if( inReg!=target+i ){
|
|
VdbeOp *pOp;
|
|
if( copyOp==OP_Copy
|
|
- && (pOp=sqlite3VdbeGetOp(v, -1))->opcode==OP_Copy
|
|
+ && (pOp=sqlite3VdbeGetLastOp(v))->opcode==OP_Copy
|
|
&& pOp->p1+pOp->p3+1==inReg
|
|
&& pOp->p2+pOp->p3+1==target+i
|
|
&& pOp->p5==0 /* The do-not-merge flag must be clear */
|
|
@@ -103351,7 +110928,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeExprList(
|
|
**
|
|
** x BETWEEN y AND z
|
|
**
|
|
-** The above is equivalent to
|
|
+** The above is equivalent to
|
|
**
|
|
** x>=y AND x<=z
|
|
**
|
|
@@ -103384,7 +110961,7 @@ static void exprCodeBetween(
|
|
memset(&compRight, 0, sizeof(Expr));
|
|
memset(&exprAnd, 0, sizeof(Expr));
|
|
|
|
- assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
|
|
+ assert( ExprUseXList(pExpr) );
|
|
pDel = sqlite3ExprDup(db, pExpr->pLeft, 0);
|
|
if( db->mallocFailed==0 ){
|
|
exprAnd.op = TK_AND;
|
|
@@ -103404,8 +110981,8 @@ static void exprCodeBetween(
|
|
** so that the sqlite3ExprCodeTarget() routine will not attempt to move
|
|
** it into the Parse.pConstExpr list. We should use a new bit for this,
|
|
** for clarity, but we are out of bits in the Expr.flags field so we
|
|
- ** have to reuse the EP_FromJoin bit. Bummer. */
|
|
- pDel->flags |= EP_FromJoin;
|
|
+ ** have to reuse the EP_OuterON bit. Bummer. */
|
|
+ pDel->flags |= EP_OuterON;
|
|
sqlite3ExprCodeTarget(pParse, &exprAnd, dest);
|
|
}
|
|
sqlite3ReleaseTempReg(pParse, regFree1);
|
|
@@ -103448,6 +111025,7 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int
|
|
assert( jumpIfNull==SQLITE_JUMPIFNULL || jumpIfNull==0 );
|
|
if( NEVER(v==0) ) return; /* Existence of VDBE checked by caller */
|
|
if( NEVER(pExpr==0) ) return; /* No way this can happen */
|
|
+ assert( !ExprHasVVAProperty(pExpr, EP_Immutable) );
|
|
op = pExpr->op;
|
|
switch( op ){
|
|
case TK_AND:
|
|
@@ -103497,7 +111075,7 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int
|
|
testcase( op==TK_ISNOT );
|
|
op = (op==TK_IS) ? TK_EQ : TK_NE;
|
|
jumpIfNull = SQLITE_NULLEQ;
|
|
- /* Fall thru */
|
|
+ /* no break */ deliberate_fall_through
|
|
case TK_LT:
|
|
case TK_LE:
|
|
case TK_GT:
|
|
@@ -103529,6 +111107,7 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int
|
|
assert( TK_ISNULL==OP_IsNull ); testcase( op==TK_ISNULL );
|
|
assert( TK_NOTNULL==OP_NotNull ); testcase( op==TK_NOTNULL );
|
|
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1);
|
|
+ sqlite3VdbeTypeofColumn(v, r1);
|
|
sqlite3VdbeAddOp2(v, op, r1, dest);
|
|
VdbeCoverageIf(v, op==TK_ISNULL);
|
|
VdbeCoverageIf(v, op==TK_NOTNULL);
|
|
@@ -103567,7 +111146,7 @@ SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int
|
|
}
|
|
}
|
|
sqlite3ReleaseTempReg(pParse, regFree1);
|
|
- sqlite3ReleaseTempReg(pParse, regFree2);
|
|
+ sqlite3ReleaseTempReg(pParse, regFree2);
|
|
}
|
|
|
|
/*
|
|
@@ -103589,6 +111168,7 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int
|
|
assert( jumpIfNull==SQLITE_JUMPIFNULL || jumpIfNull==0 );
|
|
if( NEVER(v==0) ) return; /* Existence of VDBE checked by caller */
|
|
if( pExpr==0 ) return;
|
|
+ assert( !ExprHasVVAProperty(pExpr,EP_Immutable) );
|
|
|
|
/* The value of pExpr->op and op are related as follows:
|
|
**
|
|
@@ -103672,7 +111252,7 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int
|
|
testcase( pExpr->op==TK_ISNOT );
|
|
op = (pExpr->op==TK_IS) ? TK_NE : TK_EQ;
|
|
jumpIfNull = SQLITE_NULLEQ;
|
|
- /* Fall thru */
|
|
+ /* no break */ deliberate_fall_through
|
|
case TK_LT:
|
|
case TK_LE:
|
|
case TK_GT:
|
|
@@ -103702,6 +111282,7 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int
|
|
case TK_ISNULL:
|
|
case TK_NOTNULL: {
|
|
r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free1);
|
|
+ sqlite3VdbeTypeofColumn(v, r1);
|
|
sqlite3VdbeAddOp2(v, op, r1, dest);
|
|
testcase( op==TK_ISNULL ); VdbeCoverageIf(v, op==TK_ISNULL);
|
|
testcase( op==TK_NOTNULL ); VdbeCoverageIf(v, op==TK_NOTNULL);
|
|
@@ -103726,7 +111307,7 @@ SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int
|
|
}
|
|
#endif
|
|
default: {
|
|
- default_expr:
|
|
+ default_expr:
|
|
if( ExprAlwaysFalse(pExpr) ){
|
|
sqlite3VdbeGoto(v, dest);
|
|
}else if( ExprAlwaysTrue(pExpr) ){
|
|
@@ -103772,11 +111353,15 @@ SQLITE_PRIVATE void sqlite3ExprIfFalseDup(Parse *pParse, Expr *pExpr, int dest,i
|
|
** Otherwise, if the values are not the same or if pExpr is not a simple
|
|
** SQL value, zero is returned.
|
|
*/
|
|
-static int exprCompareVariable(Parse *pParse, Expr *pVar, Expr *pExpr){
|
|
+static int exprCompareVariable(
|
|
+ const Parse *pParse,
|
|
+ const Expr *pVar,
|
|
+ const Expr *pExpr
|
|
+){
|
|
int res = 0;
|
|
int iVar;
|
|
sqlite3_value *pL, *pR = 0;
|
|
-
|
|
+
|
|
sqlite3ValueFromExpr(pParse->db, pExpr, SQLITE_UTF8, SQLITE_AFF_BLOB, &pR);
|
|
if( pR ){
|
|
iVar = pVar->iColumn;
|
|
@@ -103818,13 +111403,18 @@ static int exprCompareVariable(Parse *pParse, Expr *pVar, Expr *pExpr){
|
|
** an incorrect 0 or 1 could lead to a malfunction.
|
|
**
|
|
** If pParse is not NULL then TK_VARIABLE terms in pA with bindings in
|
|
-** pParse->pReprepare can be matched against literals in pB. The
|
|
+** pParse->pReprepare can be matched against literals in pB. The
|
|
** pParse->pVdbe->expmask bitmask is updated for each variable referenced.
|
|
-** If pParse is NULL (the normal case) then any TK_VARIABLE term in
|
|
+** If pParse is NULL (the normal case) then any TK_VARIABLE term in
|
|
** Argument pParse should normally be NULL. If it is not NULL and pA or
|
|
** pB causes a return value of 2.
|
|
*/
|
|
-SQLITE_PRIVATE int sqlite3ExprCompare(Parse *pParse, Expr *pA, Expr *pB, int iTab){
|
|
+SQLITE_PRIVATE int sqlite3ExprCompare(
|
|
+ const Parse *pParse,
|
|
+ const Expr *pA,
|
|
+ const Expr *pB,
|
|
+ int iTab
|
|
+){
|
|
u32 combinedFlags;
|
|
if( pA==0 || pB==0 ){
|
|
return pB==pA ? 0 : 2;
|
|
@@ -103846,9 +111436,17 @@ SQLITE_PRIVATE int sqlite3ExprCompare(Parse *pParse, Expr *pA, Expr *pB, int iTa
|
|
if( pB->op==TK_COLLATE && sqlite3ExprCompare(pParse, pA,pB->pLeft,iTab)<2 ){
|
|
return 1;
|
|
}
|
|
- return 2;
|
|
+ if( pA->op==TK_AGG_COLUMN && pB->op==TK_COLUMN
|
|
+ && pB->iTable<0 && pA->iTable==iTab
|
|
+ ){
|
|
+ /* fall through */
|
|
+ }else{
|
|
+ return 2;
|
|
+ }
|
|
}
|
|
- if( pA->op!=TK_COLUMN && pA->op!=TK_AGG_COLUMN && pA->u.zToken ){
|
|
+ assert( !ExprHasProperty(pA, EP_IntValue) );
|
|
+ assert( !ExprHasProperty(pB, EP_IntValue) );
|
|
+ if( pA->u.zToken ){
|
|
if( pA->op==TK_FUNCTION || pA->op==TK_AGG_FUNCTION ){
|
|
if( sqlite3StrICmp(pA->u.zToken,pB->u.zToken)!=0 ) return 2;
|
|
#ifndef SQLITE_OMIT_WINDOWFUNC
|
|
@@ -103866,13 +111464,18 @@ SQLITE_PRIVATE int sqlite3ExprCompare(Parse *pParse, Expr *pA, Expr *pB, int iTa
|
|
return 0;
|
|
}else if( pA->op==TK_COLLATE ){
|
|
if( sqlite3_stricmp(pA->u.zToken,pB->u.zToken)!=0 ) return 2;
|
|
- }else if( ALWAYS(pB->u.zToken!=0) && strcmp(pA->u.zToken,pB->u.zToken)!=0 ){
|
|
+ }else
|
|
+ if( pB->u.zToken!=0
|
|
+ && pA->op!=TK_COLUMN
|
|
+ && pA->op!=TK_AGG_COLUMN
|
|
+ && strcmp(pA->u.zToken,pB->u.zToken)!=0
|
|
+ ){
|
|
return 2;
|
|
}
|
|
}
|
|
if( (pA->flags & (EP_Distinct|EP_Commuted))
|
|
!= (pB->flags & (EP_Distinct|EP_Commuted)) ) return 2;
|
|
- if( (combinedFlags & EP_TokenOnly)==0 ){
|
|
+ if( ALWAYS((combinedFlags & EP_TokenOnly)==0) ){
|
|
if( combinedFlags & EP_xIsSelect ) return 2;
|
|
if( (combinedFlags & EP_FixedCol)==0
|
|
&& sqlite3ExprCompare(pParse, pA->pLeft, pB->pLeft, iTab) ) return 2;
|
|
@@ -103880,24 +111483,10 @@ SQLITE_PRIVATE int sqlite3ExprCompare(Parse *pParse, Expr *pA, Expr *pB, int iTa
|
|
if( sqlite3ExprListCompare(pA->x.pList, pB->x.pList, iTab) ) return 2;
|
|
if( pA->op!=TK_STRING
|
|
&& pA->op!=TK_TRUEFALSE
|
|
- && (combinedFlags & EP_Reduced)==0
|
|
+ && ALWAYS((combinedFlags & EP_Reduced)==0)
|
|
){
|
|
if( pA->iColumn!=pB->iColumn ) return 2;
|
|
- if( pA->op2!=pB->op2 ){
|
|
- if( pA->op==TK_TRUTH ) return 2;
|
|
- if( pA->op==TK_FUNCTION && iTab<0 ){
|
|
- /* Ex: CREATE TABLE t1(a CHECK( a<julianday('now') ));
|
|
- ** INSERT INTO t1(a) VALUES(julianday('now')+10);
|
|
- ** Without this test, sqlite3ExprCodeAtInit() will run on the
|
|
- ** the julianday() of INSERT first, and remember that expression.
|
|
- ** Then sqlite3ExprCodeInit() will see the julianday() in the CHECK
|
|
- ** constraint as redundant, reusing the one from the INSERT, even
|
|
- ** though the julianday() in INSERT lacks the critical NC_IsCheck
|
|
- ** flag. See ticket [830277d9db6c3ba1] (2019-10-30)
|
|
- */
|
|
- return 2;
|
|
- }
|
|
- }
|
|
+ if( pA->op2!=pB->op2 && pA->op==TK_TRUTH ) return 2;
|
|
if( pA->op!=TK_IN && pA->iTable!=pB->iTable && pA->iTable!=iTab ){
|
|
return 2;
|
|
}
|
|
@@ -103908,7 +111497,7 @@ SQLITE_PRIVATE int sqlite3ExprCompare(Parse *pParse, Expr *pA, Expr *pB, int iTa
|
|
|
|
/*
|
|
** Compare two ExprList objects. Return 0 if they are identical, 1
|
|
-** if they are certainly different, or 2 if it is not possible to
|
|
+** if they are certainly different, or 2 if it is not possible to
|
|
** determine if they are identical or not.
|
|
**
|
|
** If any subelement of pB has Expr.iTable==(-1) then it is allowed
|
|
@@ -103922,7 +111511,7 @@ SQLITE_PRIVATE int sqlite3ExprCompare(Parse *pParse, Expr *pA, Expr *pB, int iTa
|
|
** Two NULL pointers are considered to be the same. But a NULL pointer
|
|
** always differs from a non-NULL pointer.
|
|
*/
|
|
-SQLITE_PRIVATE int sqlite3ExprListCompare(ExprList *pA, ExprList *pB, int iTab){
|
|
+SQLITE_PRIVATE int sqlite3ExprListCompare(const ExprList *pA, const ExprList *pB, int iTab){
|
|
int i;
|
|
if( pA==0 && pB==0 ) return 0;
|
|
if( pA==0 || pB==0 ) return 1;
|
|
@@ -103931,7 +111520,7 @@ SQLITE_PRIVATE int sqlite3ExprListCompare(ExprList *pA, ExprList *pB, int iTab){
|
|
int res;
|
|
Expr *pExprA = pA->a[i].pExpr;
|
|
Expr *pExprB = pB->a[i].pExpr;
|
|
- if( pA->a[i].sortFlags!=pB->a[i].sortFlags ) return 1;
|
|
+ if( pA->a[i].fg.sortFlags!=pB->a[i].fg.sortFlags ) return 1;
|
|
if( (res = sqlite3ExprCompare(0, pExprA, pExprB, iTab)) ) return res;
|
|
}
|
|
return 0;
|
|
@@ -103941,7 +111530,7 @@ SQLITE_PRIVATE int sqlite3ExprListCompare(ExprList *pA, ExprList *pB, int iTab){
|
|
** Like sqlite3ExprCompare() except COLLATE operators at the top-level
|
|
** are ignored.
|
|
*/
|
|
-SQLITE_PRIVATE int sqlite3ExprCompareSkip(Expr *pA, Expr *pB, int iTab){
|
|
+SQLITE_PRIVATE int sqlite3ExprCompareSkip(Expr *pA,Expr *pB, int iTab){
|
|
return sqlite3ExprCompare(0,
|
|
sqlite3ExprSkipCollateAndLikely(pA),
|
|
sqlite3ExprSkipCollateAndLikely(pB),
|
|
@@ -103955,9 +111544,9 @@ SQLITE_PRIVATE int sqlite3ExprCompareSkip(Expr *pA, Expr *pB, int iTab){
|
|
** non-NULL if pNN is not NULL
|
|
*/
|
|
static int exprImpliesNotNull(
|
|
- Parse *pParse, /* Parsing context */
|
|
- Expr *p, /* The expression to be checked */
|
|
- Expr *pNN, /* The expression that is NOT NULL */
|
|
+ const Parse *pParse,/* Parsing context */
|
|
+ const Expr *p, /* The expression to be checked */
|
|
+ const Expr *pNN, /* The expression that is NOT NULL */
|
|
int iTab, /* Table being evaluated */
|
|
int seenNot /* Return true only if p can be any non-NULL value */
|
|
){
|
|
@@ -103969,12 +111558,13 @@ static int exprImpliesNotNull(
|
|
switch( p->op ){
|
|
case TK_IN: {
|
|
if( seenNot && ExprHasProperty(p, EP_xIsSelect) ) return 0;
|
|
- assert( ExprHasProperty(p,EP_xIsSelect)
|
|
- || (p->x.pList!=0 && p->x.pList->nExpr>0) );
|
|
+ assert( ExprUseXSelect(p) || (p->x.pList!=0 && p->x.pList->nExpr>0) );
|
|
return exprImpliesNotNull(pParse, p->pLeft, pNN, iTab, 1);
|
|
}
|
|
case TK_BETWEEN: {
|
|
- ExprList *pList = p->x.pList;
|
|
+ ExprList *pList;
|
|
+ assert( ExprUseXList(p) );
|
|
+ pList = p->x.pList;
|
|
assert( pList!=0 );
|
|
assert( pList->nExpr==2 );
|
|
if( seenNot ) return 0;
|
|
@@ -103995,16 +111585,16 @@ static int exprImpliesNotNull(
|
|
case TK_MINUS:
|
|
case TK_BITOR:
|
|
case TK_LSHIFT:
|
|
- case TK_RSHIFT:
|
|
- case TK_CONCAT:
|
|
+ case TK_RSHIFT:
|
|
+ case TK_CONCAT:
|
|
seenNot = 1;
|
|
- /* Fall thru */
|
|
+ /* no break */ deliberate_fall_through
|
|
case TK_STAR:
|
|
case TK_REM:
|
|
case TK_BITAND:
|
|
case TK_SLASH: {
|
|
if( exprImpliesNotNull(pParse, p->pRight, pNN, iTab, seenNot) ) return 1;
|
|
- /* Fall thru into the next case */
|
|
+ /* no break */ deliberate_fall_through
|
|
}
|
|
case TK_SPAN:
|
|
case TK_COLLATE:
|
|
@@ -104041,16 +111631,21 @@ static int exprImpliesNotNull(
|
|
** When comparing TK_COLUMN nodes between pE1 and pE2, if pE2 has
|
|
** Expr.iTable<0 then assume a table number given by iTab.
|
|
**
|
|
-** If pParse is not NULL, then the values of bound variables in pE1 are
|
|
+** If pParse is not NULL, then the values of bound variables in pE1 are
|
|
** compared against literal values in pE2 and pParse->pVdbe->expmask is
|
|
-** modified to record which bound variables are referenced. If pParse
|
|
+** modified to record which bound variables are referenced. If pParse
|
|
** is NULL, then false will be returned if pE1 contains any bound variables.
|
|
**
|
|
** When in doubt, return false. Returning true might give a performance
|
|
** improvement. Returning false might cause a performance reduction, but
|
|
** it will always give the correct answer and is hence always safe.
|
|
*/
|
|
-SQLITE_PRIVATE int sqlite3ExprImpliesExpr(Parse *pParse, Expr *pE1, Expr *pE2, int iTab){
|
|
+SQLITE_PRIVATE int sqlite3ExprImpliesExpr(
|
|
+ const Parse *pParse,
|
|
+ const Expr *pE1,
|
|
+ const Expr *pE2,
|
|
+ int iTab
|
|
+){
|
|
if( sqlite3ExprCompare(pParse, pE1, pE2, iTab)==0 ){
|
|
return 1;
|
|
}
|
|
@@ -104080,7 +111675,7 @@ SQLITE_PRIVATE int sqlite3ExprImpliesExpr(Parse *pParse, Expr *pE1, Expr *pE2, i
|
|
static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
|
|
testcase( pExpr->op==TK_AGG_COLUMN );
|
|
testcase( pExpr->op==TK_AGG_FUNCTION );
|
|
- if( ExprHasProperty(pExpr, EP_FromJoin) ) return WRC_Prune;
|
|
+ if( ExprHasProperty(pExpr, EP_OuterON) ) return WRC_Prune;
|
|
switch( pExpr->op ){
|
|
case TK_ISNOT:
|
|
case TK_ISNULL:
|
|
@@ -104135,19 +111730,30 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
|
|
case TK_LT:
|
|
case TK_LE:
|
|
case TK_GT:
|
|
- case TK_GE:
|
|
+ case TK_GE: {
|
|
+ Expr *pLeft = pExpr->pLeft;
|
|
+ Expr *pRight = pExpr->pRight;
|
|
testcase( pExpr->op==TK_EQ );
|
|
testcase( pExpr->op==TK_NE );
|
|
testcase( pExpr->op==TK_LT );
|
|
testcase( pExpr->op==TK_LE );
|
|
testcase( pExpr->op==TK_GT );
|
|
testcase( pExpr->op==TK_GE );
|
|
- if( (pExpr->pLeft->op==TK_COLUMN && IsVirtual(pExpr->pLeft->y.pTab))
|
|
- || (pExpr->pRight->op==TK_COLUMN && IsVirtual(pExpr->pRight->y.pTab))
|
|
+ /* The y.pTab=0 assignment in wherecode.c always happens after the
|
|
+ ** impliesNotNullRow() test */
|
|
+ assert( pLeft->op!=TK_COLUMN || ExprUseYTab(pLeft) );
|
|
+ assert( pRight->op!=TK_COLUMN || ExprUseYTab(pRight) );
|
|
+ if( (pLeft->op==TK_COLUMN
|
|
+ && ALWAYS(pLeft->y.pTab!=0)
|
|
+ && IsVirtual(pLeft->y.pTab))
|
|
+ || (pRight->op==TK_COLUMN
|
|
+ && ALWAYS(pRight->y.pTab!=0)
|
|
+ && IsVirtual(pRight->y.pTab))
|
|
){
|
|
- return WRC_Prune;
|
|
+ return WRC_Prune;
|
|
}
|
|
-
|
|
+ /* no break */ deliberate_fall_through
|
|
+ }
|
|
default:
|
|
return WRC_Continue;
|
|
}
|
|
@@ -104166,8 +111772,8 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
|
|
** False positives are not allowed, however. A false positive may result
|
|
** in an incorrect answer.
|
|
**
|
|
-** Terms of p that are marked with EP_FromJoin (and hence that come from
|
|
-** the ON or USING clauses of LEFT JOINS) are excluded from the analysis.
|
|
+** Terms of p that are marked with EP_OuterON (and hence that come from
|
|
+** the ON or USING clauses of OUTER JOINS) are excluded from the analysis.
|
|
**
|
|
** This routine is used to check if a LEFT JOIN can be converted into
|
|
** an ordinary JOIN. The p argument is the WHERE clause. If the WHERE
|
|
@@ -104209,7 +111815,7 @@ struct IdxCover {
|
|
};
|
|
|
|
/*
|
|
-** Check to see if there are references to columns in table
|
|
+** Check to see if there are references to columns in table
|
|
** pWalker->u.pIdxCover->iCur can be satisfied using the index
|
|
** pWalker->u.pIdxCover->pIdx.
|
|
*/
|
|
@@ -104251,72 +111857,180 @@ SQLITE_PRIVATE int sqlite3ExprCoveredByIndex(
|
|
}
|
|
|
|
|
|
-/*
|
|
-** An instance of the following structure is used by the tree walker
|
|
-** to count references to table columns in the arguments of an
|
|
-** aggregate function, in order to implement the
|
|
-** sqlite3FunctionThisSrc() routine.
|
|
-*/
|
|
-struct SrcCount {
|
|
- SrcList *pSrc; /* One particular FROM clause in a nested query */
|
|
- int nThis; /* Number of references to columns in pSrcList */
|
|
- int nOther; /* Number of references to columns in other FROM clauses */
|
|
+/* Structure used to pass information throught the Walker in order to
|
|
+** implement sqlite3ReferencesSrcList().
|
|
+*/
|
|
+struct RefSrcList {
|
|
+ sqlite3 *db; /* Database connection used for sqlite3DbRealloc() */
|
|
+ SrcList *pRef; /* Looking for references to these tables */
|
|
+ i64 nExclude; /* Number of tables to exclude from the search */
|
|
+ int *aiExclude; /* Cursor IDs for tables to exclude from the search */
|
|
};
|
|
|
|
/*
|
|
-** Count the number of references to columns.
|
|
+** Walker SELECT callbacks for sqlite3ReferencesSrcList().
|
|
+**
|
|
+** When entering a new subquery on the pExpr argument, add all FROM clause
|
|
+** entries for that subquery to the exclude list.
|
|
+**
|
|
+** When leaving the subquery, remove those entries from the exclude list.
|
|
*/
|
|
-static int exprSrcCount(Walker *pWalker, Expr *pExpr){
|
|
- /* There was once a NEVER() on the second term on the grounds that
|
|
- ** sqlite3FunctionUsesThisSrc() was always called before
|
|
- ** sqlite3ExprAnalyzeAggregates() and so the TK_COLUMNs have not yet
|
|
- ** been converted into TK_AGG_COLUMN. But this is no longer true due
|
|
- ** to window functions - sqlite3WindowRewrite() may now indirectly call
|
|
- ** FunctionUsesThisSrc() when creating a new sub-select. */
|
|
- if( pExpr->op==TK_COLUMN || pExpr->op==TK_AGG_COLUMN ){
|
|
+static int selectRefEnter(Walker *pWalker, Select *pSelect){
|
|
+ struct RefSrcList *p = pWalker->u.pRefSrcList;
|
|
+ SrcList *pSrc = pSelect->pSrc;
|
|
+ i64 i, j;
|
|
+ int *piNew;
|
|
+ if( pSrc->nSrc==0 ) return WRC_Continue;
|
|
+ j = p->nExclude;
|
|
+ p->nExclude += pSrc->nSrc;
|
|
+ piNew = sqlite3DbRealloc(p->db, p->aiExclude, p->nExclude*sizeof(int));
|
|
+ if( piNew==0 ){
|
|
+ p->nExclude = 0;
|
|
+ return WRC_Abort;
|
|
+ }else{
|
|
+ p->aiExclude = piNew;
|
|
+ }
|
|
+ for(i=0; i<pSrc->nSrc; i++, j++){
|
|
+ p->aiExclude[j] = pSrc->a[i].iCursor;
|
|
+ }
|
|
+ return WRC_Continue;
|
|
+}
|
|
+static void selectRefLeave(Walker *pWalker, Select *pSelect){
|
|
+ struct RefSrcList *p = pWalker->u.pRefSrcList;
|
|
+ SrcList *pSrc = pSelect->pSrc;
|
|
+ if( p->nExclude ){
|
|
+ assert( p->nExclude>=pSrc->nSrc );
|
|
+ p->nExclude -= pSrc->nSrc;
|
|
+ }
|
|
+}
|
|
+
|
|
+/* This is the Walker EXPR callback for sqlite3ReferencesSrcList().
|
|
+**
|
|
+** Set the 0x01 bit of pWalker->eCode if there is a reference to any
|
|
+** of the tables shown in RefSrcList.pRef.
|
|
+**
|
|
+** Set the 0x02 bit of pWalker->eCode if there is a reference to a
|
|
+** table is in neither RefSrcList.pRef nor RefSrcList.aiExclude.
|
|
+*/
|
|
+static int exprRefToSrcList(Walker *pWalker, Expr *pExpr){
|
|
+ if( pExpr->op==TK_COLUMN
|
|
+ || pExpr->op==TK_AGG_COLUMN
|
|
+ ){
|
|
int i;
|
|
- struct SrcCount *p = pWalker->u.pSrcCount;
|
|
- SrcList *pSrc = p->pSrc;
|
|
+ struct RefSrcList *p = pWalker->u.pRefSrcList;
|
|
+ SrcList *pSrc = p->pRef;
|
|
int nSrc = pSrc ? pSrc->nSrc : 0;
|
|
for(i=0; i<nSrc; i++){
|
|
- if( pExpr->iTable==pSrc->a[i].iCursor ) break;
|
|
+ if( pExpr->iTable==pSrc->a[i].iCursor ){
|
|
+ pWalker->eCode |= 1;
|
|
+ return WRC_Continue;
|
|
+ }
|
|
}
|
|
- if( i<nSrc ){
|
|
- p->nThis++;
|
|
- }else if( nSrc==0 || pExpr->iTable<pSrc->a[0].iCursor ){
|
|
- /* In a well-formed parse tree (no name resolution errors),
|
|
- ** TK_COLUMN nodes with smaller Expr.iTable values are in an
|
|
- ** outer context. Those are the only ones to count as "other" */
|
|
- p->nOther++;
|
|
+ for(i=0; i<p->nExclude && p->aiExclude[i]!=pExpr->iTable; i++){}
|
|
+ if( i>=p->nExclude ){
|
|
+ pWalker->eCode |= 2;
|
|
}
|
|
}
|
|
return WRC_Continue;
|
|
}
|
|
|
|
/*
|
|
-** Determine if any of the arguments to the pExpr Function reference
|
|
-** pSrcList. Return true if they do. Also return true if the function
|
|
-** has no arguments or has only constant arguments. Return false if pExpr
|
|
-** references columns but not columns of tables found in pSrcList.
|
|
+** Check to see if pExpr references any tables in pSrcList.
|
|
+** Possible return values:
|
|
+**
|
|
+** 1 pExpr does references a table in pSrcList.
|
|
+**
|
|
+** 0 pExpr references some table that is not defined in either
|
|
+** pSrcList or in subqueries of pExpr itself.
|
|
+**
|
|
+** -1 pExpr only references no tables at all, or it only
|
|
+** references tables defined in subqueries of pExpr itself.
|
|
+**
|
|
+** As currently used, pExpr is always an aggregate function call. That
|
|
+** fact is exploited for efficiency.
|
|
*/
|
|
-SQLITE_PRIVATE int sqlite3FunctionUsesThisSrc(Expr *pExpr, SrcList *pSrcList){
|
|
+SQLITE_PRIVATE int sqlite3ReferencesSrcList(Parse *pParse, Expr *pExpr, SrcList *pSrcList){
|
|
Walker w;
|
|
- struct SrcCount cnt;
|
|
- assert( pExpr->op==TK_AGG_FUNCTION );
|
|
+ struct RefSrcList x;
|
|
+ assert( pParse->db!=0 );
|
|
memset(&w, 0, sizeof(w));
|
|
- w.xExprCallback = exprSrcCount;
|
|
- w.xSelectCallback = sqlite3SelectWalkNoop;
|
|
- w.u.pSrcCount = &cnt;
|
|
- cnt.pSrc = pSrcList;
|
|
- cnt.nThis = 0;
|
|
- cnt.nOther = 0;
|
|
+ memset(&x, 0, sizeof(x));
|
|
+ w.xExprCallback = exprRefToSrcList;
|
|
+ w.xSelectCallback = selectRefEnter;
|
|
+ w.xSelectCallback2 = selectRefLeave;
|
|
+ w.u.pRefSrcList = &x;
|
|
+ x.db = pParse->db;
|
|
+ x.pRef = pSrcList;
|
|
+ assert( pExpr->op==TK_AGG_FUNCTION );
|
|
+ assert( ExprUseXList(pExpr) );
|
|
sqlite3WalkExprList(&w, pExpr->x.pList);
|
|
#ifndef SQLITE_OMIT_WINDOWFUNC
|
|
if( ExprHasProperty(pExpr, EP_WinFunc) ){
|
|
sqlite3WalkExpr(&w, pExpr->y.pWin->pFilter);
|
|
}
|
|
#endif
|
|
- return cnt.nThis>0 || cnt.nOther==0;
|
|
+ if( x.aiExclude ) sqlite3DbNNFreeNN(pParse->db, x.aiExclude);
|
|
+ if( w.eCode & 0x01 ){
|
|
+ return 1;
|
|
+ }else if( w.eCode ){
|
|
+ return 0;
|
|
+ }else{
|
|
+ return -1;
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+** This is a Walker expression node callback.
|
|
+**
|
|
+** For Expr nodes that contain pAggInfo pointers, make sure the AggInfo
|
|
+** object that is referenced does not refer directly to the Expr. If
|
|
+** it does, make a copy. This is done because the pExpr argument is
|
|
+** subject to change.
|
|
+**
|
|
+** The copy is scheduled for deletion using the sqlite3ExprDeferredDelete()
|
|
+** which builds on the sqlite3ParserAddCleanup() mechanism.
|
|
+*/
|
|
+static int agginfoPersistExprCb(Walker *pWalker, Expr *pExpr){
|
|
+ if( ALWAYS(!ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced))
|
|
+ && pExpr->pAggInfo!=0
|
|
+ ){
|
|
+ AggInfo *pAggInfo = pExpr->pAggInfo;
|
|
+ int iAgg = pExpr->iAgg;
|
|
+ Parse *pParse = pWalker->pParse;
|
|
+ sqlite3 *db = pParse->db;
|
|
+ if( pExpr->op!=TK_AGG_FUNCTION ){
|
|
+ assert( iAgg>=0 && iAgg<pAggInfo->nColumn );
|
|
+ if( pAggInfo->aCol[iAgg].pCExpr==pExpr ){
|
|
+ pExpr = sqlite3ExprDup(db, pExpr, 0);
|
|
+ if( pExpr ){
|
|
+ pAggInfo->aCol[iAgg].pCExpr = pExpr;
|
|
+ sqlite3ExprDeferredDelete(pParse, pExpr);
|
|
+ }
|
|
+ }
|
|
+ }else{
|
|
+ assert( pExpr->op==TK_AGG_FUNCTION );
|
|
+ assert( iAgg>=0 && iAgg<pAggInfo->nFunc );
|
|
+ if( pAggInfo->aFunc[iAgg].pFExpr==pExpr ){
|
|
+ pExpr = sqlite3ExprDup(db, pExpr, 0);
|
|
+ if( pExpr ){
|
|
+ pAggInfo->aFunc[iAgg].pFExpr = pExpr;
|
|
+ sqlite3ExprDeferredDelete(pParse, pExpr);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ return WRC_Continue;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Initialize a Walker object so that will persist AggInfo entries referenced
|
|
+** by the tree that is walked.
|
|
+*/
|
|
+SQLITE_PRIVATE void sqlite3AggInfoPersistWalkerInit(Walker *pWalker, Parse *pParse){
|
|
+ memset(pWalker, 0, sizeof(*pWalker));
|
|
+ pWalker->pParse = pParse;
|
|
+ pWalker->xExprCallback = agginfoPersistExprCb;
|
|
+ pWalker->xSelectCallback = sqlite3SelectWalkNoop;
|
|
}
|
|
|
|
/*
|
|
@@ -104333,7 +112047,7 @@ static int addAggInfoColumn(sqlite3 *db, AggInfo *pInfo){
|
|
&i
|
|
);
|
|
return i;
|
|
-}
|
|
+}
|
|
|
|
/*
|
|
** Add a new element to the pAggInfo->aFunc[] array. Return the index of
|
|
@@ -104342,14 +112056,81 @@ static int addAggInfoColumn(sqlite3 *db, AggInfo *pInfo){
|
|
static int addAggInfoFunc(sqlite3 *db, AggInfo *pInfo){
|
|
int i;
|
|
pInfo->aFunc = sqlite3ArrayAllocate(
|
|
- db,
|
|
+ db,
|
|
pInfo->aFunc,
|
|
sizeof(pInfo->aFunc[0]),
|
|
&pInfo->nFunc,
|
|
&i
|
|
);
|
|
return i;
|
|
-}
|
|
+}
|
|
+
|
|
+/*
|
|
+** Search the AggInfo object for an aCol[] entry that has iTable and iColumn.
|
|
+** Return the index in aCol[] of the entry that describes that column.
|
|
+**
|
|
+** If no prior entry is found, create a new one and return -1. The
|
|
+** new column will have an idex of pAggInfo->nColumn-1.
|
|
+*/
|
|
+static void findOrCreateAggInfoColumn(
|
|
+ Parse *pParse, /* Parsing context */
|
|
+ AggInfo *pAggInfo, /* The AggInfo object to search and/or modify */
|
|
+ Expr *pExpr /* Expr describing the column to find or insert */
|
|
+){
|
|
+ struct AggInfo_col *pCol;
|
|
+ int k;
|
|
+
|
|
+ assert( pAggInfo->iFirstReg==0 );
|
|
+ pCol = pAggInfo->aCol;
|
|
+ for(k=0; k<pAggInfo->nColumn; k++, pCol++){
|
|
+ if( pCol->iTable==pExpr->iTable
|
|
+ && pCol->iColumn==pExpr->iColumn
|
|
+ && pExpr->op!=TK_IF_NULL_ROW
|
|
+ ){
|
|
+ goto fix_up_expr;
|
|
+ }
|
|
+ }
|
|
+ k = addAggInfoColumn(pParse->db, pAggInfo);
|
|
+ if( k<0 ){
|
|
+ /* OOM on resize */
|
|
+ assert( pParse->db->mallocFailed );
|
|
+ return;
|
|
+ }
|
|
+ pCol = &pAggInfo->aCol[k];
|
|
+ assert( ExprUseYTab(pExpr) );
|
|
+ pCol->pTab = pExpr->y.pTab;
|
|
+ pCol->iTable = pExpr->iTable;
|
|
+ pCol->iColumn = pExpr->iColumn;
|
|
+ pCol->iSorterColumn = -1;
|
|
+ pCol->pCExpr = pExpr;
|
|
+ if( pAggInfo->pGroupBy && pExpr->op!=TK_IF_NULL_ROW ){
|
|
+ int j, n;
|
|
+ ExprList *pGB = pAggInfo->pGroupBy;
|
|
+ struct ExprList_item *pTerm = pGB->a;
|
|
+ n = pGB->nExpr;
|
|
+ for(j=0; j<n; j++, pTerm++){
|
|
+ Expr *pE = pTerm->pExpr;
|
|
+ if( pE->op==TK_COLUMN
|
|
+ && pE->iTable==pExpr->iTable
|
|
+ && pE->iColumn==pExpr->iColumn
|
|
+ ){
|
|
+ pCol->iSorterColumn = j;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ if( pCol->iSorterColumn<0 ){
|
|
+ pCol->iSorterColumn = pAggInfo->nSortingColumn++;
|
|
+ }
|
|
+fix_up_expr:
|
|
+ ExprSetVVAProperty(pExpr, EP_NoReduce);
|
|
+ assert( pExpr->pAggInfo==0 || pExpr->pAggInfo==pAggInfo );
|
|
+ pExpr->pAggInfo = pAggInfo;
|
|
+ if( pExpr->op==TK_COLUMN ){
|
|
+ pExpr->op = TK_AGG_COLUMN;
|
|
+ }
|
|
+ pExpr->iAgg = (i16)k;
|
|
+}
|
|
|
|
/*
|
|
** This is the xExprCallback for a tree walker. It is used to
|
|
@@ -104364,70 +112145,51 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
|
|
AggInfo *pAggInfo = pNC->uNC.pAggInfo;
|
|
|
|
assert( pNC->ncFlags & NC_UAggInfo );
|
|
+ assert( pAggInfo->iFirstReg==0 );
|
|
switch( pExpr->op ){
|
|
+ default: {
|
|
+ IndexedExpr *pIEpr;
|
|
+ Expr tmp;
|
|
+ assert( pParse->iSelfTab==0 );
|
|
+ if( (pNC->ncFlags & NC_InAggFunc)==0 ) break;
|
|
+ if( pParse->pIdxEpr==0 ) break;
|
|
+ for(pIEpr=pParse->pIdxEpr; pIEpr; pIEpr=pIEpr->pIENext){
|
|
+ int iDataCur = pIEpr->iDataCur;
|
|
+ if( iDataCur<0 ) continue;
|
|
+ if( sqlite3ExprCompare(0, pExpr, pIEpr->pExpr, iDataCur)==0 ) break;
|
|
+ }
|
|
+ if( pIEpr==0 ) break;
|
|
+ if( NEVER(!ExprUseYTab(pExpr)) ) break;
|
|
+ if( pExpr->pAggInfo!=0 ) break; /* Already resolved by outer context */
|
|
+
|
|
+ /* If we reach this point, it means that expression pExpr can be
|
|
+ ** translated into a reference to an index column as described by
|
|
+ ** pIEpr.
|
|
+ */
|
|
+ memset(&tmp, 0, sizeof(tmp));
|
|
+ tmp.op = TK_AGG_COLUMN;
|
|
+ tmp.iTable = pIEpr->iIdxCur;
|
|
+ tmp.iColumn = pIEpr->iIdxCol;
|
|
+ findOrCreateAggInfoColumn(pParse, pAggInfo, &tmp);
|
|
+ pAggInfo->aCol[tmp.iAgg].pCExpr = pExpr;
|
|
+ pExpr->pAggInfo = pAggInfo;
|
|
+ pExpr->iAgg = tmp.iAgg;
|
|
+ return WRC_Prune;
|
|
+ }
|
|
+ case TK_IF_NULL_ROW:
|
|
case TK_AGG_COLUMN:
|
|
case TK_COLUMN: {
|
|
testcase( pExpr->op==TK_AGG_COLUMN );
|
|
testcase( pExpr->op==TK_COLUMN );
|
|
+ testcase( pExpr->op==TK_IF_NULL_ROW );
|
|
/* Check to see if the column is in one of the tables in the FROM
|
|
** clause of the aggregate query */
|
|
if( ALWAYS(pSrcList!=0) ){
|
|
- struct SrcList_item *pItem = pSrcList->a;
|
|
+ SrcItem *pItem = pSrcList->a;
|
|
for(i=0; i<pSrcList->nSrc; i++, pItem++){
|
|
- struct AggInfo_col *pCol;
|
|
assert( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) );
|
|
if( pExpr->iTable==pItem->iCursor ){
|
|
- /* If we reach this point, it means that pExpr refers to a table
|
|
- ** that is in the FROM clause of the aggregate query.
|
|
- **
|
|
- ** Make an entry for the column in pAggInfo->aCol[] if there
|
|
- ** is not an entry there already.
|
|
- */
|
|
- int k;
|
|
- pCol = pAggInfo->aCol;
|
|
- for(k=0; k<pAggInfo->nColumn; k++, pCol++){
|
|
- if( pCol->iTable==pExpr->iTable &&
|
|
- pCol->iColumn==pExpr->iColumn ){
|
|
- break;
|
|
- }
|
|
- }
|
|
- if( (k>=pAggInfo->nColumn)
|
|
- && (k = addAggInfoColumn(pParse->db, pAggInfo))>=0
|
|
- ){
|
|
- pCol = &pAggInfo->aCol[k];
|
|
- pCol->pTab = pExpr->y.pTab;
|
|
- pCol->iTable = pExpr->iTable;
|
|
- pCol->iColumn = pExpr->iColumn;
|
|
- pCol->iMem = ++pParse->nMem;
|
|
- pCol->iSorterColumn = -1;
|
|
- pCol->pExpr = pExpr;
|
|
- if( pAggInfo->pGroupBy ){
|
|
- int j, n;
|
|
- ExprList *pGB = pAggInfo->pGroupBy;
|
|
- struct ExprList_item *pTerm = pGB->a;
|
|
- n = pGB->nExpr;
|
|
- for(j=0; j<n; j++, pTerm++){
|
|
- Expr *pE = pTerm->pExpr;
|
|
- if( pE->op==TK_COLUMN && pE->iTable==pExpr->iTable &&
|
|
- pE->iColumn==pExpr->iColumn ){
|
|
- pCol->iSorterColumn = j;
|
|
- break;
|
|
- }
|
|
- }
|
|
- }
|
|
- if( pCol->iSorterColumn<0 ){
|
|
- pCol->iSorterColumn = pAggInfo->nSortingColumn++;
|
|
- }
|
|
- }
|
|
- /* There is now an entry for pExpr in pAggInfo->aCol[] (either
|
|
- ** because it was there before or because we just created it).
|
|
- ** Convert the pExpr to be a TK_AGG_COLUMN referring to that
|
|
- ** pAggInfo->aCol[] entry.
|
|
- */
|
|
- ExprSetVVAProperty(pExpr, EP_NoReduce);
|
|
- pExpr->pAggInfo = pAggInfo;
|
|
- pExpr->op = TK_AGG_COLUMN;
|
|
- pExpr->iAgg = (i16)k;
|
|
+ findOrCreateAggInfoColumn(pParse, pAggInfo, pExpr);
|
|
break;
|
|
} /* endif pExpr->iTable==pItem->iCursor */
|
|
} /* end loop over pSrcList */
|
|
@@ -104438,12 +112200,13 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
|
|
if( (pNC->ncFlags & NC_InAggFunc)==0
|
|
&& pWalker->walkerDepth==pExpr->op2
|
|
){
|
|
- /* Check to see if pExpr is a duplicate of another aggregate
|
|
+ /* Check to see if pExpr is a duplicate of another aggregate
|
|
** function that is already in the pAggInfo structure
|
|
*/
|
|
struct AggInfo_func *pItem = pAggInfo->aFunc;
|
|
for(i=0; i<pAggInfo->nFunc; i++, pItem++){
|
|
- if( sqlite3ExprCompare(0, pItem->pExpr, pExpr, -1)==0 ){
|
|
+ if( pItem->pFExpr==pExpr ) break;
|
|
+ if( sqlite3ExprCompare(0, pItem->pFExpr, pExpr, -1)==0 ){
|
|
break;
|
|
}
|
|
}
|
|
@@ -104455,11 +112218,10 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
|
|
if( i>=0 ){
|
|
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
|
|
pItem = &pAggInfo->aFunc[i];
|
|
- pItem->pExpr = pExpr;
|
|
- pItem->iMem = ++pParse->nMem;
|
|
- assert( !ExprHasProperty(pExpr, EP_IntValue) );
|
|
+ pItem->pFExpr = pExpr;
|
|
+ assert( ExprUseUToken(pExpr) );
|
|
pItem->pFunc = sqlite3FindFunction(pParse->db,
|
|
- pExpr->u.zToken,
|
|
+ pExpr->u.zToken,
|
|
pExpr->x.pList ? pExpr->x.pList->nExpr : 0, enc, 0);
|
|
if( pExpr->flags & EP_Distinct ){
|
|
pItem->iDistinct = pParse->nTab++;
|
|
@@ -104482,15 +112244,6 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
|
|
}
|
|
return WRC_Continue;
|
|
}
|
|
-static int analyzeAggregatesInSelect(Walker *pWalker, Select *pSelect){
|
|
- UNUSED_PARAMETER(pSelect);
|
|
- pWalker->walkerDepth++;
|
|
- return WRC_Continue;
|
|
-}
|
|
-static void analyzeAggregatesInSelectEnd(Walker *pWalker, Select *pSelect){
|
|
- UNUSED_PARAMETER(pSelect);
|
|
- pWalker->walkerDepth--;
|
|
-}
|
|
|
|
/*
|
|
** Analyze the pExpr expression looking for aggregate functions and
|
|
@@ -104504,8 +112257,8 @@ static void analyzeAggregatesInSelectEnd(Walker *pWalker, Select *pSelect){
|
|
SQLITE_PRIVATE void sqlite3ExprAnalyzeAggregates(NameContext *pNC, Expr *pExpr){
|
|
Walker w;
|
|
w.xExprCallback = analyzeAggregate;
|
|
- w.xSelectCallback = analyzeAggregatesInSelect;
|
|
- w.xSelectCallback2 = analyzeAggregatesInSelectEnd;
|
|
+ w.xSelectCallback = sqlite3WalkerDepthIncrease;
|
|
+ w.xSelectCallback2 = sqlite3WalkerDepthDecrease;
|
|
w.walkerDepth = 0;
|
|
w.u.pNC = pNC;
|
|
w.pParse = 0;
|
|
@@ -104650,8 +112403,9 @@ SQLITE_PRIVATE int sqlite3NoTempsInRange(Parse *pParse, int iFirst, int iLast){
|
|
** Or, if zName is not a system table, zero is returned.
|
|
*/
|
|
static int isAlterableTable(Parse *pParse, Table *pTab){
|
|
- if( 0==sqlite3StrNICmp(pTab->zName, "sqlite_", 7)
|
|
+ if( 0==sqlite3StrNICmp(pTab->zName, "sqlite_", 7)
|
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
|
+ || (pTab->tabFlags & TF_Eponymous)!=0
|
|
|| ( (pTab->tabFlags & TF_Shadow)!=0
|
|
&& sqlite3ReadOnlyShadowTables(pParse->db)
|
|
)
|
|
@@ -104670,25 +112424,56 @@ static int isAlterableTable(Parse *pParse, Table *pTab){
|
|
** statement to ensure that the operation has not rendered any schema
|
|
** objects unusable.
|
|
*/
|
|
-static void renameTestSchema(Parse *pParse, const char *zDb, int bTemp){
|
|
- sqlite3NestedParse(pParse,
|
|
+static void renameTestSchema(
|
|
+ Parse *pParse, /* Parse context */
|
|
+ const char *zDb, /* Name of db to verify schema of */
|
|
+ int bTemp, /* True if this is the temp db */
|
|
+ const char *zWhen, /* "when" part of error message */
|
|
+ int bNoDQS /* Do not allow DQS in the schema */
|
|
+){
|
|
+ pParse->colNamesSet = 1;
|
|
+ sqlite3NestedParse(pParse,
|
|
"SELECT 1 "
|
|
- "FROM \"%w\".%s "
|
|
+ "FROM \"%w\"." LEGACY_SCHEMA_TABLE " "
|
|
"WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X'"
|
|
" AND sql NOT LIKE 'create virtual%%'"
|
|
- " AND sqlite_rename_test(%Q, sql, type, name, %d)=NULL ",
|
|
- zDb, MASTER_NAME,
|
|
- zDb, bTemp
|
|
+ " AND sqlite_rename_test(%Q, sql, type, name, %d, %Q, %d)=NULL ",
|
|
+ zDb,
|
|
+ zDb, bTemp, zWhen, bNoDQS
|
|
);
|
|
|
|
if( bTemp==0 ){
|
|
- sqlite3NestedParse(pParse,
|
|
+ sqlite3NestedParse(pParse,
|
|
"SELECT 1 "
|
|
- "FROM temp.%s "
|
|
+ "FROM temp." LEGACY_SCHEMA_TABLE " "
|
|
"WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X'"
|
|
" AND sql NOT LIKE 'create virtual%%'"
|
|
- " AND sqlite_rename_test(%Q, sql, type, name, 1)=NULL ",
|
|
- MASTER_NAME, zDb
|
|
+ " AND sqlite_rename_test(%Q, sql, type, name, 1, %Q, %d)=NULL ",
|
|
+ zDb, zWhen, bNoDQS
|
|
+ );
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+** Generate VM code to replace any double-quoted strings (but not double-quoted
|
|
+** identifiers) within the "sql" column of the sqlite_schema table in
|
|
+** database zDb with their single-quoted equivalents. If argument bTemp is
|
|
+** not true, similarly update all SQL statements in the sqlite_schema table
|
|
+** of the temp db.
|
|
+*/
|
|
+static void renameFixQuotes(Parse *pParse, const char *zDb, int bTemp){
|
|
+ sqlite3NestedParse(pParse,
|
|
+ "UPDATE \"%w\"." LEGACY_SCHEMA_TABLE
|
|
+ " SET sql = sqlite_rename_quotefix(%Q, sql)"
|
|
+ "WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X'"
|
|
+ " AND sql NOT LIKE 'create virtual%%'" , zDb, zDb
|
|
+ );
|
|
+ if( bTemp==0 ){
|
|
+ sqlite3NestedParse(pParse,
|
|
+ "UPDATE temp." LEGACY_SCHEMA_TABLE
|
|
+ " SET sql = sqlite_rename_quotefix('temp', sql)"
|
|
+ "WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X'"
|
|
+ " AND sql NOT LIKE 'create virtual%%'"
|
|
);
|
|
}
|
|
}
|
|
@@ -104697,18 +112482,18 @@ static void renameTestSchema(Parse *pParse, const char *zDb, int bTemp){
|
|
** Generate code to reload the schema for database iDb. And, if iDb!=1, for
|
|
** the temp database as well.
|
|
*/
|
|
-static void renameReloadSchema(Parse *pParse, int iDb){
|
|
+static void renameReloadSchema(Parse *pParse, int iDb, u16 p5){
|
|
Vdbe *v = pParse->pVdbe;
|
|
if( v ){
|
|
sqlite3ChangeCookie(pParse, iDb);
|
|
- sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, iDb, 0);
|
|
- if( iDb!=1 ) sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, 1, 0);
|
|
+ sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, iDb, 0, p5);
|
|
+ if( iDb!=1 ) sqlite3VdbeAddParseSchemaOp(pParse->pVdbe, 1, 0, p5);
|
|
}
|
|
}
|
|
|
|
/*
|
|
-** Generate code to implement the "ALTER TABLE xxx RENAME TO yyy"
|
|
-** command.
|
|
+** Generate code to implement the "ALTER TABLE xxx RENAME TO yyy"
|
|
+** command.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3AlterRenameTable(
|
|
Parse *pParse, /* Parser context. */
|
|
@@ -104718,15 +112503,13 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(
|
|
int iDb; /* Database that contains the table */
|
|
char *zDb; /* Name of database iDb */
|
|
Table *pTab; /* Table being renamed */
|
|
- char *zName = 0; /* NULL-terminated version of pName */
|
|
+ char *zName = 0; /* NULL-terminated version of pName */
|
|
sqlite3 *db = pParse->db; /* Database connection */
|
|
int nTabName; /* Number of UTF-8 characters in zTabName */
|
|
const char *zTabName; /* Original name of the table */
|
|
Vdbe *v;
|
|
VTable *pVTab = 0; /* Non-zero if this is a v-tab with an xRename() */
|
|
- u32 savedDbFlags; /* Saved value of db->mDbFlags */
|
|
|
|
- savedDbFlags = db->mDbFlags;
|
|
if( NEVER(db->mallocFailed) ) goto exit_rename_table;
|
|
assert( pSrc->nSrc==1 );
|
|
assert( sqlite3BtreeHoldsAllMutexes(pParse->db) );
|
|
@@ -104735,7 +112518,6 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(
|
|
if( !pTab ) goto exit_rename_table;
|
|
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
|
|
zDb = db->aDb[iDb].zDbSName;
|
|
- db->mDbFlags |= DBFLAG_PreferBuiltin;
|
|
|
|
/* Get a NULL terminated version of the new table name. */
|
|
zName = sqlite3NameFromToken(db, pName);
|
|
@@ -104744,8 +112526,11 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(
|
|
/* Check that a table or index named 'zName' does not already exist
|
|
** in database iDb. If so, this is an error.
|
|
*/
|
|
- if( sqlite3FindTable(db, zName, zDb) || sqlite3FindIndex(db, zName, zDb) ){
|
|
- sqlite3ErrorMsg(pParse,
|
|
+ if( sqlite3FindTable(db, zName, zDb)
|
|
+ || sqlite3FindIndex(db, zName, zDb)
|
|
+ || sqlite3IsShadowTableOf(db, pTab, zName)
|
|
+ ){
|
|
+ sqlite3ErrorMsg(pParse,
|
|
"there is already another table or index with this name: %s", zName);
|
|
goto exit_rename_table;
|
|
}
|
|
@@ -104761,7 +112546,7 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(
|
|
}
|
|
|
|
#ifndef SQLITE_OMIT_VIEW
|
|
- if( pTab->pSelect ){
|
|
+ if( IsView(pTab) ){
|
|
sqlite3ErrorMsg(pParse, "view %s may not be altered", pTab->zName);
|
|
goto exit_rename_table;
|
|
}
|
|
@@ -104788,7 +112573,7 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(
|
|
|
|
/* Begin a transaction for database iDb. Then modify the schema cookie
|
|
** (since the ALTER TABLE modifies the schema). Call sqlite3MayAbort(),
|
|
- ** as the scalar functions (e.g. sqlite_rename_table()) invoked by the
|
|
+ ** as the scalar functions (e.g. sqlite_rename_table()) invoked by the
|
|
** nested SQL may raise an exception. */
|
|
v = sqlite3GetVdbe(pParse);
|
|
if( v==0 ){
|
|
@@ -104802,18 +112587,18 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(
|
|
|
|
/* Rewrite all CREATE TABLE, INDEX, TRIGGER or VIEW statements in
|
|
** the schema to use the new table name. */
|
|
- sqlite3NestedParse(pParse,
|
|
- "UPDATE \"%w\".%s SET "
|
|
+ sqlite3NestedParse(pParse,
|
|
+ "UPDATE \"%w\"." LEGACY_SCHEMA_TABLE " SET "
|
|
"sql = sqlite_rename_table(%Q, type, name, sql, %Q, %Q, %d) "
|
|
"WHERE (type!='index' OR tbl_name=%Q COLLATE nocase)"
|
|
"AND name NOT LIKE 'sqliteX_%%' ESCAPE 'X'"
|
|
- , zDb, MASTER_NAME, zDb, zTabName, zName, (iDb==1), zTabName
|
|
+ , zDb, zDb, zTabName, zName, (iDb==1), zTabName
|
|
);
|
|
|
|
- /* Update the tbl_name and name columns of the sqlite_master table
|
|
+ /* Update the tbl_name and name columns of the sqlite_schema table
|
|
** as required. */
|
|
sqlite3NestedParse(pParse,
|
|
- "UPDATE %Q.%s SET "
|
|
+ "UPDATE %Q." LEGACY_SCHEMA_TABLE " SET "
|
|
"tbl_name = %Q, "
|
|
"name = CASE "
|
|
"WHEN type='table' THEN %Q "
|
|
@@ -104822,14 +112607,14 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(
|
|
"'sqlite_autoindex_' || %Q || substr(name,%d+18) "
|
|
"ELSE name END "
|
|
"WHERE tbl_name=%Q COLLATE nocase AND "
|
|
- "(type='table' OR type='index' OR type='trigger');",
|
|
- zDb, MASTER_NAME,
|
|
- zName, zName, zName,
|
|
+ "(type='table' OR type='index' OR type='trigger');",
|
|
+ zDb,
|
|
+ zName, zName, zName,
|
|
nTabName, zTabName
|
|
);
|
|
|
|
#ifndef SQLITE_OMIT_AUTOINCREMENT
|
|
- /* If the sqlite_sequence table exists in this database, then update
|
|
+ /* If the sqlite_sequence table exists in this database, then update
|
|
** it with the new table name.
|
|
*/
|
|
if( sqlite3FindTable(db, "sqlite_sequence", zDb) ){
|
|
@@ -104840,15 +112625,15 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(
|
|
#endif
|
|
|
|
/* If the table being renamed is not itself part of the temp database,
|
|
- ** edit view and trigger definitions within the temp database
|
|
+ ** edit view and trigger definitions within the temp database
|
|
** as required. */
|
|
if( iDb!=1 ){
|
|
- sqlite3NestedParse(pParse,
|
|
- "UPDATE sqlite_temp_master SET "
|
|
+ sqlite3NestedParse(pParse,
|
|
+ "UPDATE sqlite_temp_schema SET "
|
|
"sql = sqlite_rename_table(%Q, type, name, sql, %Q, %Q, 1), "
|
|
"tbl_name = "
|
|
"CASE WHEN tbl_name=%Q COLLATE nocase AND "
|
|
- " sqlite_rename_test(%Q, sql, type, name, 1) "
|
|
+ " sqlite_rename_test(%Q, sql, type, name, 1, 'after rename', 0) "
|
|
"THEN %Q ELSE tbl_name END "
|
|
"WHERE type IN ('view', 'trigger')"
|
|
, zDb, zTabName, zName, zTabName, zDb, zName);
|
|
@@ -104867,13 +112652,28 @@ SQLITE_PRIVATE void sqlite3AlterRenameTable(
|
|
}
|
|
#endif
|
|
|
|
- renameReloadSchema(pParse, iDb);
|
|
- renameTestSchema(pParse, zDb, iDb==1);
|
|
+ renameReloadSchema(pParse, iDb, INITFLAG_AlterRename);
|
|
+ renameTestSchema(pParse, zDb, iDb==1, "after rename", 0);
|
|
|
|
exit_rename_table:
|
|
sqlite3SrcListDelete(db, pSrc);
|
|
sqlite3DbFree(db, zName);
|
|
- db->mDbFlags = savedDbFlags;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Write code that will raise an error if the table described by
|
|
+** zDb and zTab is not empty.
|
|
+*/
|
|
+static void sqlite3ErrorIfNotEmpty(
|
|
+ Parse *pParse, /* Parsing context */
|
|
+ const char *zDb, /* Schema holding the table */
|
|
+ const char *zTab, /* Table to check for empty */
|
|
+ const char *zErr /* Error message text */
|
|
+){
|
|
+ sqlite3NestedParse(pParse,
|
|
+ "SELECT raise(ABORT,%Q) FROM \"%w\".\"%w\"",
|
|
+ zErr, zDb, zTab
|
|
+ );
|
|
}
|
|
|
|
/*
|
|
@@ -104898,7 +112698,9 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
|
|
int r1; /* Temporary registers */
|
|
|
|
db = pParse->db;
|
|
- if( pParse->nErr || db->mallocFailed ) return;
|
|
+ assert( db->pParse==pParse );
|
|
+ if( pParse->nErr ) return;
|
|
+ assert( db->mallocFailed==0 );
|
|
pNew = pParse->pNewTable;
|
|
assert( pNew );
|
|
|
|
@@ -104907,7 +112709,7 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
|
|
zDb = db->aDb[iDb].zDbSName;
|
|
zTab = &pNew->zName[16]; /* Skip the "sqlite_altertab_" prefix on the name */
|
|
pCol = &pNew->aCol[pNew->nCol-1];
|
|
- pDflt = pCol->pDflt;
|
|
+ pDflt = sqlite3ColumnExpr(pNew, pCol);
|
|
pTab = sqlite3FindTable(db, zTab, zDb);
|
|
assert( pTab );
|
|
|
|
@@ -104928,11 +112730,12 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
|
|
return;
|
|
}
|
|
if( pNew->pIndex ){
|
|
- sqlite3ErrorMsg(pParse, "Cannot add a UNIQUE column");
|
|
+ sqlite3ErrorMsg(pParse,
|
|
+ "Cannot add a UNIQUE column");
|
|
return;
|
|
}
|
|
if( (pCol->colFlags & COLFLAG_GENERATED)==0 ){
|
|
- /* If the default value for the new column was specified with a
|
|
+ /* If the default value for the new column was specified with a
|
|
** literal NULL, then set pDflt to 0. This simplifies checking
|
|
** for an SQL NULL default below.
|
|
*/
|
|
@@ -104940,17 +112743,17 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
|
|
if( pDflt && pDflt->pLeft->op==TK_NULL ){
|
|
pDflt = 0;
|
|
}
|
|
- if( (db->flags&SQLITE_ForeignKeys) && pNew->pFKey && pDflt ){
|
|
- sqlite3ErrorMsg(pParse,
|
|
+ assert( IsOrdinaryTable(pNew) );
|
|
+ if( (db->flags&SQLITE_ForeignKeys) && pNew->u.tab.pFKey && pDflt ){
|
|
+ sqlite3ErrorIfNotEmpty(pParse, zDb, zTab,
|
|
"Cannot add a REFERENCES column with non-NULL default value");
|
|
- return;
|
|
}
|
|
if( pCol->notNull && !pDflt ){
|
|
- sqlite3ErrorMsg(pParse,
|
|
+ sqlite3ErrorIfNotEmpty(pParse, zDb, zTab,
|
|
"Cannot add a NOT NULL column with default value NULL");
|
|
- return;
|
|
}
|
|
|
|
+
|
|
/* Ensure the default expression is something that sqlite3ValueFromExpr()
|
|
** can handle (i.e. not CURRENT_TIME etc.)
|
|
*/
|
|
@@ -104964,14 +112767,13 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
|
|
return;
|
|
}
|
|
if( !pVal ){
|
|
- sqlite3ErrorMsg(pParse,"Cannot add a column with non-constant default");
|
|
- return;
|
|
+ sqlite3ErrorIfNotEmpty(pParse, zDb, zTab,
|
|
+ "Cannot add a column with non-constant default");
|
|
}
|
|
sqlite3ValueFree(pVal);
|
|
}
|
|
}else if( pCol->colFlags & COLFLAG_STORED ){
|
|
- sqlite3ErrorMsg(pParse, "cannot add a STORED column");
|
|
- return;
|
|
+ sqlite3ErrorIfNotEmpty(pParse, zDb, zTab, "cannot add a STORED column");
|
|
}
|
|
|
|
|
|
@@ -104979,28 +112781,30 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
|
|
zCol = sqlite3DbStrNDup(db, (char*)pColDef->z, pColDef->n);
|
|
if( zCol ){
|
|
char *zEnd = &zCol[pColDef->n-1];
|
|
- u32 savedDbFlags = db->mDbFlags;
|
|
while( zEnd>zCol && (*zEnd==';' || sqlite3Isspace(*zEnd)) ){
|
|
*zEnd-- = '\0';
|
|
}
|
|
- db->mDbFlags |= DBFLAG_PreferBuiltin;
|
|
- sqlite3NestedParse(pParse,
|
|
- "UPDATE \"%w\".%s SET "
|
|
- "sql = substr(sql,1,%d) || ', ' || %Q || substr(sql,%d) "
|
|
- "WHERE type = 'table' AND name = %Q",
|
|
- zDb, MASTER_NAME, pNew->addColOffset, zCol, pNew->addColOffset+1,
|
|
+ /* substr() operations on characters, but addColOffset is in bytes. So we
|
|
+ ** have to use printf() to translate between these units: */
|
|
+ assert( IsOrdinaryTable(pTab) );
|
|
+ assert( IsOrdinaryTable(pNew) );
|
|
+ sqlite3NestedParse(pParse,
|
|
+ "UPDATE \"%w\"." LEGACY_SCHEMA_TABLE " SET "
|
|
+ "sql = printf('%%.%ds, ',sql) || %Q"
|
|
+ " || substr(sql,1+length(printf('%%.%ds',sql))) "
|
|
+ "WHERE type = 'table' AND name = %Q",
|
|
+ zDb, pNew->u.tab.addColOffset, zCol, pNew->u.tab.addColOffset,
|
|
zTab
|
|
);
|
|
sqlite3DbFree(db, zCol);
|
|
- db->mDbFlags = savedDbFlags;
|
|
}
|
|
|
|
- /* Make sure the schema version is at least 3. But do not upgrade
|
|
- ** from less than 3 to 4, as that will corrupt any preexisting DESC
|
|
- ** index.
|
|
- */
|
|
v = sqlite3GetVdbe(pParse);
|
|
if( v ){
|
|
+ /* Make sure the schema version is at least 3. But do not upgrade
|
|
+ ** from less than 3 to 4, as that will corrupt any preexisting DESC
|
|
+ ** index.
|
|
+ */
|
|
r1 = sqlite3GetTempReg(pParse);
|
|
sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, r1, BTREE_FILE_FORMAT);
|
|
sqlite3VdbeUsesBtree(v, iDb);
|
|
@@ -105009,22 +112813,37 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
|
|
VdbeCoverage(v);
|
|
sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_FILE_FORMAT, 3);
|
|
sqlite3ReleaseTempReg(pParse, r1);
|
|
- }
|
|
|
|
- /* Reload the table definition */
|
|
- renameReloadSchema(pParse, iDb);
|
|
+ /* Reload the table definition */
|
|
+ renameReloadSchema(pParse, iDb, INITFLAG_AlterAdd);
|
|
+
|
|
+ /* Verify that constraints are still satisfied */
|
|
+ if( pNew->pCheck!=0
|
|
+ || (pCol->notNull && (pCol->colFlags & COLFLAG_GENERATED)!=0)
|
|
+ ){
|
|
+ sqlite3NestedParse(pParse,
|
|
+ "SELECT CASE WHEN quick_check GLOB 'CHECK*'"
|
|
+ " THEN raise(ABORT,'CHECK constraint failed')"
|
|
+ " ELSE raise(ABORT,'NOT NULL constraint failed')"
|
|
+ " END"
|
|
+ " FROM pragma_quick_check(%Q,%Q)"
|
|
+ " WHERE quick_check GLOB 'CHECK*' OR quick_check GLOB 'NULL*'",
|
|
+ zTab, zDb
|
|
+ );
|
|
+ }
|
|
+ }
|
|
}
|
|
|
|
/*
|
|
** This function is called by the parser after the table-name in
|
|
-** an "ALTER TABLE <table-name> ADD" statement is parsed. Argument
|
|
+** an "ALTER TABLE <table-name> ADD" statement is parsed. Argument
|
|
** pSrc is the full-name of the table being altered.
|
|
**
|
|
** This routine makes a (partial) copy of the Table structure
|
|
** for the table being altered and sets Parse.pNewTable to point
|
|
** to it. Routines called by the parser as the column definition
|
|
-** is parsed (i.e. sqlite3AddColumn()) add the new Column data to
|
|
-** the copy. The copy of the Table structure is deleted by tokenize.c
|
|
+** is parsed (i.e. sqlite3AddColumn()) add the new Column data to
|
|
+** the copy. The copy of the Table structure is deleted by tokenize.c
|
|
** after parsing is finished.
|
|
**
|
|
** Routine sqlite3AlterFinishAddColumn() will be called to complete
|
|
@@ -105053,7 +112872,7 @@ SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
|
|
#endif
|
|
|
|
/* Make sure this is not an attempt to ALTER a view. */
|
|
- if( pTab->pSelect ){
|
|
+ if( IsView(pTab) ){
|
|
sqlite3ErrorMsg(pParse, "Cannot add a column to a view");
|
|
goto exit_begin_add_column;
|
|
}
|
|
@@ -105062,7 +112881,8 @@ SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
|
|
}
|
|
|
|
sqlite3MayAbort(pParse);
|
|
- assert( pTab->addColOffset>0 );
|
|
+ assert( IsOrdinaryTable(pTab) );
|
|
+ assert( pTab->u.tab.addColOffset>0 );
|
|
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
|
|
|
/* Put a copy of the Table struct in Parse.pNewTable for the
|
|
@@ -105089,12 +112909,13 @@ SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
|
|
memcpy(pNew->aCol, pTab->aCol, sizeof(Column)*pNew->nCol);
|
|
for(i=0; i<pNew->nCol; i++){
|
|
Column *pCol = &pNew->aCol[i];
|
|
- pCol->zName = sqlite3DbStrDup(db, pCol->zName);
|
|
- pCol->zColl = 0;
|
|
- pCol->pDflt = 0;
|
|
+ pCol->zCnName = sqlite3DbStrDup(db, pCol->zCnName);
|
|
+ pCol->hName = sqlite3StrIHash(pCol->zCnName);
|
|
}
|
|
+ assert( IsOrdinaryTable(pNew) );
|
|
+ pNew->u.tab.pDfltList = sqlite3ExprListDup(db, pTab->u.tab.pDfltList, 0);
|
|
pNew->pSchema = db->aDb[iDb].pSchema;
|
|
- pNew->addColOffset = pTab->addColOffset;
|
|
+ pNew->u.tab.addColOffset = pTab->u.tab.addColOffset;
|
|
pNew->nTabRef = 1;
|
|
|
|
exit_begin_add_column:
|
|
@@ -105111,10 +112932,10 @@ SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
|
|
** Or, if pTab is not a view or virtual table, zero is returned.
|
|
*/
|
|
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
|
|
-static int isRealTable(Parse *pParse, Table *pTab){
|
|
+static int isRealTable(Parse *pParse, Table *pTab, int bDrop){
|
|
const char *zType = 0;
|
|
#ifndef SQLITE_OMIT_VIEW
|
|
- if( pTab->pSelect ){
|
|
+ if( IsView(pTab) ){
|
|
zType = "view";
|
|
}
|
|
#endif
|
|
@@ -105124,15 +112945,16 @@ static int isRealTable(Parse *pParse, Table *pTab){
|
|
}
|
|
#endif
|
|
if( zType ){
|
|
- sqlite3ErrorMsg(
|
|
- pParse, "cannot rename columns of %s \"%s\"", zType, pTab->zName
|
|
+ sqlite3ErrorMsg(pParse, "cannot %s %s \"%s\"",
|
|
+ (bDrop ? "drop column from" : "rename columns of"),
|
|
+ zType, pTab->zName
|
|
);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
#else /* !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) */
|
|
-# define isRealTable(x,y) (0)
|
|
+# define isRealTable(x,y,z) (0)
|
|
#endif
|
|
|
|
/*
|
|
@@ -105161,9 +112983,9 @@ SQLITE_PRIVATE void sqlite3AlterRenameColumn(
|
|
|
|
/* Cannot alter a system table */
|
|
if( SQLITE_OK!=isAlterableTable(pParse, pTab) ) goto exit_rename_column;
|
|
- if( SQLITE_OK!=isRealTable(pParse, pTab) ) goto exit_rename_column;
|
|
+ if( SQLITE_OK!=isRealTable(pParse, pTab, 0) ) goto exit_rename_column;
|
|
|
|
- /* Which schema holds the table to be altered */
|
|
+ /* Which schema holds the table to be altered */
|
|
iSchema = sqlite3SchemaToIndex(db, pTab->pSchema);
|
|
assert( iSchema>=0 );
|
|
zDb = db->aDb[iSchema].zDbSName;
|
|
@@ -105180,44 +113002,46 @@ SQLITE_PRIVATE void sqlite3AlterRenameColumn(
|
|
zOld = sqlite3NameFromToken(db, pOld);
|
|
if( !zOld ) goto exit_rename_column;
|
|
for(iCol=0; iCol<pTab->nCol; iCol++){
|
|
- if( 0==sqlite3StrICmp(pTab->aCol[iCol].zName, zOld) ) break;
|
|
+ if( 0==sqlite3StrICmp(pTab->aCol[iCol].zCnName, zOld) ) break;
|
|
}
|
|
if( iCol==pTab->nCol ){
|
|
- sqlite3ErrorMsg(pParse, "no such column: \"%s\"", zOld);
|
|
+ sqlite3ErrorMsg(pParse, "no such column: \"%T\"", pOld);
|
|
goto exit_rename_column;
|
|
}
|
|
|
|
+ /* Ensure the schema contains no double-quoted strings */
|
|
+ renameTestSchema(pParse, zDb, iSchema==1, "", 0);
|
|
+ renameFixQuotes(pParse, zDb, iSchema==1);
|
|
+
|
|
/* Do the rename operation using a recursive UPDATE statement that
|
|
** uses the sqlite_rename_column() SQL function to compute the new
|
|
- ** CREATE statement text for the sqlite_master table.
|
|
+ ** CREATE statement text for the sqlite_schema table.
|
|
*/
|
|
sqlite3MayAbort(pParse);
|
|
zNew = sqlite3NameFromToken(db, pNew);
|
|
if( !zNew ) goto exit_rename_column;
|
|
assert( pNew->n>0 );
|
|
bQuote = sqlite3Isquote(pNew->z[0]);
|
|
- sqlite3NestedParse(pParse,
|
|
- "UPDATE \"%w\".%s SET "
|
|
+ sqlite3NestedParse(pParse,
|
|
+ "UPDATE \"%w\"." LEGACY_SCHEMA_TABLE " SET "
|
|
"sql = sqlite_rename_column(sql, type, name, %Q, %Q, %d, %Q, %d, %d) "
|
|
"WHERE name NOT LIKE 'sqliteX_%%' ESCAPE 'X' "
|
|
- " AND (type != 'index' OR tbl_name = %Q)"
|
|
- " AND sql NOT LIKE 'create virtual%%'",
|
|
- zDb, MASTER_NAME,
|
|
+ " AND (type != 'index' OR tbl_name = %Q)",
|
|
+ zDb,
|
|
zDb, pTab->zName, iCol, zNew, bQuote, iSchema==1,
|
|
pTab->zName
|
|
);
|
|
|
|
- sqlite3NestedParse(pParse,
|
|
- "UPDATE temp.%s SET "
|
|
+ sqlite3NestedParse(pParse,
|
|
+ "UPDATE temp." LEGACY_SCHEMA_TABLE " SET "
|
|
"sql = sqlite_rename_column(sql, type, name, %Q, %Q, %d, %Q, %d, 1) "
|
|
"WHERE type IN ('trigger', 'view')",
|
|
- MASTER_NAME,
|
|
zDb, pTab->zName, iCol, zNew, bQuote
|
|
);
|
|
|
|
/* Drop and reload the database schema. */
|
|
- renameReloadSchema(pParse, iSchema);
|
|
- renameTestSchema(pParse, zDb, iSchema==1);
|
|
+ renameReloadSchema(pParse, iSchema, INITFLAG_AlterRename);
|
|
+ renameTestSchema(pParse, zDb, iSchema==1, "after rename", 1);
|
|
|
|
exit_rename_column:
|
|
sqlite3SrcListDelete(db, pSrc);
|
|
@@ -105244,7 +113068,7 @@ SQLITE_PRIVATE void sqlite3AlterRenameColumn(
|
|
** the parse tree.
|
|
*/
|
|
struct RenameToken {
|
|
- void *p; /* Parse tree element created by token t */
|
|
+ const void *p; /* Parse tree element created by token t */
|
|
Token t; /* The token that created parse tree element p */
|
|
RenameToken *pNext; /* Next is a list of all RenameToken objects */
|
|
};
|
|
@@ -105258,7 +113082,7 @@ struct RenameCtx {
|
|
RenameToken *pList; /* List of tokens to overwrite */
|
|
int nList; /* Number of tokens in pList */
|
|
int iCol; /* Index of column being renamed */
|
|
- Table *pTab; /* Table being ALTERed */
|
|
+ Table *pTab; /* Table being ALTERed */
|
|
const char *zOld; /* Old column name */
|
|
};
|
|
|
|
@@ -105266,14 +113090,14 @@ struct RenameCtx {
|
|
/*
|
|
** This function is only for debugging. It performs two tasks:
|
|
**
|
|
-** 1. Checks that pointer pPtr does not already appear in the
|
|
+** 1. Checks that pointer pPtr does not already appear in the
|
|
** rename-token list.
|
|
**
|
|
** 2. Dereferences each pointer in the rename-token list.
|
|
**
|
|
** The second is most effective when debugging under valgrind or
|
|
-** address-sanitizer or similar. If any of these pointers no longer
|
|
-** point to valid objects, an exception is raised by the memory-checking
|
|
+** address-sanitizer or similar. If any of these pointers no longer
|
|
+** point to valid objects, an exception is raised by the memory-checking
|
|
** tool.
|
|
**
|
|
** The point of this is to prevent comparisons of invalid pointer values.
|
|
@@ -105286,16 +113110,19 @@ struct RenameCtx {
|
|
** Technically, as x no longer points into a valid object or to the byte
|
|
** following a valid object, it may not be used in comparison operations.
|
|
*/
|
|
-static void renameTokenCheckAll(Parse *pParse, void *pPtr){
|
|
- if( pParse->nErr==0 && pParse->db->mallocFailed==0 ){
|
|
- RenameToken *p;
|
|
- u8 i = 0;
|
|
+static void renameTokenCheckAll(Parse *pParse, const void *pPtr){
|
|
+ assert( pParse==pParse->db->pParse );
|
|
+ assert( pParse->db->mallocFailed==0 || pParse->nErr!=0 );
|
|
+ if( pParse->nErr==0 ){
|
|
+ const RenameToken *p;
|
|
+ u32 i = 1;
|
|
for(p=pParse->pRename; p; p=p->pNext){
|
|
if( p->p ){
|
|
assert( p->p!=pPtr );
|
|
- i += *(u8*)(p->p);
|
|
+ i += *(u8*)(p->p) | 1;
|
|
}
|
|
}
|
|
+ assert( i>0 );
|
|
}
|
|
}
|
|
#else
|
|
@@ -105314,11 +113141,15 @@ static void renameTokenCheckAll(Parse *pParse, void *pPtr){
|
|
** with tail recursion in tokenExpr() routine, for a small performance
|
|
** improvement.
|
|
*/
|
|
-SQLITE_PRIVATE void *sqlite3RenameTokenMap(Parse *pParse, void *pPtr, Token *pToken){
|
|
+SQLITE_PRIVATE const void *sqlite3RenameTokenMap(
|
|
+ Parse *pParse,
|
|
+ const void *pPtr,
|
|
+ const Token *pToken
|
|
+){
|
|
RenameToken *pNew;
|
|
assert( pPtr || pParse->db->mallocFailed );
|
|
renameTokenCheckAll(pParse, pPtr);
|
|
- if( pParse->eParseMode!=PARSE_MODE_UNMAP ){
|
|
+ if( ALWAYS(pParse->eParseMode!=PARSE_MODE_UNMAP) ){
|
|
pNew = sqlite3DbMallocZero(pParse->db, sizeof(RenameToken));
|
|
if( pNew ){
|
|
pNew->p = pPtr;
|
|
@@ -105336,7 +113167,7 @@ SQLITE_PRIVATE void *sqlite3RenameTokenMap(Parse *pParse, void *pPtr, Token *pTo
|
|
** with parse tree element pFrom. This function remaps the associated token
|
|
** to parse tree element pTo.
|
|
*/
|
|
-SQLITE_PRIVATE void sqlite3RenameTokenRemap(Parse *pParse, void *pTo, void *pFrom){
|
|
+SQLITE_PRIVATE void sqlite3RenameTokenRemap(Parse *pParse, const void *pTo, const void *pFrom){
|
|
RenameToken *p;
|
|
renameTokenCheckAll(pParse, pTo);
|
|
for(p=pParse->pRename; p; p=p->pNext){
|
|
@@ -105352,7 +113183,10 @@ SQLITE_PRIVATE void sqlite3RenameTokenRemap(Parse *pParse, void *pTo, void *pFro
|
|
*/
|
|
static int renameUnmapExprCb(Walker *pWalker, Expr *pExpr){
|
|
Parse *pParse = pWalker->pParse;
|
|
- sqlite3RenameTokenRemap(pParse, 0, (void*)pExpr);
|
|
+ sqlite3RenameTokenRemap(pParse, 0, (const void*)pExpr);
|
|
+ if( ExprUseYTab(pExpr) ){
|
|
+ sqlite3RenameTokenRemap(pParse, 0, (const void*)&pExpr->y.pTab);
|
|
+ }
|
|
return WRC_Continue;
|
|
}
|
|
|
|
@@ -105363,19 +113197,49 @@ static int renameUnmapExprCb(Walker *pWalker, Expr *pExpr){
|
|
static void renameWalkWith(Walker *pWalker, Select *pSelect){
|
|
With *pWith = pSelect->pWith;
|
|
if( pWith ){
|
|
+ Parse *pParse = pWalker->pParse;
|
|
int i;
|
|
+ With *pCopy = 0;
|
|
+ assert( pWith->nCte>0 );
|
|
+ if( (pWith->a[0].pSelect->selFlags & SF_Expanded)==0 ){
|
|
+ /* Push a copy of the With object onto the with-stack. We use a copy
|
|
+ ** here as the original will be expanded and resolved (flags SF_Expanded
|
|
+ ** and SF_Resolved) below. And the parser code that uses the with-stack
|
|
+ ** fails if the Select objects on it have already been expanded and
|
|
+ ** resolved. */
|
|
+ pCopy = sqlite3WithDup(pParse->db, pWith);
|
|
+ pCopy = sqlite3WithPush(pParse, pCopy, 1);
|
|
+ }
|
|
for(i=0; i<pWith->nCte; i++){
|
|
Select *p = pWith->a[i].pSelect;
|
|
NameContext sNC;
|
|
memset(&sNC, 0, sizeof(sNC));
|
|
- sNC.pParse = pWalker->pParse;
|
|
- sqlite3SelectPrep(sNC.pParse, p, &sNC);
|
|
+ sNC.pParse = pParse;
|
|
+ if( pCopy ) sqlite3SelectPrep(sNC.pParse, p, &sNC);
|
|
+ if( sNC.pParse->db->mallocFailed ) return;
|
|
sqlite3WalkSelect(pWalker, p);
|
|
- sqlite3RenameExprlistUnmap(pWalker->pParse, pWith->a[i].pCols);
|
|
+ sqlite3RenameExprlistUnmap(pParse, pWith->a[i].pCols);
|
|
+ }
|
|
+ if( pCopy && pParse->pWith==pCopy ){
|
|
+ pParse->pWith = pCopy->pOuter;
|
|
}
|
|
}
|
|
}
|
|
|
|
+/*
|
|
+** Unmap all tokens in the IdList object passed as the second argument.
|
|
+*/
|
|
+static void unmapColumnIdlistNames(
|
|
+ Parse *pParse,
|
|
+ const IdList *pIdList
|
|
+){
|
|
+ int ii;
|
|
+ assert( pIdList!=0 );
|
|
+ for(ii=0; ii<pIdList->nId; ii++){
|
|
+ sqlite3RenameTokenRemap(pParse, 0, (const void*)pIdList->a[ii].zName);
|
|
+ }
|
|
+}
|
|
+
|
|
/*
|
|
** Walker callback used by sqlite3RenameExprUnmap().
|
|
*/
|
|
@@ -105383,11 +113247,15 @@ static int renameUnmapSelectCb(Walker *pWalker, Select *p){
|
|
Parse *pParse = pWalker->pParse;
|
|
int i;
|
|
if( pParse->nErr ) return WRC_Abort;
|
|
- if( NEVER(p->selFlags & SF_View) ) return WRC_Prune;
|
|
+ testcase( p->selFlags & SF_View );
|
|
+ testcase( p->selFlags & SF_CopyCte );
|
|
+ if( p->selFlags & (SF_View|SF_CopyCte) ){
|
|
+ return WRC_Prune;
|
|
+ }
|
|
if( ALWAYS(p->pEList) ){
|
|
ExprList *pList = p->pEList;
|
|
for(i=0; i<pList->nExpr; i++){
|
|
- if( pList->a[i].zEName && pList->a[i].eEName==ENAME_NAME ){
|
|
+ if( pList->a[i].zEName && pList->a[i].fg.eEName==ENAME_NAME ){
|
|
sqlite3RenameTokenRemap(pParse, 0, (void*)pList->a[i].zEName);
|
|
}
|
|
}
|
|
@@ -105396,7 +113264,11 @@ static int renameUnmapSelectCb(Walker *pWalker, Select *p){
|
|
SrcList *pSrc = p->pSrc;
|
|
for(i=0; i<pSrc->nSrc; i++){
|
|
sqlite3RenameTokenRemap(pParse, 0, (void*)pSrc->a[i].zName);
|
|
- if( sqlite3WalkExpr(pWalker, pSrc->a[i].pOn) ) return WRC_Abort;
|
|
+ if( pSrc->a[i].fg.isUsing==0 ){
|
|
+ sqlite3WalkExpr(pWalker, pSrc->a[i].u3.pOn);
|
|
+ }else{
|
|
+ unmapColumnIdlistNames(pParse, pSrc->a[i].u3.pUsing);
|
|
+ }
|
|
}
|
|
}
|
|
|
|
@@ -105420,7 +113292,7 @@ SQLITE_PRIVATE void sqlite3RenameExprUnmap(Parse *pParse, Expr *pExpr){
|
|
}
|
|
|
|
/*
|
|
-** Remove all nodes that are part of expression-list pEList from the
|
|
+** Remove all nodes that are part of expression-list pEList from the
|
|
** rename list.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3RenameExprlistUnmap(Parse *pParse, ExprList *pEList){
|
|
@@ -105432,7 +113304,7 @@ SQLITE_PRIVATE void sqlite3RenameExprlistUnmap(Parse *pParse, ExprList *pEList){
|
|
sWalker.xExprCallback = renameUnmapExprCb;
|
|
sqlite3WalkExprList(&sWalker, pEList);
|
|
for(i=0; i<pEList->nExpr; i++){
|
|
- if( ALWAYS(pEList->a[i].eEName==ENAME_NAME) ){
|
|
+ if( ALWAYS(pEList->a[i].fg.eEName==ENAME_NAME) ){
|
|
sqlite3RenameTokenRemap(pParse, 0, (void*)pEList->a[i].zEName);
|
|
}
|
|
}
|
|
@@ -105453,23 +113325,35 @@ static void renameTokenFree(sqlite3 *db, RenameToken *pToken){
|
|
|
|
/*
|
|
** Search the Parse object passed as the first argument for a RenameToken
|
|
-** object associated with parse tree element pPtr. If found, remove it
|
|
-** from the Parse object and add it to the list maintained by the
|
|
-** RenameCtx object passed as the second argument.
|
|
+** object associated with parse tree element pPtr. If found, return a pointer
|
|
+** to it. Otherwise, return NULL.
|
|
+**
|
|
+** If the second argument passed to this function is not NULL and a matching
|
|
+** RenameToken object is found, remove it from the Parse object and add it to
|
|
+** the list maintained by the RenameCtx object.
|
|
*/
|
|
-static void renameTokenFind(Parse *pParse, struct RenameCtx *pCtx, void *pPtr){
|
|
+static RenameToken *renameTokenFind(
|
|
+ Parse *pParse,
|
|
+ struct RenameCtx *pCtx,
|
|
+ const void *pPtr
|
|
+){
|
|
RenameToken **pp;
|
|
- assert( pPtr!=0 );
|
|
+ if( NEVER(pPtr==0) ){
|
|
+ return 0;
|
|
+ }
|
|
for(pp=&pParse->pRename; (*pp); pp=&(*pp)->pNext){
|
|
if( (*pp)->p==pPtr ){
|
|
RenameToken *pToken = *pp;
|
|
- *pp = pToken->pNext;
|
|
- pToken->pNext = pCtx->pList;
|
|
- pCtx->pList = pToken;
|
|
- pCtx->nList++;
|
|
- break;
|
|
+ if( pCtx ){
|
|
+ *pp = pToken->pNext;
|
|
+ pToken->pNext = pCtx->pList;
|
|
+ pCtx->pList = pToken;
|
|
+ pCtx->nList++;
|
|
+ }
|
|
+ return pToken;
|
|
}
|
|
}
|
|
+ return 0;
|
|
}
|
|
|
|
/*
|
|
@@ -105478,7 +113362,11 @@ static void renameTokenFind(Parse *pParse, struct RenameCtx *pCtx, void *pPtr){
|
|
** descend into sub-select statements.
|
|
*/
|
|
static int renameColumnSelectCb(Walker *pWalker, Select *p){
|
|
- if( p->selFlags & SF_View ) return WRC_Prune;
|
|
+ if( p->selFlags & (SF_View|SF_CopyCte) ){
|
|
+ testcase( p->selFlags & SF_View );
|
|
+ testcase( p->selFlags & SF_CopyCte );
|
|
+ return WRC_Prune;
|
|
+ }
|
|
renameWalkWith(pWalker, p);
|
|
return WRC_Continue;
|
|
}
|
|
@@ -105494,13 +113382,14 @@ static int renameColumnSelectCb(Walker *pWalker, Select *p){
|
|
*/
|
|
static int renameColumnExprCb(Walker *pWalker, Expr *pExpr){
|
|
RenameCtx *p = pWalker->u.pRename;
|
|
- if( pExpr->op==TK_TRIGGER
|
|
- && pExpr->iColumn==p->iCol
|
|
+ if( pExpr->op==TK_TRIGGER
|
|
+ && pExpr->iColumn==p->iCol
|
|
&& pWalker->pParse->pTriggerTab==p->pTab
|
|
){
|
|
renameTokenFind(pWalker->pParse, p, (void*)pExpr);
|
|
- }else if( pExpr->op==TK_COLUMN
|
|
- && pExpr->iColumn==p->iCol
|
|
+ }else if( pExpr->op==TK_COLUMN
|
|
+ && pExpr->iColumn==p->iCol
|
|
+ && ALWAYS(ExprUseYTab(pExpr))
|
|
&& p->pTab==pExpr->y.pTab
|
|
){
|
|
renameTokenFind(pWalker->pParse, p, (void*)pExpr);
|
|
@@ -105539,8 +113428,8 @@ static RenameToken *renameColumnTokenNext(RenameCtx *pCtx){
|
|
** adds context to the error message and then stores it in pCtx.
|
|
*/
|
|
static void renameColumnParseError(
|
|
- sqlite3_context *pCtx,
|
|
- int bPost,
|
|
+ sqlite3_context *pCtx,
|
|
+ const char *zWhen,
|
|
sqlite3_value *pType,
|
|
sqlite3_value *pObject,
|
|
Parse *pParse
|
|
@@ -105549,62 +113438,63 @@ static void renameColumnParseError(
|
|
const char *zN = (const char*)sqlite3_value_text(pObject);
|
|
char *zErr;
|
|
|
|
- zErr = sqlite3_mprintf("error in %s %s%s: %s",
|
|
- zT, zN, (bPost ? " after rename" : ""),
|
|
+ zErr = sqlite3MPrintf(pParse->db, "error in %s %s%s%s: %s",
|
|
+ zT, zN, (zWhen[0] ? " " : ""), zWhen,
|
|
pParse->zErrMsg
|
|
);
|
|
sqlite3_result_error(pCtx, zErr, -1);
|
|
- sqlite3_free(zErr);
|
|
+ sqlite3DbFree(pParse->db, zErr);
|
|
}
|
|
|
|
/*
|
|
** For each name in the the expression-list pEList (i.e. each
|
|
-** pEList->a[i].zName) that matches the string in zOld, extract the
|
|
+** pEList->a[i].zName) that matches the string in zOld, extract the
|
|
** corresponding rename-token from Parse object pParse and add it
|
|
** to the RenameCtx pCtx.
|
|
*/
|
|
static void renameColumnElistNames(
|
|
- Parse *pParse,
|
|
- RenameCtx *pCtx,
|
|
- ExprList *pEList,
|
|
+ Parse *pParse,
|
|
+ RenameCtx *pCtx,
|
|
+ const ExprList *pEList,
|
|
const char *zOld
|
|
){
|
|
if( pEList ){
|
|
int i;
|
|
for(i=0; i<pEList->nExpr; i++){
|
|
- char *zName = pEList->a[i].zEName;
|
|
- if( ALWAYS(pEList->a[i].eEName==ENAME_NAME)
|
|
+ const char *zName = pEList->a[i].zEName;
|
|
+ if( ALWAYS(pEList->a[i].fg.eEName==ENAME_NAME)
|
|
&& ALWAYS(zName!=0)
|
|
&& 0==sqlite3_stricmp(zName, zOld)
|
|
){
|
|
- renameTokenFind(pParse, pCtx, (void*)zName);
|
|
+ renameTokenFind(pParse, pCtx, (const void*)zName);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
-** For each name in the the id-list pIdList (i.e. each pIdList->a[i].zName)
|
|
-** that matches the string in zOld, extract the corresponding rename-token
|
|
+** For each name in the the id-list pIdList (i.e. each pIdList->a[i].zName)
|
|
+** that matches the string in zOld, extract the corresponding rename-token
|
|
** from Parse object pParse and add it to the RenameCtx pCtx.
|
|
*/
|
|
static void renameColumnIdlistNames(
|
|
- Parse *pParse,
|
|
- RenameCtx *pCtx,
|
|
- IdList *pIdList,
|
|
+ Parse *pParse,
|
|
+ RenameCtx *pCtx,
|
|
+ const IdList *pIdList,
|
|
const char *zOld
|
|
){
|
|
if( pIdList ){
|
|
int i;
|
|
for(i=0; i<pIdList->nId; i++){
|
|
- char *zName = pIdList->a[i].zName;
|
|
+ const char *zName = pIdList->a[i].zName;
|
|
if( 0==sqlite3_stricmp(zName, zOld) ){
|
|
- renameTokenFind(pParse, pCtx, (void*)zName);
|
|
+ renameTokenFind(pParse, pCtx, (const void*)zName);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+
|
|
/*
|
|
** Parse the SQL statement zSql using Parse object (*p). The Parse object
|
|
** is initialized by this function before it is used.
|
|
@@ -105617,24 +113507,22 @@ static int renameParseSql(
|
|
int bTemp /* True if SQL is from temp schema */
|
|
){
|
|
int rc;
|
|
- char *zErr = 0;
|
|
|
|
+ sqlite3ParseObjectInit(p, db);
|
|
+ if( zSql==0 ){
|
|
+ return SQLITE_NOMEM;
|
|
+ }
|
|
+ if( sqlite3StrNICmp(zSql,"CREATE ",7)!=0 ){
|
|
+ return SQLITE_CORRUPT_BKPT;
|
|
+ }
|
|
db->init.iDb = bTemp ? 1 : sqlite3FindDbName(db, zDb);
|
|
-
|
|
- /* Parse the SQL statement passed as the first argument. If no error
|
|
- ** occurs and the parse does not result in a new table, index or
|
|
- ** trigger object, the database must be corrupt. */
|
|
- memset(p, 0, sizeof(Parse));
|
|
p->eParseMode = PARSE_MODE_RENAME;
|
|
p->db = db;
|
|
p->nQueryLoop = 1;
|
|
- rc = sqlite3RunParser(p, zSql, &zErr);
|
|
- assert( p->zErrMsg==0 );
|
|
- assert( rc!=SQLITE_OK || zErr==0 );
|
|
- p->zErrMsg = zErr;
|
|
+ rc = sqlite3RunParser(p, zSql);
|
|
if( db->mallocFailed ) rc = SQLITE_NOMEM;
|
|
- if( rc==SQLITE_OK
|
|
- && p->pNewTable==0 && p->pNewIndex==0 && p->pNewTrigger==0
|
|
+ if( rc==SQLITE_OK
|
|
+ && NEVER(p->pNewTable==0 && p->pNewIndex==0 && p->pNewTrigger==0)
|
|
){
|
|
rc = SQLITE_CORRUPT_BKPT;
|
|
}
|
|
@@ -105671,56 +113559,81 @@ static int renameEditSql(
|
|
const char *zNew, /* New token text */
|
|
int bQuote /* True to always quote token */
|
|
){
|
|
- int nNew = sqlite3Strlen30(zNew);
|
|
- int nSql = sqlite3Strlen30(zSql);
|
|
+ i64 nNew = sqlite3Strlen30(zNew);
|
|
+ i64 nSql = sqlite3Strlen30(zSql);
|
|
sqlite3 *db = sqlite3_context_db_handle(pCtx);
|
|
int rc = SQLITE_OK;
|
|
- char *zQuot;
|
|
+ char *zQuot = 0;
|
|
char *zOut;
|
|
- int nQuot;
|
|
-
|
|
- /* Set zQuot to point to a buffer containing a quoted copy of the
|
|
- ** identifier zNew. If the corresponding identifier in the original
|
|
- ** ALTER TABLE statement was quoted (bQuote==1), then set zNew to
|
|
- ** point to zQuot so that all substitutions are made using the
|
|
- ** quoted version of the new column name. */
|
|
- zQuot = sqlite3MPrintf(db, "\"%w\"", zNew);
|
|
- if( zQuot==0 ){
|
|
- return SQLITE_NOMEM;
|
|
+ i64 nQuot = 0;
|
|
+ char *zBuf1 = 0;
|
|
+ char *zBuf2 = 0;
|
|
+
|
|
+ if( zNew ){
|
|
+ /* Set zQuot to point to a buffer containing a quoted copy of the
|
|
+ ** identifier zNew. If the corresponding identifier in the original
|
|
+ ** ALTER TABLE statement was quoted (bQuote==1), then set zNew to
|
|
+ ** point to zQuot so that all substitutions are made using the
|
|
+ ** quoted version of the new column name. */
|
|
+ zQuot = sqlite3MPrintf(db, "\"%w\" ", zNew);
|
|
+ if( zQuot==0 ){
|
|
+ return SQLITE_NOMEM;
|
|
+ }else{
|
|
+ nQuot = sqlite3Strlen30(zQuot)-1;
|
|
+ }
|
|
+
|
|
+ assert( nQuot>=nNew );
|
|
+ zOut = sqlite3DbMallocZero(db, nSql + pRename->nList*nQuot + 1);
|
|
}else{
|
|
- nQuot = sqlite3Strlen30(zQuot);
|
|
- }
|
|
- if( bQuote ){
|
|
- zNew = zQuot;
|
|
- nNew = nQuot;
|
|
+ zOut = (char*)sqlite3DbMallocZero(db, (nSql*2+1) * 3);
|
|
+ if( zOut ){
|
|
+ zBuf1 = &zOut[nSql*2+1];
|
|
+ zBuf2 = &zOut[nSql*4+2];
|
|
+ }
|
|
}
|
|
|
|
/* At this point pRename->pList contains a list of RenameToken objects
|
|
** corresponding to all tokens in the input SQL that must be replaced
|
|
- ** with the new column name. All that remains is to construct and
|
|
- ** return the edited SQL string. */
|
|
- assert( nQuot>=nNew );
|
|
- zOut = sqlite3DbMallocZero(db, nSql + pRename->nList*nQuot + 1);
|
|
+ ** with the new column name, or with single-quoted versions of themselves.
|
|
+ ** All that remains is to construct and return the edited SQL string. */
|
|
if( zOut ){
|
|
int nOut = nSql;
|
|
memcpy(zOut, zSql, nSql);
|
|
while( pRename->pList ){
|
|
int iOff; /* Offset of token to replace in zOut */
|
|
- RenameToken *pBest = renameColumnTokenNext(pRename);
|
|
-
|
|
u32 nReplace;
|
|
const char *zReplace;
|
|
- if( sqlite3IsIdChar(*pBest->t.z) ){
|
|
- nReplace = nNew;
|
|
- zReplace = zNew;
|
|
+ RenameToken *pBest = renameColumnTokenNext(pRename);
|
|
+
|
|
+ if( zNew ){
|
|
+ if( bQuote==0 && sqlite3IsIdChar(*pBest->t.z) ){
|
|
+ nReplace = nNew;
|
|
+ zReplace = zNew;
|
|
+ }else{
|
|
+ nReplace = nQuot;
|
|
+ zReplace = zQuot;
|
|
+ if( pBest->t.z[pBest->t.n]=='"' ) nReplace++;
|
|
+ }
|
|
}else{
|
|
- nReplace = nQuot;
|
|
- zReplace = zQuot;
|
|
+ /* Dequote the double-quoted token. Then requote it again, this time
|
|
+ ** using single quotes. If the character immediately following the
|
|
+ ** original token within the input SQL was a single quote ('), then
|
|
+ ** add another space after the new, single-quoted version of the
|
|
+ ** token. This is so that (SELECT "string"'alias') maps to
|
|
+ ** (SELECT 'string' 'alias'), and not (SELECT 'string''alias'). */
|
|
+ memcpy(zBuf1, pBest->t.z, pBest->t.n);
|
|
+ zBuf1[pBest->t.n] = 0;
|
|
+ sqlite3Dequote(zBuf1);
|
|
+ sqlite3_snprintf(nSql*2, zBuf2, "%Q%s", zBuf1,
|
|
+ pBest->t.z[pBest->t.n]=='\'' ? " " : ""
|
|
+ );
|
|
+ zReplace = zBuf2;
|
|
+ nReplace = sqlite3Strlen30(zReplace);
|
|
}
|
|
|
|
iOff = pBest->t.z - zSql;
|
|
if( pBest->t.n!=nReplace ){
|
|
- memmove(&zOut[iOff + nReplace], &zOut[iOff + pBest->t.n],
|
|
+ memmove(&zOut[iOff + nReplace], &zOut[iOff + pBest->t.n],
|
|
nOut - (iOff + pBest->t.n)
|
|
);
|
|
nOut += nReplace - pBest->t.n;
|
|
@@ -105742,11 +113655,11 @@ static int renameEditSql(
|
|
|
|
/*
|
|
** Resolve all symbols in the trigger at pParse->pNewTrigger, assuming
|
|
-** it was read from the schema of database zDb. Return SQLITE_OK if
|
|
+** it was read from the schema of database zDb. Return SQLITE_OK if
|
|
** successful. Otherwise, return an SQLite error code and leave an error
|
|
** message in the Parse object.
|
|
*/
|
|
-static int renameResolveTrigger(Parse *pParse, const char *zDb){
|
|
+static int renameResolveTrigger(Parse *pParse){
|
|
sqlite3 *db = pParse->db;
|
|
Trigger *pNew = pParse->pNewTrigger;
|
|
TriggerStep *pStep;
|
|
@@ -105756,7 +113669,7 @@ static int renameResolveTrigger(Parse *pParse, const char *zDb){
|
|
memset(&sNC, 0, sizeof(sNC));
|
|
sNC.pParse = pParse;
|
|
assert( pNew->pTabSchema );
|
|
- pParse->pTriggerTab = sqlite3FindTable(db, pNew->table,
|
|
+ pParse->pTriggerTab = sqlite3FindTable(db, pNew->table,
|
|
db->aDb[sqlite3SchemaToIndex(db, pNew->pTabSchema)].zDbSName
|
|
);
|
|
pParse->eTriggerOp = pNew->op;
|
|
@@ -105777,27 +113690,48 @@ static int renameResolveTrigger(Parse *pParse, const char *zDb){
|
|
if( pParse->nErr ) rc = pParse->rc;
|
|
}
|
|
if( rc==SQLITE_OK && pStep->zTarget ){
|
|
- Table *pTarget = sqlite3LocateTable(pParse, 0, pStep->zTarget, zDb);
|
|
- if( pTarget==0 ){
|
|
- rc = SQLITE_ERROR;
|
|
- }else if( SQLITE_OK==(rc = sqlite3ViewGetColumnNames(pParse, pTarget)) ){
|
|
- SrcList sSrc;
|
|
- memset(&sSrc, 0, sizeof(sSrc));
|
|
- sSrc.nSrc = 1;
|
|
- sSrc.a[0].zName = pStep->zTarget;
|
|
- sSrc.a[0].pTab = pTarget;
|
|
- sNC.pSrcList = &sSrc;
|
|
- if( pStep->pWhere ){
|
|
+ SrcList *pSrc = sqlite3TriggerStepSrc(pParse, pStep);
|
|
+ if( pSrc ){
|
|
+ Select *pSel = sqlite3SelectNew(
|
|
+ pParse, pStep->pExprList, pSrc, 0, 0, 0, 0, 0, 0
|
|
+ );
|
|
+ if( pSel==0 ){
|
|
+ pStep->pExprList = 0;
|
|
+ pSrc = 0;
|
|
+ rc = SQLITE_NOMEM;
|
|
+ }else{
|
|
+ sqlite3SelectPrep(pParse, pSel, 0);
|
|
+ rc = pParse->nErr ? SQLITE_ERROR : SQLITE_OK;
|
|
+ assert( pStep->pExprList==0 || pStep->pExprList==pSel->pEList );
|
|
+ assert( pSrc==pSel->pSrc );
|
|
+ if( pStep->pExprList ) pSel->pEList = 0;
|
|
+ pSel->pSrc = 0;
|
|
+ sqlite3SelectDelete(db, pSel);
|
|
+ }
|
|
+ if( pStep->pFrom ){
|
|
+ int i;
|
|
+ for(i=0; i<pStep->pFrom->nSrc && rc==SQLITE_OK; i++){
|
|
+ SrcItem *p = &pStep->pFrom->a[i];
|
|
+ if( p->pSelect ){
|
|
+ sqlite3SelectPrep(pParse, p->pSelect, 0);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if( db->mallocFailed ){
|
|
+ rc = SQLITE_NOMEM;
|
|
+ }
|
|
+ sNC.pSrcList = pSrc;
|
|
+ if( rc==SQLITE_OK && pStep->pWhere ){
|
|
rc = sqlite3ResolveExprNames(&sNC, pStep->pWhere);
|
|
}
|
|
if( rc==SQLITE_OK ){
|
|
rc = sqlite3ResolveExprListNames(&sNC, pStep->pExprList);
|
|
}
|
|
assert( !pStep->pUpsert || (!pStep->pWhere && !pStep->pExprList) );
|
|
- if( pStep->pUpsert ){
|
|
+ if( pStep->pUpsert && rc==SQLITE_OK ){
|
|
Upsert *pUpsert = pStep->pUpsert;
|
|
- assert( rc==SQLITE_OK );
|
|
- pUpsert->pUpsertSrc = &sSrc;
|
|
+ pUpsert->pUpsertSrc = pSrc;
|
|
sNC.uNC.pUpsert = pUpsert;
|
|
sNC.ncFlags = NC_UUpsert;
|
|
rc = sqlite3ResolveExprListNames(&sNC, pUpsert->pUpsertTarget);
|
|
@@ -105814,6 +113748,9 @@ static int renameResolveTrigger(Parse *pParse, const char *zDb){
|
|
sNC.ncFlags = 0;
|
|
}
|
|
sNC.pSrcList = 0;
|
|
+ sqlite3SrcListDelete(db, pSrc);
|
|
+ }else{
|
|
+ rc = SQLITE_NOMEM;
|
|
}
|
|
}
|
|
}
|
|
@@ -105842,6 +113779,12 @@ static void renameWalkTrigger(Walker *pWalker, Trigger *pTrigger){
|
|
sqlite3WalkExpr(pWalker, pUpsert->pUpsertWhere);
|
|
sqlite3WalkExpr(pWalker, pUpsert->pUpsertTargetWhere);
|
|
}
|
|
+ if( pStep->pFrom ){
|
|
+ int i;
|
|
+ for(i=0; i<pStep->pFrom->nSrc; i++){
|
|
+ sqlite3WalkSelect(pWalker, pStep->pFrom->a[i].pSelect);
|
|
+ }
|
|
+ }
|
|
}
|
|
}
|
|
|
|
@@ -105863,13 +113806,13 @@ static void renameParseCleanup(Parse *pParse){
|
|
sqlite3DeleteTrigger(db, pParse->pNewTrigger);
|
|
sqlite3DbFree(db, pParse->zErrMsg);
|
|
renameTokenFree(db, pParse->pRename);
|
|
- sqlite3ParserReset(pParse);
|
|
+ sqlite3ParseObjectReset(pParse);
|
|
}
|
|
|
|
/*
|
|
** SQL function:
|
|
**
|
|
-** sqlite_rename_column(zSql, iCol, bQuote, zNew, zTable, zOld)
|
|
+** sqlite_rename_column(SQL,TYPE,OBJ,DB,TABLE,COL,NEWNAME,QUOTE,TEMP)
|
|
**
|
|
** 0. zSql: SQL statement to rewrite
|
|
** 1. type: Type of object ("table", "view" etc.)
|
|
@@ -105887,7 +113830,8 @@ static void renameParseCleanup(Parse *pParse){
|
|
**
|
|
** This function is used internally by the ALTER TABLE RENAME COLUMN command.
|
|
** It is only accessible to SQL created using sqlite3NestedParse(). It is
|
|
-** not reachable from ordinary SQL passed into sqlite3_prepare().
|
|
+** not reachable from ordinary SQL passed into sqlite3_prepare() unless the
|
|
+** SQLITE_TESTCTRL_INTERNAL_FUNCTIONS test setting is enabled.
|
|
*/
|
|
static void renameColumnFunc(
|
|
sqlite3_context *context,
|
|
@@ -105925,7 +113869,7 @@ static void renameColumnFunc(
|
|
sqlite3BtreeLeaveAll(db);
|
|
return;
|
|
}
|
|
- zOld = pTab->aCol[iCol].zName;
|
|
+ zOld = pTab->aCol[iCol].zCnName;
|
|
memset(&sCtx, 0, sizeof(sCtx));
|
|
sCtx.iCol = ((iCol==pTab->iPKey) ? -1 : iCol);
|
|
|
|
@@ -105944,8 +113888,8 @@ static void renameColumnFunc(
|
|
sCtx.pTab = pTab;
|
|
if( rc!=SQLITE_OK ) goto renameColumnFunc_done;
|
|
if( sParse.pNewTable ){
|
|
- Select *pSelect = sParse.pNewTable->pSelect;
|
|
- if( pSelect ){
|
|
+ if( IsView(sParse.pNewTable) ){
|
|
+ Select *pSelect = sParse.pNewTable->u.view.pSelect;
|
|
pSelect->selFlags &= ~SF_View;
|
|
sParse.rc = SQLITE_OK;
|
|
sqlite3SelectPrep(&sParse, pSelect, 0);
|
|
@@ -105954,16 +113898,17 @@ static void renameColumnFunc(
|
|
sqlite3WalkSelect(&sWalker, pSelect);
|
|
}
|
|
if( rc!=SQLITE_OK ) goto renameColumnFunc_done;
|
|
- }else{
|
|
+ }else if( IsOrdinaryTable(sParse.pNewTable) ){
|
|
/* A regular table */
|
|
int bFKOnly = sqlite3_stricmp(zTable, sParse.pNewTable->zName);
|
|
FKey *pFKey;
|
|
- assert( sParse.pNewTable->pSelect==0 );
|
|
sCtx.pTab = sParse.pNewTable;
|
|
if( bFKOnly==0 ){
|
|
- renameTokenFind(
|
|
- &sParse, &sCtx, (void*)sParse.pNewTable->aCol[iCol].zName
|
|
- );
|
|
+ if( iCol<sParse.pNewTable->nCol ){
|
|
+ renameTokenFind(
|
|
+ &sParse, &sCtx, (void*)sParse.pNewTable->aCol[iCol].zCnName
|
|
+ );
|
|
+ }
|
|
if( sCtx.iCol<0 ){
|
|
renameTokenFind(&sParse, &sCtx, (void*)&sParse.pNewTable->iPKey);
|
|
}
|
|
@@ -105974,14 +113919,17 @@ static void renameColumnFunc(
|
|
for(pIdx=sParse.pNewIndex; pIdx; pIdx=pIdx->pNext){
|
|
sqlite3WalkExprList(&sWalker, pIdx->aColExpr);
|
|
}
|
|
- }
|
|
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
|
|
- for(i=0; i<sParse.pNewTable->nCol; i++){
|
|
- sqlite3WalkExpr(&sWalker, sParse.pNewTable->aCol[i].pDflt);
|
|
- }
|
|
+ for(i=0; i<sParse.pNewTable->nCol; i++){
|
|
+ Expr *pExpr = sqlite3ColumnExpr(sParse.pNewTable,
|
|
+ &sParse.pNewTable->aCol[i]);
|
|
+ sqlite3WalkExpr(&sWalker, pExpr);
|
|
+ }
|
|
#endif
|
|
+ }
|
|
|
|
- for(pFKey=sParse.pNewTable->pFKey; pFKey; pFKey=pFKey->pNextFrom){
|
|
+ assert( IsOrdinaryTable(sParse.pNewTable) );
|
|
+ for(pFKey=sParse.pNewTable->u.tab.pFKey; pFKey; pFKey=pFKey->pNextFrom){
|
|
for(i=0; i<pFKey->nCol; i++){
|
|
if( bFKOnly==0 && pFKey->aCol[i].iFrom==iCol ){
|
|
renameTokenFind(&sParse, &sCtx, (void*)&pFKey->aCol[i]);
|
|
@@ -106000,11 +113948,11 @@ static void renameColumnFunc(
|
|
}else{
|
|
/* A trigger */
|
|
TriggerStep *pStep;
|
|
- rc = renameResolveTrigger(&sParse, (bTemp ? 0 : zDb));
|
|
+ rc = renameResolveTrigger(&sParse);
|
|
if( rc!=SQLITE_OK ) goto renameColumnFunc_done;
|
|
|
|
for(pStep=sParse.pNewTrigger->step_list; pStep; pStep=pStep->pNext){
|
|
- if( pStep->zTarget ){
|
|
+ if( pStep->zTarget ){
|
|
Table *pTarget = sqlite3LocateTable(&sParse, 0, pStep->zTarget, zDb);
|
|
if( pTarget==pTab ){
|
|
if( pStep->pUpsert ){
|
|
@@ -106032,8 +113980,10 @@ static void renameColumnFunc(
|
|
|
|
renameColumnFunc_done:
|
|
if( rc!=SQLITE_OK ){
|
|
- if( sParse.zErrMsg ){
|
|
- renameColumnParseError(context, 0, argv[1], argv[2], &sParse);
|
|
+ if( rc==SQLITE_ERROR && sqlite3WritableSchema(db) ){
|
|
+ sqlite3_result_value(context, argv[0]);
|
|
+ }else if( sParse.zErrMsg ){
|
|
+ renameColumnParseError(context, "", argv[1], argv[2], &sParse);
|
|
}else{
|
|
sqlite3_result_error_code(context, rc);
|
|
}
|
|
@@ -106048,30 +113998,37 @@ static void renameColumnFunc(
|
|
}
|
|
|
|
/*
|
|
-** Walker expression callback used by "RENAME TABLE".
|
|
+** Walker expression callback used by "RENAME TABLE".
|
|
*/
|
|
static int renameTableExprCb(Walker *pWalker, Expr *pExpr){
|
|
RenameCtx *p = pWalker->u.pRename;
|
|
- if( pExpr->op==TK_COLUMN && p->pTab==pExpr->y.pTab ){
|
|
+ if( pExpr->op==TK_COLUMN
|
|
+ && ALWAYS(ExprUseYTab(pExpr))
|
|
+ && p->pTab==pExpr->y.pTab
|
|
+ ){
|
|
renameTokenFind(pWalker->pParse, p, (void*)&pExpr->y.pTab);
|
|
}
|
|
return WRC_Continue;
|
|
}
|
|
|
|
/*
|
|
-** Walker select callback used by "RENAME TABLE".
|
|
+** Walker select callback used by "RENAME TABLE".
|
|
*/
|
|
static int renameTableSelectCb(Walker *pWalker, Select *pSelect){
|
|
int i;
|
|
RenameCtx *p = pWalker->u.pRename;
|
|
SrcList *pSrc = pSelect->pSrc;
|
|
- if( pSelect->selFlags & SF_View ) return WRC_Prune;
|
|
- if( pSrc==0 ){
|
|
+ if( pSelect->selFlags & (SF_View|SF_CopyCte) ){
|
|
+ testcase( pSelect->selFlags & SF_View );
|
|
+ testcase( pSelect->selFlags & SF_CopyCte );
|
|
+ return WRC_Prune;
|
|
+ }
|
|
+ if( NEVER(pSrc==0) ){
|
|
assert( pWalker->pParse->db->mallocFailed );
|
|
return WRC_Abort;
|
|
}
|
|
for(i=0; i<pSrc->nSrc; i++){
|
|
- struct SrcList_item *pItem = &pSrc->a[i];
|
|
+ SrcItem *pItem = &pSrc->a[i];
|
|
if( pItem->pTab==p->pTab ){
|
|
renameTokenFind(pWalker->pParse, p, pItem->zName);
|
|
}
|
|
@@ -106085,7 +114042,7 @@ static int renameTableSelectCb(Walker *pWalker, Select *pSelect){
|
|
/*
|
|
** This C function implements an SQL user function that is used by SQL code
|
|
** generated by the ALTER TABLE ... RENAME command to modify the definition
|
|
-** of any foreign key constraints that use the table being renamed as the
|
|
+** of any foreign key constraints that use the table being renamed as the
|
|
** parent table. It is passed three arguments:
|
|
**
|
|
** 0: The database containing the table being renamed.
|
|
@@ -106143,28 +114100,31 @@ static void renameTableFunc(
|
|
if( sParse.pNewTable ){
|
|
Table *pTab = sParse.pNewTable;
|
|
|
|
- if( pTab->pSelect ){
|
|
+ if( IsView(pTab) ){
|
|
if( isLegacy==0 ){
|
|
- Select *pSelect = pTab->pSelect;
|
|
+ Select *pSelect = pTab->u.view.pSelect;
|
|
NameContext sNC;
|
|
memset(&sNC, 0, sizeof(sNC));
|
|
sNC.pParse = &sParse;
|
|
|
|
assert( pSelect->selFlags & SF_View );
|
|
pSelect->selFlags &= ~SF_View;
|
|
- sqlite3SelectPrep(&sParse, pTab->pSelect, &sNC);
|
|
+ sqlite3SelectPrep(&sParse, pTab->u.view.pSelect, &sNC);
|
|
if( sParse.nErr ){
|
|
rc = sParse.rc;
|
|
}else{
|
|
- sqlite3WalkSelect(&sWalker, pTab->pSelect);
|
|
+ sqlite3WalkSelect(&sWalker, pTab->u.view.pSelect);
|
|
}
|
|
}
|
|
}else{
|
|
/* Modify any FK definitions to point to the new table. */
|
|
#ifndef SQLITE_OMIT_FOREIGN_KEY
|
|
- if( isLegacy==0 || (db->flags & SQLITE_ForeignKeys) ){
|
|
+ if( (isLegacy==0 || (db->flags & SQLITE_ForeignKeys))
|
|
+ && !IsVirtual(pTab)
|
|
+ ){
|
|
FKey *pFKey;
|
|
- for(pFKey=pTab->pFKey; pFKey; pFKey=pFKey->pNextFrom){
|
|
+ assert( IsOrdinaryTable(pTab) );
|
|
+ for(pFKey=pTab->u.tab.pFKey; pFKey; pFKey=pFKey->pNextFrom){
|
|
if( sqlite3_stricmp(pFKey->zTo, zOld)==0 ){
|
|
renameTokenFind(&sParse, &sCtx, (void*)pFKey->zTo);
|
|
}
|
|
@@ -106196,20 +114156,29 @@ static void renameTableFunc(
|
|
else{
|
|
Trigger *pTrigger = sParse.pNewTrigger;
|
|
TriggerStep *pStep;
|
|
- if( 0==sqlite3_stricmp(sParse.pNewTrigger->table, zOld)
|
|
+ if( 0==sqlite3_stricmp(sParse.pNewTrigger->table, zOld)
|
|
&& sCtx.pTab->pSchema==pTrigger->pTabSchema
|
|
){
|
|
renameTokenFind(&sParse, &sCtx, sParse.pNewTrigger->table);
|
|
}
|
|
|
|
if( isLegacy==0 ){
|
|
- rc = renameResolveTrigger(&sParse, bTemp ? 0 : zDb);
|
|
+ rc = renameResolveTrigger(&sParse);
|
|
if( rc==SQLITE_OK ){
|
|
renameWalkTrigger(&sWalker, pTrigger);
|
|
for(pStep=pTrigger->step_list; pStep; pStep=pStep->pNext){
|
|
if( pStep->zTarget && 0==sqlite3_stricmp(pStep->zTarget, zOld) ){
|
|
renameTokenFind(&sParse, &sCtx, pStep->zTarget);
|
|
}
|
|
+ if( pStep->pFrom ){
|
|
+ int i;
|
|
+ for(i=0; i<pStep->pFrom->nSrc; i++){
|
|
+ SrcItem *pItem = &pStep->pFrom->a[i];
|
|
+ if( 0==sqlite3_stricmp(pItem->zName, zOld) ){
|
|
+ renameTokenFind(&sParse, &sCtx, pItem->zName);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
@@ -106221,8 +114190,10 @@ static void renameTableFunc(
|
|
rc = renameEditSql(context, &sCtx, zInput, zNew, bQuote);
|
|
}
|
|
if( rc!=SQLITE_OK ){
|
|
- if( sParse.zErrMsg ){
|
|
- renameColumnParseError(context, 0, argv[1], argv[2], &sParse);
|
|
+ if( rc==SQLITE_ERROR && sqlite3WritableSchema(db) ){
|
|
+ sqlite3_result_value(context, argv[3]);
|
|
+ }else if( sParse.zErrMsg ){
|
|
+ renameColumnParseError(context, "", argv[1], argv[2], &sParse);
|
|
}else{
|
|
sqlite3_result_error_code(context, rc);
|
|
}
|
|
@@ -106239,7 +114210,131 @@ static void renameTableFunc(
|
|
return;
|
|
}
|
|
|
|
-/*
|
|
+static int renameQuotefixExprCb(Walker *pWalker, Expr *pExpr){
|
|
+ if( pExpr->op==TK_STRING && (pExpr->flags & EP_DblQuoted) ){
|
|
+ renameTokenFind(pWalker->pParse, pWalker->u.pRename, (const void*)pExpr);
|
|
+ }
|
|
+ return WRC_Continue;
|
|
+}
|
|
+
|
|
+/* SQL function: sqlite_rename_quotefix(DB,SQL)
|
|
+**
|
|
+** Rewrite the DDL statement "SQL" so that any string literals that use
|
|
+** double-quotes use single quotes instead.
|
|
+**
|
|
+** Two arguments must be passed:
|
|
+**
|
|
+** 0: Database name ("main", "temp" etc.).
|
|
+** 1: SQL statement to edit.
|
|
+**
|
|
+** The returned value is the modified SQL statement. For example, given
|
|
+** the database schema:
|
|
+**
|
|
+** CREATE TABLE t1(a, b, c);
|
|
+**
|
|
+** SELECT sqlite_rename_quotefix('main',
|
|
+** 'CREATE VIEW v1 AS SELECT "a", "string" FROM t1'
|
|
+** );
|
|
+**
|
|
+** returns the string:
|
|
+**
|
|
+** CREATE VIEW v1 AS SELECT "a", 'string' FROM t1
|
|
+**
|
|
+** If there is a error in the input SQL, then raise an error, except
|
|
+** if PRAGMA writable_schema=ON, then just return the input string
|
|
+** unmodified following an error.
|
|
+*/
|
|
+static void renameQuotefixFunc(
|
|
+ sqlite3_context *context,
|
|
+ int NotUsed,
|
|
+ sqlite3_value **argv
|
|
+){
|
|
+ sqlite3 *db = sqlite3_context_db_handle(context);
|
|
+ char const *zDb = (const char*)sqlite3_value_text(argv[0]);
|
|
+ char const *zInput = (const char*)sqlite3_value_text(argv[1]);
|
|
+
|
|
+#ifndef SQLITE_OMIT_AUTHORIZATION
|
|
+ sqlite3_xauth xAuth = db->xAuth;
|
|
+ db->xAuth = 0;
|
|
+#endif
|
|
+
|
|
+ sqlite3BtreeEnterAll(db);
|
|
+
|
|
+ UNUSED_PARAMETER(NotUsed);
|
|
+ if( zDb && zInput ){
|
|
+ int rc;
|
|
+ Parse sParse;
|
|
+ rc = renameParseSql(&sParse, zDb, db, zInput, 0);
|
|
+
|
|
+ if( rc==SQLITE_OK ){
|
|
+ RenameCtx sCtx;
|
|
+ Walker sWalker;
|
|
+
|
|
+ /* Walker to find tokens that need to be replaced. */
|
|
+ memset(&sCtx, 0, sizeof(RenameCtx));
|
|
+ memset(&sWalker, 0, sizeof(Walker));
|
|
+ sWalker.pParse = &sParse;
|
|
+ sWalker.xExprCallback = renameQuotefixExprCb;
|
|
+ sWalker.xSelectCallback = renameColumnSelectCb;
|
|
+ sWalker.u.pRename = &sCtx;
|
|
+
|
|
+ if( sParse.pNewTable ){
|
|
+ if( IsView(sParse.pNewTable) ){
|
|
+ Select *pSelect = sParse.pNewTable->u.view.pSelect;
|
|
+ pSelect->selFlags &= ~SF_View;
|
|
+ sParse.rc = SQLITE_OK;
|
|
+ sqlite3SelectPrep(&sParse, pSelect, 0);
|
|
+ rc = (db->mallocFailed ? SQLITE_NOMEM : sParse.rc);
|
|
+ if( rc==SQLITE_OK ){
|
|
+ sqlite3WalkSelect(&sWalker, pSelect);
|
|
+ }
|
|
+ }else{
|
|
+ int i;
|
|
+ sqlite3WalkExprList(&sWalker, sParse.pNewTable->pCheck);
|
|
+#ifndef SQLITE_OMIT_GENERATED_COLUMNS
|
|
+ for(i=0; i<sParse.pNewTable->nCol; i++){
|
|
+ sqlite3WalkExpr(&sWalker,
|
|
+ sqlite3ColumnExpr(sParse.pNewTable,
|
|
+ &sParse.pNewTable->aCol[i]));
|
|
+ }
|
|
+#endif /* SQLITE_OMIT_GENERATED_COLUMNS */
|
|
+ }
|
|
+ }else if( sParse.pNewIndex ){
|
|
+ sqlite3WalkExprList(&sWalker, sParse.pNewIndex->aColExpr);
|
|
+ sqlite3WalkExpr(&sWalker, sParse.pNewIndex->pPartIdxWhere);
|
|
+ }else{
|
|
+#ifndef SQLITE_OMIT_TRIGGER
|
|
+ rc = renameResolveTrigger(&sParse);
|
|
+ if( rc==SQLITE_OK ){
|
|
+ renameWalkTrigger(&sWalker, sParse.pNewTrigger);
|
|
+ }
|
|
+#endif /* SQLITE_OMIT_TRIGGER */
|
|
+ }
|
|
+
|
|
+ if( rc==SQLITE_OK ){
|
|
+ rc = renameEditSql(context, &sCtx, zInput, 0, 0);
|
|
+ }
|
|
+ renameTokenFree(db, sCtx.pList);
|
|
+ }
|
|
+ if( rc!=SQLITE_OK ){
|
|
+ if( sqlite3WritableSchema(db) && rc==SQLITE_ERROR ){
|
|
+ sqlite3_result_value(context, argv[1]);
|
|
+ }else{
|
|
+ sqlite3_result_error_code(context, rc);
|
|
+ }
|
|
+ }
|
|
+ renameParseCleanup(&sParse);
|
|
+ }
|
|
+
|
|
+#ifndef SQLITE_OMIT_AUTHORIZATION
|
|
+ db->xAuth = xAuth;
|
|
+#endif
|
|
+
|
|
+ sqlite3BtreeLeaveAll(db);
|
|
+}
|
|
+
|
|
+/* Function: sqlite_rename_test(DB,SQL,TYPE,NAME,ISTEMP,WHEN,DQS)
|
|
+**
|
|
** An SQL user function that checks that there are no parse or symbol
|
|
** resolution problems in a CREATE TRIGGER|TABLE|VIEW|INDEX statement.
|
|
** After an ALTER TABLE .. RENAME operation is performed and the schema
|
|
@@ -106251,12 +114346,16 @@ static void renameTableFunc(
|
|
** 2: Object type ("view", "table", "trigger" or "index").
|
|
** 3: Object name.
|
|
** 4: True if object is from temp schema.
|
|
+** 5: "when" part of error message.
|
|
+** 6: True to disable the DQS quirk when parsing SQL.
|
|
**
|
|
-** Unless it finds an error, this function normally returns NULL. However, it
|
|
-** returns integer value 1 if:
|
|
+** The return value is computed as follows:
|
|
**
|
|
-** * the SQL argument creates a trigger, and
|
|
-** * the table that the trigger is attached to is in database zDb.
|
|
+** A. If an error is seen and not in PRAGMA writable_schema=ON mode,
|
|
+** then raise the error.
|
|
+** B. Else if a trigger is created and the the table that the trigger is
|
|
+** attached to is in database zDb, then return 1.
|
|
+** C. Otherwise return NULL.
|
|
*/
|
|
static void renameTableTest(
|
|
sqlite3_context *context,
|
|
@@ -106268,6 +114367,8 @@ static void renameTableTest(
|
|
char const *zInput = (const char*)sqlite3_value_text(argv[1]);
|
|
int bTemp = sqlite3_value_int(argv[4]);
|
|
int isLegacy = (db->flags & SQLITE_LegacyAlter);
|
|
+ char const *zWhen = (const char*)sqlite3_value_text(argv[5]);
|
|
+ int bNoDQS = sqlite3_value_int(argv[6]);
|
|
|
|
#ifndef SQLITE_OMIT_AUTHORIZATION
|
|
sqlite3_xauth xAuth = db->xAuth;
|
|
@@ -106275,33 +114376,41 @@ static void renameTableTest(
|
|
#endif
|
|
|
|
UNUSED_PARAMETER(NotUsed);
|
|
+
|
|
if( zDb && zInput ){
|
|
int rc;
|
|
Parse sParse;
|
|
+ int flags = db->flags;
|
|
+ if( bNoDQS ) db->flags &= ~(SQLITE_DqsDML|SQLITE_DqsDDL);
|
|
rc = renameParseSql(&sParse, zDb, db, zInput, bTemp);
|
|
+ db->flags |= (flags & (SQLITE_DqsDML|SQLITE_DqsDDL));
|
|
if( rc==SQLITE_OK ){
|
|
- if( isLegacy==0 && sParse.pNewTable && sParse.pNewTable->pSelect ){
|
|
+ if( isLegacy==0 && sParse.pNewTable && IsView(sParse.pNewTable) ){
|
|
NameContext sNC;
|
|
memset(&sNC, 0, sizeof(sNC));
|
|
sNC.pParse = &sParse;
|
|
- sqlite3SelectPrep(&sParse, sParse.pNewTable->pSelect, &sNC);
|
|
+ sqlite3SelectPrep(&sParse, sParse.pNewTable->u.view.pSelect, &sNC);
|
|
if( sParse.nErr ) rc = sParse.rc;
|
|
}
|
|
|
|
else if( sParse.pNewTrigger ){
|
|
if( isLegacy==0 ){
|
|
- rc = renameResolveTrigger(&sParse, bTemp ? 0 : zDb);
|
|
+ rc = renameResolveTrigger(&sParse);
|
|
}
|
|
if( rc==SQLITE_OK ){
|
|
int i1 = sqlite3SchemaToIndex(db, sParse.pNewTrigger->pTabSchema);
|
|
int i2 = sqlite3FindDbName(db, zDb);
|
|
- if( i1==i2 ) sqlite3_result_int(context, 1);
|
|
+ if( i1==i2 ){
|
|
+ /* Handle output case B */
|
|
+ sqlite3_result_int(context, 1);
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
|
|
- if( rc!=SQLITE_OK ){
|
|
- renameColumnParseError(context, 1, argv[2], argv[3], &sParse);
|
|
+ if( rc!=SQLITE_OK && zWhen && !sqlite3WritableSchema(db) ){
|
|
+ /* Output case A */
|
|
+ renameColumnParseError(context, zWhen, argv[2], argv[3],&sParse);
|
|
}
|
|
renameParseCleanup(&sParse);
|
|
}
|
|
@@ -106311,14 +114420,232 @@ static void renameTableTest(
|
|
#endif
|
|
}
|
|
|
|
+/*
|
|
+** The implementation of internal UDF sqlite_drop_column().
|
|
+**
|
|
+** Arguments:
|
|
+**
|
|
+** argv[0]: An integer - the index of the schema containing the table
|
|
+** argv[1]: CREATE TABLE statement to modify.
|
|
+** argv[2]: An integer - the index of the column to remove.
|
|
+**
|
|
+** The value returned is a string containing the CREATE TABLE statement
|
|
+** with column argv[2] removed.
|
|
+*/
|
|
+static void dropColumnFunc(
|
|
+ sqlite3_context *context,
|
|
+ int NotUsed,
|
|
+ sqlite3_value **argv
|
|
+){
|
|
+ sqlite3 *db = sqlite3_context_db_handle(context);
|
|
+ int iSchema = sqlite3_value_int(argv[0]);
|
|
+ const char *zSql = (const char*)sqlite3_value_text(argv[1]);
|
|
+ int iCol = sqlite3_value_int(argv[2]);
|
|
+ const char *zDb = db->aDb[iSchema].zDbSName;
|
|
+ int rc;
|
|
+ Parse sParse;
|
|
+ RenameToken *pCol;
|
|
+ Table *pTab;
|
|
+ const char *zEnd;
|
|
+ char *zNew = 0;
|
|
+
|
|
+#ifndef SQLITE_OMIT_AUTHORIZATION
|
|
+ sqlite3_xauth xAuth = db->xAuth;
|
|
+ db->xAuth = 0;
|
|
+#endif
|
|
+
|
|
+ UNUSED_PARAMETER(NotUsed);
|
|
+ rc = renameParseSql(&sParse, zDb, db, zSql, iSchema==1);
|
|
+ if( rc!=SQLITE_OK ) goto drop_column_done;
|
|
+ pTab = sParse.pNewTable;
|
|
+ if( pTab==0 || pTab->nCol==1 || iCol>=pTab->nCol ){
|
|
+ /* This can happen if the sqlite_schema table is corrupt */
|
|
+ rc = SQLITE_CORRUPT_BKPT;
|
|
+ goto drop_column_done;
|
|
+ }
|
|
+
|
|
+ pCol = renameTokenFind(&sParse, 0, (void*)pTab->aCol[iCol].zCnName);
|
|
+ if( iCol<pTab->nCol-1 ){
|
|
+ RenameToken *pEnd;
|
|
+ pEnd = renameTokenFind(&sParse, 0, (void*)pTab->aCol[iCol+1].zCnName);
|
|
+ zEnd = (const char*)pEnd->t.z;
|
|
+ }else{
|
|
+ assert( IsOrdinaryTable(pTab) );
|
|
+ zEnd = (const char*)&zSql[pTab->u.tab.addColOffset];
|
|
+ while( ALWAYS(pCol->t.z[0]!=0) && pCol->t.z[0]!=',' ) pCol->t.z--;
|
|
+ }
|
|
+
|
|
+ zNew = sqlite3MPrintf(db, "%.*s%s", pCol->t.z-zSql, zSql, zEnd);
|
|
+ sqlite3_result_text(context, zNew, -1, SQLITE_TRANSIENT);
|
|
+ sqlite3_free(zNew);
|
|
+
|
|
+drop_column_done:
|
|
+ renameParseCleanup(&sParse);
|
|
+#ifndef SQLITE_OMIT_AUTHORIZATION
|
|
+ db->xAuth = xAuth;
|
|
+#endif
|
|
+ if( rc!=SQLITE_OK ){
|
|
+ sqlite3_result_error_code(context, rc);
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+** This function is called by the parser upon parsing an
|
|
+**
|
|
+** ALTER TABLE pSrc DROP COLUMN pName
|
|
+**
|
|
+** statement. Argument pSrc contains the possibly qualified name of the
|
|
+** table being edited, and token pName the name of the column to drop.
|
|
+*/
|
|
+SQLITE_PRIVATE void sqlite3AlterDropColumn(Parse *pParse, SrcList *pSrc, const Token *pName){
|
|
+ sqlite3 *db = pParse->db; /* Database handle */
|
|
+ Table *pTab; /* Table to modify */
|
|
+ int iDb; /* Index of db containing pTab in aDb[] */
|
|
+ const char *zDb; /* Database containing pTab ("main" etc.) */
|
|
+ char *zCol = 0; /* Name of column to drop */
|
|
+ int iCol; /* Index of column zCol in pTab->aCol[] */
|
|
+
|
|
+ /* Look up the table being altered. */
|
|
+ assert( pParse->pNewTable==0 );
|
|
+ assert( sqlite3BtreeHoldsAllMutexes(db) );
|
|
+ if( NEVER(db->mallocFailed) ) goto exit_drop_column;
|
|
+ pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]);
|
|
+ if( !pTab ) goto exit_drop_column;
|
|
+
|
|
+ /* Make sure this is not an attempt to ALTER a view, virtual table or
|
|
+ ** system table. */
|
|
+ if( SQLITE_OK!=isAlterableTable(pParse, pTab) ) goto exit_drop_column;
|
|
+ if( SQLITE_OK!=isRealTable(pParse, pTab, 1) ) goto exit_drop_column;
|
|
+
|
|
+ /* Find the index of the column being dropped. */
|
|
+ zCol = sqlite3NameFromToken(db, pName);
|
|
+ if( zCol==0 ){
|
|
+ assert( db->mallocFailed );
|
|
+ goto exit_drop_column;
|
|
+ }
|
|
+ iCol = sqlite3ColumnIndex(pTab, zCol);
|
|
+ if( iCol<0 ){
|
|
+ sqlite3ErrorMsg(pParse, "no such column: \"%T\"", pName);
|
|
+ goto exit_drop_column;
|
|
+ }
|
|
+
|
|
+ /* Do not allow the user to drop a PRIMARY KEY column or a column
|
|
+ ** constrained by a UNIQUE constraint. */
|
|
+ if( pTab->aCol[iCol].colFlags & (COLFLAG_PRIMKEY|COLFLAG_UNIQUE) ){
|
|
+ sqlite3ErrorMsg(pParse, "cannot drop %s column: \"%s\"",
|
|
+ (pTab->aCol[iCol].colFlags&COLFLAG_PRIMKEY) ? "PRIMARY KEY" : "UNIQUE",
|
|
+ zCol
|
|
+ );
|
|
+ goto exit_drop_column;
|
|
+ }
|
|
+
|
|
+ /* Do not allow the number of columns to go to zero */
|
|
+ if( pTab->nCol<=1 ){
|
|
+ sqlite3ErrorMsg(pParse, "cannot drop column \"%s\": no other columns exist",zCol);
|
|
+ goto exit_drop_column;
|
|
+ }
|
|
+
|
|
+ /* Edit the sqlite_schema table */
|
|
+ iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
|
+ assert( iDb>=0 );
|
|
+ zDb = db->aDb[iDb].zDbSName;
|
|
+#ifndef SQLITE_OMIT_AUTHORIZATION
|
|
+ /* Invoke the authorization callback. */
|
|
+ if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab->zName, zCol) ){
|
|
+ goto exit_drop_column;
|
|
+ }
|
|
+#endif
|
|
+ renameTestSchema(pParse, zDb, iDb==1, "", 0);
|
|
+ renameFixQuotes(pParse, zDb, iDb==1);
|
|
+ sqlite3NestedParse(pParse,
|
|
+ "UPDATE \"%w\"." LEGACY_SCHEMA_TABLE " SET "
|
|
+ "sql = sqlite_drop_column(%d, sql, %d) "
|
|
+ "WHERE (type=='table' AND tbl_name=%Q COLLATE nocase)"
|
|
+ , zDb, iDb, iCol, pTab->zName
|
|
+ );
|
|
+
|
|
+ /* Drop and reload the database schema. */
|
|
+ renameReloadSchema(pParse, iDb, INITFLAG_AlterDrop);
|
|
+ renameTestSchema(pParse, zDb, iDb==1, "after drop column", 1);
|
|
+
|
|
+ /* Edit rows of table on disk */
|
|
+ if( pParse->nErr==0 && (pTab->aCol[iCol].colFlags & COLFLAG_VIRTUAL)==0 ){
|
|
+ int i;
|
|
+ int addr;
|
|
+ int reg;
|
|
+ int regRec;
|
|
+ Index *pPk = 0;
|
|
+ int nField = 0; /* Number of non-virtual columns after drop */
|
|
+ int iCur;
|
|
+ Vdbe *v = sqlite3GetVdbe(pParse);
|
|
+ iCur = pParse->nTab++;
|
|
+ sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenWrite);
|
|
+ addr = sqlite3VdbeAddOp1(v, OP_Rewind, iCur); VdbeCoverage(v);
|
|
+ reg = ++pParse->nMem;
|
|
+ if( HasRowid(pTab) ){
|
|
+ sqlite3VdbeAddOp2(v, OP_Rowid, iCur, reg);
|
|
+ pParse->nMem += pTab->nCol;
|
|
+ }else{
|
|
+ pPk = sqlite3PrimaryKeyIndex(pTab);
|
|
+ pParse->nMem += pPk->nColumn;
|
|
+ for(i=0; i<pPk->nKeyCol; i++){
|
|
+ sqlite3VdbeAddOp3(v, OP_Column, iCur, i, reg+i+1);
|
|
+ }
|
|
+ nField = pPk->nKeyCol;
|
|
+ }
|
|
+ regRec = ++pParse->nMem;
|
|
+ for(i=0; i<pTab->nCol; i++){
|
|
+ if( i!=iCol && (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ){
|
|
+ int regOut;
|
|
+ if( pPk ){
|
|
+ int iPos = sqlite3TableColumnToIndex(pPk, i);
|
|
+ int iColPos = sqlite3TableColumnToIndex(pPk, iCol);
|
|
+ if( iPos<pPk->nKeyCol ) continue;
|
|
+ regOut = reg+1+iPos-(iPos>iColPos);
|
|
+ }else{
|
|
+ regOut = reg+1+nField;
|
|
+ }
|
|
+ if( i==pTab->iPKey ){
|
|
+ sqlite3VdbeAddOp2(v, OP_Null, 0, regOut);
|
|
+ }else{
|
|
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, i, regOut);
|
|
+ }
|
|
+ nField++;
|
|
+ }
|
|
+ }
|
|
+ if( nField==0 ){
|
|
+ /* dbsqlfuzz 5f09e7bcc78b4954d06bf9f2400d7715f48d1fef */
|
|
+ pParse->nMem++;
|
|
+ sqlite3VdbeAddOp2(v, OP_Null, 0, reg+1);
|
|
+ nField = 1;
|
|
+ }
|
|
+ sqlite3VdbeAddOp3(v, OP_MakeRecord, reg+1, nField, regRec);
|
|
+ if( pPk ){
|
|
+ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iCur, regRec, reg+1, pPk->nKeyCol);
|
|
+ }else{
|
|
+ sqlite3VdbeAddOp3(v, OP_Insert, iCur, regRec, reg);
|
|
+ }
|
|
+ sqlite3VdbeChangeP5(v, OPFLAG_SAVEPOSITION);
|
|
+
|
|
+ sqlite3VdbeAddOp2(v, OP_Next, iCur, addr+1); VdbeCoverage(v);
|
|
+ sqlite3VdbeJumpHere(v, addr);
|
|
+ }
|
|
+
|
|
+exit_drop_column:
|
|
+ sqlite3DbFree(db, zCol);
|
|
+ sqlite3SrcListDelete(db, pSrc);
|
|
+}
|
|
+
|
|
/*
|
|
** Register built-in functions used to help implement ALTER TABLE
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3AlterFunctions(void){
|
|
static FuncDef aAlterTableFuncs[] = {
|
|
- INTERNAL_FUNCTION(sqlite_rename_column, 9, renameColumnFunc),
|
|
- INTERNAL_FUNCTION(sqlite_rename_table, 7, renameTableFunc),
|
|
- INTERNAL_FUNCTION(sqlite_rename_test, 5, renameTableTest),
|
|
+ INTERNAL_FUNCTION(sqlite_rename_column, 9, renameColumnFunc),
|
|
+ INTERNAL_FUNCTION(sqlite_rename_table, 7, renameTableFunc),
|
|
+ INTERNAL_FUNCTION(sqlite_rename_test, 7, renameTableTest),
|
|
+ INTERNAL_FUNCTION(sqlite_drop_column, 3, dropColumnFunc),
|
|
+ INTERNAL_FUNCTION(sqlite_rename_quotefix,2, renameQuotefixFunc),
|
|
};
|
|
sqlite3InsertBuiltinFuncs(aAlterTableFuncs, ArraySize(aAlterTableFuncs));
|
|
}
|
|
@@ -106358,7 +114685,7 @@ SQLITE_PRIVATE void sqlite3AlterFunctions(void){
|
|
** created and used by SQLite versions 3.7.9 through 3.29.0 when
|
|
** SQLITE_ENABLE_STAT3 defined. The functionality of sqlite_stat3
|
|
** is a superset of sqlite_stat2 and is also now deprecated. The
|
|
-** sqlite_stat4 is an enhanced version of sqlite_stat3 and is only
|
|
+** sqlite_stat4 is an enhanced version of sqlite_stat3 and is only
|
|
** available when compiled with SQLITE_ENABLE_STAT4 and in SQLite
|
|
** versions 3.8.1 and later. STAT4 is the only variant that is still
|
|
** supported.
|
|
@@ -106377,7 +114704,7 @@ SQLITE_PRIVATE void sqlite3AlterFunctions(void){
|
|
** integer is the average number of rows in the index that have the same
|
|
** value in the first column of the index. The third integer is the average
|
|
** number of rows in the index that have the same value for the first two
|
|
-** columns. The N-th integer (for N>1) is the average number of rows in
|
|
+** columns. The N-th integer (for N>1) is the average number of rows in
|
|
** the index which have the same value for the first N-1 columns. For
|
|
** a K-column index, there will be K+1 integers in the stat column. If
|
|
** the index is unique, then the last integer will be 1.
|
|
@@ -106387,7 +114714,7 @@ SQLITE_PRIVATE void sqlite3AlterFunctions(void){
|
|
** must be separated from the last integer by a single space. If the
|
|
** "unordered" keyword is present, then the query planner assumes that
|
|
** the index is unordered and will not use the index for a range query.
|
|
-**
|
|
+**
|
|
** If the sqlite_stat1.idx column is NULL, then the sqlite_stat1.stat
|
|
** column contains a single integer which is the (estimated) number of
|
|
** rows in the table identified by sqlite_stat1.tbl.
|
|
@@ -106445,9 +114772,9 @@ SQLITE_PRIVATE void sqlite3AlterFunctions(void){
|
|
** number of entries that are strictly less than the sample. The first
|
|
** integer in nLt contains the number of entries in the index where the
|
|
** left-most column is less than the left-most column of the sample.
|
|
-** The K-th integer in the nLt entry is the number of index entries
|
|
+** The K-th integer in the nLt entry is the number of index entries
|
|
** where the first K columns are less than the first K columns of the
|
|
-** sample. The nDLt column is like nLt except that it contains the
|
|
+** sample. The nDLt column is like nLt except that it contains the
|
|
** number of distinct entries in the index that are less than the
|
|
** sample.
|
|
**
|
|
@@ -106514,8 +114841,13 @@ static void openStatTable(
|
|
sqlite3 *db = pParse->db;
|
|
Db *pDb;
|
|
Vdbe *v = sqlite3GetVdbe(pParse);
|
|
- int aRoot[ArraySize(aTable)];
|
|
+ u32 aRoot[ArraySize(aTable)];
|
|
u8 aCreateTbl[ArraySize(aTable)];
|
|
+#ifdef SQLITE_ENABLE_STAT4
|
|
+ const int nToOpen = OptimizationEnabled(db,SQLITE_Stat4) ? 2 : 1;
|
|
+#else
|
|
+ const int nToOpen = 1;
|
|
+#endif
|
|
|
|
if( v==0 ) return;
|
|
assert( sqlite3BtreeHoldsAllMutexes(db) );
|
|
@@ -106528,24 +114860,24 @@ static void openStatTable(
|
|
for(i=0; i<ArraySize(aTable); i++){
|
|
const char *zTab = aTable[i].zName;
|
|
Table *pStat;
|
|
+ aCreateTbl[i] = 0;
|
|
if( (pStat = sqlite3FindTable(db, zTab, pDb->zDbSName))==0 ){
|
|
- if( aTable[i].zCols ){
|
|
- /* The sqlite_statN table does not exist. Create it. Note that a
|
|
- ** side-effect of the CREATE TABLE statement is to leave the rootpage
|
|
- ** of the new table in register pParse->regRoot. This is important
|
|
+ if( i<nToOpen ){
|
|
+ /* The sqlite_statN table does not exist. Create it. Note that a
|
|
+ ** side-effect of the CREATE TABLE statement is to leave the rootpage
|
|
+ ** of the new table in register pParse->regRoot. This is important
|
|
** because the OpenWrite opcode below will be needing it. */
|
|
sqlite3NestedParse(pParse,
|
|
"CREATE TABLE %Q.%s(%s)", pDb->zDbSName, zTab, aTable[i].zCols
|
|
);
|
|
- aRoot[i] = pParse->regRoot;
|
|
+ aRoot[i] = (u32)pParse->regRoot;
|
|
aCreateTbl[i] = OPFLAG_P2ISREG;
|
|
}
|
|
}else{
|
|
- /* The table already exists. If zWhere is not NULL, delete all entries
|
|
+ /* The table already exists. If zWhere is not NULL, delete all entries
|
|
** associated with the table zWhere. If zWhere is NULL, delete the
|
|
** entire contents of the table. */
|
|
aRoot[i] = pStat->tnum;
|
|
- aCreateTbl[i] = 0;
|
|
sqlite3TableLock(pParse, iDb, aRoot[i], 1, zTab);
|
|
if( zWhere ){
|
|
sqlite3NestedParse(pParse,
|
|
@@ -106558,15 +114890,15 @@ static void openStatTable(
|
|
#endif
|
|
}else{
|
|
/* The sqlite_stat[134] table already exists. Delete all rows. */
|
|
- sqlite3VdbeAddOp2(v, OP_Clear, aRoot[i], iDb);
|
|
+ sqlite3VdbeAddOp2(v, OP_Clear, (int)aRoot[i], iDb);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Open the sqlite_stat[134] tables for writing. */
|
|
- for(i=0; aTable[i].zCols; i++){
|
|
+ for(i=0; i<nToOpen; i++){
|
|
assert( i<ArraySize(aTable) );
|
|
- sqlite3VdbeAddOp4Int(v, OP_OpenWrite, iStatCur+i, aRoot[i], iDb, 3);
|
|
+ sqlite3VdbeAddOp4Int(v, OP_OpenWrite, iStatCur+i, (int)aRoot[i], iDb, 3);
|
|
sqlite3VdbeChangeP5(v, aCreateTbl[i]);
|
|
VdbeComment((v, aTable[i].zName));
|
|
}
|
|
@@ -106584,9 +114916,9 @@ static void openStatTable(
|
|
** share an instance of the following structure to hold their state
|
|
** information.
|
|
*/
|
|
-typedef struct Stat4Accum Stat4Accum;
|
|
-typedef struct Stat4Sample Stat4Sample;
|
|
-struct Stat4Sample {
|
|
+typedef struct StatAccum StatAccum;
|
|
+typedef struct StatSample StatSample;
|
|
+struct StatSample {
|
|
tRowcnt *anEq; /* sqlite_stat4.nEq */
|
|
tRowcnt *anDLt; /* sqlite_stat4.nDLt */
|
|
#ifdef SQLITE_ENABLE_STAT4
|
|
@@ -106600,28 +114932,33 @@ struct Stat4Sample {
|
|
int iCol; /* If !isPSample, the reason for inclusion */
|
|
u32 iHash; /* Tiebreaker hash */
|
|
#endif
|
|
-};
|
|
-struct Stat4Accum {
|
|
- tRowcnt nRow; /* Number of rows in the entire table */
|
|
- tRowcnt nPSample; /* How often to do a periodic sample */
|
|
+};
|
|
+struct StatAccum {
|
|
+ sqlite3 *db; /* Database connection, for malloc() */
|
|
+ tRowcnt nEst; /* Estimated number of rows */
|
|
+ tRowcnt nRow; /* Number of rows visited so far */
|
|
+ int nLimit; /* Analysis row-scan limit */
|
|
int nCol; /* Number of columns in index + pk/rowid */
|
|
int nKeyCol; /* Number of index columns w/o the pk/rowid */
|
|
+ u8 nSkipAhead; /* Number of times of skip-ahead */
|
|
+ StatSample current; /* Current row as a StatSample */
|
|
+#ifdef SQLITE_ENABLE_STAT4
|
|
+ tRowcnt nPSample; /* How often to do a periodic sample */
|
|
int mxSample; /* Maximum number of samples to accumulate */
|
|
- Stat4Sample current; /* Current row as a Stat4Sample */
|
|
u32 iPrn; /* Pseudo-random number used for sampling */
|
|
- Stat4Sample *aBest; /* Array of nCol best samples */
|
|
+ StatSample *aBest; /* Array of nCol best samples */
|
|
int iMin; /* Index in a[] of entry with minimum score */
|
|
int nSample; /* Current number of samples */
|
|
int nMaxEqZero; /* Max leading 0 in anEq[] for any a[] entry */
|
|
int iGet; /* Index of current sample accessed by stat_get() */
|
|
- Stat4Sample *a; /* Array of mxSample Stat4Sample objects */
|
|
- sqlite3 *db; /* Database connection, for malloc() */
|
|
+ StatSample *a; /* Array of mxSample StatSample objects */
|
|
+#endif
|
|
};
|
|
|
|
-/* Reclaim memory used by a Stat4Sample
|
|
+/* Reclaim memory used by a StatSample
|
|
*/
|
|
#ifdef SQLITE_ENABLE_STAT4
|
|
-static void sampleClear(sqlite3 *db, Stat4Sample *p){
|
|
+static void sampleClear(sqlite3 *db, StatSample *p){
|
|
assert( db!=0 );
|
|
if( p->nRowid ){
|
|
sqlite3DbFree(db, p->u.aRowid);
|
|
@@ -106633,7 +114970,7 @@ static void sampleClear(sqlite3 *db, Stat4Sample *p){
|
|
/* Initialize the BLOB value of a ROWID
|
|
*/
|
|
#ifdef SQLITE_ENABLE_STAT4
|
|
-static void sampleSetRowid(sqlite3 *db, Stat4Sample *p, int n, const u8 *pData){
|
|
+static void sampleSetRowid(sqlite3 *db, StatSample *p, int n, const u8 *pData){
|
|
assert( db!=0 );
|
|
if( p->nRowid ) sqlite3DbFree(db, p->u.aRowid);
|
|
p->u.aRowid = sqlite3DbMallocRawNN(db, n);
|
|
@@ -106649,7 +114986,7 @@ static void sampleSetRowid(sqlite3 *db, Stat4Sample *p, int n, const u8 *pData){
|
|
/* Initialize the INTEGER value of a ROWID.
|
|
*/
|
|
#ifdef SQLITE_ENABLE_STAT4
|
|
-static void sampleSetRowidInt64(sqlite3 *db, Stat4Sample *p, i64 iRowid){
|
|
+static void sampleSetRowidInt64(sqlite3 *db, StatSample *p, i64 iRowid){
|
|
assert( db!=0 );
|
|
if( p->nRowid ) sqlite3DbFree(db, p->u.aRowid);
|
|
p->nRowid = 0;
|
|
@@ -106662,7 +114999,7 @@ static void sampleSetRowidInt64(sqlite3 *db, Stat4Sample *p, i64 iRowid){
|
|
** Copy the contents of object (*pFrom) into (*pTo).
|
|
*/
|
|
#ifdef SQLITE_ENABLE_STAT4
|
|
-static void sampleCopy(Stat4Accum *p, Stat4Sample *pTo, Stat4Sample *pFrom){
|
|
+static void sampleCopy(StatAccum *p, StatSample *pTo, StatSample *pFrom){
|
|
pTo->isPSample = pFrom->isPSample;
|
|
pTo->iCol = pFrom->iCol;
|
|
pTo->iHash = pFrom->iHash;
|
|
@@ -106678,40 +115015,41 @@ static void sampleCopy(Stat4Accum *p, Stat4Sample *pTo, Stat4Sample *pFrom){
|
|
#endif
|
|
|
|
/*
|
|
-** Reclaim all memory of a Stat4Accum structure.
|
|
+** Reclaim all memory of a StatAccum structure.
|
|
*/
|
|
-static void stat4Destructor(void *pOld){
|
|
- Stat4Accum *p = (Stat4Accum*)pOld;
|
|
+static void statAccumDestructor(void *pOld){
|
|
+ StatAccum *p = (StatAccum*)pOld;
|
|
#ifdef SQLITE_ENABLE_STAT4
|
|
- int i;
|
|
- for(i=0; i<p->nCol; i++) sampleClear(p->db, p->aBest+i);
|
|
- for(i=0; i<p->mxSample; i++) sampleClear(p->db, p->a+i);
|
|
- sampleClear(p->db, &p->current);
|
|
+ if( p->mxSample ){
|
|
+ int i;
|
|
+ for(i=0; i<p->nCol; i++) sampleClear(p->db, p->aBest+i);
|
|
+ for(i=0; i<p->mxSample; i++) sampleClear(p->db, p->a+i);
|
|
+ sampleClear(p->db, &p->current);
|
|
+ }
|
|
#endif
|
|
sqlite3DbFree(p->db, p);
|
|
}
|
|
|
|
/*
|
|
-** Implementation of the stat_init(N,K,C) SQL function. The three parameters
|
|
+** Implementation of the stat_init(N,K,C,L) SQL function. The four parameters
|
|
** are:
|
|
** N: The number of columns in the index including the rowid/pk (note 1)
|
|
** K: The number of columns in the index excluding the rowid/pk.
|
|
-** C: The number of rows in the index (note 2)
|
|
+** C: Estimated number of rows in the index
|
|
+** L: A limit on the number of rows to scan, or 0 for no-limit
|
|
**
|
|
** Note 1: In the special case of the covering index that implements a
|
|
** WITHOUT ROWID table, N is the number of PRIMARY KEY columns, not the
|
|
** total number of columns in the table.
|
|
**
|
|
-** Note 2: C is only used for STAT4.
|
|
-**
|
|
** For indexes on ordinary rowid tables, N==K+1. But for indexes on
|
|
** WITHOUT ROWID tables, N=K+P where P is the number of columns in the
|
|
** PRIMARY KEY of the table. The covering index that implements the
|
|
** original WITHOUT ROWID table as N==K as a special case.
|
|
**
|
|
-** This routine allocates the Stat4Accum object in heap memory. The return
|
|
-** value is a pointer to the Stat4Accum object. The datatype of the
|
|
-** return value is BLOB, but it is really just a pointer to the Stat4Accum
|
|
+** This routine allocates the StatAccum object in heap memory. The return
|
|
+** value is a pointer to the StatAccum object. The datatype of the
|
|
+** return value is BLOB, but it is really just a pointer to the StatAccum
|
|
** object.
|
|
*/
|
|
static void statInit(
|
|
@@ -106719,14 +115057,15 @@ static void statInit(
|
|
int argc,
|
|
sqlite3_value **argv
|
|
){
|
|
- Stat4Accum *p;
|
|
+ StatAccum *p;
|
|
int nCol; /* Number of columns in index being sampled */
|
|
int nKeyCol; /* Number of key columns */
|
|
int nColUp; /* nCol rounded up for alignment */
|
|
int n; /* Bytes of space to allocate */
|
|
- sqlite3 *db; /* Database connection */
|
|
+ sqlite3 *db = sqlite3_context_db_handle(context); /* Database connection */
|
|
#ifdef SQLITE_ENABLE_STAT4
|
|
- int mxSample = SQLITE_STAT4_SAMPLES;
|
|
+ /* Maximum number of samples. 0 if STAT4 data is not collected */
|
|
+ int mxSample = OptimizationEnabled(db,SQLITE_Stat4) ?SQLITE_STAT4_SAMPLES :0;
|
|
#endif
|
|
|
|
/* Decode the three function arguments */
|
|
@@ -106738,17 +115077,17 @@ static void statInit(
|
|
assert( nKeyCol<=nCol );
|
|
assert( nKeyCol>0 );
|
|
|
|
- /* Allocate the space required for the Stat4Accum object */
|
|
- n = sizeof(*p)
|
|
- + sizeof(tRowcnt)*nColUp /* Stat4Accum.anEq */
|
|
- + sizeof(tRowcnt)*nColUp /* Stat4Accum.anDLt */
|
|
+ /* Allocate the space required for the StatAccum object */
|
|
+ n = sizeof(*p)
|
|
+ + sizeof(tRowcnt)*nColUp /* StatAccum.anEq */
|
|
+ + sizeof(tRowcnt)*nColUp; /* StatAccum.anDLt */
|
|
#ifdef SQLITE_ENABLE_STAT4
|
|
- + sizeof(tRowcnt)*nColUp /* Stat4Accum.anLt */
|
|
- + sizeof(Stat4Sample)*(nCol+mxSample) /* Stat4Accum.aBest[], a[] */
|
|
- + sizeof(tRowcnt)*3*nColUp*(nCol+mxSample)
|
|
+ if( mxSample ){
|
|
+ n += sizeof(tRowcnt)*nColUp /* StatAccum.anLt */
|
|
+ + sizeof(StatSample)*(nCol+mxSample) /* StatAccum.aBest[], a[] */
|
|
+ + sizeof(tRowcnt)*3*nColUp*(nCol+mxSample);
|
|
+ }
|
|
#endif
|
|
- ;
|
|
- db = sqlite3_context_db_handle(context);
|
|
p = sqlite3DbMallocZero(db, n);
|
|
if( p==0 ){
|
|
sqlite3_result_error_nomem(context);
|
|
@@ -106756,25 +115095,28 @@ static void statInit(
|
|
}
|
|
|
|
p->db = db;
|
|
+ p->nEst = sqlite3_value_int64(argv[2]);
|
|
p->nRow = 0;
|
|
+ p->nLimit = sqlite3_value_int64(argv[3]);
|
|
p->nCol = nCol;
|
|
p->nKeyCol = nKeyCol;
|
|
+ p->nSkipAhead = 0;
|
|
p->current.anDLt = (tRowcnt*)&p[1];
|
|
p->current.anEq = &p->current.anDLt[nColUp];
|
|
|
|
#ifdef SQLITE_ENABLE_STAT4
|
|
- {
|
|
+ p->mxSample = p->nLimit==0 ? mxSample : 0;
|
|
+ if( mxSample ){
|
|
u8 *pSpace; /* Allocated space not yet assigned */
|
|
int i; /* Used to iterate through p->aSample[] */
|
|
|
|
p->iGet = -1;
|
|
- p->mxSample = mxSample;
|
|
- p->nPSample = (tRowcnt)(sqlite3_value_int64(argv[2])/(mxSample/3+1) + 1);
|
|
+ p->nPSample = (tRowcnt)(p->nEst/(mxSample/3+1) + 1);
|
|
p->current.anLt = &p->current.anEq[nColUp];
|
|
p->iPrn = 0x689e962d*(u32)nCol ^ 0xd0944565*(u32)sqlite3_value_int(argv[2]);
|
|
-
|
|
- /* Set up the Stat4Accum.a[] and aBest[] arrays */
|
|
- p->a = (struct Stat4Sample*)&p->current.anLt[nColUp];
|
|
+
|
|
+ /* Set up the StatAccum.a[] and aBest[] arrays */
|
|
+ p->a = (struct StatSample*)&p->current.anLt[nColUp];
|
|
p->aBest = &p->a[mxSample];
|
|
pSpace = (u8*)(&p->a[mxSample+nCol]);
|
|
for(i=0; i<(mxSample+nCol); i++){
|
|
@@ -106783,7 +115125,7 @@ static void statInit(
|
|
p->a[i].anDLt = (tRowcnt *)pSpace; pSpace += (sizeof(tRowcnt) * nColUp);
|
|
}
|
|
assert( (pSpace - (u8*)p)==n );
|
|
-
|
|
+
|
|
for(i=0; i<nCol; i++){
|
|
p->aBest[i].iCol = i;
|
|
}
|
|
@@ -106794,10 +115136,10 @@ static void statInit(
|
|
** only the pointer (the 2nd parameter) matters. The size of the object
|
|
** (given by the 3rd parameter) is never used and can be any positive
|
|
** value. */
|
|
- sqlite3_result_blob(context, p, sizeof(*p), stat4Destructor);
|
|
+ sqlite3_result_blob(context, p, sizeof(*p), statAccumDestructor);
|
|
}
|
|
static const FuncDef statInitFuncdef = {
|
|
- 2+IsStat4, /* nArg */
|
|
+ 4, /* nArg */
|
|
SQLITE_UTF8, /* funcFlags */
|
|
0, /* pUserData */
|
|
0, /* pNext */
|
|
@@ -106810,20 +115152,20 @@ static const FuncDef statInitFuncdef = {
|
|
|
|
#ifdef SQLITE_ENABLE_STAT4
|
|
/*
|
|
-** pNew and pOld are both candidate non-periodic samples selected for
|
|
-** the same column (pNew->iCol==pOld->iCol). Ignoring this column and
|
|
+** pNew and pOld are both candidate non-periodic samples selected for
|
|
+** the same column (pNew->iCol==pOld->iCol). Ignoring this column and
|
|
** considering only any trailing columns and the sample hash value, this
|
|
** function returns true if sample pNew is to be preferred over pOld.
|
|
** In other words, if we assume that the cardinalities of the selected
|
|
** column for pNew and pOld are equal, is pNew to be preferred over pOld.
|
|
**
|
|
** This function assumes that for each argument sample, the contents of
|
|
-** the anEq[] array from pSample->anEq[pSample->iCol+1] onwards are valid.
|
|
+** the anEq[] array from pSample->anEq[pSample->iCol+1] onwards are valid.
|
|
*/
|
|
static int sampleIsBetterPost(
|
|
- Stat4Accum *pAccum,
|
|
- Stat4Sample *pNew,
|
|
- Stat4Sample *pOld
|
|
+ StatAccum *pAccum,
|
|
+ StatSample *pNew,
|
|
+ StatSample *pOld
|
|
){
|
|
int nCol = pAccum->nCol;
|
|
int i;
|
|
@@ -106842,12 +115184,12 @@ static int sampleIsBetterPost(
|
|
** Return true if pNew is to be preferred over pOld.
|
|
**
|
|
** This function assumes that for each argument sample, the contents of
|
|
-** the anEq[] array from pSample->anEq[pSample->iCol] onwards are valid.
|
|
+** the anEq[] array from pSample->anEq[pSample->iCol] onwards are valid.
|
|
*/
|
|
static int sampleIsBetter(
|
|
- Stat4Accum *pAccum,
|
|
- Stat4Sample *pNew,
|
|
- Stat4Sample *pOld
|
|
+ StatAccum *pAccum,
|
|
+ StatSample *pNew,
|
|
+ StatSample *pOld
|
|
){
|
|
tRowcnt nEqNew = pNew->anEq[pNew->iCol];
|
|
tRowcnt nEqOld = pOld->anEq[pOld->iCol];
|
|
@@ -106867,30 +115209,30 @@ static int sampleIsBetter(
|
|
** Copy the contents of sample *pNew into the p->a[] array. If necessary,
|
|
** remove the least desirable sample from p->a[] to make room.
|
|
*/
|
|
-static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){
|
|
- Stat4Sample *pSample = 0;
|
|
+static void sampleInsert(StatAccum *p, StatSample *pNew, int nEqZero){
|
|
+ StatSample *pSample = 0;
|
|
int i;
|
|
|
|
assert( IsStat4 || nEqZero==0 );
|
|
|
|
- /* Stat4Accum.nMaxEqZero is set to the maximum number of leading 0
|
|
- ** values in the anEq[] array of any sample in Stat4Accum.a[]. In
|
|
+ /* StatAccum.nMaxEqZero is set to the maximum number of leading 0
|
|
+ ** values in the anEq[] array of any sample in StatAccum.a[]. In
|
|
** other words, if nMaxEqZero is n, then it is guaranteed that there
|
|
- ** are no samples with Stat4Sample.anEq[m]==0 for (m>=n). */
|
|
+ ** are no samples with StatSample.anEq[m]==0 for (m>=n). */
|
|
if( nEqZero>p->nMaxEqZero ){
|
|
p->nMaxEqZero = nEqZero;
|
|
}
|
|
if( pNew->isPSample==0 ){
|
|
- Stat4Sample *pUpgrade = 0;
|
|
+ StatSample *pUpgrade = 0;
|
|
assert( pNew->anEq[pNew->iCol]>0 );
|
|
|
|
- /* This sample is being added because the prefix that ends in column
|
|
+ /* This sample is being added because the prefix that ends in column
|
|
** iCol occurs many times in the table. However, if we have already
|
|
** added a sample that shares this prefix, there is no need to add
|
|
** this one. Instead, upgrade the priority of the highest priority
|
|
** existing sample that shares this prefix. */
|
|
for(i=p->nSample-1; i>=0; i--){
|
|
- Stat4Sample *pOld = &p->a[i];
|
|
+ StatSample *pOld = &p->a[i];
|
|
if( pOld->anEq[pNew->iCol]==0 ){
|
|
if( pOld->isPSample ) return;
|
|
assert( pOld->iCol>pNew->iCol );
|
|
@@ -106909,7 +115251,7 @@ static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){
|
|
|
|
/* If necessary, remove sample iMin to make room for the new sample. */
|
|
if( p->nSample>=p->mxSample ){
|
|
- Stat4Sample *pMin = &p->a[p->iMin];
|
|
+ StatSample *pMin = &p->a[p->iMin];
|
|
tRowcnt *anEq = pMin->anEq;
|
|
tRowcnt *anLt = pMin->anLt;
|
|
tRowcnt *anDLt = pMin->anDLt;
|
|
@@ -106926,7 +115268,7 @@ static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){
|
|
/* The "rows less-than" for the rowid column must be greater than that
|
|
** for the last sample in the p->a[] array. Otherwise, the samples would
|
|
** be out of order. */
|
|
- assert( p->nSample==0
|
|
+ assert( p->nSample==0
|
|
|| pNew->anLt[p->nCol-1] > p->a[p->nSample-1].anLt[p->nCol-1] );
|
|
|
|
/* Insert the new sample */
|
|
@@ -106952,20 +115294,20 @@ static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){
|
|
}
|
|
#endif /* SQLITE_ENABLE_STAT4 */
|
|
|
|
+#ifdef SQLITE_ENABLE_STAT4
|
|
/*
|
|
** Field iChng of the index being scanned has changed. So at this point
|
|
** p->current contains a sample that reflects the previous row of the
|
|
** index. The value of anEq[iChng] and subsequent anEq[] elements are
|
|
** correct at this point.
|
|
*/
|
|
-static void samplePushPrevious(Stat4Accum *p, int iChng){
|
|
-#ifdef SQLITE_ENABLE_STAT4
|
|
+static void samplePushPrevious(StatAccum *p, int iChng){
|
|
int i;
|
|
|
|
/* Check if any samples from the aBest[] array should be pushed
|
|
** into IndexSample.a[] at this point. */
|
|
for(i=(p->nCol-2); i>=iChng; i--){
|
|
- Stat4Sample *pBest = &p->aBest[i];
|
|
+ StatSample *pBest = &p->aBest[i];
|
|
pBest->anEq[i] = p->current.anEq[i];
|
|
if( p->nSample<p->mxSample || sampleIsBetter(p, pBest, &p->a[p->iMin]) ){
|
|
sampleInsert(p, pBest, i);
|
|
@@ -106989,27 +115331,25 @@ static void samplePushPrevious(Stat4Accum *p, int iChng){
|
|
}
|
|
p->nMaxEqZero = iChng;
|
|
}
|
|
-#endif
|
|
-
|
|
-#ifndef SQLITE_ENABLE_STAT4
|
|
- UNUSED_PARAMETER( p );
|
|
- UNUSED_PARAMETER( iChng );
|
|
-#endif
|
|
}
|
|
+#endif /* SQLITE_ENABLE_STAT4 */
|
|
|
|
/*
|
|
** Implementation of the stat_push SQL function: stat_push(P,C,R)
|
|
** Arguments:
|
|
**
|
|
-** P Pointer to the Stat4Accum object created by stat_init()
|
|
+** P Pointer to the StatAccum object created by stat_init()
|
|
** C Index of left-most column to differ from previous row
|
|
** R Rowid for the current row. Might be a key record for
|
|
** WITHOUT ROWID tables.
|
|
**
|
|
-** This SQL function always returns NULL. It's purpose it to accumulate
|
|
-** statistical data and/or samples in the Stat4Accum object about the
|
|
-** index being analyzed. The stat_get() SQL function will later be used to
|
|
-** extract relevant information for constructing the sqlite_statN tables.
|
|
+** The purpose of this routine is to collect statistical data and/or
|
|
+** samples from the index being analyzed into the StatAccum object.
|
|
+** The stat_get() SQL function will be used afterwards to
|
|
+** retrieve the information gathered.
|
|
+**
|
|
+** This SQL function usually returns NULL, but might return an integer
|
|
+** if it wants the byte-code to do special processing.
|
|
**
|
|
** The R parameter is only used for STAT4
|
|
*/
|
|
@@ -107021,7 +115361,7 @@ static void statPush(
|
|
int i;
|
|
|
|
/* The three function arguments */
|
|
- Stat4Accum *p = (Stat4Accum*)sqlite3_value_blob(argv[0]);
|
|
+ StatAccum *p = (StatAccum*)sqlite3_value_blob(argv[0]);
|
|
int iChng = sqlite3_value_int(argv[1]);
|
|
|
|
UNUSED_PARAMETER( argc );
|
|
@@ -107034,7 +115374,9 @@ static void statPush(
|
|
for(i=0; i<p->nCol; i++) p->current.anEq[i] = 1;
|
|
}else{
|
|
/* Second and subsequent calls get processed here */
|
|
- samplePushPrevious(p, iChng);
|
|
+#ifdef SQLITE_ENABLE_STAT4
|
|
+ if( p->mxSample ) samplePushPrevious(p, iChng);
|
|
+#endif
|
|
|
|
/* Update anDLt[], anLt[] and anEq[] to reflect the values that apply
|
|
** to the current row of the index. */
|
|
@@ -107044,26 +115386,25 @@ static void statPush(
|
|
for(i=iChng; i<p->nCol; i++){
|
|
p->current.anDLt[i]++;
|
|
#ifdef SQLITE_ENABLE_STAT4
|
|
- p->current.anLt[i] += p->current.anEq[i];
|
|
+ if( p->mxSample ) p->current.anLt[i] += p->current.anEq[i];
|
|
#endif
|
|
p->current.anEq[i] = 1;
|
|
}
|
|
}
|
|
- p->nRow++;
|
|
-#ifdef SQLITE_ENABLE_STAT4
|
|
- if( sqlite3_value_type(argv[2])==SQLITE_INTEGER ){
|
|
- sampleSetRowidInt64(p->db, &p->current, sqlite3_value_int64(argv[2]));
|
|
- }else{
|
|
- sampleSetRowid(p->db, &p->current, sqlite3_value_bytes(argv[2]),
|
|
- sqlite3_value_blob(argv[2]));
|
|
- }
|
|
- p->current.iHash = p->iPrn = p->iPrn*1103515245 + 12345;
|
|
-#endif
|
|
|
|
+ p->nRow++;
|
|
#ifdef SQLITE_ENABLE_STAT4
|
|
- {
|
|
- tRowcnt nLt = p->current.anLt[p->nCol-1];
|
|
+ if( p->mxSample ){
|
|
+ tRowcnt nLt;
|
|
+ if( sqlite3_value_type(argv[2])==SQLITE_INTEGER ){
|
|
+ sampleSetRowidInt64(p->db, &p->current, sqlite3_value_int64(argv[2]));
|
|
+ }else{
|
|
+ sampleSetRowid(p->db, &p->current, sqlite3_value_bytes(argv[2]),
|
|
+ sqlite3_value_blob(argv[2]));
|
|
+ }
|
|
+ p->current.iHash = p->iPrn = p->iPrn*1103515245 + 12345;
|
|
|
|
+ nLt = p->current.anLt[p->nCol-1];
|
|
/* Check if this is to be a periodic sample. If so, add it. */
|
|
if( (nLt/p->nPSample)!=(nLt+1)/p->nPSample ){
|
|
p->current.isPSample = 1;
|
|
@@ -107079,9 +115420,14 @@ static void statPush(
|
|
sampleCopy(p, &p->aBest[i], &p->current);
|
|
}
|
|
}
|
|
- }
|
|
+ }else
|
|
#endif
|
|
+ if( p->nLimit && p->nRow>(tRowcnt)p->nLimit*(p->nSkipAhead+1) ){
|
|
+ p->nSkipAhead++;
|
|
+ sqlite3_result_int(context, p->current.anDLt[0]>0);
|
|
+ }
|
|
}
|
|
+
|
|
static const FuncDef statPushFuncdef = {
|
|
2+IsStat4, /* nArg */
|
|
SQLITE_UTF8, /* funcFlags */
|
|
@@ -107103,15 +115449,15 @@ static const FuncDef statPushFuncdef = {
|
|
/*
|
|
** Implementation of the stat_get(P,J) SQL function. This routine is
|
|
** used to query statistical information that has been gathered into
|
|
-** the Stat4Accum object by prior calls to stat_push(). The P parameter
|
|
-** has type BLOB but it is really just a pointer to the Stat4Accum object.
|
|
+** the StatAccum object by prior calls to stat_push(). The P parameter
|
|
+** has type BLOB but it is really just a pointer to the StatAccum object.
|
|
** The content to returned is determined by the parameter J
|
|
** which is one of the STAT_GET_xxxx values defined above.
|
|
**
|
|
** The stat_get(P,J) function is not available to generic SQL. It is
|
|
** inserted as part of a manually constructed bytecode program. (See
|
|
** the callStatGet() routine below.) It is guaranteed that the P
|
|
-** parameter will always be a poiner to a Stat4Accum object, never a
|
|
+** parameter will always be a pointer to a StatAccum object, never a
|
|
** NULL.
|
|
**
|
|
** If STAT4 is not enabled, then J is always
|
|
@@ -107124,15 +115470,16 @@ static void statGet(
|
|
int argc,
|
|
sqlite3_value **argv
|
|
){
|
|
- Stat4Accum *p = (Stat4Accum*)sqlite3_value_blob(argv[0]);
|
|
+ StatAccum *p = (StatAccum*)sqlite3_value_blob(argv[0]);
|
|
#ifdef SQLITE_ENABLE_STAT4
|
|
/* STAT4 has a parameter on this routine. */
|
|
int eCall = sqlite3_value_int(argv[1]);
|
|
assert( argc==2 );
|
|
- assert( eCall==STAT_GET_STAT1 || eCall==STAT_GET_NEQ
|
|
+ assert( eCall==STAT_GET_STAT1 || eCall==STAT_GET_NEQ
|
|
|| eCall==STAT_GET_ROWID || eCall==STAT_GET_NLT
|
|
- || eCall==STAT_GET_NDLT
|
|
+ || eCall==STAT_GET_NDLT
|
|
);
|
|
+ assert( eCall==STAT_GET_STAT1 || p->mxSample );
|
|
if( eCall==STAT_GET_STAT1 )
|
|
#else
|
|
assert( argc==1 );
|
|
@@ -107141,45 +115488,43 @@ static void statGet(
|
|
/* Return the value to store in the "stat" column of the sqlite_stat1
|
|
** table for this index.
|
|
**
|
|
- ** The value is a string composed of a list of integers describing
|
|
- ** the index. The first integer in the list is the total number of
|
|
- ** entries in the index. There is one additional integer in the list
|
|
+ ** The value is a string composed of a list of integers describing
|
|
+ ** the index. The first integer in the list is the total number of
|
|
+ ** entries in the index. There is one additional integer in the list
|
|
** for each indexed column. This additional integer is an estimate of
|
|
- ** the number of rows matched by a stabbing query on the index using
|
|
+ ** the number of rows matched by a equality query on the index using
|
|
** a key with the corresponding number of fields. In other words,
|
|
- ** if the index is on columns (a,b) and the sqlite_stat1 value is
|
|
+ ** if the index is on columns (a,b) and the sqlite_stat1 value is
|
|
** "100 10 2", then SQLite estimates that:
|
|
**
|
|
** * the index contains 100 rows,
|
|
** * "WHERE a=?" matches 10 rows, and
|
|
** * "WHERE a=? AND b=?" matches 2 rows.
|
|
**
|
|
- ** If D is the count of distinct values and K is the total number of
|
|
- ** rows, then each estimate is computed as:
|
|
+ ** If D is the count of distinct values and K is the total number of
|
|
+ ** rows, then each estimate is usually computed as:
|
|
**
|
|
** I = (K+D-1)/D
|
|
+ **
|
|
+ ** In other words, I is K/D rounded up to the next whole integer.
|
|
+ ** However, if I is between 1.0 and 1.1 (in other words if I is
|
|
+ ** close to 1.0 but just a little larger) then do not round up but
|
|
+ ** instead keep the I value at 1.0.
|
|
*/
|
|
- char *z;
|
|
- int i;
|
|
+ sqlite3_str sStat; /* Text of the constructed "stat" line */
|
|
+ int i; /* Loop counter */
|
|
|
|
- char *zRet = sqlite3MallocZero( (p->nKeyCol+1)*25 );
|
|
- if( zRet==0 ){
|
|
- sqlite3_result_error_nomem(context);
|
|
- return;
|
|
- }
|
|
-
|
|
- sqlite3_snprintf(24, zRet, "%llu", (u64)p->nRow);
|
|
- z = zRet + sqlite3Strlen30(zRet);
|
|
+ sqlite3StrAccumInit(&sStat, 0, 0, 0, (p->nKeyCol+1)*100);
|
|
+ sqlite3_str_appendf(&sStat, "%llu",
|
|
+ p->nSkipAhead ? (u64)p->nEst : (u64)p->nRow);
|
|
for(i=0; i<p->nKeyCol; i++){
|
|
u64 nDistinct = p->current.anDLt[i] + 1;
|
|
u64 iVal = (p->nRow + nDistinct - 1) / nDistinct;
|
|
- sqlite3_snprintf(24, z, " %llu", iVal);
|
|
- z += sqlite3Strlen30(z);
|
|
+ if( iVal==2 && p->nRow*10 <= nDistinct*11 ) iVal = 1;
|
|
+ sqlite3_str_appendf(&sStat, " %llu", iVal);
|
|
assert( p->current.anEq[i] );
|
|
}
|
|
- assert( z[0]=='\0' && z>zRet );
|
|
-
|
|
- sqlite3_result_text(context, zRet, -1, sqlite3_free);
|
|
+ sqlite3ResultStrAccum(context, &sStat);
|
|
}
|
|
#ifdef SQLITE_ENABLE_STAT4
|
|
else if( eCall==STAT_GET_ROWID ){
|
|
@@ -107188,7 +115533,7 @@ static void statGet(
|
|
p->iGet = 0;
|
|
}
|
|
if( p->iGet<p->nSample ){
|
|
- Stat4Sample *pS = p->a + p->iGet;
|
|
+ StatSample *pS = p->a + p->iGet;
|
|
if( pS->nRowid==0 ){
|
|
sqlite3_result_int64(context, pS->u.iRowid);
|
|
}else{
|
|
@@ -107198,34 +115543,25 @@ static void statGet(
|
|
}
|
|
}else{
|
|
tRowcnt *aCnt = 0;
|
|
+ sqlite3_str sStat;
|
|
+ int i;
|
|
|
|
assert( p->iGet<p->nSample );
|
|
switch( eCall ){
|
|
case STAT_GET_NEQ: aCnt = p->a[p->iGet].anEq; break;
|
|
case STAT_GET_NLT: aCnt = p->a[p->iGet].anLt; break;
|
|
default: {
|
|
- aCnt = p->a[p->iGet].anDLt;
|
|
+ aCnt = p->a[p->iGet].anDLt;
|
|
p->iGet++;
|
|
break;
|
|
}
|
|
}
|
|
-
|
|
- {
|
|
- char *zRet = sqlite3MallocZero(p->nCol * 25);
|
|
- if( zRet==0 ){
|
|
- sqlite3_result_error_nomem(context);
|
|
- }else{
|
|
- int i;
|
|
- char *z = zRet;
|
|
- for(i=0; i<p->nCol; i++){
|
|
- sqlite3_snprintf(24, z, "%llu ", (u64)aCnt[i]);
|
|
- z += sqlite3Strlen30(z);
|
|
- }
|
|
- assert( z[0]=='\0' && z>zRet );
|
|
- z[-1] = '\0';
|
|
- sqlite3_result_text(context, zRet, -1, sqlite3_free);
|
|
- }
|
|
+ sqlite3StrAccumInit(&sStat, 0, 0, 0, p->nCol*100);
|
|
+ for(i=0; i<p->nCol; i++){
|
|
+ sqlite3_str_appendf(&sStat, "%llu ", (u64)aCnt[i]);
|
|
}
|
|
+ if( sStat.nChar ) sStat.nChar--;
|
|
+ sqlite3ResultStrAccum(context, &sStat);
|
|
}
|
|
#endif /* SQLITE_ENABLE_STAT4 */
|
|
#ifndef SQLITE_DEBUG
|
|
@@ -107244,19 +115580,44 @@ static const FuncDef statGetFuncdef = {
|
|
{0}
|
|
};
|
|
|
|
-static void callStatGet(Parse *pParse, int regStat4, int iParam, int regOut){
|
|
+static void callStatGet(Parse *pParse, int regStat, int iParam, int regOut){
|
|
#ifdef SQLITE_ENABLE_STAT4
|
|
- sqlite3VdbeAddOp2(pParse->pVdbe, OP_Integer, iParam, regStat4+1);
|
|
+ sqlite3VdbeAddOp2(pParse->pVdbe, OP_Integer, iParam, regStat+1);
|
|
#elif SQLITE_DEBUG
|
|
assert( iParam==STAT_GET_STAT1 );
|
|
#else
|
|
UNUSED_PARAMETER( iParam );
|
|
#endif
|
|
- assert( regOut!=regStat4 && regOut!=regStat4+1 );
|
|
- sqlite3VdbeAddFunctionCall(pParse, 0, regStat4, regOut, 1+IsStat4,
|
|
+ assert( regOut!=regStat && regOut!=regStat+1 );
|
|
+ sqlite3VdbeAddFunctionCall(pParse, 0, regStat, regOut, 1+IsStat4,
|
|
&statGetFuncdef, 0);
|
|
}
|
|
|
|
+#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
|
|
+/* Add a comment to the most recent VDBE opcode that is the name
|
|
+** of the k-th column of the pIdx index.
|
|
+*/
|
|
+static void analyzeVdbeCommentIndexWithColumnName(
|
|
+ Vdbe *v, /* Prepared statement under construction */
|
|
+ Index *pIdx, /* Index whose column is being loaded */
|
|
+ int k /* Which column index */
|
|
+){
|
|
+ int i; /* Index of column in the table */
|
|
+ assert( k>=0 && k<pIdx->nColumn );
|
|
+ i = pIdx->aiColumn[k];
|
|
+ if( NEVER(i==XN_ROWID) ){
|
|
+ VdbeComment((v,"%s.rowid",pIdx->zName));
|
|
+ }else if( i==XN_EXPR ){
|
|
+ assert( pIdx->bHasExpr );
|
|
+ VdbeComment((v,"%s.expr(%d)",pIdx->zName, k));
|
|
+ }else{
|
|
+ VdbeComment((v,"%s.%s", pIdx->zName, pIdx->pTable->aCol[i].zCnName));
|
|
+ }
|
|
+}
|
|
+#else
|
|
+# define analyzeVdbeCommentIndexWithColumnName(a,b,c)
|
|
+#endif /* SQLITE_DEBUG */
|
|
+
|
|
/*
|
|
** Generate code to do an analysis of all indices associated with
|
|
** a single table.
|
|
@@ -107279,18 +115640,17 @@ static void analyzeOneTable(
|
|
int iDb; /* Index of database containing pTab */
|
|
u8 needTableCnt = 1; /* True to count the table */
|
|
int regNewRowid = iMem++; /* Rowid for the inserted record */
|
|
- int regStat4 = iMem++; /* Register to hold Stat4Accum object */
|
|
+ int regStat = iMem++; /* Register to hold StatAccum object */
|
|
int regChng = iMem++; /* Index of changed index field */
|
|
-#ifdef SQLITE_ENABLE_STAT4
|
|
int regRowid = iMem++; /* Rowid argument passed to stat_push() */
|
|
-#endif
|
|
int regTemp = iMem++; /* Temporary use register */
|
|
+ int regTemp2 = iMem++; /* Second temporary use register */
|
|
int regTabname = iMem++; /* Register containing table name */
|
|
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_PREUPDATE_HOOK
|
|
- Table *pStat1 = 0;
|
|
+ Table *pStat1 = 0;
|
|
#endif
|
|
|
|
pParse->nMem = MAX(pParse->nMem, iMem);
|
|
@@ -107298,7 +115658,7 @@ static void analyzeOneTable(
|
|
if( v==0 || NEVER(pTab==0) ){
|
|
return;
|
|
}
|
|
- if( pTab->tnum==0 ){
|
|
+ if( !IsOrdinaryTable(pTab) ){
|
|
/* Do not gather statistics on views or virtual tables */
|
|
return;
|
|
}
|
|
@@ -107325,11 +115685,11 @@ static void analyzeOneTable(
|
|
memcpy(pStat1->zName, "sqlite_stat1", 13);
|
|
pStat1->nCol = 3;
|
|
pStat1->iPKey = -1;
|
|
- sqlite3VdbeAddOp4(pParse->pVdbe, OP_Noop, 0, 0, 0,(char*)pStat1,P4_DYNBLOB);
|
|
+ sqlite3VdbeAddOp4(pParse->pVdbe, OP_Noop, 0, 0, 0,(char*)pStat1,P4_DYNAMIC);
|
|
}
|
|
#endif
|
|
|
|
- /* Establish a read-lock on the table at the shared-cache level.
|
|
+ /* Establish a read-lock on the table at the shared-cache level.
|
|
** Open a read-only cursor on the table. Also allocate a cursor number
|
|
** to use for scanning indexes (iIdxCur). No index cursor is opened at
|
|
** this time though. */
|
|
@@ -107395,9 +115755,9 @@ static void analyzeOneTable(
|
|
** end_of_scan:
|
|
*/
|
|
|
|
- /* Make sure there are enough memory cells allocated to accommodate
|
|
+ /* Make sure there are enough memory cells allocated to accommodate
|
|
** the regPrev array and a trailing rowid (the rowid slot is required
|
|
- ** when building a record to insert into the sample column of
|
|
+ ** when building a record to insert into the sample column of
|
|
** the sqlite_stat4 table. */
|
|
pParse->nMem = MAX(pParse->nMem, regPrev+nColTest);
|
|
|
|
@@ -107408,21 +115768,30 @@ static void analyzeOneTable(
|
|
VdbeComment((v, "%s", pIdx->zName));
|
|
|
|
/* Invoke the stat_init() function. The arguments are:
|
|
- **
|
|
+ **
|
|
** (1) the number of columns in the index including the rowid
|
|
** (or for a WITHOUT ROWID table, the number of PK columns),
|
|
** (2) the number of columns in the key without the rowid/pk
|
|
- ** (3) the number of rows in the index,
|
|
- **
|
|
- **
|
|
- ** The third argument is only used for STAT4
|
|
+ ** (3) estimated number of rows in the index,
|
|
*/
|
|
+ sqlite3VdbeAddOp2(v, OP_Integer, nCol, regStat+1);
|
|
+ assert( regRowid==regStat+2 );
|
|
+ sqlite3VdbeAddOp2(v, OP_Integer, pIdx->nKeyCol, regRowid);
|
|
#ifdef SQLITE_ENABLE_STAT4
|
|
- sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regStat4+3);
|
|
+ if( OptimizationEnabled(db, SQLITE_Stat4) ){
|
|
+ sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regTemp);
|
|
+ addrRewind = sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur);
|
|
+ VdbeCoverage(v);
|
|
+ }else
|
|
#endif
|
|
- sqlite3VdbeAddOp2(v, OP_Integer, nCol, regStat4+1);
|
|
- sqlite3VdbeAddOp2(v, OP_Integer, pIdx->nKeyCol, regStat4+2);
|
|
- sqlite3VdbeAddFunctionCall(pParse, 0, regStat4+1, regStat4, 2+IsStat4,
|
|
+ {
|
|
+ addrRewind = sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur);
|
|
+ VdbeCoverage(v);
|
|
+ sqlite3VdbeAddOp3(v, OP_Count, iIdxCur, regTemp, 1);
|
|
+ }
|
|
+ assert( regTemp2==regStat+4 );
|
|
+ sqlite3VdbeAddOp2(v, OP_Integer, db->nAnalysisLimit, regTemp2);
|
|
+ sqlite3VdbeAddFunctionCall(pParse, 0, regStat+1, regStat, 4,
|
|
&statInitFuncdef, 0);
|
|
|
|
/* Implementation of the following:
|
|
@@ -107433,8 +115802,6 @@ static void analyzeOneTable(
|
|
** goto next_push_0;
|
|
**
|
|
*/
|
|
- addrRewind = sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur);
|
|
- VdbeCoverage(v);
|
|
sqlite3VdbeAddOp2(v, OP_Integer, 0, regChng);
|
|
addrNextRow = sqlite3VdbeCurrentAddr(v);
|
|
|
|
@@ -107458,7 +115825,7 @@ static void analyzeOneTable(
|
|
addrNextRow = sqlite3VdbeCurrentAddr(v);
|
|
if( nColTest==1 && pIdx->nKeyCol==1 && IsUniqueIndex(pIdx) ){
|
|
/* For a single-column UNIQUE index, once we have found a non-NULL
|
|
- ** row, we know that all the rest will be distinct, so skip
|
|
+ ** row, we know that all the rest will be distinct, so skip
|
|
** subsequent distinctness tests. */
|
|
sqlite3VdbeAddOp2(v, OP_NotNull, regPrev, endDistinctTest);
|
|
VdbeCoverage(v);
|
|
@@ -107467,15 +115834,16 @@ static void analyzeOneTable(
|
|
char *pColl = (char*)sqlite3LocateCollSeq(pParse, pIdx->azColl[i]);
|
|
sqlite3VdbeAddOp2(v, OP_Integer, i, regChng);
|
|
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, regTemp);
|
|
- aGotoChng[i] =
|
|
+ analyzeVdbeCommentIndexWithColumnName(v,pIdx,i);
|
|
+ aGotoChng[i] =
|
|
sqlite3VdbeAddOp4(v, OP_Ne, regTemp, 0, regPrev+i, pColl, P4_COLLSEQ);
|
|
sqlite3VdbeChangeP5(v, SQLITE_NULLEQ);
|
|
VdbeCoverage(v);
|
|
}
|
|
sqlite3VdbeAddOp2(v, OP_Integer, nColTest, regChng);
|
|
sqlite3VdbeGoto(v, endDistinctTest);
|
|
-
|
|
-
|
|
+
|
|
+
|
|
/*
|
|
** chng_addr_0:
|
|
** regPrev(0) = idx(0)
|
|
@@ -107487,11 +115855,12 @@ static void analyzeOneTable(
|
|
for(i=0; i<nColTest; i++){
|
|
sqlite3VdbeJumpHere(v, aGotoChng[i]);
|
|
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, regPrev+i);
|
|
+ analyzeVdbeCommentIndexWithColumnName(v,pIdx,i);
|
|
}
|
|
sqlite3VdbeResolveLabel(v, endDistinctTest);
|
|
sqlite3DbFree(db, aGotoChng);
|
|
}
|
|
-
|
|
+
|
|
/*
|
|
** chng_addr_N:
|
|
** regRowid = idx(rowid) // STAT4 only
|
|
@@ -107500,30 +115869,46 @@ static void analyzeOneTable(
|
|
** if !eof(csr) goto next_row;
|
|
*/
|
|
#ifdef SQLITE_ENABLE_STAT4
|
|
- assert( regRowid==(regStat4+2) );
|
|
- if( HasRowid(pTab) ){
|
|
- sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, regRowid);
|
|
- }else{
|
|
- Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable);
|
|
- int j, k, regKey;
|
|
- regKey = sqlite3GetTempRange(pParse, pPk->nKeyCol);
|
|
- for(j=0; j<pPk->nKeyCol; j++){
|
|
- k = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[j]);
|
|
- assert( k>=0 && k<pIdx->nColumn );
|
|
- sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, regKey+j);
|
|
- VdbeComment((v, "%s", pTab->aCol[pPk->aiColumn[j]].zName));
|
|
+ if( OptimizationEnabled(db, SQLITE_Stat4) ){
|
|
+ assert( regRowid==(regStat+2) );
|
|
+ if( HasRowid(pTab) ){
|
|
+ sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, regRowid);
|
|
+ }else{
|
|
+ Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable);
|
|
+ int j, k, regKey;
|
|
+ regKey = sqlite3GetTempRange(pParse, pPk->nKeyCol);
|
|
+ for(j=0; j<pPk->nKeyCol; j++){
|
|
+ k = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[j]);
|
|
+ assert( k>=0 && k<pIdx->nColumn );
|
|
+ sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, regKey+j);
|
|
+ analyzeVdbeCommentIndexWithColumnName(v,pIdx,k);
|
|
+ }
|
|
+ sqlite3VdbeAddOp3(v, OP_MakeRecord, regKey, pPk->nKeyCol, regRowid);
|
|
+ sqlite3ReleaseTempRange(pParse, regKey, pPk->nKeyCol);
|
|
}
|
|
- sqlite3VdbeAddOp3(v, OP_MakeRecord, regKey, pPk->nKeyCol, regRowid);
|
|
- sqlite3ReleaseTempRange(pParse, regKey, pPk->nKeyCol);
|
|
}
|
|
#endif
|
|
- assert( regChng==(regStat4+1) );
|
|
- sqlite3VdbeAddFunctionCall(pParse, 1, regStat4, regTemp, 2+IsStat4,
|
|
- &statPushFuncdef, 0);
|
|
- sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, addrNextRow); VdbeCoverage(v);
|
|
+ assert( regChng==(regStat+1) );
|
|
+ {
|
|
+ sqlite3VdbeAddFunctionCall(pParse, 1, regStat, regTemp, 2+IsStat4,
|
|
+ &statPushFuncdef, 0);
|
|
+ if( db->nAnalysisLimit ){
|
|
+ int j1, j2, j3;
|
|
+ j1 = sqlite3VdbeAddOp1(v, OP_IsNull, regTemp); VdbeCoverage(v);
|
|
+ j2 = sqlite3VdbeAddOp1(v, OP_If, regTemp); VdbeCoverage(v);
|
|
+ j3 = sqlite3VdbeAddOp4Int(v, OP_SeekGT, iIdxCur, 0, regPrev, 1);
|
|
+ VdbeCoverage(v);
|
|
+ sqlite3VdbeJumpHere(v, j1);
|
|
+ sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, addrNextRow); VdbeCoverage(v);
|
|
+ sqlite3VdbeJumpHere(v, j2);
|
|
+ sqlite3VdbeJumpHere(v, j3);
|
|
+ }else{
|
|
+ sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, addrNextRow); VdbeCoverage(v);
|
|
+ }
|
|
+ }
|
|
|
|
/* Add the entry to the stat1 table. */
|
|
- callStatGet(pParse, regStat4, STAT_GET_STAT1, regStat1);
|
|
+ callStatGet(pParse, regStat, STAT_GET_STAT1, regStat1);
|
|
assert( "BBB"[0]==SQLITE_AFF_TEXT );
|
|
sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "BBB", 0);
|
|
sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid);
|
|
@@ -107535,7 +115920,7 @@ static void analyzeOneTable(
|
|
|
|
/* Add the entries to the stat4 table. */
|
|
#ifdef SQLITE_ENABLE_STAT4
|
|
- {
|
|
+ if( OptimizationEnabled(db, SQLITE_Stat4) && db->nAnalysisLimit==0 ){
|
|
int regEq = regStat1;
|
|
int regLt = regStat1+1;
|
|
int regDLt = regStat1+2;
|
|
@@ -107549,12 +115934,12 @@ static void analyzeOneTable(
|
|
pParse->nMem = MAX(pParse->nMem, regCol+nCol);
|
|
|
|
addrNext = sqlite3VdbeCurrentAddr(v);
|
|
- callStatGet(pParse, regStat4, STAT_GET_ROWID, regSampleRowid);
|
|
+ callStatGet(pParse, regStat, STAT_GET_ROWID, regSampleRowid);
|
|
addrIsNull = sqlite3VdbeAddOp1(v, OP_IsNull, regSampleRowid);
|
|
VdbeCoverage(v);
|
|
- callStatGet(pParse, regStat4, STAT_GET_NEQ, regEq);
|
|
- callStatGet(pParse, regStat4, STAT_GET_NLT, regLt);
|
|
- callStatGet(pParse, regStat4, STAT_GET_NDLT, regDLt);
|
|
+ callStatGet(pParse, regStat, STAT_GET_NEQ, regEq);
|
|
+ callStatGet(pParse, regStat, STAT_GET_NLT, regLt);
|
|
+ callStatGet(pParse, regStat, STAT_GET_NDLT, regDLt);
|
|
sqlite3VdbeAddOp4Int(v, seekOp, iTabCur, addrNext, regSampleRowid, 0);
|
|
VdbeCoverage(v);
|
|
for(i=0; i<nCol; i++){
|
|
@@ -107794,7 +116179,7 @@ static void decodeIntArray(
|
|
|
|
/*
|
|
** This callback is invoked once for each index when reading the
|
|
-** sqlite_stat1 table.
|
|
+** sqlite_stat1 table.
|
|
**
|
|
** argv[0] = name of the table
|
|
** argv[1] = name of the index (might be NULL)
|
|
@@ -107832,7 +116217,7 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){
|
|
tRowcnt *aiRowEst = 0;
|
|
int nCol = pIndex->nKeyCol+1;
|
|
#ifdef SQLITE_ENABLE_STAT4
|
|
- /* Index.aiRowEst may already be set here if there are duplicate
|
|
+ /* Index.aiRowEst may already be set here if there are duplicate
|
|
** sqlite_stat1 entries for this index. In that case just clobber
|
|
** the old data with the new instead of allocating a new array. */
|
|
if( pIndex->aiRowEst==0 ){
|
|
@@ -107867,6 +116252,8 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){
|
|
** and its contents.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3DeleteIndexSamples(sqlite3 *db, Index *pIdx){
|
|
+ assert( db!=0 );
|
|
+ assert( pIdx!=0 );
|
|
#ifdef SQLITE_ENABLE_STAT4
|
|
if( pIdx->aSample ){
|
|
int j;
|
|
@@ -107876,7 +116263,7 @@ SQLITE_PRIVATE void sqlite3DeleteIndexSamples(sqlite3 *db, Index *pIdx){
|
|
}
|
|
sqlite3DbFree(db, pIdx->aSample);
|
|
}
|
|
- if( db && db->pnBytesFreed==0 ){
|
|
+ if( db->pnBytesFreed==0 ){
|
|
pIdx->nSample = 0;
|
|
pIdx->aSample = 0;
|
|
}
|
|
@@ -107889,7 +116276,7 @@ SQLITE_PRIVATE void sqlite3DeleteIndexSamples(sqlite3 *db, Index *pIdx){
|
|
#ifdef SQLITE_ENABLE_STAT4
|
|
/*
|
|
** Populate the pIdx->aAvgEq[] array based on the samples currently
|
|
-** stored in pIdx->aSample[].
|
|
+** stored in pIdx->aSample[].
|
|
*/
|
|
static void initAvgEq(Index *pIdx){
|
|
if( pIdx ){
|
|
@@ -107925,12 +116312,12 @@ static void initAvgEq(Index *pIdx){
|
|
pIdx->nRowEst0 = nRow;
|
|
|
|
/* Set nSum to the number of distinct (iCol+1) field prefixes that
|
|
- ** occur in the stat4 table for this index. Set sumEq to the sum of
|
|
- ** the nEq values for column iCol for the same set (adding the value
|
|
+ ** occur in the stat4 table for this index. Set sumEq to the sum of
|
|
+ ** the nEq values for column iCol for the same set (adding the value
|
|
** only once where there exist duplicate prefixes). */
|
|
for(i=0; i<nSample; i++){
|
|
if( i==(pIdx->nSample-1)
|
|
- || aSample[i].anDLt[iCol]!=aSample[i+1].anDLt[iCol]
|
|
+ || aSample[i].anDLt[iCol]!=aSample[i+1].anDLt[iCol]
|
|
){
|
|
sumEq += aSample[i].anEq[iCol];
|
|
nSum100 += 100;
|
|
@@ -108030,6 +116417,7 @@ static int loadStatTbl(
|
|
}
|
|
pSpace = (tRowcnt*)&pIdx->aSample[nSample];
|
|
pIdx->aAvgEq = pSpace; pSpace += nIdxCol;
|
|
+ pIdx->pTable->tabFlags |= TF_HasStat4;
|
|
for(i=0; i<nSample; i++){
|
|
pIdx->aSample[i].anEq = pSpace; pSpace += nIdxCol;
|
|
pIdx->aSample[i].anLt = pSpace; pSpace += nIdxCol;
|
|
@@ -108057,7 +116445,7 @@ static int loadStatTbl(
|
|
if( zIndex==0 ) continue;
|
|
pIdx = findIndexOrPrimaryKey(db, zIndex, zDb);
|
|
if( pIdx==0 ) continue;
|
|
- /* This next condition is true if data has already been loaded from
|
|
+ /* This next condition is true if data has already been loaded from
|
|
** the sqlite_stat4 table. */
|
|
nCol = pIdx->nSampleCol;
|
|
if( pIdx!=pPrevIdx ){
|
|
@@ -108092,16 +116480,19 @@ static int loadStatTbl(
|
|
}
|
|
|
|
/*
|
|
-** Load content from the sqlite_stat4 table into
|
|
+** Load content from the sqlite_stat4 table into
|
|
** the Index.aSample[] arrays of all indices.
|
|
*/
|
|
static int loadStat4(sqlite3 *db, const char *zDb){
|
|
int rc = SQLITE_OK; /* Result codes from subroutines */
|
|
+ const Table *pStat4;
|
|
|
|
assert( db->lookaside.bDisable );
|
|
- if( sqlite3FindTable(db, "sqlite_stat4", zDb) ){
|
|
+ if( (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",
|
|
"SELECT idx,neq,nlt,ndlt,sample FROM %Q.sqlite_stat4",
|
|
zDb
|
|
);
|
|
@@ -108117,11 +116508,11 @@ static int loadStat4(sqlite3 *db, const char *zDb){
|
|
** Index.aSample[] arrays.
|
|
**
|
|
** If the sqlite_stat1 table is not present in the database, SQLITE_ERROR
|
|
-** is returned. In this case, even if SQLITE_ENABLE_STAT4 was defined
|
|
-** during compilation and the sqlite_stat4 table is present, no data is
|
|
+** is returned. In this case, even if SQLITE_ENABLE_STAT4 was defined
|
|
+** during compilation and the sqlite_stat4 table is present, no data is
|
|
** read from it.
|
|
**
|
|
-** If SQLITE_ENABLE_STAT4 was defined during compilation and the
|
|
+** If SQLITE_ENABLE_STAT4 was defined during compilation and the
|
|
** sqlite_stat4 table is not present in the database, SQLITE_ERROR is
|
|
** returned. However, in this case, data is read from the sqlite_stat1
|
|
** table (if it is present) before returning.
|
|
@@ -108136,6 +116527,7 @@ SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
|
|
char *zSql;
|
|
int rc = SQLITE_OK;
|
|
Schema *pSchema = db->aDb[iDb].pSchema;
|
|
+ const Table *pStat1;
|
|
|
|
assert( iDb>=0 && iDb<db->nDb );
|
|
assert( db->aDb[iDb].pBt!=0 );
|
|
@@ -108158,8 +116550,10 @@ SQLITE_PRIVATE int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
|
|
/* Load new statistics out of the sqlite_stat1 table */
|
|
sInfo.db = db;
|
|
sInfo.zDatabase = db->aDb[iDb].zDbSName;
|
|
- if( sqlite3FindTable(db, "sqlite_stat1", sInfo.zDatabase)!=0 ){
|
|
- zSql = sqlite3MPrintf(db,
|
|
+ if( (pStat1 = sqlite3FindTable(db, "sqlite_stat1", sInfo.zDatabase))
|
|
+ && IsOrdinaryTable(pStat1)
|
|
+ ){
|
|
+ zSql = sqlite3MPrintf(db,
|
|
"SELECT tbl,idx,stat FROM %Q.sqlite_stat1", sInfo.zDatabase);
|
|
if( zSql==0 ){
|
|
rc = SQLITE_NOMEM_BKPT;
|
|
@@ -108248,6 +116642,17 @@ static int resolveAttachExpr(NameContext *pName, Expr *pExpr)
|
|
return rc;
|
|
}
|
|
|
|
+/*
|
|
+** Return true if zName points to a name that may be used to refer to
|
|
+** database iDb attached to handle db.
|
|
+*/
|
|
+SQLITE_PRIVATE int sqlite3DbIsNamed(sqlite3 *db, int iDb, const char *zName){
|
|
+ return (
|
|
+ sqlite3StrICmp(db->aDb[iDb].zDbSName, zName)==0
|
|
+ || (iDb==0 && sqlite3StrICmp("main", zName)==0)
|
|
+ );
|
|
+}
|
|
+
|
|
/*
|
|
** 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:
|
|
@@ -108277,7 +116682,7 @@ static void attachFunc(
|
|
char *zErr = 0;
|
|
unsigned int flags;
|
|
Db *aNew; /* New array of Db pointers */
|
|
- Db *pNew; /* Db object for the newly attached database */
|
|
+ Db *pNew = 0; /* Db object for the newly attached database */
|
|
char *zErrDyn = 0;
|
|
sqlite3_vfs *pVfs;
|
|
|
|
@@ -108287,7 +116692,7 @@ static void attachFunc(
|
|
if( zFile==0 ) zFile = "";
|
|
if( zName==0 ) zName = "";
|
|
|
|
-#ifdef SQLITE_ENABLE_DESERIALIZE
|
|
+#ifndef SQLITE_OMIT_DESERIALIZE
|
|
# define REOPEN_AS_MEMDB(db) (db->init.reopenMemdb)
|
|
#else
|
|
# define REOPEN_AS_MEMDB(db) (0)
|
|
@@ -108297,13 +116702,26 @@ static void attachFunc(
|
|
/* This is not a real ATTACH. Instead, this routine is being called
|
|
** from sqlite3_deserialize() to close database db->init.iDb and
|
|
** reopen it as a MemDB */
|
|
+ Btree *pNewBt = 0;
|
|
pVfs = sqlite3_vfs_find("memdb");
|
|
if( pVfs==0 ) return;
|
|
- pNew = &db->aDb[db->init.iDb];
|
|
- if( pNew->pBt ) sqlite3BtreeClose(pNew->pBt);
|
|
- pNew->pBt = 0;
|
|
- pNew->pSchema = 0;
|
|
- rc = sqlite3BtreeOpen(pVfs, "x\0", db, &pNew->pBt, 0, SQLITE_OPEN_MAIN_DB);
|
|
+ rc = sqlite3BtreeOpen(pVfs, "x\0", db, &pNewBt, 0, SQLITE_OPEN_MAIN_DB);
|
|
+ if( rc==SQLITE_OK ){
|
|
+ Schema *pNewSchema = sqlite3SchemaGet(db, pNewBt);
|
|
+ if( pNewSchema ){
|
|
+ /* Both the Btree and the new Schema were allocated successfully.
|
|
+ ** Close the old db and update the aDb[] slot with the new memdb
|
|
+ ** values. */
|
|
+ pNew = &db->aDb[db->init.iDb];
|
|
+ if( ALWAYS(pNew->pBt) ) sqlite3BtreeClose(pNew->pBt);
|
|
+ pNew->pBt = pNewBt;
|
|
+ pNew->pSchema = pNewSchema;
|
|
+ }else{
|
|
+ sqlite3BtreeClose(pNewBt);
|
|
+ rc = SQLITE_NOMEM;
|
|
+ }
|
|
+ }
|
|
+ if( rc ) goto attach_error;
|
|
}else{
|
|
/* This is a real ATTACH
|
|
**
|
|
@@ -108314,20 +116732,19 @@ static void attachFunc(
|
|
** * Specified database name already being used.
|
|
*/
|
|
if( db->nDb>=db->aLimit[SQLITE_LIMIT_ATTACHED]+2 ){
|
|
- zErrDyn = sqlite3MPrintf(db, "too many attached databases - max %d",
|
|
+ zErrDyn = sqlite3MPrintf(db, "too many attached databases - max %d",
|
|
db->aLimit[SQLITE_LIMIT_ATTACHED]
|
|
);
|
|
goto attach_error;
|
|
}
|
|
for(i=0; i<db->nDb; i++){
|
|
- char *z = db->aDb[i].zDbSName;
|
|
- assert( z && zName );
|
|
- if( sqlite3StrICmp(z, zName)==0 ){
|
|
+ assert( zName );
|
|
+ if( sqlite3DbIsNamed(db, i, zName) ){
|
|
zErrDyn = sqlite3MPrintf(db, "database %s is already in use", zName);
|
|
goto attach_error;
|
|
}
|
|
}
|
|
-
|
|
+
|
|
/* Allocate the new entry in the db->aDb[] array and initialize the schema
|
|
** hash tables.
|
|
*/
|
|
@@ -108342,7 +116759,7 @@ static void attachFunc(
|
|
db->aDb = aNew;
|
|
pNew = &db->aDb[db->nDb];
|
|
memset(pNew, 0, sizeof(*pNew));
|
|
-
|
|
+
|
|
/* Open the database file. If the btree is successfully opened, use
|
|
** it to obtain the database schema. At this point the schema may
|
|
** or may not be initialized.
|
|
@@ -108371,7 +116788,7 @@ static void attachFunc(
|
|
if( !pNew->pSchema ){
|
|
rc = SQLITE_NOMEM_BKPT;
|
|
}else if( pNew->pSchema->file_format && pNew->pSchema->enc!=ENC(db) ){
|
|
- zErrDyn = sqlite3MPrintf(db,
|
|
+ zErrDyn = sqlite3MPrintf(db,
|
|
"attached databases must use the same text encoding as main database");
|
|
rc = SQLITE_ERROR;
|
|
}
|
|
@@ -108390,46 +116807,10 @@ static void attachFunc(
|
|
if( rc==SQLITE_OK && pNew->zDbSName==0 ){
|
|
rc = SQLITE_NOMEM_BKPT;
|
|
}
|
|
-
|
|
-
|
|
-#ifdef SQLITE_HAS_CODEC
|
|
- if( rc==SQLITE_OK ){
|
|
- extern int sqlite3CodecAttach(sqlite3*, int, const void*, int);
|
|
- extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*);
|
|
- int nKey;
|
|
- char *zKey;
|
|
- int t = sqlite3_value_type(argv[2]);
|
|
- switch( t ){
|
|
- case SQLITE_INTEGER:
|
|
- case SQLITE_FLOAT:
|
|
- zErrDyn = sqlite3DbStrDup(db, "Invalid key value");
|
|
- rc = SQLITE_ERROR;
|
|
- break;
|
|
-
|
|
- case SQLITE_TEXT:
|
|
- case SQLITE_BLOB:
|
|
- nKey = sqlite3_value_bytes(argv[2]);
|
|
- zKey = (char *)sqlite3_value_blob(argv[2]);
|
|
- rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey);
|
|
- break;
|
|
-
|
|
- case SQLITE_NULL:
|
|
- /* No key specified. Use the key from URI filename, or if none,
|
|
- ** use the key from the main database. */
|
|
- if( sqlite3CodecQueryParameters(db, zName, zPath)==0 ){
|
|
- sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey);
|
|
- if( nKey || sqlite3BtreeGetOptimalReserve(db->aDb[0].pBt)>0 ){
|
|
- rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey);
|
|
- }
|
|
- }
|
|
- break;
|
|
- }
|
|
- }
|
|
-#endif
|
|
- sqlite3_free( zPath );
|
|
+ sqlite3_free_filename( zPath );
|
|
|
|
/* If the file was opened successfully, read the schema for the new database.
|
|
- ** If this fails, or if opening the file failed, then close the file and
|
|
+ ** If this fails, or if opening the file failed, then close the file and
|
|
** remove the entry from the db->aDb[] array. i.e. put everything back the
|
|
** way we found it.
|
|
*/
|
|
@@ -108453,7 +116834,7 @@ static void attachFunc(
|
|
}
|
|
#endif
|
|
if( rc ){
|
|
- if( !REOPEN_AS_MEMDB(db) ){
|
|
+ if( ALWAYS(!REOPEN_AS_MEMDB(db)) ){
|
|
int iDb = db->nDb - 1;
|
|
assert( iDb>=2 );
|
|
if( db->aDb[iDb].pBt ){
|
|
@@ -108473,7 +116854,7 @@ static void attachFunc(
|
|
}
|
|
goto attach_error;
|
|
}
|
|
-
|
|
+
|
|
return;
|
|
|
|
attach_error:
|
|
@@ -108511,7 +116892,7 @@ static void detachFunc(
|
|
for(i=0; i<db->nDb; i++){
|
|
pDb = &db->aDb[i];
|
|
if( pDb->pBt==0 ) continue;
|
|
- if( sqlite3StrICmp(pDb->zDbSName, zName)==0 ) break;
|
|
+ if( sqlite3DbIsNamed(db, i, zName) ) break;
|
|
}
|
|
|
|
if( i>=db->nDb ){
|
|
@@ -108522,7 +116903,9 @@ static void detachFunc(
|
|
sqlite3_snprintf(sizeof(zErr),zErr, "cannot detach database %s", zName);
|
|
goto detach_error;
|
|
}
|
|
- if( sqlite3BtreeIsInReadTrans(pDb->pBt) || sqlite3BtreeIsInBackup(pDb->pBt) ){
|
|
+ if( sqlite3BtreeTxnState(pDb->pBt)!=SQLITE_TXN_NONE
|
|
+ || sqlite3BtreeIsInBackup(pDb->pBt)
|
|
+ ){
|
|
sqlite3_snprintf(sizeof(zErr),zErr, "database %s is locked", zName);
|
|
goto detach_error;
|
|
}
|
|
@@ -108568,22 +116951,25 @@ static void codeAttach(
|
|
sqlite3* db = pParse->db;
|
|
int regArgs;
|
|
|
|
+ if( SQLITE_OK!=sqlite3ReadSchema(pParse) ) goto attach_end;
|
|
+
|
|
if( pParse->nErr ) goto attach_end;
|
|
memset(&sName, 0, sizeof(NameContext));
|
|
sName.pParse = pParse;
|
|
|
|
- if(
|
|
- SQLITE_OK!=(rc = resolveAttachExpr(&sName, pFilename)) ||
|
|
- SQLITE_OK!=(rc = resolveAttachExpr(&sName, pDbname)) ||
|
|
- SQLITE_OK!=(rc = resolveAttachExpr(&sName, pKey))
|
|
+ if(
|
|
+ SQLITE_OK!=resolveAttachExpr(&sName, pFilename) ||
|
|
+ SQLITE_OK!=resolveAttachExpr(&sName, pDbname) ||
|
|
+ SQLITE_OK!=resolveAttachExpr(&sName, pKey)
|
|
){
|
|
goto attach_end;
|
|
}
|
|
|
|
#ifndef SQLITE_OMIT_AUTHORIZATION
|
|
- if( pAuthArg ){
|
|
+ if( ALWAYS(pAuthArg) ){
|
|
char *zAuthArg;
|
|
if( pAuthArg->op==TK_STRING ){
|
|
+ assert( !ExprHasProperty(pAuthArg, EP_IntValue) );
|
|
zAuthArg = pAuthArg->u.zToken;
|
|
}else{
|
|
zAuthArg = 0;
|
|
@@ -108612,7 +116998,7 @@ static void codeAttach(
|
|
*/
|
|
sqlite3VdbeAddOp1(v, OP_Expire, (type==SQLITE_ATTACH));
|
|
}
|
|
-
|
|
+
|
|
attach_end:
|
|
sqlite3ExprDelete(db, pFilename);
|
|
sqlite3ExprDelete(db, pDbname);
|
|
@@ -108660,6 +117046,69 @@ SQLITE_PRIVATE void sqlite3Attach(Parse *pParse, Expr *p, Expr *pDbname, Expr *p
|
|
}
|
|
#endif /* SQLITE_OMIT_ATTACH */
|
|
|
|
+/*
|
|
+** Expression callback used by sqlite3FixAAAA() routines.
|
|
+*/
|
|
+static int fixExprCb(Walker *p, Expr *pExpr){
|
|
+ DbFixer *pFix = p->u.pFix;
|
|
+ if( !pFix->bTemp ) ExprSetProperty(pExpr, EP_FromDDL);
|
|
+ if( pExpr->op==TK_VARIABLE ){
|
|
+ if( pFix->pParse->db->init.busy ){
|
|
+ pExpr->op = TK_NULL;
|
|
+ }else{
|
|
+ sqlite3ErrorMsg(pFix->pParse, "%s cannot use variables", pFix->zType);
|
|
+ return WRC_Abort;
|
|
+ }
|
|
+ }
|
|
+ return WRC_Continue;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Select callback used by sqlite3FixAAAA() routines.
|
|
+*/
|
|
+static int fixSelectCb(Walker *p, Select *pSelect){
|
|
+ DbFixer *pFix = p->u.pFix;
|
|
+ int i;
|
|
+ SrcItem *pItem;
|
|
+ sqlite3 *db = pFix->pParse->db;
|
|
+ int iDb = sqlite3FindDbName(db, pFix->zDb);
|
|
+ SrcList *pList = pSelect->pSrc;
|
|
+
|
|
+ if( NEVER(pList==0) ) return WRC_Continue;
|
|
+ for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
|
|
+ if( pFix->bTemp==0 ){
|
|
+ if( pItem->zDatabase ){
|
|
+ if( iDb!=sqlite3FindDbName(db, pItem->zDatabase) ){
|
|
+ sqlite3ErrorMsg(pFix->pParse,
|
|
+ "%s %T cannot reference objects in database %s",
|
|
+ pFix->zType, pFix->pName, pItem->zDatabase);
|
|
+ return WRC_Abort;
|
|
+ }
|
|
+ sqlite3DbFree(db, pItem->zDatabase);
|
|
+ pItem->zDatabase = 0;
|
|
+ pItem->fg.notCte = 1;
|
|
+ }
|
|
+ pItem->pSchema = pFix->pSchema;
|
|
+ pItem->fg.fromDDL = 1;
|
|
+ }
|
|
+#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)
|
|
+ if( pList->a[i].fg.isUsing==0
|
|
+ && sqlite3WalkExpr(&pFix->w, pList->a[i].u3.pOn)
|
|
+ ){
|
|
+ return WRC_Abort;
|
|
+ }
|
|
+#endif
|
|
+ }
|
|
+ if( pSelect->pWith ){
|
|
+ for(i=0; i<pSelect->pWith->nCte; i++){
|
|
+ if( sqlite3WalkSelect(p, pSelect->pWith->a[i].pSelect) ){
|
|
+ return WRC_Abort;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ return WRC_Continue;
|
|
+}
|
|
+
|
|
/*
|
|
** Initialize a DbFixer structure. This routine must be called prior
|
|
** to passing the structure to one of the sqliteFixAAAA() routines below.
|
|
@@ -108671,9 +117120,7 @@ SQLITE_PRIVATE void sqlite3FixInit(
|
|
const char *zType, /* "view", "trigger", or "index" */
|
|
const Token *pName /* Name of the view, trigger, or index */
|
|
){
|
|
- sqlite3 *db;
|
|
-
|
|
- db = pParse->db;
|
|
+ sqlite3 *db = pParse->db;
|
|
assert( db->nDb>iDb );
|
|
pFix->pParse = pParse;
|
|
pFix->zDb = db->aDb[iDb].zDbSName;
|
|
@@ -108681,6 +117128,13 @@ SQLITE_PRIVATE void sqlite3FixInit(
|
|
pFix->zType = zType;
|
|
pFix->pName = pName;
|
|
pFix->bTemp = (iDb==1);
|
|
+ pFix->w.pParse = pParse;
|
|
+ pFix->w.xExprCallback = fixExprCb;
|
|
+ pFix->w.xSelectCallback = fixSelectCb;
|
|
+ pFix->w.xSelectCallback2 = sqlite3WalkWinDefnDummyCallback;
|
|
+ pFix->w.walkerDepth = 0;
|
|
+ pFix->w.eCode = 0;
|
|
+ pFix->w.u.pFix = pFix;
|
|
}
|
|
|
|
/*
|
|
@@ -108701,114 +117155,27 @@ SQLITE_PRIVATE int sqlite3FixSrcList(
|
|
DbFixer *pFix, /* Context of the fixation */
|
|
SrcList *pList /* The Source list to check and modify */
|
|
){
|
|
- int i;
|
|
- const char *zDb;
|
|
- struct SrcList_item *pItem;
|
|
-
|
|
- if( NEVER(pList==0) ) return 0;
|
|
- zDb = pFix->zDb;
|
|
- for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
|
|
- if( pFix->bTemp==0 ){
|
|
- if( pItem->zDatabase && sqlite3StrICmp(pItem->zDatabase, zDb) ){
|
|
- sqlite3ErrorMsg(pFix->pParse,
|
|
- "%s %T cannot reference objects in database %s",
|
|
- pFix->zType, pFix->pName, pItem->zDatabase);
|
|
- return 1;
|
|
- }
|
|
- sqlite3DbFree(pFix->pParse->db, pItem->zDatabase);
|
|
- pItem->zDatabase = 0;
|
|
- pItem->pSchema = pFix->pSchema;
|
|
- pItem->fg.fromDDL = 1;
|
|
- }
|
|
-#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)
|
|
- if( sqlite3FixSelect(pFix, pItem->pSelect) ) return 1;
|
|
- if( sqlite3FixExpr(pFix, pItem->pOn) ) return 1;
|
|
-#endif
|
|
- if( pItem->fg.isTabFunc && sqlite3FixExprList(pFix, pItem->u1.pFuncArg) ){
|
|
- return 1;
|
|
- }
|
|
+ int res = 0;
|
|
+ if( pList ){
|
|
+ Select s;
|
|
+ memset(&s, 0, sizeof(s));
|
|
+ s.pSrc = pList;
|
|
+ res = sqlite3WalkSelect(&pFix->w, &s);
|
|
}
|
|
- return 0;
|
|
+ return res;
|
|
}
|
|
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)
|
|
SQLITE_PRIVATE int sqlite3FixSelect(
|
|
DbFixer *pFix, /* Context of the fixation */
|
|
Select *pSelect /* The SELECT statement to be fixed to one database */
|
|
){
|
|
- while( pSelect ){
|
|
- if( sqlite3FixExprList(pFix, pSelect->pEList) ){
|
|
- return 1;
|
|
- }
|
|
- if( sqlite3FixSrcList(pFix, pSelect->pSrc) ){
|
|
- return 1;
|
|
- }
|
|
- if( sqlite3FixExpr(pFix, pSelect->pWhere) ){
|
|
- return 1;
|
|
- }
|
|
- if( sqlite3FixExprList(pFix, pSelect->pGroupBy) ){
|
|
- return 1;
|
|
- }
|
|
- if( sqlite3FixExpr(pFix, pSelect->pHaving) ){
|
|
- return 1;
|
|
- }
|
|
- if( sqlite3FixExprList(pFix, pSelect->pOrderBy) ){
|
|
- return 1;
|
|
- }
|
|
- if( sqlite3FixExpr(pFix, pSelect->pLimit) ){
|
|
- return 1;
|
|
- }
|
|
- if( pSelect->pWith ){
|
|
- int i;
|
|
- for(i=0; i<pSelect->pWith->nCte; i++){
|
|
- if( sqlite3FixSelect(pFix, pSelect->pWith->a[i].pSelect) ){
|
|
- return 1;
|
|
- }
|
|
- }
|
|
- }
|
|
- pSelect = pSelect->pPrior;
|
|
- }
|
|
- return 0;
|
|
+ return sqlite3WalkSelect(&pFix->w, pSelect);
|
|
}
|
|
SQLITE_PRIVATE int sqlite3FixExpr(
|
|
DbFixer *pFix, /* Context of the fixation */
|
|
Expr *pExpr /* The expression to be fixed to one database */
|
|
){
|
|
- while( pExpr ){
|
|
- if( !pFix->bTemp ) ExprSetProperty(pExpr, EP_FromDDL);
|
|
- if( pExpr->op==TK_VARIABLE ){
|
|
- if( pFix->pParse->db->init.busy ){
|
|
- pExpr->op = TK_NULL;
|
|
- }else{
|
|
- sqlite3ErrorMsg(pFix->pParse, "%s cannot use variables", pFix->zType);
|
|
- return 1;
|
|
- }
|
|
- }
|
|
- if( ExprHasProperty(pExpr, EP_TokenOnly|EP_Leaf) ) break;
|
|
- if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
|
- if( sqlite3FixSelect(pFix, pExpr->x.pSelect) ) return 1;
|
|
- }else{
|
|
- if( sqlite3FixExprList(pFix, pExpr->x.pList) ) return 1;
|
|
- }
|
|
- if( sqlite3FixExpr(pFix, pExpr->pRight) ){
|
|
- return 1;
|
|
- }
|
|
- pExpr = pExpr->pLeft;
|
|
- }
|
|
- return 0;
|
|
-}
|
|
-SQLITE_PRIVATE int sqlite3FixExprList(
|
|
- DbFixer *pFix, /* Context of the fixation */
|
|
- ExprList *pList /* The expression to be fixed to one database */
|
|
-){
|
|
- int i;
|
|
- struct ExprList_item *pItem;
|
|
- if( pList==0 ) return 0;
|
|
- for(i=0, pItem=pList->a; i<pList->nExpr; i++, pItem++){
|
|
- if( sqlite3FixExpr(pFix, pItem->pExpr) ){
|
|
- return 1;
|
|
- }
|
|
- }
|
|
- return 0;
|
|
+ return sqlite3WalkExpr(&pFix->w, pExpr);
|
|
}
|
|
#endif
|
|
|
|
@@ -108818,29 +117185,30 @@ SQLITE_PRIVATE int sqlite3FixTriggerStep(
|
|
TriggerStep *pStep /* The trigger step be fixed to one database */
|
|
){
|
|
while( pStep ){
|
|
- if( sqlite3FixSelect(pFix, pStep->pSelect) ){
|
|
- return 1;
|
|
- }
|
|
- if( sqlite3FixExpr(pFix, pStep->pWhere) ){
|
|
- return 1;
|
|
- }
|
|
- if( sqlite3FixExprList(pFix, pStep->pExprList) ){
|
|
+ if( sqlite3WalkSelect(&pFix->w, pStep->pSelect)
|
|
+ || sqlite3WalkExpr(&pFix->w, pStep->pWhere)
|
|
+ || sqlite3WalkExprList(&pFix->w, pStep->pExprList)
|
|
+ || sqlite3FixSrcList(pFix, pStep->pFrom)
|
|
+ ){
|
|
return 1;
|
|
}
|
|
#ifndef SQLITE_OMIT_UPSERT
|
|
- if( pStep->pUpsert ){
|
|
- Upsert *pUp = pStep->pUpsert;
|
|
- if( sqlite3FixExprList(pFix, pUp->pUpsertTarget)
|
|
- || sqlite3FixExpr(pFix, pUp->pUpsertTargetWhere)
|
|
- || sqlite3FixExprList(pFix, pUp->pUpsertSet)
|
|
- || sqlite3FixExpr(pFix, pUp->pUpsertWhere)
|
|
- ){
|
|
- return 1;
|
|
+ {
|
|
+ Upsert *pUp;
|
|
+ for(pUp=pStep->pUpsert; pUp; pUp=pUp->pNextUpsert){
|
|
+ if( sqlite3WalkExprList(&pFix->w, pUp->pUpsertTarget)
|
|
+ || sqlite3WalkExpr(&pFix->w, pUp->pUpsertTargetWhere)
|
|
+ || sqlite3WalkExprList(&pFix->w, pUp->pUpsertSet)
|
|
+ || sqlite3WalkExpr(&pFix->w, pUp->pUpsertWhere)
|
|
+ ){
|
|
+ return 1;
|
|
+ }
|
|
}
|
|
}
|
|
#endif
|
|
pStep = pStep->pNext;
|
|
}
|
|
+
|
|
return 0;
|
|
}
|
|
#endif
|
|
@@ -108979,10 +117347,10 @@ SQLITE_PRIVATE int sqlite3AuthReadCol(
|
|
|
|
/*
|
|
** The pExpr should be a TK_COLUMN expression. The table referred to
|
|
-** is in pTabList or else it is the NEW or OLD table of a trigger.
|
|
+** is in pTabList or else it is the NEW or OLD table of a trigger.
|
|
** Check to see if it is OK to read this particular column.
|
|
**
|
|
-** If the auth function returns SQLITE_IGNORE, change the TK_COLUMN
|
|
+** If the auth function returns SQLITE_IGNORE, change the TK_COLUMN
|
|
** instruction into a TK_NULL. If the auth function returns SQLITE_DENY,
|
|
** then generate an error.
|
|
*/
|
|
@@ -108992,7 +117360,6 @@ SQLITE_PRIVATE void sqlite3AuthRead(
|
|
Schema *pSchema, /* The schema of the expression */
|
|
SrcList *pTabList /* All table that pExpr might refer to */
|
|
){
|
|
- sqlite3 *db = pParse->db;
|
|
Table *pTab = 0; /* The table being read */
|
|
const char *zCol; /* Name of the column of the table */
|
|
int iSrc; /* Index in pTabList->a[] of table being read */
|
|
@@ -109000,8 +117367,8 @@ SQLITE_PRIVATE void sqlite3AuthRead(
|
|
int iCol; /* Index of column in table */
|
|
|
|
assert( pExpr->op==TK_COLUMN || pExpr->op==TK_TRIGGER );
|
|
- assert( !IN_RENAME_OBJECT || db->xAuth==0 );
|
|
- if( db->xAuth==0 ) return;
|
|
+ assert( !IN_RENAME_OBJECT );
|
|
+ assert( pParse->db->xAuth!=0 );
|
|
iDb = sqlite3SchemaToIndex(pParse->db, pSchema);
|
|
if( iDb<0 ){
|
|
/* An attempt to read a column out of a subquery or other
|
|
@@ -109013,7 +117380,7 @@ SQLITE_PRIVATE void sqlite3AuthRead(
|
|
pTab = pParse->pTriggerTab;
|
|
}else{
|
|
assert( pTabList );
|
|
- for(iSrc=0; ALWAYS(iSrc<pTabList->nSrc); iSrc++){
|
|
+ for(iSrc=0; iSrc<pTabList->nSrc; iSrc++){
|
|
if( pExpr->iTable==pTabList->a[iSrc].iCursor ){
|
|
pTab = pTabList->a[iSrc].pTab;
|
|
break;
|
|
@@ -109021,18 +117388,18 @@ SQLITE_PRIVATE void sqlite3AuthRead(
|
|
}
|
|
}
|
|
iCol = pExpr->iColumn;
|
|
- if( NEVER(pTab==0) ) return;
|
|
+ if( pTab==0 ) return;
|
|
|
|
if( iCol>=0 ){
|
|
assert( iCol<pTab->nCol );
|
|
- zCol = pTab->aCol[iCol].zName;
|
|
+ zCol = pTab->aCol[iCol].zCnName;
|
|
}else if( pTab->iPKey>=0 ){
|
|
assert( pTab->iPKey<pTab->nCol );
|
|
- zCol = pTab->aCol[pTab->iPKey].zName;
|
|
+ zCol = pTab->aCol[pTab->iPKey].zCnName;
|
|
}else{
|
|
zCol = "ROWID";
|
|
}
|
|
- assert( iDb>=0 && iDb<db->nDb );
|
|
+ assert( iDb>=0 && iDb<pParse->db->nDb );
|
|
if( SQLITE_IGNORE==sqlite3AuthReadCol(pParse, pTab->zName, zCol, iDb) ){
|
|
pExpr->op = TK_NULL;
|
|
}
|
|
@@ -109058,11 +117425,7 @@ SQLITE_PRIVATE int sqlite3AuthCheck(
|
|
** or if the parser is being invoked from within sqlite3_declare_vtab.
|
|
*/
|
|
assert( !IN_RENAME_OBJECT || db->xAuth==0 );
|
|
- if( db->init.busy || IN_SPECIAL_PARSE ){
|
|
- return SQLITE_OK;
|
|
- }
|
|
-
|
|
- if( db->xAuth==0 ){
|
|
+ if( db->xAuth==0 || db->init.busy || IN_SPECIAL_PARSE ){
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
@@ -109099,7 +117462,7 @@ SQLITE_PRIVATE int sqlite3AuthCheck(
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3AuthContextPush(
|
|
Parse *pParse,
|
|
- AuthContext *pContext,
|
|
+ AuthContext *pContext,
|
|
const char *zContext
|
|
){
|
|
assert( pParse );
|
|
@@ -109156,13 +117519,13 @@ SQLITE_PRIVATE void sqlite3AuthContextPop(AuthContext *pContext){
|
|
*/
|
|
struct TableLock {
|
|
int iDb; /* The database containing the table to be locked */
|
|
- int iTab; /* The root page of the table to be locked */
|
|
+ Pgno iTab; /* The root page of the table to be locked */
|
|
u8 isWriteLock; /* True for write lock. False for a read lock */
|
|
const char *zLockName; /* Name of the table */
|
|
};
|
|
|
|
/*
|
|
-** Record the fact that we want to lock a table at run-time.
|
|
+** Record the fact that we want to lock a table at run-time.
|
|
**
|
|
** The table to be locked has root page iTab and is found in database iDb.
|
|
** A read or a write lock can be taken depending on isWritelock.
|
|
@@ -109171,21 +117534,20 @@ struct TableLock {
|
|
** code to make the lock occur is generated by a later call to
|
|
** codeTableLocks() which occurs during sqlite3FinishCoding().
|
|
*/
|
|
-SQLITE_PRIVATE void sqlite3TableLock(
|
|
+static SQLITE_NOINLINE void lockTable(
|
|
Parse *pParse, /* Parsing context */
|
|
int iDb, /* Index of the database containing the table to lock */
|
|
- int iTab, /* Root page number of the table to be locked */
|
|
+ Pgno iTab, /* Root page number of the table to be locked */
|
|
u8 isWriteLock, /* True for a write lock */
|
|
const char *zName /* Name of the table to be locked */
|
|
){
|
|
- Parse *pToplevel = sqlite3ParseToplevel(pParse);
|
|
+ Parse *pToplevel;
|
|
int i;
|
|
int nBytes;
|
|
TableLock *p;
|
|
assert( iDb>=0 );
|
|
|
|
- if( iDb==1 ) return;
|
|
- if( !sqlite3BtreeSharable(pParse->db->aDb[iDb].pBt) ) return;
|
|
+ pToplevel = sqlite3ParseToplevel(pParse);
|
|
for(i=0; i<pToplevel->nTableLock; i++){
|
|
p = &pToplevel->aTableLock[i];
|
|
if( p->iDb==iDb && p->iTab==iTab ){
|
|
@@ -109208,6 +117570,17 @@ SQLITE_PRIVATE void sqlite3TableLock(
|
|
sqlite3OomFault(pToplevel->db);
|
|
}
|
|
}
|
|
+SQLITE_PRIVATE void sqlite3TableLock(
|
|
+ Parse *pParse, /* Parsing context */
|
|
+ int iDb, /* Index of the database containing the table to lock */
|
|
+ Pgno iTab, /* Root page number of the table to be locked */
|
|
+ u8 isWriteLock, /* True for a write lock */
|
|
+ const char *zName /* Name of the table to be locked */
|
|
+){
|
|
+ if( iDb==1 ) return;
|
|
+ if( !sqlite3BtreeSharable(pParse->db->aDb[iDb].pBt) ) return;
|
|
+ lockTable(pParse, iDb, iTab, isWriteLock, zName);
|
|
+}
|
|
|
|
/*
|
|
** Code an OP_TableLock instruction for each table locked by the
|
|
@@ -109215,10 +117588,8 @@ SQLITE_PRIVATE void sqlite3TableLock(
|
|
*/
|
|
static void codeTableLocks(Parse *pParse){
|
|
int i;
|
|
- Vdbe *pVdbe;
|
|
-
|
|
- pVdbe = sqlite3GetVdbe(pParse);
|
|
- assert( pVdbe!=0 ); /* sqlite3GetVdbe cannot fail: VDBE already allocated */
|
|
+ Vdbe *pVdbe = pParse->pVdbe;
|
|
+ assert( pVdbe!=0 );
|
|
|
|
for(i=0; i<pParse->nTableLock; i++){
|
|
TableLock *p = &pParse->aTableLock[i];
|
|
@@ -109257,22 +117628,53 @@ SQLITE_PRIVATE int sqlite3DbMaskAllZero(yDbMask m){
|
|
SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){
|
|
sqlite3 *db;
|
|
Vdbe *v;
|
|
+ int iDb, i;
|
|
|
|
assert( pParse->pToplevel==0 );
|
|
db = pParse->db;
|
|
+ assert( db->pParse==pParse );
|
|
if( pParse->nested ) return;
|
|
- if( db->mallocFailed || pParse->nErr ){
|
|
- if( pParse->rc==SQLITE_OK ) pParse->rc = SQLITE_ERROR;
|
|
+ if( pParse->nErr ){
|
|
+ if( db->mallocFailed ) pParse->rc = SQLITE_NOMEM;
|
|
return;
|
|
}
|
|
+ assert( db->mallocFailed==0 );
|
|
|
|
/* Begin by generating some termination code at the end of the
|
|
** vdbe program
|
|
*/
|
|
- v = sqlite3GetVdbe(pParse);
|
|
- assert( !pParse->isMultiWrite
|
|
+ v = pParse->pVdbe;
|
|
+ if( v==0 ){
|
|
+ if( db->init.busy ){
|
|
+ pParse->rc = SQLITE_DONE;
|
|
+ return;
|
|
+ }
|
|
+ v = sqlite3GetVdbe(pParse);
|
|
+ if( v==0 ) pParse->rc = SQLITE_ERROR;
|
|
+ }
|
|
+ assert( !pParse->isMultiWrite
|
|
|| sqlite3VdbeAssertMayAbort(v, pParse->mayAbort));
|
|
if( v ){
|
|
+ if( pParse->bReturning ){
|
|
+ Returning *pReturning = pParse->u1.pReturning;
|
|
+ int addrRewind;
|
|
+ int reg;
|
|
+
|
|
+ if( pReturning->nRetCol ){
|
|
+ sqlite3VdbeAddOp0(v, OP_FkCheck);
|
|
+ addrRewind =
|
|
+ sqlite3VdbeAddOp1(v, OP_Rewind, pReturning->iRetCur);
|
|
+ VdbeCoverage(v);
|
|
+ reg = pReturning->iRetReg;
|
|
+ for(i=0; i<pReturning->nRetCol; i++){
|
|
+ sqlite3VdbeAddOp3(v, OP_Column, pReturning->iRetCur, i, reg+i);
|
|
+ }
|
|
+ sqlite3VdbeAddOp2(v, OP_ResultRow, reg, i);
|
|
+ sqlite3VdbeAddOp2(v, OP_Next, pReturning->iRetCur, addrRewind+1);
|
|
+ VdbeCoverage(v);
|
|
+ sqlite3VdbeJumpHere(v, addrRewind);
|
|
+ }
|
|
+ }
|
|
sqlite3VdbeAddOp0(v, OP_Halt);
|
|
|
|
#if SQLITE_USER_AUTHENTICATION
|
|
@@ -109292,64 +117694,76 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){
|
|
** transaction on each used database and to verify the schema cookie
|
|
** on each used database.
|
|
*/
|
|
- if( db->mallocFailed==0
|
|
- && (DbMaskNonZero(pParse->cookieMask) || pParse->pConstExpr)
|
|
- ){
|
|
- int iDb, i;
|
|
- assert( sqlite3VdbeGetOp(v, 0)->opcode==OP_Init );
|
|
- sqlite3VdbeJumpHere(v, 0);
|
|
- for(iDb=0; iDb<db->nDb; iDb++){
|
|
- Schema *pSchema;
|
|
- if( DbMaskTest(pParse->cookieMask, iDb)==0 ) continue;
|
|
- sqlite3VdbeUsesBtree(v, iDb);
|
|
- pSchema = db->aDb[iDb].pSchema;
|
|
- sqlite3VdbeAddOp4Int(v,
|
|
- OP_Transaction, /* Opcode */
|
|
- iDb, /* P1 */
|
|
- DbMaskTest(pParse->writeMask,iDb), /* P2 */
|
|
- pSchema->schema_cookie, /* P3 */
|
|
- pSchema->iGeneration /* P4 */
|
|
- );
|
|
- if( db->init.busy==0 ) sqlite3VdbeChangeP5(v, 1);
|
|
- VdbeComment((v,
|
|
- "usesStmtJournal=%d", pParse->mayAbort && pParse->isMultiWrite));
|
|
- }
|
|
+ assert( pParse->nErr>0 || sqlite3VdbeGetOp(v, 0)->opcode==OP_Init );
|
|
+ sqlite3VdbeJumpHere(v, 0);
|
|
+ assert( db->nDb>0 );
|
|
+ iDb = 0;
|
|
+ do{
|
|
+ Schema *pSchema;
|
|
+ if( DbMaskTest(pParse->cookieMask, iDb)==0 ) continue;
|
|
+ sqlite3VdbeUsesBtree(v, iDb);
|
|
+ pSchema = db->aDb[iDb].pSchema;
|
|
+ sqlite3VdbeAddOp4Int(v,
|
|
+ OP_Transaction, /* Opcode */
|
|
+ iDb, /* P1 */
|
|
+ DbMaskTest(pParse->writeMask,iDb), /* P2 */
|
|
+ pSchema->schema_cookie, /* P3 */
|
|
+ pSchema->iGeneration /* P4 */
|
|
+ );
|
|
+ if( db->init.busy==0 ) sqlite3VdbeChangeP5(v, 1);
|
|
+ VdbeComment((v,
|
|
+ "usesStmtJournal=%d", pParse->mayAbort && pParse->isMultiWrite));
|
|
+ }while( ++iDb<db->nDb );
|
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
|
- for(i=0; i<pParse->nVtabLock; i++){
|
|
- char *vtab = (char *)sqlite3GetVTable(db, pParse->apVtabLock[i]);
|
|
- sqlite3VdbeAddOp4(v, OP_VBegin, 0, 0, 0, vtab, P4_VTAB);
|
|
- }
|
|
- pParse->nVtabLock = 0;
|
|
+ for(i=0; i<pParse->nVtabLock; i++){
|
|
+ char *vtab = (char *)sqlite3GetVTable(db, pParse->apVtabLock[i]);
|
|
+ sqlite3VdbeAddOp4(v, OP_VBegin, 0, 0, 0, vtab, P4_VTAB);
|
|
+ }
|
|
+ pParse->nVtabLock = 0;
|
|
#endif
|
|
|
|
- /* 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);
|
|
+ /* 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);
|
|
|
|
- /* Initialize any AUTOINCREMENT data structures required.
|
|
- */
|
|
- sqlite3AutoincrementBegin(pParse);
|
|
+ /* Initialize any AUTOINCREMENT data structures required.
|
|
+ */
|
|
+ sqlite3AutoincrementBegin(pParse);
|
|
|
|
- /* Code constant expressions that where factored out of inner loops */
|
|
- if( pParse->pConstExpr ){
|
|
- ExprList *pEL = pParse->pConstExpr;
|
|
- pParse->okConstFactor = 0;
|
|
- for(i=0; i<pEL->nExpr; i++){
|
|
- sqlite3ExprCode(pParse, pEL->a[i].pExpr, pEL->a[i].u.iConstExprReg);
|
|
- }
|
|
+ /* Code constant expressions that where factored out of inner loops.
|
|
+ **
|
|
+ ** The pConstExpr list might also contain expressions that we simply
|
|
+ ** want to keep around until the Parse object is deleted. Such
|
|
+ ** expressions have iConstExprReg==0. Do not generate code for
|
|
+ ** those expressions, of course.
|
|
+ */
|
|
+ if( pParse->pConstExpr ){
|
|
+ ExprList *pEL = pParse->pConstExpr;
|
|
+ pParse->okConstFactor = 0;
|
|
+ for(i=0; i<pEL->nExpr; i++){
|
|
+ int iReg = pEL->a[i].u.iConstExprReg;
|
|
+ sqlite3ExprCode(pParse, pEL->a[i].pExpr, iReg);
|
|
}
|
|
+ }
|
|
|
|
- /* Finally, jump back to the beginning of the executable code. */
|
|
- sqlite3VdbeGoto(v, 1);
|
|
+ if( pParse->bReturning ){
|
|
+ Returning *pRet = pParse->u1.pReturning;
|
|
+ if( pRet->nRetCol ){
|
|
+ sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRet->iRetCur, pRet->nRetCol);
|
|
+ }
|
|
}
|
|
- }
|
|
|
|
+ /* Finally, jump back to the beginning of the executable code. */
|
|
+ sqlite3VdbeGoto(v, 1);
|
|
+ }
|
|
|
|
/* Get the VDBE program ready for execution
|
|
*/
|
|
- if( v && pParse->nErr==0 && !db->mallocFailed ){
|
|
+ assert( v!=0 || pParse->nErr );
|
|
+ assert( db->mallocFailed==0 || pParse->nErr );
|
|
+ if( pParse->nErr==0 ){
|
|
/* A minimum of one cursor is required if autoincrement is used
|
|
* See ticket [a696379c1f08866] */
|
|
assert( pParse->pAinc==0 || pParse->nTab>0 );
|
|
@@ -109363,23 +117777,25 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){
|
|
/*
|
|
** Run the parser and code generator recursively in order to generate
|
|
** code for the SQL statement given onto the end of the pParse context
|
|
-** currently under construction. When the parser is run recursively
|
|
-** this way, the final OP_Halt is not appended and other initialization
|
|
-** and finalization steps are omitted because those are handling by the
|
|
-** outermost parser.
|
|
+** currently under construction. Notes:
|
|
**
|
|
-** Not everything is nestable. This facility is designed to permit
|
|
-** INSERT, UPDATE, and DELETE operations against SQLITE_MASTER. Use
|
|
-** care if you decide to try to use this routine for some other purposes.
|
|
+** * The final OP_Halt is not appended and other initialization
|
|
+** and finalization steps are omitted because those are handling by the
|
|
+** outermost parser.
|
|
+**
|
|
+** * Built-in SQL functions always take precedence over application-defined
|
|
+** SQL functions. In other words, it is not possible to override a
|
|
+** built-in function.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){
|
|
va_list ap;
|
|
char *zSql;
|
|
- char *zErrMsg = 0;
|
|
sqlite3 *db = pParse->db;
|
|
+ u32 savedDbFlags = db->mDbFlags;
|
|
char saveBuf[PARSE_TAIL_SZ];
|
|
|
|
if( pParse->nErr ) return;
|
|
+ if( pParse->eParseMode ) return;
|
|
assert( pParse->nested<10 ); /* Nesting should only be of limited depth */
|
|
va_start(ap, zFormat);
|
|
zSql = sqlite3VMPrintf(db, zFormat, ap);
|
|
@@ -109395,8 +117811,9 @@ SQLITE_PRIVATE void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){
|
|
pParse->nested++;
|
|
memcpy(saveBuf, PARSE_TAIL(pParse), PARSE_TAIL_SZ);
|
|
memset(PARSE_TAIL(pParse), 0, PARSE_TAIL_SZ);
|
|
- sqlite3RunParser(pParse, zSql, &zErrMsg);
|
|
- sqlite3DbFree(db, zErrMsg);
|
|
+ db->mDbFlags |= DBFLAG_PreferBuiltin;
|
|
+ sqlite3RunParser(pParse, zSql);
|
|
+ db->mDbFlags = savedDbFlags;
|
|
sqlite3DbFree(db, zSql);
|
|
memcpy(PARSE_TAIL(pParse), saveBuf, PARSE_TAIL_SZ);
|
|
pParse->nested--;
|
|
@@ -109437,22 +117854,59 @@ SQLITE_PRIVATE Table *sqlite3FindTable(sqlite3 *db, const char *zName, const cha
|
|
return 0;
|
|
}
|
|
#endif
|
|
- while(1){
|
|
- for(i=OMIT_TEMPDB; i<db->nDb; i++){
|
|
- int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
|
|
- if( zDatabase==0 || sqlite3StrICmp(zDatabase, db->aDb[j].zDbSName)==0 ){
|
|
- assert( sqlite3SchemaMutexHeld(db, j, 0) );
|
|
- p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName);
|
|
- if( p ) return p;
|
|
+ if( zDatabase ){
|
|
+ for(i=0; i<db->nDb; i++){
|
|
+ if( sqlite3StrICmp(zDatabase, db->aDb[i].zDbSName)==0 ) break;
|
|
+ }
|
|
+ if( i>=db->nDb ){
|
|
+ /* No match against the official names. But always match "main"
|
|
+ ** to schema 0 as a legacy fallback. */
|
|
+ if( sqlite3StrICmp(zDatabase,"main")==0 ){
|
|
+ i = 0;
|
|
+ }else{
|
|
+ return 0;
|
|
+ }
|
|
+ }
|
|
+ p = sqlite3HashFind(&db->aDb[i].pSchema->tblHash, zName);
|
|
+ if( p==0 && sqlite3StrNICmp(zName, "sqlite_", 7)==0 ){
|
|
+ if( i==1 ){
|
|
+ if( sqlite3StrICmp(zName+7, &PREFERRED_TEMP_SCHEMA_TABLE[7])==0
|
|
+ || sqlite3StrICmp(zName+7, &PREFERRED_SCHEMA_TABLE[7])==0
|
|
+ || sqlite3StrICmp(zName+7, &LEGACY_SCHEMA_TABLE[7])==0
|
|
+ ){
|
|
+ p = sqlite3HashFind(&db->aDb[1].pSchema->tblHash,
|
|
+ LEGACY_TEMP_SCHEMA_TABLE);
|
|
+ }
|
|
+ }else{
|
|
+ if( sqlite3StrICmp(zName+7, &PREFERRED_SCHEMA_TABLE[7])==0 ){
|
|
+ p = sqlite3HashFind(&db->aDb[i].pSchema->tblHash,
|
|
+ LEGACY_SCHEMA_TABLE);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }else{
|
|
+ /* Match against TEMP first */
|
|
+ p = sqlite3HashFind(&db->aDb[1].pSchema->tblHash, zName);
|
|
+ if( p ) return p;
|
|
+ /* The main database is second */
|
|
+ p = sqlite3HashFind(&db->aDb[0].pSchema->tblHash, zName);
|
|
+ if( p ) return p;
|
|
+ /* Attached databases are in order of attachment */
|
|
+ for(i=2; i<db->nDb; i++){
|
|
+ assert( sqlite3SchemaMutexHeld(db, i, 0) );
|
|
+ p = sqlite3HashFind(&db->aDb[i].pSchema->tblHash, zName);
|
|
+ if( p ) break;
|
|
+ }
|
|
+ if( p==0 && sqlite3StrNICmp(zName, "sqlite_", 7)==0 ){
|
|
+ if( sqlite3StrICmp(zName+7, &PREFERRED_SCHEMA_TABLE[7])==0 ){
|
|
+ p = sqlite3HashFind(&db->aDb[0].pSchema->tblHash, LEGACY_SCHEMA_TABLE);
|
|
+ }else if( sqlite3StrICmp(zName+7, &PREFERRED_TEMP_SCHEMA_TABLE[7])==0 ){
|
|
+ p = sqlite3HashFind(&db->aDb[1].pSchema->tblHash,
|
|
+ LEGACY_TEMP_SCHEMA_TABLE);
|
|
}
|
|
}
|
|
- /* Not found. If the name we were looking for was temp.sqlite_master
|
|
- ** then change the name to sqlite_temp_master and try again. */
|
|
- if( sqlite3StrICmp(zName, MASTER_NAME)!=0 ) break;
|
|
- if( sqlite3_stricmp(zDatabase, db->aDb[1].zDbSName)!=0 ) break;
|
|
- zName = TEMP_MASTER_NAME;
|
|
}
|
|
- return 0;
|
|
+ return p;
|
|
}
|
|
|
|
/*
|
|
@@ -109476,7 +117930,7 @@ SQLITE_PRIVATE Table *sqlite3LocateTable(
|
|
|
|
/* Read the database schema. If an error occurs, leave an error message
|
|
** and code in pParse and return NULL. */
|
|
- if( (db->mDbFlags & DBFLAG_SchemaKnownOk)==0
|
|
+ if( (db->mDbFlags & DBFLAG_SchemaKnownOk)==0
|
|
&& SQLITE_OK!=sqlite3ReadSchema(pParse)
|
|
){
|
|
return 0;
|
|
@@ -109488,19 +117942,20 @@ SQLITE_PRIVATE Table *sqlite3LocateTable(
|
|
/* If zName is the not the name of a table in the schema created using
|
|
** CREATE, then check to see if it is the name of an virtual table that
|
|
** can be an eponymous virtual table. */
|
|
- if( pParse->disableVtab==0 ){
|
|
+ if( (pParse->prepFlags & SQLITE_PREPARE_NO_VTAB)==0 && db->init.busy==0 ){
|
|
Module *pMod = (Module*)sqlite3HashFind(&db->aModule, zName);
|
|
if( pMod==0 && sqlite3_strnicmp(zName, "pragma_", 7)==0 ){
|
|
pMod = sqlite3PragmaVtabRegister(db, zName);
|
|
}
|
|
if( pMod && sqlite3VtabEponymousTableInit(pParse, pMod) ){
|
|
+ testcase( pMod->pEpoTab==0 );
|
|
return pMod->pEpoTab;
|
|
}
|
|
}
|
|
#endif
|
|
if( flags & LOCATE_NOERR ) return 0;
|
|
pParse->checkSchema = 1;
|
|
- }else if( IsVirtual(p) && pParse->disableVtab ){
|
|
+ }else if( IsVirtual(p) && (pParse->prepFlags & SQLITE_PREPARE_NO_VTAB)!=0 ){
|
|
p = 0;
|
|
}
|
|
|
|
@@ -109511,6 +117966,8 @@ SQLITE_PRIVATE Table *sqlite3LocateTable(
|
|
}else{
|
|
sqlite3ErrorMsg(pParse, "%s: %s", zMsg, zName);
|
|
}
|
|
+ }else{
|
|
+ assert( HasRowid(p) || p->iPKey<0 );
|
|
}
|
|
|
|
return p;
|
|
@@ -109526,9 +117983,9 @@ SQLITE_PRIVATE Table *sqlite3LocateTable(
|
|
** sqlite3FixSrcList() for details.
|
|
*/
|
|
SQLITE_PRIVATE Table *sqlite3LocateTableItem(
|
|
- Parse *pParse,
|
|
+ Parse *pParse,
|
|
u32 flags,
|
|
- struct SrcList_item *p
|
|
+ SrcItem *p
|
|
){
|
|
const char *zDb;
|
|
assert( p->pSchema==0 || p->zDatabase==0 );
|
|
@@ -109542,7 +117999,23 @@ SQLITE_PRIVATE Table *sqlite3LocateTableItem(
|
|
}
|
|
|
|
/*
|
|
-** Locate the in-memory structure that describes
|
|
+** Return the preferred table name for system tables. Translate legacy
|
|
+** names into the new preferred names, as appropriate.
|
|
+*/
|
|
+SQLITE_PRIVATE const char *sqlite3PreferredTableName(const char *zName){
|
|
+ if( sqlite3StrNICmp(zName, "sqlite_", 7)==0 ){
|
|
+ if( sqlite3StrICmp(zName+7, &LEGACY_SCHEMA_TABLE[7])==0 ){
|
|
+ return PREFERRED_SCHEMA_TABLE;
|
|
+ }
|
|
+ if( sqlite3StrICmp(zName+7, &LEGACY_TEMP_SCHEMA_TABLE[7])==0 ){
|
|
+ return PREFERRED_TEMP_SCHEMA_TABLE;
|
|
+ }
|
|
+ }
|
|
+ return zName;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Locate the in-memory structure that describes
|
|
** a particular index given the name of that index
|
|
** and the name of the database that contains the index.
|
|
** Return NULL if not found.
|
|
@@ -109562,7 +118035,7 @@ SQLITE_PRIVATE Index *sqlite3FindIndex(sqlite3 *db, const char *zName, const cha
|
|
int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
|
|
Schema *pSchema = db->aDb[j].pSchema;
|
|
assert( pSchema );
|
|
- if( zDb && sqlite3StrICmp(zDb, db->aDb[j].zDbSName) ) continue;
|
|
+ if( zDb && sqlite3DbIsNamed(db, j, zDb)==0 ) continue;
|
|
assert( sqlite3SchemaMutexHeld(db, j, 0) );
|
|
p = sqlite3HashFind(&pSchema->idxHash, zName);
|
|
if( p ) break;
|
|
@@ -109705,6 +118178,84 @@ SQLITE_PRIVATE void sqlite3CommitInternalChanges(sqlite3 *db){
|
|
db->mDbFlags &= ~DBFLAG_SchemaChange;
|
|
}
|
|
|
|
+/*
|
|
+** Set the expression associated with a column. This is usually
|
|
+** the DEFAULT value, but might also be the expression that computes
|
|
+** the value for a generated column.
|
|
+*/
|
|
+SQLITE_PRIVATE void sqlite3ColumnSetExpr(
|
|
+ Parse *pParse, /* Parsing context */
|
|
+ Table *pTab, /* The table containing the column */
|
|
+ Column *pCol, /* The column to receive the new DEFAULT expression */
|
|
+ Expr *pExpr /* The new default expression */
|
|
+){
|
|
+ ExprList *pList;
|
|
+ assert( IsOrdinaryTable(pTab) );
|
|
+ pList = pTab->u.tab.pDfltList;
|
|
+ if( pCol->iDflt==0
|
|
+ || NEVER(pList==0)
|
|
+ || NEVER(pList->nExpr<pCol->iDflt)
|
|
+ ){
|
|
+ pCol->iDflt = pList==0 ? 1 : pList->nExpr+1;
|
|
+ pTab->u.tab.pDfltList = sqlite3ExprListAppend(pParse, pList, pExpr);
|
|
+ }else{
|
|
+ sqlite3ExprDelete(pParse->db, pList->a[pCol->iDflt-1].pExpr);
|
|
+ pList->a[pCol->iDflt-1].pExpr = pExpr;
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+** Return the expression associated with a column. The expression might be
|
|
+** the DEFAULT clause or the AS clause of a generated column.
|
|
+** Return NULL if the column has no associated expression.
|
|
+*/
|
|
+SQLITE_PRIVATE Expr *sqlite3ColumnExpr(Table *pTab, Column *pCol){
|
|
+ if( pCol->iDflt==0 ) return 0;
|
|
+ if( NEVER(!IsOrdinaryTable(pTab)) ) return 0;
|
|
+ if( NEVER(pTab->u.tab.pDfltList==0) ) return 0;
|
|
+ if( NEVER(pTab->u.tab.pDfltList->nExpr<pCol->iDflt) ) return 0;
|
|
+ return pTab->u.tab.pDfltList->a[pCol->iDflt-1].pExpr;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Set the collating sequence name for a column.
|
|
+*/
|
|
+SQLITE_PRIVATE void sqlite3ColumnSetColl(
|
|
+ sqlite3 *db,
|
|
+ Column *pCol,
|
|
+ const char *zColl
|
|
+){
|
|
+ i64 nColl;
|
|
+ i64 n;
|
|
+ char *zNew;
|
|
+ assert( zColl!=0 );
|
|
+ n = sqlite3Strlen30(pCol->zCnName) + 1;
|
|
+ if( pCol->colFlags & COLFLAG_HASTYPE ){
|
|
+ n += sqlite3Strlen30(pCol->zCnName+n) + 1;
|
|
+ }
|
|
+ nColl = sqlite3Strlen30(zColl) + 1;
|
|
+ zNew = sqlite3DbRealloc(db, pCol->zCnName, nColl+n);
|
|
+ if( zNew ){
|
|
+ pCol->zCnName = zNew;
|
|
+ memcpy(pCol->zCnName + n, zColl, nColl);
|
|
+ pCol->colFlags |= COLFLAG_HASCOLL;
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+** Return the collating squence name for a column
|
|
+*/
|
|
+SQLITE_PRIVATE const char *sqlite3ColumnColl(Column *pCol){
|
|
+ const char *z;
|
|
+ if( (pCol->colFlags & COLFLAG_HASCOLL)==0 ) return 0;
|
|
+ z = pCol->zCnName;
|
|
+ while( *z ){ z++; }
|
|
+ if( pCol->colFlags & COLFLAG_HASTYPE ){
|
|
+ do{ z++; }while( *z );
|
|
+ }
|
|
+ return z+1;
|
|
+}
|
|
+
|
|
/*
|
|
** Delete memory allocated for the column names of a table or view (the
|
|
** Table.aCol[] array).
|
|
@@ -109713,13 +118264,23 @@ SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3 *db, Table *pTable){
|
|
int i;
|
|
Column *pCol;
|
|
assert( pTable!=0 );
|
|
+ assert( db!=0 );
|
|
if( (pCol = pTable->aCol)!=0 ){
|
|
for(i=0; i<pTable->nCol; i++, pCol++){
|
|
- sqlite3DbFree(db, pCol->zName);
|
|
- sqlite3ExprDelete(db, pCol->pDflt);
|
|
- sqlite3DbFree(db, pCol->zColl);
|
|
+ assert( pCol->zCnName==0 || pCol->hName==sqlite3StrIHash(pCol->zCnName) );
|
|
+ sqlite3DbFree(db, pCol->zCnName);
|
|
+ }
|
|
+ sqlite3DbNNFreeNN(db, pTable->aCol);
|
|
+ if( IsOrdinaryTable(pTable) ){
|
|
+ sqlite3ExprListDelete(db, pTable->u.tab.pDfltList);
|
|
+ }
|
|
+ if( db->pnBytesFreed==0 ){
|
|
+ pTable->aCol = 0;
|
|
+ pTable->nCol = 0;
|
|
+ if( IsOrdinaryTable(pTable) ){
|
|
+ pTable->u.tab.pDfltList = 0;
|
|
+ }
|
|
}
|
|
- sqlite3DbFree(db, pTable->aCol);
|
|
}
|
|
}
|
|
|
|
@@ -109729,10 +118290,10 @@ SQLITE_PRIVATE void sqlite3DeleteColumnNames(sqlite3 *db, Table *pTable){
|
|
**
|
|
** This routine just deletes the data structure. It does not unlink
|
|
** the table data structure from the hash table. But it does destroy
|
|
-** memory structures of the indices and foreign keys associated with
|
|
+** memory structures of the indices and foreign keys associated with
|
|
** the table.
|
|
**
|
|
-** The db parameter is optional. It is needed if the Table object
|
|
+** The db parameter is optional. It is needed if the Table object
|
|
** contains lookaside memory. (Table objects in the schema do not use
|
|
** lookaside memory, but some ephemeral Table objects do.) Or the
|
|
** db parameter can be used with db->pnBytesFreed to measure the memory
|
|
@@ -109744,13 +118305,14 @@ static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){
|
|
#ifdef SQLITE_DEBUG
|
|
/* Record the number of outstanding lookaside allocations in schema Tables
|
|
** prior to doing any free() operations. Since schema Tables do not use
|
|
- ** lookaside, this number should not change.
|
|
+ ** lookaside, this number should not change.
|
|
**
|
|
** If malloc has already failed, it may be that it failed while allocating
|
|
** a Table object that was going to be marked ephemeral. So do not check
|
|
** that no lookaside memory is used in this case either. */
|
|
int nLookaside = 0;
|
|
- if( db && !db->mallocFailed && (pTable->tabFlags & TF_Ephemeral)==0 ){
|
|
+ assert( db!=0 );
|
|
+ if( !db->mallocFailed && (pTable->tabFlags & TF_Ephemeral)==0 ){
|
|
nLookaside = sqlite3LookasideUsed(db, 0);
|
|
}
|
|
#endif
|
|
@@ -109760,8 +118322,8 @@ static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){
|
|
pNext = pIndex->pNext;
|
|
assert( pIndex->pSchema==pTable->pSchema
|
|
|| (IsVirtual(pTable) && pIndex->idxType!=SQLITE_IDXTYPE_APPDEF) );
|
|
- if( (db==0 || db->pnBytesFreed==0) && !IsVirtual(pTable) ){
|
|
- char *zName = pIndex->zName;
|
|
+ if( db->pnBytesFreed==0 && !IsVirtual(pTable) ){
|
|
+ char *zName = pIndex->zName;
|
|
TESTONLY ( Index *pOld = ) sqlite3HashInsert(
|
|
&pIndex->pSchema->idxHash, zName, 0
|
|
);
|
|
@@ -109771,19 +118333,25 @@ static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){
|
|
sqlite3FreeIndex(db, pIndex);
|
|
}
|
|
|
|
- /* Delete any foreign keys attached to this table. */
|
|
- sqlite3FkDelete(db, pTable);
|
|
+ if( IsOrdinaryTable(pTable) ){
|
|
+ sqlite3FkDelete(db, pTable);
|
|
+ }
|
|
+#ifndef SQLITE_OMIT_VIRTUAL_TABLE
|
|
+ else if( IsVirtual(pTable) ){
|
|
+ sqlite3VtabClear(db, pTable);
|
|
+ }
|
|
+#endif
|
|
+ else{
|
|
+ assert( IsView(pTable) );
|
|
+ sqlite3SelectDelete(db, pTable->u.view.pSelect);
|
|
+ }
|
|
|
|
/* Delete the Table structure itself.
|
|
*/
|
|
sqlite3DeleteColumnNames(db, pTable);
|
|
sqlite3DbFree(db, pTable->zName);
|
|
sqlite3DbFree(db, pTable->zColAff);
|
|
- sqlite3SelectDelete(db, pTable->pSelect);
|
|
sqlite3ExprListDelete(db, pTable->pCheck);
|
|
-#ifndef SQLITE_OMIT_VIRTUALTABLE
|
|
- sqlite3VtabClear(db, pTable);
|
|
-#endif
|
|
sqlite3DbFree(db, pTable);
|
|
|
|
/* Verify that no lookaside memory was used by schema tables */
|
|
@@ -109791,8 +118359,9 @@ static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){
|
|
}
|
|
SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
|
|
/* Do not delete the table until the reference count reaches zero. */
|
|
+ assert( db!=0 );
|
|
if( !pTable ) return;
|
|
- if( ((!db || db->pnBytesFreed==0) && (--pTable->nTabRef)>0) ) return;
|
|
+ if( db->pnBytesFreed==0 && (--pTable->nTabRef)>0 ) return;
|
|
deleteTable(db, pTable);
|
|
}
|
|
|
|
@@ -109829,10 +118398,10 @@ SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTable(sqlite3 *db, int iDb, const char
|
|
** are not \000 terminated and are not persistent. The returned string
|
|
** is \000 terminated and is persistent.
|
|
*/
|
|
-SQLITE_PRIVATE char *sqlite3NameFromToken(sqlite3 *db, Token *pName){
|
|
+SQLITE_PRIVATE char *sqlite3NameFromToken(sqlite3 *db, const Token *pName){
|
|
char *zName;
|
|
if( pName ){
|
|
- zName = sqlite3DbStrNDup(db, (char*)pName->z, pName->n);
|
|
+ zName = sqlite3DbStrNDup(db, (const char*)pName->z, pName->n);
|
|
sqlite3Dequote(zName);
|
|
}else{
|
|
zName = 0;
|
|
@@ -109841,13 +118410,13 @@ SQLITE_PRIVATE char *sqlite3NameFromToken(sqlite3 *db, Token *pName){
|
|
}
|
|
|
|
/*
|
|
-** Open the sqlite_master table stored in database number iDb for
|
|
+** Open the sqlite_schema table stored in database number iDb for
|
|
** writing. The table is opened using cursor 0.
|
|
*/
|
|
-SQLITE_PRIVATE void sqlite3OpenMasterTable(Parse *p, int iDb){
|
|
+SQLITE_PRIVATE void sqlite3OpenSchemaTable(Parse *p, int iDb){
|
|
Vdbe *v = sqlite3GetVdbe(p);
|
|
- sqlite3TableLock(p, iDb, MASTER_ROOT, 1, MASTER_NAME);
|
|
- sqlite3VdbeAddOp4Int(v, OP_OpenWrite, 0, MASTER_ROOT, iDb, 5);
|
|
+ sqlite3TableLock(p, iDb, SCHEMA_ROOT, 1, LEGACY_SCHEMA_TABLE);
|
|
+ sqlite3VdbeAddOp4Int(v, OP_OpenWrite, 0, SCHEMA_ROOT, iDb, 5);
|
|
if( p->nTab==0 ){
|
|
p->nTab = 1;
|
|
}
|
|
@@ -109876,7 +118445,7 @@ SQLITE_PRIVATE int sqlite3FindDbName(sqlite3 *db, const char *zName){
|
|
/*
|
|
** The token *pName contains the name of a database (either "main" or
|
|
** "temp" or the name of an attached db). This routine returns the
|
|
-** index of the named database in db->aDb[], or -1 if the named db
|
|
+** index of the named database in db->aDb[], or -1 if the named db
|
|
** does not exist.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3FindDb(sqlite3 *db, Token *pName){
|
|
@@ -109892,7 +118461,7 @@ SQLITE_PRIVATE int sqlite3FindDb(sqlite3 *db, Token *pName){
|
|
** pName1 and pName2. If the table name was fully qualified, for example:
|
|
**
|
|
** CREATE TABLE xxx.yyy (...);
|
|
-**
|
|
+**
|
|
** Then pName1 is set to "xxx" and pName2 "yyy". On the other hand if
|
|
** the table name is not fully qualified, i.e.:
|
|
**
|
|
@@ -109926,7 +118495,7 @@ SQLITE_PRIVATE int sqlite3TwoPartName(
|
|
return -1;
|
|
}
|
|
}else{
|
|
- assert( db->init.iDb==0 || db->init.busy || IN_RENAME_OBJECT
|
|
+ assert( db->init.iDb==0 || db->init.busy || IN_SPECIAL_PARSE
|
|
|| (db->mDbFlags & DBFLAG_Vacuum)!=0);
|
|
iDb = db->init.iDb;
|
|
*pUnqual = pName1;
|
|
@@ -109955,7 +118524,7 @@ SQLITE_PRIVATE int sqlite3WritableSchema(sqlite3 *db){
|
|
** "sqlite_" (in upper, lower or mixed case). This portion of the namespace
|
|
** is reserved for internal use.
|
|
**
|
|
-** When parsing the sqlite_master table, this routine also checks to
|
|
+** When parsing the sqlite_schema table, this routine also checks to
|
|
** make sure the "type", "name", and "tbl_name" columns are consistent
|
|
** with the SQL.
|
|
*/
|
|
@@ -109966,7 +118535,10 @@ SQLITE_PRIVATE int sqlite3CheckObjectName(
|
|
const char *zTblName /* Parent table name for triggers and indexes */
|
|
){
|
|
sqlite3 *db = pParse->db;
|
|
- if( sqlite3WritableSchema(db) || db->init.imposterTable ){
|
|
+ if( sqlite3WritableSchema(db)
|
|
+ || db->init.imposterTable
|
|
+ || !sqlite3Config.bExtraSchemaChecks
|
|
+ ){
|
|
/* Skip these error checks for writable_schema=ON */
|
|
return SQLITE_OK;
|
|
}
|
|
@@ -109975,10 +118547,8 @@ SQLITE_PRIVATE int sqlite3CheckObjectName(
|
|
|| sqlite3_stricmp(zName, db->init.azInit[1])
|
|
|| sqlite3_stricmp(zTblName, db->init.azInit[2])
|
|
){
|
|
- if( sqlite3Config.bExtraSchemaChecks ){
|
|
- sqlite3ErrorMsg(pParse, ""); /* corruptSchema() will supply the error */
|
|
- return SQLITE_ERROR;
|
|
- }
|
|
+ sqlite3ErrorMsg(pParse, ""); /* corruptSchema() will supply the error */
|
|
+ return SQLITE_ERROR;
|
|
}
|
|
}else{
|
|
if( (pParse->nested==0 && 0==sqlite3StrNICmp(zName, "sqlite_", 7))
|
|
@@ -110045,7 +118615,7 @@ SQLITE_PRIVATE i16 sqlite3StorageColumnToTable(Table *pTab, i16 iCol){
|
|
** The storage column number (0,1,2,....) is the index of the value
|
|
** as it appears in the record on disk. Or, if the input column is
|
|
** the N-th virtual column (zero-based) then the storage number is
|
|
-** the number of non-virtual columns in the table plus N.
|
|
+** the number of non-virtual columns in the table plus N.
|
|
**
|
|
** The true column number is the index (0,1,2,...) of the column in
|
|
** the CREATE TABLE statement.
|
|
@@ -110094,6 +118664,23 @@ SQLITE_PRIVATE i16 sqlite3TableColumnToStorage(Table *pTab, i16 iCol){
|
|
}
|
|
#endif
|
|
|
|
+/*
|
|
+** Insert a single OP_JournalMode query opcode in order to force the
|
|
+** prepared statement to return false for sqlite3_stmt_readonly(). This
|
|
+** is used by CREATE TABLE IF NOT EXISTS and similar if the table already
|
|
+** exists, so that the prepared statement for CREATE TABLE IF NOT EXISTS
|
|
+** will return false for sqlite3_stmt_readonly() even if that statement
|
|
+** is a read-only no-op.
|
|
+*/
|
|
+static void sqlite3ForceNotReadOnly(Parse *pParse){
|
|
+ int iReg = ++pParse->nMem;
|
|
+ Vdbe *v = sqlite3GetVdbe(pParse);
|
|
+ if( v ){
|
|
+ sqlite3VdbeAddOp3(v, OP_JournalMode, 0, iReg, PAGER_JOURNALMODE_QUERY);
|
|
+ sqlite3VdbeUsesBtree(v, 0);
|
|
+ }
|
|
+}
|
|
+
|
|
/*
|
|
** Begin constructing a new table representation in memory. This is
|
|
** the first of several action routines that get called in response
|
|
@@ -110127,7 +118714,7 @@ SQLITE_PRIVATE void sqlite3StartTable(
|
|
Token *pName; /* Unqualified name of the table to create */
|
|
|
|
if( db->init.busy && db->init.newTnum==1 ){
|
|
- /* Special case: Parsing the sqlite_master or sqlite_temp_master schema */
|
|
+ /* Special case: Parsing the sqlite_schema or sqlite_temp_schema schema */
|
|
iDb = db->init.iDb;
|
|
zName = sqlite3DbStrDup(db, SCHEMA_TABLE(iDb));
|
|
pName = pName1;
|
|
@@ -110136,7 +118723,7 @@ SQLITE_PRIVATE void sqlite3StartTable(
|
|
iDb = sqlite3TwoPartName(pParse, pName1, pName2, &pName);
|
|
if( iDb<0 ) return;
|
|
if( !OMIT_TEMPDB && isTemp && pName2->n>0 && iDb!=1 ){
|
|
- /* If creating a temp table, the name may not be qualified. Unless
|
|
+ /* If creating a temp table, the name may not be qualified. Unless
|
|
** the database name is "temp" anyway. */
|
|
sqlite3ErrorMsg(pParse, "temporary table name must be unqualified");
|
|
return;
|
|
@@ -110189,10 +118776,12 @@ SQLITE_PRIVATE void sqlite3StartTable(
|
|
pTable = sqlite3FindTable(db, zName, zDb);
|
|
if( pTable ){
|
|
if( !noErr ){
|
|
- sqlite3ErrorMsg(pParse, "table %T already exists", pName);
|
|
+ sqlite3ErrorMsg(pParse, "%s %T already exists",
|
|
+ (IsView(pTable)? "view" : "table"), pName);
|
|
}else{
|
|
assert( !db->init.busy || CORRUPT_DB );
|
|
sqlite3CodeVerifySchema(pParse, iDb);
|
|
+ sqlite3ForceNotReadOnly(pParse);
|
|
}
|
|
goto begin_table_error;
|
|
}
|
|
@@ -110221,22 +118810,11 @@ SQLITE_PRIVATE void sqlite3StartTable(
|
|
assert( pParse->pNewTable==0 );
|
|
pParse->pNewTable = pTable;
|
|
|
|
- /* If this is the magic sqlite_sequence table used by autoincrement,
|
|
- ** then record a pointer to this table in the main database structure
|
|
- ** so that INSERT can find the table easily.
|
|
- */
|
|
-#ifndef SQLITE_OMIT_AUTOINCREMENT
|
|
- if( !pParse->nested && strcmp(zName, "sqlite_sequence")==0 ){
|
|
- assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
|
- pTable->pSchema->pSeqTab = pTable;
|
|
- }
|
|
-#endif
|
|
-
|
|
/* Begin generating the code that will insert the table record into
|
|
- ** the SQLITE_MASTER table. Note in particular that we must go ahead
|
|
+ ** the schema table. Note in particular that we must go ahead
|
|
** and allocate the record number for the table entry now. Before any
|
|
** PRIMARY KEY or UNIQUE keywords are parsed. Those keywords will cause
|
|
- ** indices to be created and the table record must come before the
|
|
+ ** indices to be created and the table record must come before the
|
|
** indices. Hence, the record number for the table must be allocated
|
|
** now.
|
|
*/
|
|
@@ -110254,7 +118832,7 @@ SQLITE_PRIVATE void sqlite3StartTable(
|
|
}
|
|
#endif
|
|
|
|
- /* If the file format and encoding in the database have not been set,
|
|
+ /* If the file format and encoding in the database have not been set,
|
|
** set them now.
|
|
*/
|
|
reg1 = pParse->regRowid = ++pParse->nMem;
|
|
@@ -110269,7 +118847,7 @@ SQLITE_PRIVATE void sqlite3StartTable(
|
|
sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_TEXT_ENCODING, ENC(db));
|
|
sqlite3VdbeJumpHere(v, addr1);
|
|
|
|
- /* This just creates a place-holder record in the sqlite_master table.
|
|
+ /* This just creates a place-holder record in the sqlite_schema table.
|
|
** The record created does not contain anything yet. It will be replaced
|
|
** by the real entry in code generated at sqlite3EndTable().
|
|
**
|
|
@@ -110284,10 +118862,11 @@ SQLITE_PRIVATE void sqlite3StartTable(
|
|
}else
|
|
#endif
|
|
{
|
|
- pParse->addrCrTab =
|
|
+ assert( !pParse->bReturning );
|
|
+ pParse->u1.addrCrTab =
|
|
sqlite3VdbeAddOp3(v, OP_CreateBtree, iDb, reg2, BTREE_INTKEY);
|
|
}
|
|
- sqlite3OpenMasterTable(pParse, iDb);
|
|
+ sqlite3OpenSchemaTable(pParse, iDb);
|
|
sqlite3VdbeAddOp2(v, OP_NewRowid, 0, reg1);
|
|
sqlite3VdbeAddOp4(v, OP_Blob, 6, reg3, 0, nullRow, P4_STATIC);
|
|
sqlite3VdbeAddOp3(v, OP_Insert, 0, reg3, reg1);
|
|
@@ -110300,6 +118879,7 @@ SQLITE_PRIVATE void sqlite3StartTable(
|
|
|
|
/* If an error occurs, we jump here */
|
|
begin_table_error:
|
|
+ pParse->checkSchema = 1;
|
|
sqlite3DbFree(db, zName);
|
|
return;
|
|
}
|
|
@@ -110309,14 +118889,89 @@ SQLITE_PRIVATE void sqlite3StartTable(
|
|
*/
|
|
#if SQLITE_ENABLE_HIDDEN_COLUMNS
|
|
SQLITE_PRIVATE void sqlite3ColumnPropertiesFromName(Table *pTab, Column *pCol){
|
|
- if( sqlite3_strnicmp(pCol->zName, "__hidden__", 10)==0 ){
|
|
+ if( sqlite3_strnicmp(pCol->zCnName, "__hidden__", 10)==0 ){
|
|
pCol->colFlags |= COLFLAG_HIDDEN;
|
|
+ if( pTab ) pTab->tabFlags |= TF_HasHidden;
|
|
}else if( pTab && pCol!=pTab->aCol && (pCol[-1].colFlags & COLFLAG_HIDDEN) ){
|
|
pTab->tabFlags |= TF_OOOHidden;
|
|
}
|
|
}
|
|
#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);
|
|
+ sqlite3ExprListDelete(db, pRet->pReturnEL);
|
|
+ sqlite3DbFree(db, pRet);
|
|
+}
|
|
+
|
|
+/*
|
|
+** Add the RETURNING clause to the parse currently underway.
|
|
+**
|
|
+** This routine creates a special TEMP trigger that will fire for each row
|
|
+** of the DML statement. That TEMP trigger contains a single SELECT
|
|
+** statement with a result set that is the argument of the RETURNING clause.
|
|
+** The trigger has the Trigger.bReturning flag and an opcode of
|
|
+** TK_RETURNING instead of TK_SELECT, so that the trigger code generator
|
|
+** knows to handle it specially. The TEMP trigger is automatically
|
|
+** removed at the end of the parse.
|
|
+**
|
|
+** When this routine is called, we do not yet know if the RETURNING clause
|
|
+** is attached to a DELETE, INSERT, or UPDATE, so construct it as a
|
|
+** RETURNING trigger instead. It will then be converted into the appropriate
|
|
+** type on the first call to sqlite3TriggersExist().
|
|
+*/
|
|
+SQLITE_PRIVATE void sqlite3AddReturning(Parse *pParse, ExprList *pList){
|
|
+ Returning *pRet;
|
|
+ Hash *pHash;
|
|
+ sqlite3 *db = pParse->db;
|
|
+ if( pParse->pNewTrigger ){
|
|
+ sqlite3ErrorMsg(pParse, "cannot use RETURNING in a trigger");
|
|
+ }else{
|
|
+ assert( pParse->bReturning==0 || pParse->ifNotExists );
|
|
+ }
|
|
+ pParse->bReturning = 1;
|
|
+ pRet = sqlite3DbMallocZero(db, sizeof(*pRet));
|
|
+ if( pRet==0 ){
|
|
+ sqlite3ExprListDelete(db, pList);
|
|
+ return;
|
|
+ }
|
|
+ pParse->u1.pReturning = pRet;
|
|
+ pRet->pParse = pParse;
|
|
+ pRet->pReturnEL = pList;
|
|
+ sqlite3ParserAddCleanup(pParse,
|
|
+ (void(*)(sqlite3*,void*))sqlite3DeleteReturning, pRet);
|
|
+ testcase( pParse->earlyCleanup );
|
|
+ if( db->mallocFailed ) return;
|
|
+ pRet->retTrig.zName = RETURNING_TRIGGER_NAME;
|
|
+ pRet->retTrig.op = TK_RETURNING;
|
|
+ pRet->retTrig.tr_tm = TRIGGER_AFTER;
|
|
+ pRet->retTrig.bReturning = 1;
|
|
+ pRet->retTrig.pSchema = db->aDb[1].pSchema;
|
|
+ pRet->retTrig.pTabSchema = db->aDb[1].pSchema;
|
|
+ pRet->retTrig.step_list = &pRet->retTStep;
|
|
+ pRet->retTStep.op = TK_RETURNING;
|
|
+ pRet->retTStep.pTrig = &pRet->retTrig;
|
|
+ pRet->retTStep.pExprList = pList;
|
|
+ pHash = &(db->aDb[1].pSchema->trigHash);
|
|
+ assert( sqlite3HashFind(pHash, RETURNING_TRIGGER_NAME)==0
|
|
+ || pParse->nErr || pParse->ifNotExists );
|
|
+ if( sqlite3HashInsert(pHash, RETURNING_TRIGGER_NAME, &pRet->retTrig)
|
|
+ ==&pRet->retTrig ){
|
|
+ sqlite3OomFault(db);
|
|
+ }
|
|
+}
|
|
|
|
/*
|
|
** Add a new column to the table currently being constructed.
|
|
@@ -110326,59 +118981,104 @@ SQLITE_PRIVATE void sqlite3ColumnPropertiesFromName(Table *pTab, Column *pCol){
|
|
** first to get things going. Then this routine is called for each
|
|
** column.
|
|
*/
|
|
-SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token *pName, Token *pType){
|
|
+SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token sName, Token sType){
|
|
Table *p;
|
|
int i;
|
|
char *z;
|
|
char *zType;
|
|
Column *pCol;
|
|
sqlite3 *db = pParse->db;
|
|
+ u8 hName;
|
|
+ Column *aNew;
|
|
+ u8 eType = COLTYPE_CUSTOM;
|
|
+ u8 szEst = 1;
|
|
+ char affinity = SQLITE_AFF_BLOB;
|
|
+
|
|
if( (p = pParse->pNewTable)==0 ) return;
|
|
if( p->nCol+1>db->aLimit[SQLITE_LIMIT_COLUMN] ){
|
|
sqlite3ErrorMsg(pParse, "too many columns on %s", p->zName);
|
|
return;
|
|
}
|
|
- z = sqlite3DbMallocRaw(db, pName->n + pType->n + 2);
|
|
+ if( !IN_RENAME_OBJECT ) sqlite3DequoteToken(&sName);
|
|
+
|
|
+ /* Because keywords GENERATE ALWAYS can be converted into indentifiers
|
|
+ ** by the parser, we can sometimes end up with a typename that ends
|
|
+ ** with "generated always". Check for this case and omit the surplus
|
|
+ ** text. */
|
|
+ if( sType.n>=16
|
|
+ && sqlite3_strnicmp(sType.z+(sType.n-6),"always",6)==0
|
|
+ ){
|
|
+ sType.n -= 6;
|
|
+ while( ALWAYS(sType.n>0) && sqlite3Isspace(sType.z[sType.n-1]) ) sType.n--;
|
|
+ if( sType.n>=9
|
|
+ && sqlite3_strnicmp(sType.z+(sType.n-9),"generated",9)==0
|
|
+ ){
|
|
+ sType.n -= 9;
|
|
+ while( sType.n>0 && sqlite3Isspace(sType.z[sType.n-1]) ) sType.n--;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Check for standard typenames. For standard typenames we will
|
|
+ ** set the Column.eType field rather than storing the typename after
|
|
+ ** the column name, in order to save space. */
|
|
+ if( sType.n>=3 ){
|
|
+ sqlite3DequoteToken(&sType);
|
|
+ for(i=0; i<SQLITE_N_STDTYPE; i++){
|
|
+ if( sType.n==sqlite3StdTypeLen[i]
|
|
+ && sqlite3_strnicmp(sType.z, sqlite3StdType[i], sType.n)==0
|
|
+ ){
|
|
+ sType.n = 0;
|
|
+ eType = i+1;
|
|
+ affinity = sqlite3StdTypeAffinity[i];
|
|
+ if( affinity<=SQLITE_AFF_TEXT ) szEst = 5;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ z = sqlite3DbMallocRaw(db, (i64)sName.n + 1 + (i64)sType.n + (sType.n>0) );
|
|
if( z==0 ) return;
|
|
- if( IN_RENAME_OBJECT ) sqlite3RenameTokenMap(pParse, (void*)z, pName);
|
|
- memcpy(z, pName->z, pName->n);
|
|
- z[pName->n] = 0;
|
|
+ if( IN_RENAME_OBJECT ) sqlite3RenameTokenMap(pParse, (void*)z, &sName);
|
|
+ memcpy(z, sName.z, sName.n);
|
|
+ z[sName.n] = 0;
|
|
sqlite3Dequote(z);
|
|
+ hName = sqlite3StrIHash(z);
|
|
for(i=0; i<p->nCol; i++){
|
|
- if( sqlite3_stricmp(z, p->aCol[i].zName)==0 ){
|
|
+ if( p->aCol[i].hName==hName && sqlite3StrICmp(z, p->aCol[i].zCnName)==0 ){
|
|
sqlite3ErrorMsg(pParse, "duplicate column name: %s", z);
|
|
sqlite3DbFree(db, z);
|
|
return;
|
|
}
|
|
}
|
|
- if( (p->nCol & 0x7)==0 ){
|
|
- Column *aNew;
|
|
- aNew = sqlite3DbRealloc(db,p->aCol,(p->nCol+8)*sizeof(p->aCol[0]));
|
|
- if( aNew==0 ){
|
|
- sqlite3DbFree(db, z);
|
|
- return;
|
|
- }
|
|
- p->aCol = aNew;
|
|
+ aNew = sqlite3DbRealloc(db,p->aCol,((i64)p->nCol+1)*sizeof(p->aCol[0]));
|
|
+ if( aNew==0 ){
|
|
+ sqlite3DbFree(db, z);
|
|
+ return;
|
|
}
|
|
+ p->aCol = aNew;
|
|
pCol = &p->aCol[p->nCol];
|
|
memset(pCol, 0, sizeof(p->aCol[0]));
|
|
- pCol->zName = z;
|
|
+ pCol->zCnName = z;
|
|
+ pCol->hName = hName;
|
|
sqlite3ColumnPropertiesFromName(p, pCol);
|
|
-
|
|
- if( pType->n==0 ){
|
|
+
|
|
+ if( sType.n==0 ){
|
|
/* If there is no type specified, columns have the default affinity
|
|
** 'BLOB' with a default size of 4 bytes. */
|
|
- pCol->affinity = SQLITE_AFF_BLOB;
|
|
- pCol->szEst = 1;
|
|
+ pCol->affinity = affinity;
|
|
+ pCol->eCType = eType;
|
|
+ pCol->szEst = szEst;
|
|
#ifdef SQLITE_ENABLE_SORTER_REFERENCES
|
|
- if( 4>=sqlite3GlobalConfig.szSorterRef ){
|
|
- pCol->colFlags |= COLFLAG_SORTERREF;
|
|
+ if( affinity==SQLITE_AFF_BLOB ){
|
|
+ if( 4>=sqlite3GlobalConfig.szSorterRef ){
|
|
+ pCol->colFlags |= COLFLAG_SORTERREF;
|
|
+ }
|
|
}
|
|
#endif
|
|
}else{
|
|
zType = z + sqlite3Strlen30(z) + 1;
|
|
- memcpy(zType, pType->z, pType->n);
|
|
- zType[pType->n] = 0;
|
|
+ memcpy(zType, sType.z, sType.n);
|
|
+ zType[sType.n] = 0;
|
|
sqlite3Dequote(zType);
|
|
pCol->affinity = sqlite3AffinityType(zType, pCol);
|
|
pCol->colFlags |= COLFLAG_HASTYPE;
|
|
@@ -110420,11 +119120,11 @@ SQLITE_PRIVATE void sqlite3AddNotNull(Parse *pParse, int onError){
|
|
** Scan the column type name zType (length nType) and return the
|
|
** associated affinity type.
|
|
**
|
|
-** This routine does a case-independent search of zType for the
|
|
+** This routine does a case-independent search of zType for the
|
|
** substrings in the following table. If one of the substrings is
|
|
** found, the corresponding affinity is returned. If zType contains
|
|
-** more than one of the substrings, entries toward the top of
|
|
-** the table take priority. For example, if zType is 'BLOBINT',
|
|
+** more than one of the substrings, entries toward the top of
|
|
+** the table take priority. For example, if zType is 'BLOBINT',
|
|
** SQLITE_AFF_INTEGER is returned.
|
|
**
|
|
** Substring | Affinity
|
|
@@ -110533,7 +119233,7 @@ SQLITE_PRIVATE void sqlite3AddDefaultValue(
|
|
pCol = &(p->aCol[p->nCol-1]);
|
|
if( !sqlite3ExprIsConstantOrFunction(pExpr, isInit) ){
|
|
sqlite3ErrorMsg(pParse, "default value of column [%s] is not constant",
|
|
- pCol->zName);
|
|
+ pCol->zCnName);
|
|
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
|
|
}else if( pCol->colFlags & COLFLAG_GENERATED ){
|
|
testcase( pCol->colFlags & COLFLAG_VIRTUAL );
|
|
@@ -110544,15 +119244,15 @@ SQLITE_PRIVATE void sqlite3AddDefaultValue(
|
|
/* A copy of pExpr is used instead of the original, as pExpr contains
|
|
** tokens that point to volatile memory.
|
|
*/
|
|
- Expr x;
|
|
- sqlite3ExprDelete(db, pCol->pDflt);
|
|
+ Expr x, *pDfltExpr;
|
|
memset(&x, 0, sizeof(x));
|
|
x.op = TK_SPAN;
|
|
x.u.zToken = sqlite3DbSpanDup(db, zStart, zEnd);
|
|
x.pLeft = pExpr;
|
|
x.flags = EP_Skip;
|
|
- pCol->pDflt = sqlite3ExprDup(db, &x, EXPRDUP_REDUCE);
|
|
+ pDfltExpr = sqlite3ExprDup(db, &x, EXPRDUP_REDUCE);
|
|
sqlite3DbFree(db, x.u.zToken);
|
|
+ sqlite3ColumnSetExpr(pParse, p, pCol, pDfltExpr);
|
|
}
|
|
}
|
|
if( IN_RENAME_OBJECT ){
|
|
@@ -110563,7 +119263,7 @@ SQLITE_PRIVATE void sqlite3AddDefaultValue(
|
|
|
|
/*
|
|
** Backwards Compatibility Hack:
|
|
-**
|
|
+**
|
|
** Historical versions of SQLite accepted strings as column names in
|
|
** indexes and PRIMARY KEY constraints and in UNIQUE constraints. Example:
|
|
**
|
|
@@ -110597,11 +119297,11 @@ static void makeColumnPartOfPrimaryKey(Parse *pParse, Column *pCol){
|
|
sqlite3ErrorMsg(pParse,
|
|
"generated columns cannot be part of the PRIMARY KEY");
|
|
}
|
|
-#endif
|
|
+#endif
|
|
}
|
|
|
|
/*
|
|
-** Designate the PRIMARY KEY for the table. pList is a list of names
|
|
+** Designate the PRIMARY KEY for the table. pList is a list of names
|
|
** of columns that form the primary key. If pList is NULL, then the
|
|
** most recently added column of the table is the primary key.
|
|
**
|
|
@@ -110631,7 +119331,7 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey(
|
|
int nTerm;
|
|
if( pTab==0 ) goto primary_key_exit;
|
|
if( pTab->tabFlags & TF_HasPrimaryKey ){
|
|
- sqlite3ErrorMsg(pParse,
|
|
+ sqlite3ErrorMsg(pParse,
|
|
"table \"%s\" has more than one primary key", pTab->zName);
|
|
goto primary_key_exit;
|
|
}
|
|
@@ -110648,9 +119348,11 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey(
|
|
assert( pCExpr!=0 );
|
|
sqlite3StringToId(pCExpr);
|
|
if( pCExpr->op==TK_ID ){
|
|
- const char *zCName = pCExpr->u.zToken;
|
|
+ const char *zCName;
|
|
+ assert( !ExprHasProperty(pCExpr, EP_IntValue) );
|
|
+ zCName = pCExpr->u.zToken;
|
|
for(iCol=0; iCol<pTab->nCol; iCol++){
|
|
- if( sqlite3StrICmp(zCName, pTab->aCol[iCol].zName)==0 ){
|
|
+ if( sqlite3StrICmp(zCName, pTab->aCol[iCol].zCnName)==0 ){
|
|
pCol = &pTab->aCol[iCol];
|
|
makeColumnPartOfPrimaryKey(pParse, pCol);
|
|
break;
|
|
@@ -110661,7 +119363,7 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey(
|
|
}
|
|
if( nTerm==1
|
|
&& pCol
|
|
- && sqlite3StrICmp(sqlite3ColumnType(pCol,""), "INTEGER")==0
|
|
+ && pCol->eCType==COLTYPE_INTEGER
|
|
&& sortOrder!=SQLITE_SO_DESC
|
|
){
|
|
if( IN_RENAME_OBJECT && pList ){
|
|
@@ -110672,7 +119374,7 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey(
|
|
pTab->keyConf = (u8)onError;
|
|
assert( autoInc==0 || autoInc==1 );
|
|
pTab->tabFlags |= autoInc*TF_Autoincrement;
|
|
- if( pList ) pParse->iPkSortOrder = pList->a[0].sortFlags;
|
|
+ if( pList ) pParse->iPkSortOrder = pList->a[0].fg.sortFlags;
|
|
(void)sqlite3HasExplicitNulls(pParse, pList);
|
|
}else if( autoInc ){
|
|
#ifndef SQLITE_OMIT_AUTOINCREMENT
|
|
@@ -110694,8 +119396,10 @@ SQLITE_PRIVATE void sqlite3AddPrimaryKey(
|
|
** Add a new CHECK constraint to the table currently under construction.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3AddCheckConstraint(
|
|
- Parse *pParse, /* Parsing context */
|
|
- Expr *pCheckExpr /* The check expression */
|
|
+ Parse *pParse, /* Parsing context */
|
|
+ Expr *pCheckExpr, /* The check expression */
|
|
+ const char *zStart, /* Opening "(" */
|
|
+ const char *zEnd /* Closing ")" */
|
|
){
|
|
#ifndef SQLITE_OMIT_CHECK
|
|
Table *pTab = pParse->pNewTable;
|
|
@@ -110706,6 +119410,13 @@ SQLITE_PRIVATE void sqlite3AddCheckConstraint(
|
|
pTab->pCheck = sqlite3ExprListAppend(pParse, pTab->pCheck, pCheckExpr);
|
|
if( pParse->constraintName.n ){
|
|
sqlite3ExprListSetName(pParse, pTab->pCheck, &pParse->constraintName, 1);
|
|
+ }else{
|
|
+ Token t;
|
|
+ for(zStart++; sqlite3Isspace(zStart[0]); zStart++){}
|
|
+ while( sqlite3Isspace(zEnd[-1]) ){ zEnd--; }
|
|
+ t.z = zStart;
|
|
+ t.n = (int)(zEnd - t.z);
|
|
+ sqlite3ExprListSetName(pParse, pTab->pCheck, &t, 1);
|
|
}
|
|
}else
|
|
#endif
|
|
@@ -110724,7 +119435,7 @@ SQLITE_PRIVATE void sqlite3AddCollateType(Parse *pParse, Token *pToken){
|
|
char *zColl; /* Dequoted name of collation sequence */
|
|
sqlite3 *db;
|
|
|
|
- if( (p = pParse->pNewTable)==0 ) return;
|
|
+ if( (p = pParse->pNewTable)==0 || IN_RENAME_OBJECT ) return;
|
|
i = p->nCol-1;
|
|
db = pParse->db;
|
|
zColl = sqlite3NameFromToken(db, pToken);
|
|
@@ -110732,9 +119443,8 @@ SQLITE_PRIVATE void sqlite3AddCollateType(Parse *pParse, Token *pToken){
|
|
|
|
if( sqlite3LocateCollSeq(pParse, zColl) ){
|
|
Index *pIdx;
|
|
- sqlite3DbFree(db, p->aCol[i].zColl);
|
|
- p->aCol[i].zColl = zColl;
|
|
-
|
|
+ sqlite3ColumnSetColl(db, &p->aCol[i], zColl);
|
|
+
|
|
/* If the column is declared as "<name> PRIMARY KEY COLLATE <type>",
|
|
** then an index may have been created on this column before the
|
|
** collation type was added. Correct this if it is the case.
|
|
@@ -110742,12 +119452,11 @@ SQLITE_PRIVATE void sqlite3AddCollateType(Parse *pParse, Token *pToken){
|
|
for(pIdx=p->pIndex; pIdx; pIdx=pIdx->pNext){
|
|
assert( pIdx->nKeyCol==1 );
|
|
if( pIdx->aiColumn[0]==i ){
|
|
- pIdx->azColl[0] = p->aCol[i].zColl;
|
|
+ pIdx->azColl[0] = sqlite3ColumnColl(&p->aCol[i]);
|
|
}
|
|
}
|
|
- }else{
|
|
- sqlite3DbFree(db, zColl);
|
|
}
|
|
+ sqlite3DbFree(db, zColl);
|
|
}
|
|
|
|
/* Change the most recently parsed column to be a GENERATED ALWAYS AS
|
|
@@ -110767,7 +119476,7 @@ SQLITE_PRIVATE void sqlite3AddGenerated(Parse *pParse, Expr *pExpr, Token *pType
|
|
sqlite3ErrorMsg(pParse, "virtual tables cannot use computed columns");
|
|
goto generated_done;
|
|
}
|
|
- if( pCol->pDflt ) goto generated_error;
|
|
+ if( pCol->iDflt>0 ) goto generated_error;
|
|
if( pType ){
|
|
if( pType->n==7 && sqlite3StrNICmp("virtual",pType->z,7)==0 ){
|
|
/* no-op */
|
|
@@ -110785,13 +119494,21 @@ SQLITE_PRIVATE void sqlite3AddGenerated(Parse *pParse, Expr *pExpr, Token *pType
|
|
if( pCol->colFlags & COLFLAG_PRIMKEY ){
|
|
makeColumnPartOfPrimaryKey(pParse, pCol); /* For the error message */
|
|
}
|
|
- pCol->pDflt = pExpr;
|
|
+ if( ALWAYS(pExpr) && pExpr->op==TK_ID ){
|
|
+ /* The value of a generated column needs to be a real expression, not
|
|
+ ** just a reference to another column, in order for covering index
|
|
+ ** optimizations to work correctly. So if the value is not an expression,
|
|
+ ** turn it into one by adding a unary "+" operator. */
|
|
+ pExpr = sqlite3PExpr(pParse, TK_UPLUS, pExpr, 0);
|
|
+ }
|
|
+ if( pExpr && pExpr->op!=TK_RAISE ) pExpr->affExpr = pCol->affinity;
|
|
+ sqlite3ColumnSetExpr(pParse, pTab, pCol, pExpr);
|
|
pExpr = 0;
|
|
goto generated_done;
|
|
|
|
generated_error:
|
|
sqlite3ErrorMsg(pParse, "error in generated column \"%s\"",
|
|
- pCol->zName);
|
|
+ pCol->zCnName);
|
|
generated_done:
|
|
sqlite3ExprDelete(pParse->db, pExpr);
|
|
#else
|
|
@@ -110825,7 +119542,7 @@ SQLITE_PRIVATE void sqlite3ChangeCookie(Parse *pParse, int iDb){
|
|
sqlite3 *db = pParse->db;
|
|
Vdbe *v = pParse->pVdbe;
|
|
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
|
- sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_SCHEMA_VERSION,
|
|
+ sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_SCHEMA_VERSION,
|
|
(int)(1+(unsigned)db->aDb[iDb].pSchema->schema_cookie));
|
|
}
|
|
|
|
@@ -110846,13 +119563,13 @@ static int identLength(const char *z){
|
|
}
|
|
|
|
/*
|
|
-** The first parameter is a pointer to an output buffer. The second
|
|
+** The first parameter is a pointer to an output buffer. The second
|
|
** parameter is a pointer to an integer that contains the offset at
|
|
** which to write into the output buffer. This function copies the
|
|
** nul-terminated string pointed to by the third parameter, zSignedIdent,
|
|
** 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
|
|
** 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,
|
|
@@ -110893,10 +119610,10 @@ static char *createTableStmt(sqlite3 *db, Table *p){
|
|
Column *pCol;
|
|
n = 0;
|
|
for(pCol = p->aCol, i=0; i<p->nCol; i++, pCol++){
|
|
- n += identLength(pCol->zName) + 5;
|
|
+ n += identLength(pCol->zCnName) + 5;
|
|
}
|
|
n += identLength(p->zName);
|
|
- if( n<50 ){
|
|
+ if( n<50 ){
|
|
zSep = "";
|
|
zSep2 = ",";
|
|
zEnd = ")";
|
|
@@ -110921,7 +119638,8 @@ static char *createTableStmt(sqlite3 *db, Table *p){
|
|
/* SQLITE_AFF_TEXT */ " TEXT",
|
|
/* SQLITE_AFF_NUMERIC */ " NUM",
|
|
/* SQLITE_AFF_INTEGER */ " INT",
|
|
- /* SQLITE_AFF_REAL */ " REAL"
|
|
+ /* SQLITE_AFF_REAL */ " REAL",
|
|
+ /* SQLITE_AFF_FLEXNUM */ " NUM",
|
|
};
|
|
int len;
|
|
const char *zType;
|
|
@@ -110929,7 +119647,7 @@ static char *createTableStmt(sqlite3 *db, Table *p){
|
|
sqlite3_snprintf(n-k, &zStmt[k], zSep);
|
|
k += sqlite3Strlen30(&zStmt[k]);
|
|
zSep = zSep2;
|
|
- identPut(zStmt, &k, pCol->zName);
|
|
+ identPut(zStmt, &k, pCol->zCnName);
|
|
assert( pCol->affinity-SQLITE_AFF_BLOB >= 0 );
|
|
assert( pCol->affinity-SQLITE_AFF_BLOB < ArraySize(azType) );
|
|
testcase( pCol->affinity==SQLITE_AFF_BLOB );
|
|
@@ -110937,10 +119655,12 @@ static char *createTableStmt(sqlite3 *db, Table *p){
|
|
testcase( pCol->affinity==SQLITE_AFF_NUMERIC );
|
|
testcase( pCol->affinity==SQLITE_AFF_INTEGER );
|
|
testcase( pCol->affinity==SQLITE_AFF_REAL );
|
|
-
|
|
+ testcase( pCol->affinity==SQLITE_AFF_FLEXNUM );
|
|
+
|
|
zType = azType[pCol->affinity - SQLITE_AFF_BLOB];
|
|
len = sqlite3Strlen30(zType);
|
|
- assert( pCol->affinity==SQLITE_AFF_BLOB
|
|
+ assert( pCol->affinity==SQLITE_AFF_BLOB
|
|
+ || pCol->affinity==SQLITE_AFF_FLEXNUM
|
|
|| pCol->affinity==sqlite3AffinityType(zType, 0) );
|
|
memcpy(&zStmt[k], zType, len);
|
|
k += len;
|
|
@@ -110959,12 +119679,15 @@ static int resizeIndexObject(sqlite3 *db, Index *pIdx, int N){
|
|
int nByte;
|
|
if( pIdx->nColumn>=N ) return SQLITE_OK;
|
|
assert( pIdx->isResized==0 );
|
|
- nByte = (sizeof(char*) + sizeof(i16) + 1)*N;
|
|
+ nByte = (sizeof(char*) + sizeof(LogEst) + sizeof(i16) + 1)*N;
|
|
zExtra = sqlite3DbMallocZero(db, nByte);
|
|
if( zExtra==0 ) return SQLITE_NOMEM_BKPT;
|
|
memcpy(zExtra, pIdx->azColl, sizeof(char*)*pIdx->nColumn);
|
|
pIdx->azColl = (const char**)zExtra;
|
|
zExtra += sizeof(char*)*N;
|
|
+ memcpy(zExtra, pIdx->aiRowLogEst, sizeof(LogEst)*(pIdx->nKeyCol+1));
|
|
+ pIdx->aiRowLogEst = (LogEst*)zExtra;
|
|
+ zExtra += sizeof(LogEst)*N;
|
|
memcpy(zExtra, pIdx->aiColumn, sizeof(i16)*pIdx->nColumn);
|
|
pIdx->aiColumn = (i16*)zExtra;
|
|
zExtra += sizeof(i16)*N;
|
|
@@ -111010,7 +119733,6 @@ static void estimateIndexWidth(Index *pIdx){
|
|
*/
|
|
static int hasColumn(const i16 *aiCol, int nCol, int x){
|
|
while( nCol-- > 0 ){
|
|
- assert( aiCol[0]>=0 );
|
|
if( x==*(aiCol++) ){
|
|
return 1;
|
|
}
|
|
@@ -111043,7 +119765,7 @@ static int isDupColumn(Index *pIdx, int nKey, Index *pPk, int iCol){
|
|
assert( j!=XN_ROWID && j!=XN_EXPR );
|
|
for(i=0; i<nKey; i++){
|
|
assert( pIdx->aiColumn[i]>=0 || j>=0 );
|
|
- if( pIdx->aiColumn[i]==j
|
|
+ if( pIdx->aiColumn[i]==j
|
|
&& sqlite3StrICmp(pIdx->azColl[i], pPk->azColl[iCol])==0
|
|
){
|
|
return 1;
|
|
@@ -111055,7 +119777,8 @@ static int isDupColumn(Index *pIdx, int nKey, Index *pPk, int iCol){
|
|
/* Recompute the colNotIdxed field of the Index.
|
|
**
|
|
** colNotIdxed is a bitmask that has a 0 bit representing each indexed
|
|
-** columns that are within the first 63 columns of the table. The
|
|
+** columns that are within the first 63 columns of the table and a 1 for
|
|
+** all other bits (all columns that are not in the index). The
|
|
** high-order bit of colNotIdxed is always 1. All unindexed columns
|
|
** of the table have a 1.
|
|
**
|
|
@@ -111083,7 +119806,7 @@ static void recomputeColumnsNotIndexed(Index *pIdx){
|
|
}
|
|
}
|
|
pIdx->colNotIdxed = ~m;
|
|
- assert( (pIdx->colNotIdxed>>63)==1 );
|
|
+ assert( (pIdx->colNotIdxed>>63)==1 ); /* See note-20221022-a */
|
|
}
|
|
|
|
/*
|
|
@@ -111094,11 +119817,11 @@ static void recomputeColumnsNotIndexed(Index *pIdx){
|
|
** Changes include:
|
|
**
|
|
** (1) Set all columns of the PRIMARY KEY schema object to be NOT NULL.
|
|
-** (2) Convert P3 parameter of the OP_CreateBtree from BTREE_INTKEY
|
|
+** (2) Convert P3 parameter of the OP_CreateBtree from BTREE_INTKEY
|
|
** into BTREE_BLOBKEY.
|
|
-** (3) Bypass the creation of the sqlite_master table entry
|
|
+** (3) Bypass the creation of the sqlite_schema table entry
|
|
** for the PRIMARY KEY as the primary key index is now
|
|
-** identified by the sqlite_master table entry of the table itself.
|
|
+** identified by the sqlite_schema table entry of the table itself.
|
|
** (4) Set the Index.tnum of the PRIMARY KEY Index object in the
|
|
** schema to the rootpage from the main table.
|
|
** (5) Add all table columns to the PRIMARY KEY Index object
|
|
@@ -111123,7 +119846,9 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
|
|
*/
|
|
if( !db->init.imposterTable ){
|
|
for(i=0; i<pTab->nCol; i++){
|
|
- if( (pTab->aCol[i].colFlags & COLFLAG_PRIMKEY)!=0 ){
|
|
+ if( (pTab->aCol[i].colFlags & COLFLAG_PRIMKEY)!=0
|
|
+ && (pTab->aCol[i].notNull==OE_None)
|
|
+ ){
|
|
pTab->aCol[i].notNull = OE_Abort;
|
|
}
|
|
}
|
|
@@ -111133,30 +119858,38 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
|
|
/* Convert the P3 operand of the OP_CreateBtree opcode from BTREE_INTKEY
|
|
** into BTREE_BLOBKEY.
|
|
*/
|
|
- if( pParse->addrCrTab ){
|
|
+ assert( !pParse->bReturning );
|
|
+ if( pParse->u1.addrCrTab ){
|
|
assert( v );
|
|
- sqlite3VdbeChangeP3(v, pParse->addrCrTab, BTREE_BLOBKEY);
|
|
+ sqlite3VdbeChangeP3(v, pParse->u1.addrCrTab, BTREE_BLOBKEY);
|
|
}
|
|
|
|
/* Locate the PRIMARY KEY index. Or, if this table was originally
|
|
- ** an INTEGER PRIMARY KEY table, create a new PRIMARY KEY index.
|
|
+ ** an INTEGER PRIMARY KEY table, create a new PRIMARY KEY index.
|
|
*/
|
|
if( pTab->iPKey>=0 ){
|
|
ExprList *pList;
|
|
Token ipkToken;
|
|
- sqlite3TokenInit(&ipkToken, pTab->aCol[pTab->iPKey].zName);
|
|
- pList = sqlite3ExprListAppend(pParse, 0,
|
|
+ sqlite3TokenInit(&ipkToken, pTab->aCol[pTab->iPKey].zCnName);
|
|
+ pList = sqlite3ExprListAppend(pParse, 0,
|
|
sqlite3ExprAlloc(db, TK_ID, &ipkToken, 0));
|
|
- if( pList==0 ) return;
|
|
+ if( pList==0 ){
|
|
+ pTab->tabFlags &= ~TF_WithoutRowid;
|
|
+ return;
|
|
+ }
|
|
if( IN_RENAME_OBJECT ){
|
|
sqlite3RenameTokenRemap(pParse, pList->a[0].pExpr, &pTab->iPKey);
|
|
}
|
|
- pList->a[0].sortFlags = pParse->iPkSortOrder;
|
|
+ pList->a[0].fg.sortFlags = pParse->iPkSortOrder;
|
|
assert( pParse->pNewTable==pTab );
|
|
pTab->iPKey = -1;
|
|
sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0,
|
|
SQLITE_IDXTYPE_PRIMARYKEY);
|
|
- if( db->mallocFailed || pParse->nErr ) return;
|
|
+ if( pParse->nErr ){
|
|
+ pTab->tabFlags &= ~TF_WithoutRowid;
|
|
+ return;
|
|
+ }
|
|
+ assert( db->mallocFailed==0 );
|
|
pPk = sqlite3PrimaryKeyIndex(pTab);
|
|
assert( pPk->nKeyCol==1 );
|
|
}else{
|
|
@@ -111185,13 +119918,13 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
|
|
if( !db->init.imposterTable ) pPk->uniqNotNull = 1;
|
|
nPk = pPk->nColumn = pPk->nKeyCol;
|
|
|
|
- /* Bypass the creation of the PRIMARY KEY btree and the sqlite_master
|
|
+ /* Bypass the creation of the PRIMARY KEY btree and the sqlite_schema
|
|
** table entry. This is only required if currently generating VDBE
|
|
** code for a CREATE TABLE (not when parsing one as part of reading
|
|
** a database schema). */
|
|
if( v && pPk->tnum>0 ){
|
|
assert( db->init.busy==0 );
|
|
- sqlite3VdbeChangeOpcode(v, pPk->tnum, OP_Goto);
|
|
+ sqlite3VdbeChangeOpcode(v, (int)pPk->tnum, OP_Goto);
|
|
}
|
|
|
|
/* The root page of the PRIMARY KEY is the table root page */
|
|
@@ -111254,6 +119987,63 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
|
|
recomputeColumnsNotIndexed(pPk);
|
|
}
|
|
|
|
+
|
|
+#ifndef SQLITE_OMIT_VIRTUALTABLE
|
|
+/*
|
|
+** Return true if pTab is a virtual table and zName is a shadow table name
|
|
+** for that virtual table.
|
|
+*/
|
|
+SQLITE_PRIVATE int sqlite3IsShadowTableOf(sqlite3 *db, Table *pTab, const char *zName){
|
|
+ int nName; /* Length of zName */
|
|
+ Module *pMod; /* Module for the virtual table */
|
|
+
|
|
+ if( !IsVirtual(pTab) ) return 0;
|
|
+ nName = sqlite3Strlen30(pTab->zName);
|
|
+ if( sqlite3_strnicmp(zName, pTab->zName, nName)!=0 ) return 0;
|
|
+ if( zName[nName]!='_' ) return 0;
|
|
+ pMod = (Module*)sqlite3HashFind(&db->aModule, pTab->u.vtab.azArg[0]);
|
|
+ if( pMod==0 ) return 0;
|
|
+ if( pMod->pModule->iVersion<3 ) return 0;
|
|
+ if( pMod->pModule->xShadowName==0 ) return 0;
|
|
+ return pMod->pModule->xShadowName(zName+nName+1);
|
|
+}
|
|
+#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */
|
|
+
|
|
+#ifndef SQLITE_OMIT_VIRTUALTABLE
|
|
+/*
|
|
+** Table pTab is a virtual table. If it the virtual table implementation
|
|
+** exists and has an xShadowName method, then loop over all other ordinary
|
|
+** tables within the same schema looking for shadow tables of pTab, and mark
|
|
+** any shadow tables seen using the TF_Shadow flag.
|
|
+*/
|
|
+SQLITE_PRIVATE void sqlite3MarkAllShadowTablesOf(sqlite3 *db, Table *pTab){
|
|
+ int nName; /* Length of pTab->zName */
|
|
+ Module *pMod; /* Module for the virtual table */
|
|
+ HashElem *k; /* For looping through the symbol table */
|
|
+
|
|
+ assert( IsVirtual(pTab) );
|
|
+ pMod = (Module*)sqlite3HashFind(&db->aModule, pTab->u.vtab.azArg[0]);
|
|
+ if( pMod==0 ) return;
|
|
+ if( NEVER(pMod->pModule==0) ) return;
|
|
+ if( pMod->pModule->iVersion<3 ) return;
|
|
+ if( pMod->pModule->xShadowName==0 ) return;
|
|
+ assert( pTab->zName!=0 );
|
|
+ nName = sqlite3Strlen30(pTab->zName);
|
|
+ for(k=sqliteHashFirst(&pTab->pSchema->tblHash); k; k=sqliteHashNext(k)){
|
|
+ Table *pOther = sqliteHashData(k);
|
|
+ assert( pOther->zName!=0 );
|
|
+ if( !IsOrdinaryTable(pOther) ) continue;
|
|
+ if( pOther->tabFlags & TF_Shadow ) continue;
|
|
+ if( sqlite3StrNICmp(pOther->zName, pTab->zName, nName)==0
|
|
+ && pOther->zName[nName]=='_'
|
|
+ && pMod->pModule->xShadowName(pOther->zName+nName+1)
|
|
+ ){
|
|
+ pOther->tabFlags |= TF_Shadow;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */
|
|
+
|
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
|
/*
|
|
** Return true if zName is a shadow table name in the current database
|
|
@@ -111265,8 +120055,6 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
|
|
SQLITE_PRIVATE int sqlite3ShadowTableName(sqlite3 *db, const char *zName){
|
|
char *zTail; /* Pointer to the last "_" in zName */
|
|
Table *pTab; /* Table that zName is a shadow of */
|
|
- Module *pMod; /* Module for the virtual table */
|
|
-
|
|
zTail = strrchr(zName, '_');
|
|
if( zTail==0 ) return 0;
|
|
*zTail = 0;
|
|
@@ -111274,14 +120062,38 @@ SQLITE_PRIVATE int sqlite3ShadowTableName(sqlite3 *db, const char *zName){
|
|
*zTail = '_';
|
|
if( pTab==0 ) return 0;
|
|
if( !IsVirtual(pTab) ) return 0;
|
|
- pMod = (Module*)sqlite3HashFind(&db->aModule, pTab->azModuleArg[0]);
|
|
- if( pMod==0 ) return 0;
|
|
- if( pMod->pModule->iVersion<3 ) return 0;
|
|
- if( pMod->pModule->xShadowName==0 ) return 0;
|
|
- return pMod->pModule->xShadowName(zTail+1);
|
|
+ return sqlite3IsShadowTableOf(db, pTab, zName);
|
|
}
|
|
#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */
|
|
|
|
+
|
|
+#ifdef SQLITE_DEBUG
|
|
+/*
|
|
+** Mark all nodes of an expression as EP_Immutable, indicating that
|
|
+** they should not be changed. Expressions attached to a table or
|
|
+** index definition are tagged this way to help ensure that we do
|
|
+** not pass them into code generator routines by mistake.
|
|
+*/
|
|
+static int markImmutableExprStep(Walker *pWalker, Expr *pExpr){
|
|
+ (void)pWalker;
|
|
+ ExprSetVVAProperty(pExpr, EP_Immutable);
|
|
+ return WRC_Continue;
|
|
+}
|
|
+static void markExprListImmutable(ExprList *pList){
|
|
+ if( pList ){
|
|
+ Walker w;
|
|
+ memset(&w, 0, sizeof(w));
|
|
+ w.xExprCallback = markImmutableExprStep;
|
|
+ w.xSelectCallback = sqlite3SelectWalkNoop;
|
|
+ w.xSelectCallback2 = 0;
|
|
+ sqlite3WalkExprList(&w, pList);
|
|
+ }
|
|
+}
|
|
+#else
|
|
+#define markExprListImmutable(X) /* no-op */
|
|
+#endif /* SQLITE_DEBUG */
|
|
+
|
|
+
|
|
/*
|
|
** This routine is called to report the final ")" that terminates
|
|
** a CREATE TABLE statement.
|
|
@@ -111290,15 +120102,15 @@ SQLITE_PRIVATE int sqlite3ShadowTableName(sqlite3 *db, const char *zName){
|
|
** is added to the internal hash tables, assuming no errors have
|
|
** occurred.
|
|
**
|
|
-** An entry for the table is made in the master table on disk, unless
|
|
+** An entry for the table is made in the schema table on disk, unless
|
|
** this is a temporary table or db->init.busy==1. When db->init.busy==1
|
|
-** it means we are reading the sqlite_master table because we just
|
|
-** connected to the database or because the sqlite_master table has
|
|
+** it means we are reading the sqlite_schema table because we just
|
|
+** connected to the database or because the sqlite_schema table has
|
|
** recently changed, so the entry for this table already exists in
|
|
-** the sqlite_master table. We do not want to create it again.
|
|
+** the sqlite_schema table. We do not want to create it again.
|
|
**
|
|
** If the pSelect argument is not NULL, it means that this routine
|
|
-** was called to create a table generated from a
|
|
+** was called to create a table generated from a
|
|
** "CREATE TABLE ... AS SELECT ..." statement. The column names of
|
|
** the new table will match the result set of the SELECT.
|
|
*/
|
|
@@ -111306,7 +120118,7 @@ SQLITE_PRIVATE void sqlite3EndTable(
|
|
Parse *pParse, /* Parse context */
|
|
Token *pCons, /* The ',' token after the last column defn. */
|
|
Token *pEnd, /* The ')' before options in the CREATE TABLE */
|
|
- u8 tabOpts, /* Extra table options. Usually 0. */
|
|
+ u32 tabOpts, /* Extra table options. Usually 0. */
|
|
Select *pSelect /* Select from a "CREATE ... AS SELECT" */
|
|
){
|
|
Table *p; /* The new table */
|
|
@@ -111317,7 +120129,6 @@ SQLITE_PRIVATE void sqlite3EndTable(
|
|
if( pEnd==0 && pSelect==0 ){
|
|
return;
|
|
}
|
|
- assert( !db->mallocFailed );
|
|
p = pParse->pNewTable;
|
|
if( p==0 ) return;
|
|
|
|
@@ -111326,16 +120137,16 @@ SQLITE_PRIVATE void sqlite3EndTable(
|
|
}
|
|
|
|
/* If the db->init.busy is 1 it means we are reading the SQL off the
|
|
- ** "sqlite_master" or "sqlite_temp_master" table on the disk.
|
|
+ ** "sqlite_schema" or "sqlite_temp_schema" table on the disk.
|
|
** So do not write to the disk again. Extract the root page number
|
|
** for the table from the db->init.newTnum field. (The page number
|
|
** should have been put there by the sqliteOpenCb routine.)
|
|
**
|
|
- ** If the root page number is 1, that means this is the sqlite_master
|
|
+ ** If the root page number is 1, that means this is the sqlite_schema
|
|
** table itself. So mark it read-only.
|
|
*/
|
|
if( db->init.busy ){
|
|
- if( pSelect ){
|
|
+ if( pSelect || (!IsOrdinaryTable(p) && db->init.newTnum) ){
|
|
sqlite3ErrorMsg(pParse, "");
|
|
return;
|
|
}
|
|
@@ -111343,6 +120154,44 @@ SQLITE_PRIVATE void sqlite3EndTable(
|
|
if( p->tnum==1 ) p->tabFlags |= TF_Readonly;
|
|
}
|
|
|
|
+ /* Special processing for tables that include the STRICT keyword:
|
|
+ **
|
|
+ ** * Do not allow custom column datatypes. Every column must have
|
|
+ ** a datatype that is one of INT, INTEGER, REAL, TEXT, or BLOB.
|
|
+ **
|
|
+ ** * If a PRIMARY KEY is defined, other than the INTEGER PRIMARY KEY,
|
|
+ ** then all columns of the PRIMARY KEY must have a NOT NULL
|
|
+ ** constraint.
|
|
+ */
|
|
+ if( tabOpts & TF_Strict ){
|
|
+ int ii;
|
|
+ p->tabFlags |= TF_Strict;
|
|
+ for(ii=0; ii<p->nCol; ii++){
|
|
+ Column *pCol = &p->aCol[ii];
|
|
+ if( pCol->eCType==COLTYPE_CUSTOM ){
|
|
+ if( pCol->colFlags & COLFLAG_HASTYPE ){
|
|
+ sqlite3ErrorMsg(pParse,
|
|
+ "unknown datatype for %s.%s: \"%s\"",
|
|
+ p->zName, pCol->zCnName, sqlite3ColumnType(pCol, "")
|
|
+ );
|
|
+ }else{
|
|
+ sqlite3ErrorMsg(pParse, "missing datatype for %s.%s",
|
|
+ p->zName, pCol->zCnName);
|
|
+ }
|
|
+ return;
|
|
+ }else if( pCol->eCType==COLTYPE_ANY ){
|
|
+ pCol->affinity = SQLITE_AFF_BLOB;
|
|
+ }
|
|
+ if( (pCol->colFlags & COLFLAG_PRIMKEY)!=0
|
|
+ && p->iPKey!=ii
|
|
+ && pCol->notNull == OE_None
|
|
+ ){
|
|
+ pCol->notNull = OE_Abort;
|
|
+ p->tabFlags |= TF_HasNotNull;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
assert( (p->tabFlags & TF_HasPrimaryKey)==0
|
|
|| p->iPKey>=0 || sqlite3PrimaryKeyIndex(p)!=0 );
|
|
assert( (p->tabFlags & TF_HasPrimaryKey)!=0
|
|
@@ -111374,6 +120223,8 @@ SQLITE_PRIVATE void sqlite3EndTable(
|
|
** actually be used if PRAGMA writable_schema=ON is set. */
|
|
sqlite3ExprListDelete(db, p->pCheck);
|
|
p->pCheck = 0;
|
|
+ }else{
|
|
+ markExprListImmutable(p->pCheck);
|
|
}
|
|
}
|
|
#endif /* !defined(SQLITE_OMIT_CHECK) */
|
|
@@ -111385,7 +120236,7 @@ SQLITE_PRIVATE void sqlite3EndTable(
|
|
for(ii=0; ii<p->nCol; ii++){
|
|
u32 colFlags = p->aCol[ii].colFlags;
|
|
if( (colFlags & COLFLAG_GENERATED)!=0 ){
|
|
- Expr *pX = p->aCol[ii].pDflt;
|
|
+ Expr *pX = sqlite3ColumnExpr(p, &p->aCol[ii]);
|
|
testcase( colFlags & COLFLAG_VIRTUAL );
|
|
testcase( colFlags & COLFLAG_STORED );
|
|
if( sqlite3ResolveSelfReference(pParse, p, NC_GenCol, pX, 0) ){
|
|
@@ -111395,8 +120246,8 @@ SQLITE_PRIVATE void sqlite3EndTable(
|
|
** tree that have been allocated from lookaside memory, which is
|
|
** illegal in a schema and will lead to errors or heap corruption
|
|
** when the database connection closes. */
|
|
- sqlite3ExprDelete(db, pX);
|
|
- p->aCol[ii].pDflt = sqlite3ExprAlloc(db, TK_NULL, 0, 0);
|
|
+ sqlite3ColumnSetExpr(pParse, p, &p->aCol[ii],
|
|
+ sqlite3ExprAlloc(db, TK_NULL, 0, 0));
|
|
}
|
|
}else{
|
|
nNG++;
|
|
@@ -111416,7 +120267,7 @@ SQLITE_PRIVATE void sqlite3EndTable(
|
|
}
|
|
|
|
/* If not initializing, then create a record for the new table
|
|
- ** in the SQLITE_MASTER table of the database.
|
|
+ ** in the schema table of the database.
|
|
**
|
|
** If this is a TEMPORARY table, write the entry into the auxiliary
|
|
** file instead of into the main database file.
|
|
@@ -111433,10 +120284,10 @@ SQLITE_PRIVATE void sqlite3EndTable(
|
|
|
|
sqlite3VdbeAddOp1(v, OP_Close, 0);
|
|
|
|
- /*
|
|
+ /*
|
|
** Initialize zType for the new view or table.
|
|
*/
|
|
- if( p->pSelect==0 ){
|
|
+ if( IsOrdinaryTable(p) ){
|
|
/* A regular table */
|
|
zType = "table";
|
|
zType2 = "TABLE";
|
|
@@ -111470,6 +120321,11 @@ SQLITE_PRIVATE void sqlite3EndTable(
|
|
int addrInsLoop; /* Top of the loop for inserting rows */
|
|
Table *pSelTab; /* A table that describes the SELECT results */
|
|
|
|
+ if( IN_SPECIAL_PARSE ){
|
|
+ pParse->rc = SQLITE_ERROR;
|
|
+ pParse->nErr++;
|
|
+ return;
|
|
+ }
|
|
regYield = ++pParse->nMem;
|
|
regRec = ++pParse->nMem;
|
|
regRowid = ++pParse->nMem;
|
|
@@ -111512,20 +120368,20 @@ SQLITE_PRIVATE void sqlite3EndTable(
|
|
Token *pEnd2 = tabOpts ? &pParse->sLastToken : pEnd;
|
|
n = (int)(pEnd2->z - pParse->sNameToken.z);
|
|
if( pEnd2->z[0]!=';' ) n += pEnd2->n;
|
|
- zStmt = sqlite3MPrintf(db,
|
|
+ zStmt = sqlite3MPrintf(db,
|
|
"CREATE %s %.*s", zType2, n, pParse->sNameToken.z
|
|
);
|
|
}
|
|
|
|
- /* A slot for the record has already been allocated in the
|
|
- ** SQLITE_MASTER table. We just need to update that slot with all
|
|
+ /* A slot for the record has already been allocated in the
|
|
+ ** schema table. We just need to update that slot with all
|
|
** the information we've collected.
|
|
*/
|
|
sqlite3NestedParse(pParse,
|
|
- "UPDATE %Q.%s "
|
|
- "SET type='%s', name=%Q, tbl_name=%Q, rootpage=#%d, sql=%Q "
|
|
- "WHERE rowid=#%d",
|
|
- db->aDb[iDb].zDbSName, MASTER_NAME,
|
|
+ "UPDATE %Q." LEGACY_SCHEMA_TABLE
|
|
+ " SET type='%s', name=%Q, tbl_name=%Q, rootpage=#%d, sql=%Q"
|
|
+ " WHERE rowid=#%d",
|
|
+ db->aDb[iDb].zDbSName,
|
|
zType,
|
|
p->zName,
|
|
p->zName,
|
|
@@ -111540,7 +120396,7 @@ SQLITE_PRIVATE void sqlite3EndTable(
|
|
/* Check to see if we need to create an sqlite_sequence table for
|
|
** keeping track of autoincrement keys.
|
|
*/
|
|
- if( (p->tabFlags & TF_Autoincrement)!=0 ){
|
|
+ if( (p->tabFlags & TF_Autoincrement)!=0 && !IN_SPECIAL_PARSE ){
|
|
Db *pDb = &db->aDb[iDb];
|
|
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
|
if( pDb->pSchema->pSeqTab==0 ){
|
|
@@ -111554,7 +120410,7 @@ 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));
|
|
+ sqlite3MPrintf(db, "tbl_name='%q' AND type!='trigger'", p->zName),0);
|
|
}
|
|
|
|
/* Add the table to the in-memory representation of the database.
|
|
@@ -111563,6 +120419,7 @@ SQLITE_PRIVATE void sqlite3EndTable(
|
|
Table *pOld;
|
|
Schema *pSchema = p->pSchema;
|
|
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
|
+ assert( HasRowid(p) || p->iPKey<0 );
|
|
pOld = sqlite3HashInsert(&pSchema->tblHash, p->zName, p);
|
|
if( pOld ){
|
|
assert( p==pOld ); /* Malloc must have failed inside HashInsert() */
|
|
@@ -111572,19 +120429,27 @@ SQLITE_PRIVATE void sqlite3EndTable(
|
|
pParse->pNewTable = 0;
|
|
db->mDbFlags |= DBFLAG_SchemaChange;
|
|
|
|
-#ifndef SQLITE_OMIT_ALTERTABLE
|
|
- if( !p->pSelect ){
|
|
- const char *zName = (const char *)pParse->sNameToken.z;
|
|
- int nName;
|
|
- assert( !pSelect && pCons && pEnd );
|
|
- if( pCons->z==0 ){
|
|
- pCons = pEnd;
|
|
- }
|
|
- nName = (int)((const char *)pCons->z - zName);
|
|
- p->addColOffset = 13 + sqlite3Utf8CharLen(zName, nName);
|
|
+ /* If this is the magic sqlite_sequence table used by autoincrement,
|
|
+ ** then record a pointer to this table in the main database structure
|
|
+ ** so that INSERT can find the table easily. */
|
|
+ assert( !pParse->nested );
|
|
+#ifndef SQLITE_OMIT_AUTOINCREMENT
|
|
+ if( strcmp(p->zName, "sqlite_sequence")==0 ){
|
|
+ assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
|
+ p->pSchema->pSeqTab = p;
|
|
}
|
|
#endif
|
|
}
|
|
+
|
|
+#ifndef SQLITE_OMIT_ALTERTABLE
|
|
+ if( !pSelect && IsOrdinaryTable(p) ){
|
|
+ assert( pCons && pEnd );
|
|
+ if( pCons->z==0 ){
|
|
+ pCons = pEnd;
|
|
+ }
|
|
+ p->u.tab.addColOffset = 13 + (int)(pCons->z - pParse->sNameToken.z);
|
|
+ }
|
|
+#endif
|
|
}
|
|
|
|
#ifndef SQLITE_OMIT_VIEW
|
|
@@ -111617,6 +120482,16 @@ SQLITE_PRIVATE void sqlite3CreateView(
|
|
sqlite3StartTable(pParse, pName1, pName2, isTemp, 1, 0, noErr);
|
|
p = pParse->pNewTable;
|
|
if( p==0 || pParse->nErr ) goto create_view_fail;
|
|
+
|
|
+ /* Legacy versions of SQLite allowed the use of the magic "rowid" column
|
|
+ ** on a view, even though views do not have rowids. The following flag
|
|
+ ** setting fixes this problem. But the fix can be disabled by compiling
|
|
+ ** with -DSQLITE_ALLOW_ROWID_IN_VIEW in case there are legacy apps that
|
|
+ ** depend upon the old buggy behavior. */
|
|
+#ifndef SQLITE_ALLOW_ROWID_IN_VIEW
|
|
+ p->tabFlags |= TF_NoVisibleRowid;
|
|
+#endif
|
|
+
|
|
sqlite3TwoPartName(pParse, pName1, pName2, &pName);
|
|
iDb = sqlite3SchemaToIndex(db, p->pSchema);
|
|
sqlite3FixInit(&sFix, pParse, iDb, "view", pName);
|
|
@@ -111629,12 +120504,13 @@ SQLITE_PRIVATE void sqlite3CreateView(
|
|
*/
|
|
pSelect->selFlags |= SF_View;
|
|
if( IN_RENAME_OBJECT ){
|
|
- p->pSelect = pSelect;
|
|
+ p->u.view.pSelect = pSelect;
|
|
pSelect = 0;
|
|
}else{
|
|
- p->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
|
|
+ p->u.view.pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
|
|
}
|
|
p->pCheck = sqlite3ExprListDup(db, pCNames, EXPRDUP_REDUCE);
|
|
+ p->eTabType = TABTYP_VIEW;
|
|
if( db->mallocFailed ) goto create_view_fail;
|
|
|
|
/* Locate the end of the CREATE VIEW statement. Make sEnd point to
|
|
@@ -111653,7 +120529,7 @@ SQLITE_PRIVATE void sqlite3CreateView(
|
|
sEnd.z = &z[n-1];
|
|
sEnd.n = 1;
|
|
|
|
- /* Use sqlite3EndTable() to add the view to the SQLITE_MASTER table */
|
|
+ /* Use sqlite3EndTable() to add the view to the schema table */
|
|
sqlite3EndTable(pParse, 0, &sEnd, 0, 0);
|
|
|
|
create_view_fail:
|
|
@@ -111672,11 +120548,10 @@ SQLITE_PRIVATE void sqlite3CreateView(
|
|
** the columns of the view in the pTable structure. Return the number
|
|
** of errors. If an error is seen leave an error message in pParse->zErrMsg.
|
|
*/
|
|
-SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
|
|
+static SQLITE_NOINLINE int viewGetColumnNames(Parse *pParse, Table *pTable){
|
|
Table *pSelTab; /* A fake table from which we get the result set */
|
|
Select *pSel; /* Copy of the SELECT that implements the view */
|
|
int nErr = 0; /* Number of errors encountered */
|
|
- int n; /* Temporarily holds the number of cursors assigned */
|
|
sqlite3 *db = pParse->db; /* Database connection for malloc errors */
|
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
|
int rc;
|
|
@@ -111688,20 +120563,20 @@ SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
|
|
assert( pTable );
|
|
|
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
|
- db->nSchemaLock++;
|
|
- rc = sqlite3VtabCallConnect(pParse, pTable);
|
|
- db->nSchemaLock--;
|
|
- if( rc ){
|
|
- return 1;
|
|
+ if( IsVirtual(pTable) ){
|
|
+ db->nSchemaLock++;
|
|
+ rc = sqlite3VtabCallConnect(pParse, pTable);
|
|
+ db->nSchemaLock--;
|
|
+ return rc;
|
|
}
|
|
- if( IsVirtual(pTable) ) return 0;
|
|
#endif
|
|
|
|
#ifndef SQLITE_OMIT_VIEW
|
|
/* A positive nCol means the columns names for this view are
|
|
- ** already known.
|
|
+ ** already known. This routine is not called unless either the
|
|
+ ** table is virtual or nCol is zero.
|
|
*/
|
|
- if( pTable->nCol>0 ) return 0;
|
|
+ assert( pTable->nCol<=0 );
|
|
|
|
/* A negative nCol is a special marker meaning that we are currently
|
|
** trying to compute the column names. If we enter this routine with
|
|
@@ -111713,7 +120588,7 @@ SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
|
|
** Actually, the error above is now caught prior to reaching this point.
|
|
** But the following test is still important as it does come up
|
|
** in the following:
|
|
- **
|
|
+ **
|
|
** CREATE TABLE main.ex1(a);
|
|
** CREATE TEMP VIEW ex1 AS SELECT a FROM ex1;
|
|
** SELECT * FROM temp.ex1;
|
|
@@ -111731,14 +120606,13 @@ SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
|
|
** to be permanent. So the computation is done on a copy of the SELECT
|
|
** statement that defines the view.
|
|
*/
|
|
- assert( pTable->pSelect );
|
|
- pSel = sqlite3SelectDup(db, pTable->pSelect, 0);
|
|
+ assert( IsView(pTable) );
|
|
+ pSel = sqlite3SelectDup(db, pTable->u.view.pSelect, 0);
|
|
if( pSel ){
|
|
-#ifndef SQLITE_OMIT_ALTERTABLE
|
|
u8 eParseMode = pParse->eParseMode;
|
|
+ int nTab = pParse->nTab;
|
|
+ int nSelect = pParse->nSelect;
|
|
pParse->eParseMode = PARSE_MODE_NORMAL;
|
|
-#endif
|
|
- n = pParse->nTab;
|
|
sqlite3SrcListAssignCursors(pParse, pSel->pSrc);
|
|
pTable->nCol = -1;
|
|
DisableLookaside;
|
|
@@ -111750,7 +120624,8 @@ SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
|
|
#else
|
|
pSelTab = sqlite3ResultSetOfSelect(pParse, pSel, SQLITE_AFF_NONE);
|
|
#endif
|
|
- pParse->nTab = n;
|
|
+ pParse->nTab = nTab;
|
|
+ pParse->nSelect = nSelect;
|
|
if( pSelTab==0 ){
|
|
pTable->nCol = 0;
|
|
nErr++;
|
|
@@ -111761,14 +120636,13 @@ SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
|
|
** normally holds CHECK constraints on an ordinary table, but for
|
|
** a VIEW it holds the list of column names.
|
|
*/
|
|
- sqlite3ColumnsFromExprList(pParse, pTable->pCheck,
|
|
+ sqlite3ColumnsFromExprList(pParse, pTable->pCheck,
|
|
&pTable->nCol, &pTable->aCol);
|
|
- if( db->mallocFailed==0
|
|
- && pParse->nErr==0
|
|
+ if( pParse->nErr==0
|
|
&& pTable->nCol==pSel->pEList->nExpr
|
|
){
|
|
- sqlite3SelectAddColumnTypeAndCollation(pParse, pTable, pSel,
|
|
- SQLITE_AFF_NONE);
|
|
+ assert( db->mallocFailed==0 );
|
|
+ sqlite3SubqueryColumnTypes(pParse, pTable, pSel, SQLITE_AFF_NONE);
|
|
}
|
|
}else{
|
|
/* CREATE VIEW name AS... without an argument list. Construct
|
|
@@ -111777,6 +120651,7 @@ SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
|
|
assert( pTable->aCol==0 );
|
|
pTable->nCol = pSelTab->nCol;
|
|
pTable->aCol = pSelTab->aCol;
|
|
+ pTable->tabFlags |= (pSelTab->tabFlags & COLFLAG_NOINSERT);
|
|
pSelTab->nCol = 0;
|
|
pSelTab->aCol = 0;
|
|
assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) );
|
|
@@ -111785,20 +120660,21 @@ SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
|
|
sqlite3DeleteTable(db, pSelTab);
|
|
sqlite3SelectDelete(db, pSel);
|
|
EnableLookaside;
|
|
-#ifndef SQLITE_OMIT_ALTERTABLE
|
|
pParse->eParseMode = eParseMode;
|
|
-#endif
|
|
} else {
|
|
nErr++;
|
|
}
|
|
pTable->pSchema->schemaFlags |= DB_UnresetViews;
|
|
if( db->mallocFailed ){
|
|
sqlite3DeleteColumnNames(db, pTable);
|
|
- pTable->aCol = 0;
|
|
- pTable->nCol = 0;
|
|
}
|
|
#endif /* SQLITE_OMIT_VIEW */
|
|
- return nErr;
|
|
+ return nErr;
|
|
+}
|
|
+SQLITE_PRIVATE int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
|
|
+ assert( pTable!=0 );
|
|
+ if( !IsVirtual(pTable) && pTable->nCol>0 ) return 0;
|
|
+ return viewGetColumnNames(pParse, pTable);
|
|
}
|
|
#endif /* !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) */
|
|
|
|
@@ -111812,10 +120688,8 @@ static void sqliteViewResetAll(sqlite3 *db, int idx){
|
|
if( !DbHasProperty(db, idx, DB_UnresetViews) ) return;
|
|
for(i=sqliteHashFirst(&db->aDb[idx].pSchema->tblHash); i;i=sqliteHashNext(i)){
|
|
Table *pTab = sqliteHashData(i);
|
|
- if( pTab->pSelect ){
|
|
+ if( IsView(pTab) ){
|
|
sqlite3DeleteColumnNames(db, pTab);
|
|
- pTab->aCol = 0;
|
|
- pTab->nCol = 0;
|
|
}
|
|
}
|
|
DbClearProperty(db, idx, DB_UnresetViews);
|
|
@@ -111834,7 +120708,7 @@ static void sqliteViewResetAll(sqlite3 *db, int idx){
|
|
** on tables and/or indices that are the process of being deleted.
|
|
** If you are unlucky, one of those deleted indices or tables might
|
|
** have the same rootpage number as the real table or index that is
|
|
-** being moved. So we cannot stop searching after the first match
|
|
+** being moved. So we cannot stop searching after the first match
|
|
** because the first match might be for one of the deleted indices
|
|
** or tables and not the table/index that is actually being moved.
|
|
** We must continue looping until all tables and indices with
|
|
@@ -111842,7 +120716,7 @@ static void sqliteViewResetAll(sqlite3 *db, int idx){
|
|
** in order to be certain that we got the right one.
|
|
*/
|
|
#ifndef SQLITE_OMIT_AUTOVACUUM
|
|
-SQLITE_PRIVATE void sqlite3RootPageMoved(sqlite3 *db, int iDb, int iFrom, int iTo){
|
|
+SQLITE_PRIVATE void sqlite3RootPageMoved(sqlite3 *db, int iDb, Pgno iFrom, Pgno iTo){
|
|
HashElem *pElem;
|
|
Hash *pHash;
|
|
Db *pDb;
|
|
@@ -111868,10 +120742,10 @@ SQLITE_PRIVATE void sqlite3RootPageMoved(sqlite3 *db, int iDb, int iFrom, int iT
|
|
|
|
/*
|
|
** Write code to erase the table with root-page iTable from database iDb.
|
|
-** Also write code to modify the sqlite_master table and internal schema
|
|
+** Also write code to modify the sqlite_schema table and internal schema
|
|
** if a root-page of another table is moved by the btree-layer whilst
|
|
** erasing iTable (this can happen with an auto-vacuum database).
|
|
-*/
|
|
+*/
|
|
static void destroyRootPage(Parse *pParse, int iTable, int iDb){
|
|
Vdbe *v = sqlite3GetVdbe(pParse);
|
|
int r1 = sqlite3GetTempReg(pParse);
|
|
@@ -111881,30 +120755,31 @@ static void destroyRootPage(Parse *pParse, int iTable, int iDb){
|
|
#ifndef SQLITE_OMIT_AUTOVACUUM
|
|
/* OP_Destroy stores an in integer r1. If this integer
|
|
** is non-zero, then it is the root page number of a table moved to
|
|
- ** location iTable. The following code modifies the sqlite_master table to
|
|
+ ** location iTable. The following code modifies the sqlite_schema table to
|
|
** reflect this.
|
|
**
|
|
** The "#NNN" in the SQL is a special constant that means whatever value
|
|
** is in register NNN. See grammar rules associated with the TK_REGISTER
|
|
** token for additional information.
|
|
*/
|
|
- sqlite3NestedParse(pParse,
|
|
- "UPDATE %Q.%s SET rootpage=%d WHERE #%d AND rootpage=#%d",
|
|
- pParse->db->aDb[iDb].zDbSName, MASTER_NAME, iTable, r1, r1);
|
|
+ sqlite3NestedParse(pParse,
|
|
+ "UPDATE %Q." LEGACY_SCHEMA_TABLE
|
|
+ " SET rootpage=%d WHERE #%d AND rootpage=#%d",
|
|
+ pParse->db->aDb[iDb].zDbSName, iTable, r1, r1);
|
|
#endif
|
|
sqlite3ReleaseTempReg(pParse, r1);
|
|
}
|
|
|
|
/*
|
|
** Write VDBE code to erase table pTab and all associated indices on disk.
|
|
-** Code to update the sqlite_master tables and internal schema definitions
|
|
+** Code to update the sqlite_schema tables and internal schema definitions
|
|
** in case a root-page belonging to another table is moved by the btree layer
|
|
** is also added (this can happen with an auto-vacuum database).
|
|
*/
|
|
static void destroyTable(Parse *pParse, Table *pTab){
|
|
/* If the database may be auto-vacuum capable (if SQLITE_OMIT_AUTOVACUUM
|
|
** is not defined), then it is important to call OP_Destroy on the
|
|
- ** table and index root-pages in order, starting with the numerically
|
|
+ ** table and index root-pages in order, starting with the numerically
|
|
** largest root-page number. This guarantees that none of the root-pages
|
|
** to be destroyed is relocated by an earlier OP_Destroy. i.e. if the
|
|
** following were coded:
|
|
@@ -111914,22 +120789,22 @@ static void destroyTable(Parse *pParse, Table *pTab){
|
|
** OP_Destroy 5 0
|
|
**
|
|
** and root page 5 happened to be the largest root-page number in the
|
|
- ** database, then root page 5 would be moved to page 4 by the
|
|
+ ** database, then root page 5 would be moved to page 4 by the
|
|
** "OP_Destroy 4 0" opcode. The subsequent "OP_Destroy 5 0" would hit
|
|
** a free-list page.
|
|
*/
|
|
- int iTab = pTab->tnum;
|
|
- int iDestroyed = 0;
|
|
+ Pgno iTab = pTab->tnum;
|
|
+ Pgno iDestroyed = 0;
|
|
|
|
while( 1 ){
|
|
Index *pIdx;
|
|
- int iLargest = 0;
|
|
+ Pgno iLargest = 0;
|
|
|
|
if( iDestroyed==0 || iTab<iDestroyed ){
|
|
iLargest = iTab;
|
|
}
|
|
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
|
- int iIdx = pIdx->tnum;
|
|
+ Pgno iIdx = pIdx->tnum;
|
|
assert( pIdx->pSchema==pTab->pSchema );
|
|
if( (iDestroyed==0 || (iIdx<iDestroyed)) && iIdx>iLargest ){
|
|
iLargest = iIdx;
|
|
@@ -111990,12 +120865,12 @@ SQLITE_PRIVATE void sqlite3CodeDropTable(Parse *pParse, Table *pTab, int iDb, in
|
|
#endif
|
|
|
|
/* Drop all triggers associated with the table being dropped. Code
|
|
- ** is generated to remove entries from sqlite_master and/or
|
|
- ** sqlite_temp_master if required.
|
|
+ ** is generated to remove entries from sqlite_schema and/or
|
|
+ ** sqlite_temp_schema if required.
|
|
*/
|
|
pTrigger = sqlite3TriggerList(pParse, pTab);
|
|
while( pTrigger ){
|
|
- assert( pTrigger->pSchema==pTab->pSchema ||
|
|
+ assert( pTrigger->pSchema==pTab->pSchema ||
|
|
pTrigger->pSchema==db->aDb[1].pSchema );
|
|
sqlite3DropTriggerPtr(pParse, pTrigger);
|
|
pTrigger = pTrigger->pNext;
|
|
@@ -112015,16 +120890,17 @@ SQLITE_PRIVATE void sqlite3CodeDropTable(Parse *pParse, Table *pTab, int iDb, in
|
|
}
|
|
#endif
|
|
|
|
- /* Drop all SQLITE_MASTER table and index entries that refer to the
|
|
- ** table. The program name loops through the master table and deletes
|
|
+ /* Drop all entries in the schema table that refer to the
|
|
+ ** table. The program name loops through the schema table and deletes
|
|
** every row that refers to a table of the same name as the one being
|
|
** dropped. Triggers are handled separately because a trigger can be
|
|
** created in the temp database that refers to a table in another
|
|
** database.
|
|
*/
|
|
- sqlite3NestedParse(pParse,
|
|
- "DELETE FROM %Q.%s WHERE tbl_name=%Q and type!='trigger'",
|
|
- pDb->zDbSName, MASTER_NAME, pTab->zName);
|
|
+ sqlite3NestedParse(pParse,
|
|
+ "DELETE FROM %Q." LEGACY_SCHEMA_TABLE
|
|
+ " WHERE tbl_name=%Q and type!='trigger'",
|
|
+ pDb->zDbSName, pTab->zName);
|
|
if( !isView && !IsVirtual(pTab) ){
|
|
destroyTable(pParse, pTab);
|
|
}
|
|
@@ -112050,6 +120926,7 @@ SQLITE_PRIVATE int sqlite3ReadOnlyShadowTables(sqlite3 *db){
|
|
if( (db->flags & SQLITE_Defensive)!=0
|
|
&& db->pVtabCtx==0
|
|
&& db->nVdbeExec==0
|
|
+ && !sqlite3VtabInSync(db)
|
|
){
|
|
return 1;
|
|
}
|
|
@@ -112069,6 +120946,9 @@ static int tableMayNotBeDropped(sqlite3 *db, Table *pTab){
|
|
if( (pTab->tabFlags & TF_Shadow)!=0 && sqlite3ReadOnlyShadowTables(db) ){
|
|
return 1;
|
|
}
|
|
+ if( pTab->tabFlags & TF_Eponymous ){
|
|
+ return 1;
|
|
+ }
|
|
return 0;
|
|
}
|
|
|
|
@@ -112094,7 +120974,10 @@ SQLITE_PRIVATE void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView,
|
|
if( noErr ) db->suppressErr--;
|
|
|
|
if( pTab==0 ){
|
|
- if( noErr ) sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase);
|
|
+ if( noErr ){
|
|
+ sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase);
|
|
+ sqlite3ForceNotReadOnly(pParse);
|
|
+ }
|
|
goto exit_drop_table;
|
|
}
|
|
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
|
@@ -112150,17 +121033,17 @@ SQLITE_PRIVATE void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView,
|
|
/* Ensure DROP TABLE is not used on a view, and DROP VIEW is not used
|
|
** on a table.
|
|
*/
|
|
- if( isView && pTab->pSelect==0 ){
|
|
+ if( isView && !IsView(pTab) ){
|
|
sqlite3ErrorMsg(pParse, "use DROP TABLE to delete table %s", pTab->zName);
|
|
goto exit_drop_table;
|
|
}
|
|
- if( !isView && pTab->pSelect ){
|
|
+ if( !isView && IsView(pTab) ){
|
|
sqlite3ErrorMsg(pParse, "use DROP VIEW to delete view %s", pTab->zName);
|
|
goto exit_drop_table;
|
|
}
|
|
#endif
|
|
|
|
- /* Generate code to remove the table from the master table
|
|
+ /* Generate code to remove the table from the schema table
|
|
** on disk.
|
|
*/
|
|
v = sqlite3GetVdbe(pParse);
|
|
@@ -112205,7 +121088,7 @@ SQLITE_PRIVATE void sqlite3CreateForeignKey(
|
|
FKey *pFKey = 0;
|
|
FKey *pNextTo;
|
|
Table *p = pParse->pNewTable;
|
|
- int nByte;
|
|
+ i64 nByte;
|
|
int i;
|
|
int nCol;
|
|
char *z;
|
|
@@ -112218,7 +121101,7 @@ SQLITE_PRIVATE void sqlite3CreateForeignKey(
|
|
if( pToCol && pToCol->nExpr!=1 ){
|
|
sqlite3ErrorMsg(pParse, "foreign key on %s"
|
|
" should reference only one column of table %T",
|
|
- p->aCol[iCol].zName, pTo);
|
|
+ p->aCol[iCol].zCnName, pTo);
|
|
goto fk_end;
|
|
}
|
|
nCol = 1;
|
|
@@ -112241,7 +121124,8 @@ SQLITE_PRIVATE void sqlite3CreateForeignKey(
|
|
goto fk_end;
|
|
}
|
|
pFKey->pFrom = p;
|
|
- pFKey->pNextFrom = p->pFKey;
|
|
+ assert( IsOrdinaryTable(p) );
|
|
+ pFKey->pNextFrom = p->u.tab.pFKey;
|
|
z = (char*)&pFKey->aCol[nCol];
|
|
pFKey->zTo = z;
|
|
if( IN_RENAME_OBJECT ){
|
|
@@ -112258,14 +121142,14 @@ SQLITE_PRIVATE void sqlite3CreateForeignKey(
|
|
for(i=0; i<nCol; i++){
|
|
int j;
|
|
for(j=0; j<p->nCol; j++){
|
|
- if( sqlite3StrICmp(p->aCol[j].zName, pFromCol->a[i].zEName)==0 ){
|
|
+ if( sqlite3StrICmp(p->aCol[j].zCnName, pFromCol->a[i].zEName)==0 ){
|
|
pFKey->aCol[i].iFrom = j;
|
|
break;
|
|
}
|
|
}
|
|
if( j>=p->nCol ){
|
|
- sqlite3ErrorMsg(pParse,
|
|
- "unknown column \"%s\" in foreign key definition",
|
|
+ sqlite3ErrorMsg(pParse,
|
|
+ "unknown column \"%s\" in foreign key definition",
|
|
pFromCol->a[i].zEName);
|
|
goto fk_end;
|
|
}
|
|
@@ -112291,7 +121175,7 @@ SQLITE_PRIVATE void sqlite3CreateForeignKey(
|
|
pFKey->aAction[1] = (u8)((flags >> 8 ) & 0xff); /* ON UPDATE action */
|
|
|
|
assert( sqlite3SchemaMutexHeld(db, 0, p->pSchema) );
|
|
- pNextTo = (FKey *)sqlite3HashInsert(&p->pSchema->fkeyHash,
|
|
+ pNextTo = (FKey *)sqlite3HashInsert(&p->pSchema->fkeyHash,
|
|
pFKey->zTo, (void *)pFKey
|
|
);
|
|
if( pNextTo==pFKey ){
|
|
@@ -112306,7 +121190,8 @@ SQLITE_PRIVATE void sqlite3CreateForeignKey(
|
|
|
|
/* Link the foreign key to the table as the last step.
|
|
*/
|
|
- p->pFKey = pFKey;
|
|
+ assert( IsOrdinaryTable(p) );
|
|
+ p->u.tab.pFKey = pFKey;
|
|
pFKey = 0;
|
|
|
|
fk_end:
|
|
@@ -112327,7 +121212,9 @@ SQLITE_PRIVATE void sqlite3DeferForeignKey(Parse *pParse, int isDeferred){
|
|
#ifndef SQLITE_OMIT_FOREIGN_KEY
|
|
Table *pTab;
|
|
FKey *pFKey;
|
|
- if( (pTab = pParse->pNewTable)==0 || (pFKey = pTab->pFKey)==0 ) return;
|
|
+ if( (pTab = pParse->pNewTable)==0 ) return;
|
|
+ if( NEVER(!IsOrdinaryTable(pTab)) ) return;
|
|
+ if( (pFKey = pTab->u.tab.pFKey)==0 ) return;
|
|
assert( isDeferred==0 || isDeferred==1 ); /* EV: R-30323-21917 */
|
|
pFKey->isDeferred = (u8)isDeferred;
|
|
#endif
|
|
@@ -112351,7 +121238,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
|
|
int iSorter; /* Cursor opened by OpenSorter (if in use) */
|
|
int addr1; /* Address of top of loop */
|
|
int addr2; /* Address to jump to for next iteration */
|
|
- int tnum; /* Root page of index */
|
|
+ Pgno tnum; /* Root page of index */
|
|
int iPartIdxLabel; /* Jump to this label to skip a row */
|
|
Vdbe *v; /* Generate code into this virtual machine */
|
|
KeyInfo *pKey; /* KeyInfo for index */
|
|
@@ -112372,12 +121259,12 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
|
|
v = sqlite3GetVdbe(pParse);
|
|
if( v==0 ) return;
|
|
if( memRootPage>=0 ){
|
|
- tnum = memRootPage;
|
|
+ tnum = (Pgno)memRootPage;
|
|
}else{
|
|
tnum = pIndex->tnum;
|
|
}
|
|
pKey = sqlite3KeyInfoOfIndex(pParse, pIndex);
|
|
- assert( pKey!=0 || db->mallocFailed || pParse->nErr );
|
|
+ assert( pKey!=0 || pParse->nErr );
|
|
|
|
/* Open the sorter cursor if we are to use one. */
|
|
iSorter = pParse->nTab++;
|
|
@@ -112397,7 +121284,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
|
|
sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1+1); VdbeCoverage(v);
|
|
sqlite3VdbeJumpHere(v, addr1);
|
|
if( memRootPage<0 ) sqlite3VdbeAddOp2(v, OP_Clear, tnum, iDb);
|
|
- sqlite3VdbeAddOp4(v, OP_OpenWrite, iIdx, tnum, iDb,
|
|
+ sqlite3VdbeAddOp4(v, OP_OpenWrite, iIdx, (int)tnum, iDb,
|
|
(char *)pKey, P4_KEYINFO);
|
|
sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR|((memRootPage>=0)?OPFLAG_P2ISREG:0));
|
|
|
|
@@ -112416,7 +121303,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
|
|
** user function that throws an exception when it is evaluated. But the
|
|
** overhead of adding a statement journal to a CREATE INDEX statement is
|
|
** very small (since most of the pages written do not contain content that
|
|
- ** needs to be restored if the statement aborts), so we call
|
|
+ ** needs to be restored if the statement aborts), so we call
|
|
** sqlite3MayAbort() for all CREATE INDEX statements. */
|
|
sqlite3MayAbort(pParse);
|
|
addr2 = sqlite3VdbeCurrentAddr(v);
|
|
@@ -112487,9 +121374,9 @@ SQLITE_PRIVATE int sqlite3HasExplicitNulls(Parse *pParse, ExprList *pList){
|
|
if( pList ){
|
|
int i;
|
|
for(i=0; i<pList->nExpr; i++){
|
|
- if( pList->a[i].bNulls ){
|
|
- u8 sf = pList->a[i].sortFlags;
|
|
- sqlite3ErrorMsg(pParse, "unsupported use of NULLS %s",
|
|
+ if( pList->a[i].fg.bNulls ){
|
|
+ u8 sf = pList->a[i].fg.sortFlags;
|
|
+ sqlite3ErrorMsg(pParse, "unsupported use of NULLS %s",
|
|
(sf==0 || sf==3) ? "FIRST" : "LAST"
|
|
);
|
|
return 1;
|
|
@@ -112500,8 +121387,8 @@ SQLITE_PRIVATE int sqlite3HasExplicitNulls(Parse *pParse, ExprList *pList){
|
|
}
|
|
|
|
/*
|
|
-** Create a new index for an SQL table. pName1.pName2 is the name of the index
|
|
-** and pTblList is the name of the table that is to be indexed. Both will
|
|
+** Create a new index for an SQL table. pName1.pName2 is the name of the index
|
|
+** and pTblList is the name of the table that is to be indexed. Both will
|
|
** be NULL for a primary key or an index that is created to satisfy a
|
|
** UNIQUE constraint. If pTable and pIndex are NULL, use pParse->pNewTable
|
|
** as the table to be indexed. pParse->pNewTable is a table that is
|
|
@@ -112509,7 +121396,7 @@ SQLITE_PRIVATE int sqlite3HasExplicitNulls(Parse *pParse, ExprList *pList){
|
|
**
|
|
** pList is a list of columns to be indexed. pList will be NULL if this
|
|
** is a primary key or unique-constraint on the most recent column added
|
|
-** to the table currently under construction.
|
|
+** to the table currently under construction.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3CreateIndex(
|
|
Parse *pParse, /* All information about this parse */
|
|
@@ -112541,9 +121428,11 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
|
|
char *zExtra = 0; /* Extra space after the Index object */
|
|
Index *pPk = 0; /* PRIMARY KEY index for WITHOUT ROWID tables */
|
|
|
|
- if( db->mallocFailed || pParse->nErr>0 ){
|
|
+ assert( db->pParse==pParse );
|
|
+ if( pParse->nErr ){
|
|
goto exit_create_index;
|
|
}
|
|
+ assert( db->mallocFailed==0 );
|
|
if( IN_DECLARE_VTAB && idxType!=SQLITE_IDXTYPE_PRIMARYKEY ){
|
|
goto exit_create_index;
|
|
}
|
|
@@ -112559,7 +121448,7 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
|
|
*/
|
|
if( pTblName!=0 ){
|
|
|
|
- /* Use the two-part index name to determine the database
|
|
+ /* Use the two-part index name to determine the database
|
|
** to search for the table. 'Fix' the table name to this db
|
|
** before looking up the table.
|
|
*/
|
|
@@ -112591,7 +121480,7 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
|
|
assert( db->mallocFailed==0 || pTab==0 );
|
|
if( pTab==0 ) goto exit_create_index;
|
|
if( iDb==1 && db->aDb[iDb].pSchema!=pTab->pSchema ){
|
|
- sqlite3ErrorMsg(pParse,
|
|
+ sqlite3ErrorMsg(pParse,
|
|
"cannot create a TEMP index on non-TEMP table \"%s\"",
|
|
pTab->zName);
|
|
goto exit_create_index;
|
|
@@ -112607,22 +121496,18 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
|
|
pDb = &db->aDb[iDb];
|
|
|
|
assert( pTab!=0 );
|
|
- assert( pParse->nErr==0 );
|
|
- if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0
|
|
+ if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0
|
|
&& db->init.busy==0
|
|
&& pTblName!=0
|
|
#if SQLITE_USER_AUTHENTICATION
|
|
&& sqlite3UserAuthTable(pTab->zName)==0
|
|
#endif
|
|
-#ifdef SQLITE_ALLOW_SQLITE_MASTER_INDEX
|
|
- && sqlite3StrICmp(&pTab->zName[7],"master")!=0
|
|
-#endif
|
|
- ){
|
|
+ ){
|
|
sqlite3ErrorMsg(pParse, "table %s may not be indexed", pTab->zName);
|
|
goto exit_create_index;
|
|
}
|
|
#ifndef SQLITE_OMIT_VIEW
|
|
- if( pTab->pSelect ){
|
|
+ if( IsView(pTab) ){
|
|
sqlite3ErrorMsg(pParse, "views may not be indexed");
|
|
goto exit_create_index;
|
|
}
|
|
@@ -112636,10 +121521,10 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
|
|
|
|
/*
|
|
** Find the name of the index. Make sure there is not already another
|
|
- ** index or table with the same name.
|
|
+ ** index or table with the same name.
|
|
**
|
|
** Exception: If we are reading the names of permanent indices from the
|
|
- ** sqlite_master table (because some other process changed the schema) and
|
|
+ ** sqlite_schema table (because some other process changed the schema) and
|
|
** one of the index names collides with the name of a temporary table or
|
|
** index, then we will continue to process this index.
|
|
**
|
|
@@ -112656,7 +121541,7 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
|
|
}
|
|
if( !IN_RENAME_OBJECT ){
|
|
if( !db->init.busy ){
|
|
- if( sqlite3FindTable(db, zName, 0)!=0 ){
|
|
+ if( sqlite3FindTable(db, zName, pDb->zDbSName)!=0 ){
|
|
sqlite3ErrorMsg(pParse, "there is already a table named %s", zName);
|
|
goto exit_create_index;
|
|
}
|
|
@@ -112667,6 +121552,7 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
|
|
}else{
|
|
assert( !db->init.busy );
|
|
sqlite3CodeVerifySchema(pParse, iDb);
|
|
+ sqlite3ForceNotReadOnly(pParse);
|
|
}
|
|
goto exit_create_index;
|
|
}
|
|
@@ -112712,7 +121598,7 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
|
|
Token prevCol;
|
|
Column *pCol = &pTab->aCol[pTab->nCol-1];
|
|
pCol->colFlags |= COLFLAG_UNIQUE;
|
|
- sqlite3TokenInit(&prevCol, pCol->zName);
|
|
+ sqlite3TokenInit(&prevCol, pCol->zCnName);
|
|
pList = sqlite3ExprListAppend(pParse, 0,
|
|
sqlite3ExprAlloc(db, TK_ID, &prevCol, 0));
|
|
if( pList==0 ) goto exit_create_index;
|
|
@@ -112730,12 +121616,13 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
|
|
Expr *pExpr = pList->a[i].pExpr;
|
|
assert( pExpr!=0 );
|
|
if( pExpr->op==TK_COLLATE ){
|
|
+ assert( !ExprHasProperty(pExpr, EP_IntValue) );
|
|
nExtra += (1 + sqlite3Strlen30(pExpr->u.zToken));
|
|
}
|
|
}
|
|
|
|
- /*
|
|
- ** Allocate the index structure.
|
|
+ /*
|
|
+ ** Allocate the index structure.
|
|
*/
|
|
nName = sqlite3Strlen30(zName);
|
|
nExtraCol = pPk ? pPk->nKeyCol : 1;
|
|
@@ -112807,6 +121694,7 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
|
|
j = XN_EXPR;
|
|
pIndex->aiColumn[i] = XN_EXPR;
|
|
pIndex->uniqNotNull = 0;
|
|
+ pIndex->bHasExpr = 1;
|
|
}else{
|
|
j = pCExpr->iColumn;
|
|
assert( j<=0x7fff );
|
|
@@ -112818,6 +121706,7 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
|
|
}
|
|
if( pTab->aCol[j].colFlags & COLFLAG_VIRTUAL ){
|
|
pIndex->bHasVCol = 1;
|
|
+ pIndex->bHasExpr = 1;
|
|
}
|
|
}
|
|
pIndex->aiColumn[i] = (i16)j;
|
|
@@ -112825,6 +121714,7 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
|
|
zColl = 0;
|
|
if( pListItem->pExpr->op==TK_COLLATE ){
|
|
int nColl;
|
|
+ assert( !ExprHasProperty(pListItem->pExpr, EP_IntValue) );
|
|
zColl = pListItem->pExpr->u.zToken;
|
|
nColl = sqlite3Strlen30(zColl) + 1;
|
|
assert( nExtra>=nColl );
|
|
@@ -112833,14 +121723,14 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
|
|
zExtra += nColl;
|
|
nExtra -= nColl;
|
|
}else if( j>=0 ){
|
|
- zColl = pTab->aCol[j].zColl;
|
|
+ zColl = sqlite3ColumnColl(&pTab->aCol[j]);
|
|
}
|
|
if( !zColl ) zColl = sqlite3StrBINARY;
|
|
if( !db->init.busy && !sqlite3LocateCollSeq(pParse, zColl) ){
|
|
goto exit_create_index;
|
|
}
|
|
pIndex->azColl[i] = zColl;
|
|
- requestedSortOrder = pListItem->sortFlags & sortOrderMask;
|
|
+ requestedSortOrder = pListItem->fg.sortFlags & sortOrderMask;
|
|
pIndex->aSortOrder[i] = (u8)requestedSortOrder;
|
|
}
|
|
|
|
@@ -112853,7 +121743,7 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
|
|
int x = pPk->aiColumn[j];
|
|
assert( x>=0 );
|
|
if( isDupColumn(pIndex, pIndex->nKeyCol, pPk, j) ){
|
|
- pIndex->nColumn--;
|
|
+ pIndex->nColumn--;
|
|
}else{
|
|
testcase( hasColumn(pIndex->aiColumn,pIndex->nKeyCol,x) );
|
|
pIndex->aiColumn[i] = x;
|
|
@@ -112872,7 +121762,7 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
|
|
|
|
/* If this index contains every column of its table, then mark
|
|
** it as a covering index */
|
|
- assert( HasRowid(pTab)
|
|
+ assert( HasRowid(pTab)
|
|
|| pTab->iPKey<0 || sqlite3TableColumnToIndex(pIndex, pTab->iPKey)>=0 );
|
|
recomputeColumnsNotIndexed(pIndex);
|
|
if( pTblName!=0 && pIndex->nColumn>=pTab->nCol ){
|
|
@@ -112928,13 +121818,13 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
|
|
if( pIdx->onError!=pIndex->onError ){
|
|
/* This constraint creates the same index as a previous
|
|
** constraint specified somewhere in the CREATE TABLE statement.
|
|
- ** However the ON CONFLICT clauses are different. If both this
|
|
+ ** However the ON CONFLICT clauses are different. If both this
|
|
** constraint and the previous equivalent constraint have explicit
|
|
** ON CONFLICT clauses this is an error. Otherwise, use the
|
|
** explicitly specified behavior for the index.
|
|
*/
|
|
if( !(pIdx->onError==OE_Default || pIndex->onError==OE_Default) ){
|
|
- sqlite3ErrorMsg(pParse,
|
|
+ sqlite3ErrorMsg(pParse,
|
|
"conflicting ON CONFLICT clauses specified", 0);
|
|
}
|
|
if( pIdx->onError==OE_Default ){
|
|
@@ -112955,7 +121845,7 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
|
|
if( !IN_RENAME_OBJECT ){
|
|
|
|
/* Link the new Index structure to its table and to the other
|
|
- ** in-memory database structures.
|
|
+ ** in-memory database structures.
|
|
*/
|
|
assert( pParse->nErr==0 );
|
|
if( db->init.busy ){
|
|
@@ -112970,7 +121860,7 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
|
|
goto exit_create_index;
|
|
}
|
|
}
|
|
- p = sqlite3HashInsert(&pIndex->pSchema->idxHash,
|
|
+ p = sqlite3HashInsert(&pIndex->pSchema->idxHash,
|
|
pIndex->zName, pIndex);
|
|
if( p ){
|
|
assert( p==pIndex ); /* Malloc must have failed */
|
|
@@ -112983,8 +121873,8 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
|
|
/* If this is the initial CREATE INDEX statement (or CREATE TABLE if the
|
|
** index is an implied index for a UNIQUE or PRIMARY KEY constraint) then
|
|
** emit code to allocate the index rootpage on disk and make an entry for
|
|
- ** the index in the sqlite_master table and populate the index with
|
|
- ** content. But, do not do this if we are simply reading the sqlite_master
|
|
+ ** the index in the sqlite_schema table and populate the index with
|
|
+ ** content. But, do not do this if we are simply reading the sqlite_schema
|
|
** table to parse the schema, or if this index is the PRIMARY KEY index
|
|
** of a WITHOUT ROWID table.
|
|
**
|
|
@@ -113004,12 +121894,12 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
|
|
sqlite3BeginWriteOperation(pParse, 1, iDb);
|
|
|
|
/* Create the rootpage for the index using CreateIndex. But before
|
|
- ** doing so, code a Noop instruction and store its address in
|
|
- ** Index.tnum. This is required in case this index is actually a
|
|
- ** PRIMARY KEY and the table is actually a WITHOUT ROWID table. In
|
|
+ ** doing so, code a Noop instruction and store its address in
|
|
+ ** Index.tnum. This is required in case this index is actually a
|
|
+ ** PRIMARY KEY and the table is actually a WITHOUT ROWID table. In
|
|
** that case the convertToWithoutRowidTable() routine will replace
|
|
** the Noop with a Goto to jump over the VDBE code generated below. */
|
|
- pIndex->tnum = sqlite3VdbeAddOp0(v, OP_Noop);
|
|
+ pIndex->tnum = (Pgno)sqlite3VdbeAddOp0(v, OP_Noop);
|
|
sqlite3VdbeAddOp3(v, OP_CreateBtree, iDb, iMem, BTREE_BLOBKEY);
|
|
|
|
/* Gather the complete text of the CREATE INDEX statement into
|
|
@@ -113028,16 +121918,16 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
|
|
zStmt = 0;
|
|
}
|
|
|
|
- /* Add an entry in sqlite_master for this index
|
|
+ /* Add an entry in sqlite_schema for this index
|
|
*/
|
|
- sqlite3NestedParse(pParse,
|
|
- "INSERT INTO %Q.%s VALUES('index',%Q,%Q,#%d,%Q);",
|
|
- db->aDb[iDb].zDbSName, MASTER_NAME,
|
|
- pIndex->zName,
|
|
- pTab->zName,
|
|
- iMem,
|
|
- zStmt
|
|
- );
|
|
+ sqlite3NestedParse(pParse,
|
|
+ "INSERT INTO %Q." LEGACY_SCHEMA_TABLE " VALUES('index',%Q,%Q,#%d,%Q);",
|
|
+ db->aDb[iDb].zDbSName,
|
|
+ pIndex->zName,
|
|
+ pTab->zName,
|
|
+ iMem,
|
|
+ zStmt
|
|
+ );
|
|
sqlite3DbFree(db, zStmt);
|
|
|
|
/* Fill the index with data and reparse the schema. Code an OP_Expire
|
|
@@ -113047,11 +121937,11 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
|
|
sqlite3RefillIndex(pParse, pIndex, iMem);
|
|
sqlite3ChangeCookie(pParse, iDb);
|
|
sqlite3VdbeAddParseSchemaOp(v, iDb,
|
|
- sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName));
|
|
+ sqlite3MPrintf(db, "name='%q' AND type='index'", pIndex->zName), 0);
|
|
sqlite3VdbeAddOp2(v, OP_Expire, 0, 1);
|
|
}
|
|
|
|
- sqlite3VdbeJumpHere(v, pIndex->tnum);
|
|
+ sqlite3VdbeJumpHere(v, (int)pIndex->tnum);
|
|
}
|
|
}
|
|
if( db->init.busy || pTblName==0 ){
|
|
@@ -113068,8 +121958,12 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
|
|
/* Clean up before exiting */
|
|
exit_create_index:
|
|
if( pIndex ) sqlite3FreeIndex(db, pIndex);
|
|
- if( pTab ){ /* Ensure all REPLACE indexes are at the end of the list */
|
|
- Index **ppFrom = &pTab->pIndex;
|
|
+ if( pTab ){
|
|
+ /* Ensure all REPLACE indexes on pTab are at the end of the pIndex list.
|
|
+ ** The list was already ordered when this routine was entered, so at this
|
|
+ ** point at most a single index (the newly added index) will be out of
|
|
+ ** order. So we have to reorder at most one index. */
|
|
+ Index **ppFrom;
|
|
Index *pThis;
|
|
for(ppFrom=&pTab->pIndex; (pThis = *ppFrom)!=0; ppFrom=&pThis->pNext){
|
|
Index *pNext;
|
|
@@ -113082,6 +121976,16 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
|
|
}
|
|
break;
|
|
}
|
|
+#ifdef SQLITE_DEBUG
|
|
+ /* Verify that all REPLACE indexes really are now at the end
|
|
+ ** of the index list. In other words, no other index type ever
|
|
+ ** comes after a REPLACE index on the list. */
|
|
+ for(pThis = pTab->pIndex; pThis; pThis=pThis->pNext){
|
|
+ assert( pThis->onError!=OE_Replace
|
|
+ || pThis->pNext==0
|
|
+ || pThis->pNext->onError==OE_Replace );
|
|
+ }
|
|
+#endif
|
|
}
|
|
sqlite3ExprDelete(db, pPIWhere);
|
|
sqlite3ExprListDelete(db, pList);
|
|
@@ -113108,21 +122012,33 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
|
|
** are based on typical values found in actual indices.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3DefaultRowEst(Index *pIdx){
|
|
- /* 10, 9, 8, 7, 6 */
|
|
- LogEst aVal[] = { 33, 32, 30, 28, 26 };
|
|
+ /* 10, 9, 8, 7, 6 */
|
|
+ static const LogEst aVal[] = { 33, 32, 30, 28, 26 };
|
|
LogEst *a = pIdx->aiRowLogEst;
|
|
+ LogEst x;
|
|
int nCopy = MIN(ArraySize(aVal), pIdx->nKeyCol);
|
|
int i;
|
|
|
|
/* Indexes with default row estimates should not have stat1 data */
|
|
assert( !pIdx->hasStat1 );
|
|
|
|
- /* Set the first entry (number of rows in the index) to the estimated
|
|
+ /* Set the first entry (number of rows in the index) to the estimated
|
|
** number of rows in the table, or half the number of rows in the table
|
|
- ** for a partial index. But do not let the estimate drop below 10. */
|
|
- a[0] = pIdx->pTable->nRowLogEst;
|
|
- if( pIdx->pPartIdxWhere!=0 ) a[0] -= 10; assert( 10==sqlite3LogEst(2) );
|
|
- if( a[0]<33 ) a[0] = 33; assert( 33==sqlite3LogEst(10) );
|
|
+ ** for a partial index.
|
|
+ **
|
|
+ ** 2020-05-27: If some of the stat data is coming from the sqlite_stat1
|
|
+ ** table but other parts we are having to guess at, then do not let the
|
|
+ ** estimated number of rows in the table be less than 1000 (LogEst 99).
|
|
+ ** Failure to do this can cause the indexes for which we do not have
|
|
+ ** stat1 data to be ignored by the query planner.
|
|
+ */
|
|
+ x = pIdx->pTable->nRowLogEst;
|
|
+ assert( 99==sqlite3LogEst(1000) );
|
|
+ if( x<99 ){
|
|
+ pIdx->pTable->nRowLogEst = x = 99;
|
|
+ }
|
|
+ if( pIdx->pPartIdxWhere!=0 ){ x -= 10; assert( 10==sqlite3LogEst(2) ); }
|
|
+ a[0] = x;
|
|
|
|
/* Estimate that a[1] is 10, a[2] is 9, a[3] is 8, a[4] is 7, a[5] is
|
|
** 6 and each subsequent value (if any) is 5. */
|
|
@@ -113145,10 +122061,10 @@ SQLITE_PRIVATE void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists
|
|
sqlite3 *db = pParse->db;
|
|
int iDb;
|
|
|
|
- assert( pParse->nErr==0 ); /* Never called with prior errors */
|
|
if( db->mallocFailed ){
|
|
goto exit_drop_index;
|
|
}
|
|
+ assert( pParse->nErr==0 ); /* Never called with prior non-OOM errors */
|
|
assert( pName->nSrc==1 );
|
|
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){
|
|
goto exit_drop_index;
|
|
@@ -113156,9 +122072,10 @@ SQLITE_PRIVATE void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists
|
|
pIndex = sqlite3FindIndex(db, pName->a[0].zName, pName->a[0].zDatabase);
|
|
if( pIndex==0 ){
|
|
if( !ifExists ){
|
|
- sqlite3ErrorMsg(pParse, "no such index: %S", pName, 0);
|
|
+ sqlite3ErrorMsg(pParse, "no such index: %S", pName->a);
|
|
}else{
|
|
sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase);
|
|
+ sqlite3ForceNotReadOnly(pParse);
|
|
}
|
|
pParse->checkSchema = 1;
|
|
goto exit_drop_index;
|
|
@@ -113178,20 +122095,20 @@ SQLITE_PRIVATE void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists
|
|
if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){
|
|
goto exit_drop_index;
|
|
}
|
|
- if( !OMIT_TEMPDB && iDb ) code = SQLITE_DROP_TEMP_INDEX;
|
|
+ if( !OMIT_TEMPDB && iDb==1 ) code = SQLITE_DROP_TEMP_INDEX;
|
|
if( sqlite3AuthCheck(pParse, code, pIndex->zName, pTab->zName, zDb) ){
|
|
goto exit_drop_index;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
- /* Generate code to remove the index and from the master table */
|
|
+ /* Generate code to remove the index and from the schema table */
|
|
v = sqlite3GetVdbe(pParse);
|
|
if( v ){
|
|
sqlite3BeginWriteOperation(pParse, 1, iDb);
|
|
sqlite3NestedParse(pParse,
|
|
- "DELETE FROM %Q.%s WHERE name=%Q AND type='index'",
|
|
- db->aDb[iDb].zDbSName, MASTER_NAME, pIndex->zName
|
|
+ "DELETE FROM %Q." LEGACY_SCHEMA_TABLE " WHERE name=%Q AND type='index'",
|
|
+ db->aDb[iDb].zDbSName, pIndex->zName
|
|
);
|
|
sqlite3ClearStatTables(pParse, iDb, "idx", pIndex->zName);
|
|
sqlite3ChangeCookie(pParse, iDb);
|
|
@@ -113256,18 +122173,17 @@ SQLITE_PRIVATE IdList *sqlite3IdListAppend(Parse *pParse, IdList *pList, Token *
|
|
if( pList==0 ){
|
|
pList = sqlite3DbMallocZero(db, sizeof(IdList) );
|
|
if( pList==0 ) return 0;
|
|
+ }else{
|
|
+ IdList *pNew;
|
|
+ pNew = sqlite3DbRealloc(db, pList,
|
|
+ sizeof(IdList) + pList->nId*sizeof(pList->a));
|
|
+ if( pNew==0 ){
|
|
+ sqlite3IdListDelete(db, pList);
|
|
+ return 0;
|
|
+ }
|
|
+ pList = pNew;
|
|
}
|
|
- pList->a = sqlite3ArrayAllocate(
|
|
- db,
|
|
- pList->a,
|
|
- sizeof(pList->a[0]),
|
|
- &pList->nId,
|
|
- &i
|
|
- );
|
|
- if( i<0 ){
|
|
- sqlite3IdListDelete(db, pList);
|
|
- return 0;
|
|
- }
|
|
+ i = pList->nId++;
|
|
pList->a[i].zName = sqlite3NameFromToken(db, pToken);
|
|
if( IN_RENAME_OBJECT && pList->a[i].zName ){
|
|
sqlite3RenameTokenMap(pParse, (void*)pList->a[i].zName, pToken);
|
|
@@ -113280,12 +122196,13 @@ SQLITE_PRIVATE IdList *sqlite3IdListAppend(Parse *pParse, IdList *pList, Token *
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3IdListDelete(sqlite3 *db, IdList *pList){
|
|
int i;
|
|
+ assert( db!=0 );
|
|
if( pList==0 ) return;
|
|
+ assert( pList->eU4!=EU4_EXPR ); /* EU4_EXPR mode is not currently used */
|
|
for(i=0; i<pList->nId; i++){
|
|
sqlite3DbFree(db, pList->a[i].zName);
|
|
}
|
|
- sqlite3DbFree(db, pList->a);
|
|
- sqlite3DbFreeNN(db, pList);
|
|
+ sqlite3DbNNFreeNN(db, pList);
|
|
}
|
|
|
|
/*
|
|
@@ -113294,7 +122211,7 @@ SQLITE_PRIVATE void sqlite3IdListDelete(sqlite3 *db, IdList *pList){
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3IdListIndex(IdList *pList, const char *zName){
|
|
int i;
|
|
- if( pList==0 ) return -1;
|
|
+ assert( pList!=0 );
|
|
for(i=0; i<pList->nId; i++){
|
|
if( sqlite3StrICmp(pList->a[i].zName, zName)==0 ) return i;
|
|
}
|
|
@@ -113401,7 +122318,7 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge(
|
|
** database name prefix. Like this: "database.table". The pDatabase
|
|
** points to the table name and the pTable points to the database name.
|
|
** The SrcList.a[].zName field is filled with the table name which might
|
|
-** come from pTable (if pDatabase is NULL) or from pDatabase.
|
|
+** come from pTable (if pDatabase is NULL) or from pDatabase.
|
|
** SrcList.a[].zDatabase is filled with the database name from pTable,
|
|
** or with NULL if no database is specified.
|
|
**
|
|
@@ -113428,7 +122345,7 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListAppend(
|
|
Token *pTable, /* Table to append */
|
|
Token *pDatabase /* Database of the table */
|
|
){
|
|
- struct SrcList_item *pItem;
|
|
+ SrcItem *pItem;
|
|
sqlite3 *db;
|
|
assert( pDatabase==0 || pTable!=0 ); /* Cannot have C without B */
|
|
assert( pParse!=0 );
|
|
@@ -113469,11 +122386,11 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListAppend(
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3SrcListAssignCursors(Parse *pParse, SrcList *pList){
|
|
int i;
|
|
- struct SrcList_item *pItem;
|
|
- assert(pList || pParse->db->mallocFailed );
|
|
- if( pList ){
|
|
+ SrcItem *pItem;
|
|
+ assert( pList || pParse->db->mallocFailed );
|
|
+ if( ALWAYS(pList) ){
|
|
for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
|
|
- if( pItem->iCursor>=0 ) break;
|
|
+ if( pItem->iCursor>=0 ) continue;
|
|
pItem->iCursor = pParse->nTab++;
|
|
if( pItem->pSelect ){
|
|
sqlite3SrcListAssignCursors(pParse, pItem->pSelect->pSrc);
|
|
@@ -113487,20 +122404,24 @@ SQLITE_PRIVATE void sqlite3SrcListAssignCursors(Parse *pParse, SrcList *pList){
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){
|
|
int i;
|
|
- struct SrcList_item *pItem;
|
|
+ SrcItem *pItem;
|
|
+ assert( db!=0 );
|
|
if( pList==0 ) return;
|
|
for(pItem=pList->a, i=0; i<pList->nSrc; i++, pItem++){
|
|
- sqlite3DbFree(db, pItem->zDatabase);
|
|
- sqlite3DbFree(db, pItem->zName);
|
|
- sqlite3DbFree(db, pItem->zAlias);
|
|
+ if( pItem->zDatabase ) sqlite3DbNNFreeNN(db, pItem->zDatabase);
|
|
+ if( pItem->zName ) sqlite3DbNNFreeNN(db, pItem->zName);
|
|
+ if( pItem->zAlias ) sqlite3DbNNFreeNN(db, pItem->zAlias);
|
|
if( pItem->fg.isIndexedBy ) sqlite3DbFree(db, pItem->u1.zIndexedBy);
|
|
if( pItem->fg.isTabFunc ) sqlite3ExprListDelete(db, pItem->u1.pFuncArg);
|
|
sqlite3DeleteTable(db, pItem->pTab);
|
|
- sqlite3SelectDelete(db, pItem->pSelect);
|
|
- sqlite3ExprDelete(db, pItem->pOn);
|
|
- sqlite3IdListDelete(db, pItem->pUsing);
|
|
+ if( pItem->pSelect ) sqlite3SelectDelete(db, pItem->pSelect);
|
|
+ if( pItem->fg.isUsing ){
|
|
+ sqlite3IdListDelete(db, pItem->u3.pUsing);
|
|
+ }else if( pItem->u3.pOn ){
|
|
+ sqlite3ExprDelete(db, pItem->u3.pOn);
|
|
+ }
|
|
}
|
|
- sqlite3DbFreeNN(db, pList);
|
|
+ sqlite3DbNNFreeNN(db, pList);
|
|
}
|
|
|
|
/*
|
|
@@ -113526,14 +122447,13 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListAppendFromTerm(
|
|
Token *pDatabase, /* Name of the database containing pTable */
|
|
Token *pAlias, /* The right-hand side of the AS subexpression */
|
|
Select *pSubquery, /* A subquery used in place of a table name */
|
|
- Expr *pOn, /* The ON clause of a join */
|
|
- IdList *pUsing /* The USING clause of a join */
|
|
+ OnOrUsing *pOnUsing /* Either the ON clause or the USING clause */
|
|
){
|
|
- struct SrcList_item *pItem;
|
|
+ SrcItem *pItem;
|
|
sqlite3 *db = pParse->db;
|
|
- if( !p && (pOn || pUsing) ){
|
|
- sqlite3ErrorMsg(pParse, "a JOIN clause is required before %s",
|
|
- (pOn ? "ON" : "USING")
|
|
+ if( !p && pOnUsing!=0 && (pOnUsing->pOn || pOnUsing->pUsing) ){
|
|
+ sqlite3ErrorMsg(pParse, "a JOIN clause is required before %s",
|
|
+ (pOnUsing->pOn ? "ON" : "USING")
|
|
);
|
|
goto append_from_error;
|
|
}
|
|
@@ -113553,50 +122473,84 @@ SQLITE_PRIVATE SrcList *sqlite3SrcListAppendFromTerm(
|
|
if( pAlias->n ){
|
|
pItem->zAlias = sqlite3NameFromToken(db, pAlias);
|
|
}
|
|
- pItem->pSelect = pSubquery;
|
|
- pItem->pOn = pOn;
|
|
- pItem->pUsing = pUsing;
|
|
+ if( pSubquery ){
|
|
+ pItem->pSelect = pSubquery;
|
|
+ if( pSubquery->selFlags & SF_NestedFrom ){
|
|
+ pItem->fg.isNestedFrom = 1;
|
|
+ }
|
|
+ }
|
|
+ assert( pOnUsing==0 || pOnUsing->pOn==0 || pOnUsing->pUsing==0 );
|
|
+ assert( pItem->fg.isUsing==0 );
|
|
+ if( pOnUsing==0 ){
|
|
+ pItem->u3.pOn = 0;
|
|
+ }else if( pOnUsing->pUsing ){
|
|
+ pItem->fg.isUsing = 1;
|
|
+ pItem->u3.pUsing = pOnUsing->pUsing;
|
|
+ }else{
|
|
+ pItem->u3.pOn = pOnUsing->pOn;
|
|
+ }
|
|
return p;
|
|
|
|
- append_from_error:
|
|
+append_from_error:
|
|
assert( p==0 );
|
|
- sqlite3ExprDelete(db, pOn);
|
|
- sqlite3IdListDelete(db, pUsing);
|
|
+ sqlite3ClearOnOrUsing(db, pOnUsing);
|
|
sqlite3SelectDelete(db, pSubquery);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
-** Add an INDEXED BY or NOT INDEXED clause to the most recently added
|
|
+** Add an INDEXED BY or NOT INDEXED clause to the most recently added
|
|
** element of the source-list passed as the second argument.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3SrcListIndexedBy(Parse *pParse, SrcList *p, Token *pIndexedBy){
|
|
assert( pIndexedBy!=0 );
|
|
if( p && pIndexedBy->n>0 ){
|
|
- struct SrcList_item *pItem;
|
|
+ SrcItem *pItem;
|
|
assert( p->nSrc>0 );
|
|
pItem = &p->a[p->nSrc-1];
|
|
assert( pItem->fg.notIndexed==0 );
|
|
assert( pItem->fg.isIndexedBy==0 );
|
|
assert( pItem->fg.isTabFunc==0 );
|
|
if( pIndexedBy->n==1 && !pIndexedBy->z ){
|
|
- /* A "NOT INDEXED" clause was supplied. See parse.y
|
|
+ /* A "NOT INDEXED" clause was supplied. See parse.y
|
|
** construct "indexed_opt" for details. */
|
|
pItem->fg.notIndexed = 1;
|
|
}else{
|
|
pItem->u1.zIndexedBy = sqlite3NameFromToken(pParse->db, pIndexedBy);
|
|
pItem->fg.isIndexedBy = 1;
|
|
+ assert( pItem->fg.isCte==0 ); /* No collision on union u2 */
|
|
}
|
|
}
|
|
}
|
|
|
|
+/*
|
|
+** Append the contents of SrcList p2 to SrcList p1 and return the resulting
|
|
+** SrcList. Or, if an error occurs, return NULL. In all cases, p1 and p2
|
|
+** are deleted by this function.
|
|
+*/
|
|
+SQLITE_PRIVATE SrcList *sqlite3SrcListAppendList(Parse *pParse, SrcList *p1, SrcList *p2){
|
|
+ assert( p1 && p1->nSrc==1 );
|
|
+ if( p2 ){
|
|
+ SrcList *pNew = sqlite3SrcListEnlarge(pParse, p1, p2->nSrc, 1);
|
|
+ if( pNew==0 ){
|
|
+ sqlite3SrcListDelete(pParse->db, p2);
|
|
+ }else{
|
|
+ p1 = pNew;
|
|
+ memcpy(&p1->a[1], p2->a, p2->nSrc*sizeof(SrcItem));
|
|
+ sqlite3DbFree(pParse->db, p2);
|
|
+ p1->a[0].fg.jointype |= (JT_LTORJ & p1->a[1].fg.jointype);
|
|
+ }
|
|
+ }
|
|
+ return p1;
|
|
+}
|
|
+
|
|
/*
|
|
** Add the list of function arguments to the SrcList entry for a
|
|
** table-valued-function.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3SrcListFuncArgs(Parse *pParse, SrcList *p, ExprList *pList){
|
|
if( p ){
|
|
- struct SrcList_item *pItem = &p->a[p->nSrc-1];
|
|
+ SrcItem *pItem = &p->a[p->nSrc-1];
|
|
assert( pItem->fg.notIndexed==0 );
|
|
assert( pItem->fg.isIndexedBy==0 );
|
|
assert( pItem->fg.isTabFunc==0 );
|
|
@@ -113621,14 +122575,34 @@ SQLITE_PRIVATE void sqlite3SrcListFuncArgs(Parse *pParse, SrcList *p, ExprList *
|
|
** The operator is "natural cross join". The A and B operands are stored
|
|
** in p->a[0] and p->a[1], respectively. The parser initially stores the
|
|
** operator with A. This routine shifts that operator over to B.
|
|
+**
|
|
+** Additional changes:
|
|
+**
|
|
+** * All tables to the left of the right-most RIGHT JOIN are tagged with
|
|
+** JT_LTORJ (mnemonic: Left Table Of Right Join) so that the
|
|
+** code generator can easily tell that the table is part of
|
|
+** the left operand of at least one RIGHT JOIN.
|
|
*/
|
|
-SQLITE_PRIVATE void sqlite3SrcListShiftJoinType(SrcList *p){
|
|
- if( p ){
|
|
- int i;
|
|
- for(i=p->nSrc-1; i>0; i--){
|
|
- p->a[i].fg.jointype = p->a[i-1].fg.jointype;
|
|
- }
|
|
+SQLITE_PRIVATE void sqlite3SrcListShiftJoinType(Parse *pParse, SrcList *p){
|
|
+ (void)pParse;
|
|
+ if( p && p->nSrc>1 ){
|
|
+ int i = p->nSrc-1;
|
|
+ u8 allFlags = 0;
|
|
+ do{
|
|
+ allFlags |= p->a[i].fg.jointype = p->a[i-1].fg.jointype;
|
|
+ }while( (--i)>0 );
|
|
p->a[0].fg.jointype = 0;
|
|
+
|
|
+ /* All terms to the left of a RIGHT JOIN should be tagged with the
|
|
+ ** JT_LTORJ flags */
|
|
+ if( allFlags & JT_RIGHT ){
|
|
+ for(i=p->nSrc-1; ALWAYS(i>0) && (p->a[i].fg.jointype&JT_RIGHT)==0; i--){}
|
|
+ i--;
|
|
+ assert( i>=0 );
|
|
+ do{
|
|
+ p->a[i].fg.jointype |= JT_LTORJ;
|
|
+ }while( (--i)>=0 );
|
|
+ }
|
|
}
|
|
}
|
|
|
|
@@ -113650,7 +122624,16 @@ SQLITE_PRIVATE void sqlite3BeginTransaction(Parse *pParse, int type){
|
|
if( !v ) return;
|
|
if( type!=TK_DEFERRED ){
|
|
for(i=0; i<db->nDb; i++){
|
|
- sqlite3VdbeAddOp2(v, OP_Transaction, i, (type==TK_EXCLUSIVE)+1);
|
|
+ int eTxnType;
|
|
+ Btree *pBt = db->aDb[i].pBt;
|
|
+ if( pBt && sqlite3BtreeIsReadonly(pBt) ){
|
|
+ eTxnType = 0; /* Read txn */
|
|
+ }else if( type==TK_EXCLUSIVE ){
|
|
+ eTxnType = 2; /* Exclusive txn */
|
|
+ }else{
|
|
+ eTxnType = 1; /* Write txn */
|
|
+ }
|
|
+ sqlite3VdbeAddOp2(v, OP_Transaction, i, eTxnType);
|
|
sqlite3VdbeUsesBtree(v, i);
|
|
}
|
|
}
|
|
@@ -113670,7 +122653,7 @@ SQLITE_PRIVATE void sqlite3EndTransaction(Parse *pParse, int eType){
|
|
assert( pParse->db!=0 );
|
|
assert( eType==TK_COMMIT || eType==TK_END || eType==TK_ROLLBACK );
|
|
isRollback = eType==TK_ROLLBACK;
|
|
- if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION,
|
|
+ if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION,
|
|
isRollback ? "ROLLBACK" : "COMMIT", 0, 0) ){
|
|
return;
|
|
}
|
|
@@ -113682,7 +122665,7 @@ SQLITE_PRIVATE void sqlite3EndTransaction(Parse *pParse, int eType){
|
|
|
|
/*
|
|
** This function is called by the parser when it parses a command to create,
|
|
-** release or rollback an SQL savepoint.
|
|
+** release or rollback an SQL savepoint.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3Savepoint(Parse *pParse, int op, Token *pName){
|
|
char *zName = sqlite3NameFromToken(pParse->db, pName);
|
|
@@ -113709,7 +122692,7 @@ SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *pParse){
|
|
if( db->aDb[1].pBt==0 && !pParse->explain ){
|
|
int rc;
|
|
Btree *pBt;
|
|
- static const int flags =
|
|
+ static const int flags =
|
|
SQLITE_OPEN_READWRITE |
|
|
SQLITE_OPEN_CREATE |
|
|
SQLITE_OPEN_EXCLUSIVE |
|
|
@@ -113725,7 +122708,7 @@ SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *pParse){
|
|
}
|
|
db->aDb[1].pBt = pBt;
|
|
assert( db->aDb[1].pSchema );
|
|
- if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize, -1, 0) ){
|
|
+ if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize, 0, 0) ){
|
|
sqlite3OomFault(db);
|
|
return 1;
|
|
}
|
|
@@ -113739,13 +122722,11 @@ SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *pParse){
|
|
** will occur at the end of the top-level VDBE and will be generated
|
|
** later, by sqlite3FinishCoding().
|
|
*/
|
|
-SQLITE_PRIVATE void sqlite3CodeVerifySchema(Parse *pParse, int iDb){
|
|
- Parse *pToplevel = sqlite3ParseToplevel(pParse);
|
|
-
|
|
- assert( iDb>=0 && iDb<pParse->db->nDb );
|
|
- assert( pParse->db->aDb[iDb].pBt!=0 || iDb==1 );
|
|
- assert( iDb<SQLITE_MAX_ATTACHED+2 );
|
|
- assert( sqlite3SchemaMutexHeld(pParse->db, iDb, 0) );
|
|
+static void sqlite3CodeVerifySchemaAtToplevel(Parse *pToplevel, int iDb){
|
|
+ assert( iDb>=0 && iDb<pToplevel->db->nDb );
|
|
+ assert( pToplevel->db->aDb[iDb].pBt!=0 || iDb==1 );
|
|
+ assert( iDb<SQLITE_MAX_DB );
|
|
+ assert( sqlite3SchemaMutexHeld(pToplevel->db, iDb, 0) );
|
|
if( DbMaskTest(pToplevel->cookieMask, iDb)==0 ){
|
|
DbMaskSet(pToplevel->cookieMask, iDb);
|
|
if( !OMIT_TEMPDB && iDb==1 ){
|
|
@@ -113753,9 +122734,13 @@ SQLITE_PRIVATE void sqlite3CodeVerifySchema(Parse *pParse, int iDb){
|
|
}
|
|
}
|
|
}
|
|
+SQLITE_PRIVATE void sqlite3CodeVerifySchema(Parse *pParse, int iDb){
|
|
+ sqlite3CodeVerifySchemaAtToplevel(sqlite3ParseToplevel(pParse), iDb);
|
|
+}
|
|
+
|
|
|
|
/*
|
|
-** If argument zDb is NULL, then call sqlite3CodeVerifySchema() for each
|
|
+** If argument zDb is NULL, then call sqlite3CodeVerifySchema() for each
|
|
** attached database. Otherwise, invoke it for the database named zDb only.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3CodeVerifyNamedSchema(Parse *pParse, const char *zDb){
|
|
@@ -113784,7 +122769,7 @@ SQLITE_PRIVATE void sqlite3CodeVerifyNamedSchema(Parse *pParse, const char *zDb)
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3BeginWriteOperation(Parse *pParse, int setStatement, int iDb){
|
|
Parse *pToplevel = sqlite3ParseToplevel(pParse);
|
|
- sqlite3CodeVerifySchema(pParse, iDb);
|
|
+ sqlite3CodeVerifySchemaAtToplevel(pToplevel, iDb);
|
|
DbMaskSet(pToplevel->writeMask, iDb);
|
|
pToplevel->isMultiWrite |= setStatement;
|
|
}
|
|
@@ -113801,9 +122786,9 @@ SQLITE_PRIVATE void sqlite3MultiWrite(Parse *pParse){
|
|
pToplevel->isMultiWrite = 1;
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** The code generator calls this routine if is discovers that it is
|
|
-** possible to abort a statement prior to completion. In order to
|
|
+** possible to abort a statement prior to completion. In order to
|
|
** perform this abort without corrupting the database, we need to make
|
|
** sure that the statement is protected by a statement transaction.
|
|
**
|
|
@@ -113812,7 +122797,7 @@ SQLITE_PRIVATE void sqlite3MultiWrite(Parse *pParse){
|
|
** such that the abort must occur after the multiwrite. This makes
|
|
** some statements involving the REPLACE conflict resolution algorithm
|
|
** go a little faster. But taking advantage of this time dependency
|
|
-** makes it more difficult to prove that the code is correct (in
|
|
+** makes it more difficult to prove that the code is correct (in
|
|
** particular, it prevents us from writing an effective
|
|
** implementation of sqlite3AssertMayAbort()) and so we have chosen
|
|
** to take the safe route and skip the optimization.
|
|
@@ -113835,8 +122820,10 @@ SQLITE_PRIVATE void sqlite3HaltConstraint(
|
|
i8 p4type, /* P4_STATIC or P4_TRANSIENT */
|
|
u8 p5Errmsg /* P5_ErrMsg type */
|
|
){
|
|
- Vdbe *v = sqlite3GetVdbe(pParse);
|
|
- assert( (errCode&0xff)==SQLITE_CONSTRAINT );
|
|
+ Vdbe *v;
|
|
+ assert( pParse->pVdbe!=0 );
|
|
+ v = sqlite3GetVdbe(pParse);
|
|
+ assert( (errCode&0xff)==SQLITE_CONSTRAINT || pParse->nested );
|
|
if( onError==OE_Abort ){
|
|
sqlite3MayAbort(pParse);
|
|
}
|
|
@@ -113857,7 +122844,7 @@ SQLITE_PRIVATE void sqlite3UniqueConstraint(
|
|
StrAccum errMsg;
|
|
Table *pTab = pIdx->pTable;
|
|
|
|
- sqlite3StrAccumInit(&errMsg, pParse->db, 0, 0,
|
|
+ sqlite3StrAccumInit(&errMsg, pParse->db, 0, 0,
|
|
pParse->db->aLimit[SQLITE_LIMIT_LENGTH]);
|
|
if( pIdx->aColExpr ){
|
|
sqlite3_str_appendf(&errMsg, "index '%q'", pIdx->zName);
|
|
@@ -113865,7 +122852,7 @@ SQLITE_PRIVATE void sqlite3UniqueConstraint(
|
|
for(j=0; j<pIdx->nKeyCol; j++){
|
|
char *zCol;
|
|
assert( pIdx->aiColumn[j]>=0 );
|
|
- zCol = pTab->aCol[pIdx->aiColumn[j]].zName;
|
|
+ zCol = pTab->aCol[pIdx->aiColumn[j]].zCnName;
|
|
if( j ) sqlite3_str_append(&errMsg, ", ", 2);
|
|
sqlite3_str_appendall(&errMsg, pTab->zName);
|
|
sqlite3_str_append(&errMsg, ".", 1);
|
|
@@ -113873,8 +122860,8 @@ SQLITE_PRIVATE void sqlite3UniqueConstraint(
|
|
}
|
|
}
|
|
zErr = sqlite3StrAccumFinish(&errMsg);
|
|
- sqlite3HaltConstraint(pParse,
|
|
- IsPrimaryKeyIndex(pIdx) ? SQLITE_CONSTRAINT_PRIMARYKEY
|
|
+ sqlite3HaltConstraint(pParse,
|
|
+ IsPrimaryKeyIndex(pIdx) ? SQLITE_CONSTRAINT_PRIMARYKEY
|
|
: SQLITE_CONSTRAINT_UNIQUE,
|
|
onError, zErr, P4_DYNAMIC, P5_ConstraintUnique);
|
|
}
|
|
@@ -113886,13 +122873,13 @@ SQLITE_PRIVATE void sqlite3UniqueConstraint(
|
|
SQLITE_PRIVATE void sqlite3RowidConstraint(
|
|
Parse *pParse, /* Parsing context */
|
|
int onError, /* Conflict resolution algorithm */
|
|
- Table *pTab /* The table with the non-unique rowid */
|
|
+ Table *pTab /* The table with the non-unique rowid */
|
|
){
|
|
char *zMsg;
|
|
int rc;
|
|
if( pTab->iPKey>=0 ){
|
|
zMsg = sqlite3MPrintf(pParse->db, "%s.%s", pTab->zName,
|
|
- pTab->aCol[pTab->iPKey].zName);
|
|
+ pTab->aCol[pTab->iPKey].zCnName);
|
|
rc = SQLITE_CONSTRAINT_PRIMARYKEY;
|
|
}else{
|
|
zMsg = sqlite3MPrintf(pParse->db, "%s.rowid", pTab->zName);
|
|
@@ -114080,24 +123067,76 @@ SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoOfIndex(Parse *pParse, Index *pIdx){
|
|
}
|
|
|
|
#ifndef SQLITE_OMIT_CTE
|
|
-/*
|
|
-** This routine is invoked once per CTE by the parser while parsing a
|
|
-** WITH clause.
|
|
+/*
|
|
+** Create a new CTE object
|
|
*/
|
|
-SQLITE_PRIVATE With *sqlite3WithAdd(
|
|
+SQLITE_PRIVATE Cte *sqlite3CteNew(
|
|
Parse *pParse, /* Parsing context */
|
|
- With *pWith, /* Existing WITH clause, or NULL */
|
|
Token *pName, /* Name of the common-table */
|
|
ExprList *pArglist, /* Optional column name list for the table */
|
|
- Select *pQuery /* Query used to initialize the table */
|
|
+ Select *pQuery, /* Query used to initialize the table */
|
|
+ u8 eM10d /* The MATERIALIZED flag */
|
|
+){
|
|
+ Cte *pNew;
|
|
+ sqlite3 *db = pParse->db;
|
|
+
|
|
+ pNew = sqlite3DbMallocZero(db, sizeof(*pNew));
|
|
+ assert( pNew!=0 || db->mallocFailed );
|
|
+
|
|
+ if( db->mallocFailed ){
|
|
+ sqlite3ExprListDelete(db, pArglist);
|
|
+ sqlite3SelectDelete(db, pQuery);
|
|
+ }else{
|
|
+ pNew->pSelect = pQuery;
|
|
+ pNew->pCols = pArglist;
|
|
+ pNew->zName = sqlite3NameFromToken(pParse->db, pName);
|
|
+ pNew->eM10d = eM10d;
|
|
+ }
|
|
+ return pNew;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Clear information from a Cte object, but do not deallocate storage
|
|
+** for the object itself.
|
|
+*/
|
|
+static void cteClear(sqlite3 *db, Cte *pCte){
|
|
+ assert( pCte!=0 );
|
|
+ sqlite3ExprListDelete(db, pCte->pCols);
|
|
+ sqlite3SelectDelete(db, pCte->pSelect);
|
|
+ sqlite3DbFree(db, pCte->zName);
|
|
+}
|
|
+
|
|
+/*
|
|
+** Free the contents of the CTE object passed as the second argument.
|
|
+*/
|
|
+SQLITE_PRIVATE void sqlite3CteDelete(sqlite3 *db, Cte *pCte){
|
|
+ assert( pCte!=0 );
|
|
+ cteClear(db, pCte);
|
|
+ sqlite3DbFree(db, 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
|
|
+** the WITH clause of the second argument. If the second argument is
|
|
+** NULL, then a new WITH argument is created.
|
|
+*/
|
|
+SQLITE_PRIVATE With *sqlite3WithAdd(
|
|
+ Parse *pParse, /* Parsing context */
|
|
+ With *pWith, /* Existing WITH clause, or NULL */
|
|
+ Cte *pCte /* CTE to add to the WITH clause */
|
|
){
|
|
sqlite3 *db = pParse->db;
|
|
With *pNew;
|
|
char *zName;
|
|
|
|
+ if( pCte==0 ){
|
|
+ return pWith;
|
|
+ }
|
|
+
|
|
/* Check that the CTE name is unique within this WITH clause. If
|
|
** not, store an error in the Parse structure. */
|
|
- zName = sqlite3NameFromToken(pParse->db, pName);
|
|
+ zName = pCte->zName;
|
|
if( zName && pWith ){
|
|
int i;
|
|
for(i=0; i<pWith->nCte; i++){
|
|
@@ -114116,16 +123155,11 @@ SQLITE_PRIVATE With *sqlite3WithAdd(
|
|
assert( (pNew!=0 && zName!=0) || db->mallocFailed );
|
|
|
|
if( db->mallocFailed ){
|
|
- sqlite3ExprListDelete(db, pArglist);
|
|
- sqlite3SelectDelete(db, pQuery);
|
|
- sqlite3DbFree(db, zName);
|
|
+ sqlite3CteDelete(db, pCte);
|
|
pNew = pWith;
|
|
}else{
|
|
- pNew->a[pNew->nCte].pSelect = pQuery;
|
|
- pNew->a[pNew->nCte].pCols = pArglist;
|
|
- pNew->a[pNew->nCte].zName = zName;
|
|
- pNew->a[pNew->nCte].zCteErr = 0;
|
|
- pNew->nCte++;
|
|
+ pNew->a[pNew->nCte++] = *pCte;
|
|
+ sqlite3DbFree(db, pCte);
|
|
}
|
|
|
|
return pNew;
|
|
@@ -114138,10 +123172,7 @@ SQLITE_PRIVATE void sqlite3WithDelete(sqlite3 *db, With *pWith){
|
|
if( pWith ){
|
|
int i;
|
|
for(i=0; i<pWith->nCte; i++){
|
|
- struct Cte *pCte = &pWith->a[i];
|
|
- sqlite3ExprListDelete(db, pCte->pCols);
|
|
- sqlite3SelectDelete(db, pCte->pSelect);
|
|
- sqlite3DbFree(db, pCte->zName);
|
|
+ cteClear(db, &pWith->a[i]);
|
|
}
|
|
sqlite3DbFree(db, pWith);
|
|
}
|
|
@@ -114151,7 +123182,7 @@ SQLITE_PRIVATE void sqlite3WithDelete(sqlite3 *db, With *pWith){
|
|
/************** End of build.c ***********************************************/
|
|
/************** Begin file callback.c ****************************************/
|
|
/*
|
|
-** 2005 May 23
|
|
+** 2005 May 23
|
|
**
|
|
** The author disclaims copyright to this source code. In place of
|
|
** a legal notice, here is a blessing:
|
|
@@ -114224,7 +123255,7 @@ static int synthCollSeq(sqlite3 *db, CollSeq *pColl){
|
|
** that have not been defined by sqlite3_create_collation() etc.
|
|
**
|
|
** If required, this routine calls the 'collation needed' callback to
|
|
-** request a definition of the collating sequence. If this doesn't work,
|
|
+** request a definition of the collating sequence. If this doesn't work,
|
|
** an equivalent collating sequence that uses a text encoding different
|
|
** from the main database is substituted, if one is available.
|
|
*/
|
|
@@ -114278,7 +123309,7 @@ static CollSeq *findCollSeqEntry(
|
|
memcpy(pColl[0].zName, zName, nName);
|
|
pDel = sqlite3HashInsert(&db->aCollSeq, pColl[0].zName, pColl);
|
|
|
|
- /* If a malloc() failure occurred in sqlite3HashInsert(), it will
|
|
+ /* If a malloc() failure occurred in sqlite3HashInsert(), it will
|
|
** return the pColl pointer to be deleted (because it wasn't added
|
|
** to the hash table).
|
|
*/
|
|
@@ -114315,23 +123346,36 @@ SQLITE_PRIVATE CollSeq *sqlite3FindCollSeq(
|
|
int create /* True to create CollSeq if doesn't already exist */
|
|
){
|
|
CollSeq *pColl;
|
|
+ assert( SQLITE_UTF8==1 && SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 );
|
|
+ assert( enc>=SQLITE_UTF8 && enc<=SQLITE_UTF16BE );
|
|
if( zName ){
|
|
pColl = findCollSeqEntry(db, zName, create);
|
|
+ if( pColl ) pColl += enc-1;
|
|
}else{
|
|
pColl = db->pDfltColl;
|
|
}
|
|
- assert( SQLITE_UTF8==1 && SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 );
|
|
- assert( enc>=SQLITE_UTF8 && enc<=SQLITE_UTF16BE );
|
|
- if( pColl ) pColl += enc-1;
|
|
return pColl;
|
|
}
|
|
|
|
+/*
|
|
+** Change the text encoding for a database connection. This means that
|
|
+** the pDfltColl must change as well.
|
|
+*/
|
|
+SQLITE_PRIVATE void sqlite3SetTextEncoding(sqlite3 *db, u8 enc){
|
|
+ assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE );
|
|
+ db->enc = enc;
|
|
+ /* EVIDENCE-OF: R-08308-17224 The default collating function for all
|
|
+ ** strings is BINARY.
|
|
+ */
|
|
+ db->pDfltColl = sqlite3FindCollSeq(db, enc, sqlite3StrBINARY, 0);
|
|
+}
|
|
+
|
|
/*
|
|
** This function is responsible for invoking the collation factory callback
|
|
** or substituting a collation sequence of a different encoding when the
|
|
** requested collation sequence is not available in the desired encoding.
|
|
-**
|
|
-** If it is not NULL, then pColl must point to the database native encoding
|
|
+**
|
|
+** If it is not NULL, then pColl must point to the database native encoding
|
|
** collation sequence with name zName, length nName.
|
|
**
|
|
** The return value is either the collation sequence to be used in database
|
|
@@ -114415,7 +123459,7 @@ SQLITE_PRIVATE CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName){
|
|
** is also -1. In other words, we are searching for a function that
|
|
** takes a variable number of arguments.
|
|
**
|
|
-** If nArg is -2 that means that we are searching for any function
|
|
+** If nArg is -2 that means that we are searching for any function
|
|
** regardless of the number of arguments it uses, so return a positive
|
|
** match score for any
|
|
**
|
|
@@ -114476,6 +123520,7 @@ SQLITE_PRIVATE FuncDef *sqlite3FunctionSearch(
|
|
){
|
|
FuncDef *p;
|
|
for(p=sqlite3BuiltinFunctions.a[h]; p; p=p->u.pHash){
|
|
+ assert( p->funcFlags & SQLITE_FUNC_BUILTIN );
|
|
if( sqlite3StrICmp(p->zName, zFunc)==0 ){
|
|
return p;
|
|
}
|
|
@@ -114496,7 +123541,7 @@ SQLITE_PRIVATE void sqlite3InsertBuiltinFuncs(
|
|
const char *zName = aDef[i].zName;
|
|
int nName = sqlite3Strlen30(zName);
|
|
int h = SQLITE_FUNC_HASH(zName[0], nName);
|
|
- assert( zName[0]>='a' && zName[0]<='z' );
|
|
+ assert( aDef[i].funcFlags & SQLITE_FUNC_BUILTIN );
|
|
pOther = sqlite3FunctionSearch(h, zName);
|
|
if( pOther ){
|
|
assert( pOther!=&aDef[i] && pOther->pNext!=&aDef[i] );
|
|
@@ -114509,8 +123554,8 @@ SQLITE_PRIVATE void sqlite3InsertBuiltinFuncs(
|
|
}
|
|
}
|
|
}
|
|
-
|
|
-
|
|
+
|
|
+
|
|
|
|
/*
|
|
** Locate a user function given a name, a number of arguments and a flag
|
|
@@ -114571,7 +123616,7 @@ SQLITE_PRIVATE FuncDef *sqlite3FindFunction(
|
|
** have fields overwritten with new information appropriate for the
|
|
** new function. But the FuncDefs for built-in functions are read-only.
|
|
** So we must not search for built-ins when creating a new function.
|
|
- */
|
|
+ */
|
|
if( !createFlag && (pBest==0 || (db->mDbFlags & DBFLAG_PreferBuiltin)!=0) ){
|
|
bestScore = 0;
|
|
h = SQLITE_FUNC_HASH(sqlite3UpperToLower[(u8)zName[0]], nName);
|
|
@@ -114590,7 +123635,7 @@ SQLITE_PRIVATE FuncDef *sqlite3FindFunction(
|
|
** exact match for the name, number of arguments and encoding, then add a
|
|
** new entry to the hash table and return it.
|
|
*/
|
|
- if( createFlag && bestScore<FUNC_PERFECT_MATCH &&
|
|
+ if( createFlag && bestScore<FUNC_PERFECT_MATCH &&
|
|
(pBest = sqlite3DbMallocZero(db, sizeof(*pBest)+nName+1))!=0 ){
|
|
FuncDef *pOther;
|
|
u8 *z;
|
|
@@ -114617,7 +123662,7 @@ SQLITE_PRIVATE FuncDef *sqlite3FindFunction(
|
|
|
|
/*
|
|
** Free all resources held by the schema structure. The void* argument points
|
|
-** at a Schema struct. This function does not call sqlite3DbFree(db, ) on the
|
|
+** at a Schema struct. This function does not call sqlite3DbFree(db, ) on the
|
|
** pointer itself, it just cleans up subsidiary resources (i.e. the contents
|
|
** of the schema hash tables).
|
|
**
|
|
@@ -114628,19 +123673,21 @@ SQLITE_PRIVATE void sqlite3SchemaClear(void *p){
|
|
Hash temp2;
|
|
HashElem *pElem;
|
|
Schema *pSchema = (Schema *)p;
|
|
+ sqlite3 xdb;
|
|
|
|
+ memset(&xdb, 0, sizeof(xdb));
|
|
temp1 = pSchema->tblHash;
|
|
temp2 = pSchema->trigHash;
|
|
sqlite3HashInit(&pSchema->trigHash);
|
|
sqlite3HashClear(&pSchema->idxHash);
|
|
for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){
|
|
- sqlite3DeleteTrigger(0, (Trigger*)sqliteHashData(pElem));
|
|
+ sqlite3DeleteTrigger(&xdb, (Trigger*)sqliteHashData(pElem));
|
|
}
|
|
sqlite3HashClear(&temp2);
|
|
sqlite3HashInit(&pSchema->tblHash);
|
|
for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
|
|
Table *pTab = sqliteHashData(pElem);
|
|
- sqlite3DeleteTable(0, pTab);
|
|
+ sqlite3DeleteTable(&xdb, pTab);
|
|
}
|
|
sqlite3HashClear(&temp1);
|
|
sqlite3HashClear(&pSchema->fkeyHash);
|
|
@@ -114697,7 +123744,7 @@ SQLITE_PRIVATE Schema *sqlite3SchemaGet(sqlite3 *db, Btree *pBt){
|
|
** (as in the FROM clause of a SELECT statement) in this case it contains
|
|
** the name of a single table, as one might find in an INSERT, DELETE,
|
|
** or UPDATE statement. Look up that table in the symbol table and
|
|
-** return a pointer. Set an error message and return NULL if the table
|
|
+** return a pointer. Set an error message and return NULL if the table
|
|
** name is not found or if any other error occurs.
|
|
**
|
|
** The following fields are initialized appropriate in pSrc:
|
|
@@ -114707,21 +123754,31 @@ SQLITE_PRIVATE Schema *sqlite3SchemaGet(sqlite3 *db, Btree *pBt){
|
|
**
|
|
*/
|
|
SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
|
|
- struct SrcList_item *pItem = pSrc->a;
|
|
+ SrcItem *pItem = pSrc->a;
|
|
Table *pTab;
|
|
- assert( pItem && pSrc->nSrc==1 );
|
|
+ assert( pItem && pSrc->nSrc>=1 );
|
|
pTab = sqlite3LocateTableItem(pParse, 0, pItem);
|
|
sqlite3DeleteTable(pParse->db, pItem->pTab);
|
|
pItem->pTab = pTab;
|
|
if( pTab ){
|
|
pTab->nTabRef++;
|
|
- }
|
|
- if( sqlite3IndexedByLookup(pParse, pItem) ){
|
|
- pTab = 0;
|
|
+ if( pItem->fg.isIndexedBy && sqlite3IndexedByLookup(pParse, pItem) ){
|
|
+ pTab = 0;
|
|
+ }
|
|
}
|
|
return pTab;
|
|
}
|
|
|
|
+/* Generate byte-code that will report the number of rows modified
|
|
+** by a DELETE, INSERT, or UPDATE statement.
|
|
+*/
|
|
+SQLITE_PRIVATE void sqlite3CodeChangeCount(Vdbe *v, int regCounter, const char *zColName){
|
|
+ sqlite3VdbeAddOp0(v, OP_FkCheck);
|
|
+ sqlite3VdbeAddOp2(v, OP_ResultRow, regCounter, 1);
|
|
+ sqlite3VdbeSetNumCols(v, 1);
|
|
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zColName, SQLITE_STATIC);
|
|
+}
|
|
+
|
|
/* Return true if table pTab is read-only.
|
|
**
|
|
** A table is read-only if any of the following are true:
|
|
@@ -114729,18 +123786,42 @@ SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
|
|
** 1) It is a virtual table and no implementation of the xUpdate method
|
|
** has been provided
|
|
**
|
|
-** 2) It is a system table (i.e. sqlite_master), this call is not
|
|
-** part of a nested parse and writable_schema pragma has not
|
|
+** 2) A trigger is currently being coded and the table is a virtual table
|
|
+** that is SQLITE_VTAB_DIRECTONLY or if PRAGMA trusted_schema=OFF and
|
|
+** the table is not SQLITE_VTAB_INNOCUOUS.
|
|
+**
|
|
+** 3) It is a system table (i.e. sqlite_schema), this call is not
|
|
+** part of a nested parse and writable_schema pragma has not
|
|
** been specified
|
|
**
|
|
-** 3) The table is a shadow table, the database connection is in
|
|
+** 4) The table is a shadow table, the database connection is in
|
|
** defensive mode, and the current sqlite3_prepare()
|
|
** is for a top-level SQL statement.
|
|
*/
|
|
+static int vtabIsReadOnly(Parse *pParse, Table *pTab){
|
|
+ if( sqlite3GetVTable(pParse->db, pTab)->pMod->pModule->xUpdate==0 ){
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ /* Within triggers:
|
|
+ ** * Do not allow DELETE, INSERT, or UPDATE of SQLITE_VTAB_DIRECTONLY
|
|
+ ** virtual tables
|
|
+ ** * Only allow DELETE, INSERT, or UPDATE of non-SQLITE_VTAB_INNOCUOUS
|
|
+ ** virtual tables if PRAGMA trusted_schema=ON.
|
|
+ */
|
|
+ if( pParse->pToplevel!=0
|
|
+ && pTab->u.vtab.p->eVtabRisk >
|
|
+ ((pParse->db->flags & SQLITE_TrustedSchema)!=0)
|
|
+ ){
|
|
+ sqlite3ErrorMsg(pParse, "unsafe use of virtual table \"%s\"",
|
|
+ pTab->zName);
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
static int tabIsReadOnly(Parse *pParse, Table *pTab){
|
|
sqlite3 *db;
|
|
if( IsVirtual(pTab) ){
|
|
- return sqlite3GetVTable(pParse->db, pTab)->pMod->pModule->xUpdate==0;
|
|
+ return vtabIsReadOnly(pParse, pTab);
|
|
}
|
|
if( (pTab->tabFlags & (TF_Readonly|TF_Shadow))==0 ) return 0;
|
|
db = pParse->db;
|
|
@@ -114752,9 +123833,11 @@ static int tabIsReadOnly(Parse *pParse, Table *pTab){
|
|
}
|
|
|
|
/*
|
|
-** Check to make sure the given table is writable. If it is not
|
|
-** writable, generate an error message and return 1. If it is
|
|
-** writable return 0;
|
|
+** Check to make sure the given table is writable.
|
|
+**
|
|
+** If pTab is not writable -> generate an error message and return 1.
|
|
+** 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){
|
|
if( tabIsReadOnly(pParse, pTab) ){
|
|
@@ -114762,7 +123845,7 @@ SQLITE_PRIVATE int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){
|
|
return 1;
|
|
}
|
|
#ifndef SQLITE_OMIT_VIEW
|
|
- if( !viewOk && pTab->pSelect ){
|
|
+ if( !viewOk && IsView(pTab) ){
|
|
sqlite3ErrorMsg(pParse,"cannot modify %s because it is a view",pTab->zName);
|
|
return 1;
|
|
}
|
|
@@ -114796,10 +123879,10 @@ SQLITE_PRIVATE void sqlite3MaterializeView(
|
|
assert( pFrom->nSrc==1 );
|
|
pFrom->a[0].zName = sqlite3DbStrDup(db, pView->zName);
|
|
pFrom->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName);
|
|
- assert( pFrom->a[0].pOn==0 );
|
|
- assert( pFrom->a[0].pUsing==0 );
|
|
+ assert( pFrom->a[0].fg.isUsing==0 );
|
|
+ assert( pFrom->a[0].u3.pOn==0 );
|
|
}
|
|
- pSel = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, pOrderBy,
|
|
+ pSel = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, pOrderBy,
|
|
SF_IncludeHidden, pLimit);
|
|
sqlite3SelectDestInit(&dest, SRT_EphemTab, iCur);
|
|
sqlite3Select(pParse, pSel, &dest);
|
|
@@ -114848,11 +123931,11 @@ SQLITE_PRIVATE Expr *sqlite3LimitWhere(
|
|
return pWhere;
|
|
}
|
|
|
|
- /* Generate a select expression tree to enforce the limit/offset
|
|
+ /* Generate a select expression tree to enforce the limit/offset
|
|
** term for the DELETE or UPDATE statement. For example:
|
|
** DELETE FROM table_a WHERE col1=1 ORDER BY col2 LIMIT 1 OFFSET 1
|
|
** becomes:
|
|
- ** DELETE FROM table_a WHERE rowid IN (
|
|
+ ** DELETE FROM table_a WHERE rowid IN (
|
|
** SELECT rowid FROM table_a WHERE col1=1 ORDER BY col2 LIMIT 1 OFFSET 1
|
|
** );
|
|
*/
|
|
@@ -114866,13 +123949,13 @@ SQLITE_PRIVATE Expr *sqlite3LimitWhere(
|
|
}else{
|
|
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
|
|
if( pPk->nKeyCol==1 ){
|
|
- const char *zName = pTab->aCol[pPk->aiColumn[0]].zName;
|
|
+ const char *zName = pTab->aCol[pPk->aiColumn[0]].zCnName;
|
|
pLhs = sqlite3Expr(db, TK_ID, zName);
|
|
pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ID, zName));
|
|
}else{
|
|
int i;
|
|
for(i=0; i<pPk->nKeyCol; i++){
|
|
- Expr *p = sqlite3Expr(db, TK_ID, pTab->aCol[pPk->aiColumn[i]].zName);
|
|
+ Expr *p = sqlite3Expr(db, TK_ID, pTab->aCol[pPk->aiColumn[i]].zCnName);
|
|
pEList = sqlite3ExprListAppend(pParse, pEList, p);
|
|
}
|
|
pLhs = sqlite3PExpr(pParse, TK_VECTOR, 0, 0);
|
|
@@ -114885,12 +123968,19 @@ SQLITE_PRIVATE Expr *sqlite3LimitWhere(
|
|
/* duplicate the FROM clause as it is needed by both the DELETE/UPDATE tree
|
|
** and the SELECT subtree. */
|
|
pSrc->a[0].pTab = 0;
|
|
- pSelectSrc = sqlite3SrcListDup(pParse->db, pSrc, 0);
|
|
+ pSelectSrc = sqlite3SrcListDup(db, pSrc, 0);
|
|
pSrc->a[0].pTab = pTab;
|
|
- pSrc->a[0].pIBIndex = 0;
|
|
+ if( pSrc->a[0].fg.isIndexedBy ){
|
|
+ assert( pSrc->a[0].fg.isCte==0 );
|
|
+ pSrc->a[0].u2.pIBIndex = 0;
|
|
+ pSrc->a[0].fg.isIndexedBy = 0;
|
|
+ sqlite3DbFree(db, pSrc->a[0].u1.zIndexedBy);
|
|
+ }else if( pSrc->a[0].fg.isCte ){
|
|
+ pSrc->a[0].u2.pCteUse->nUse++;
|
|
+ }
|
|
|
|
/* generate the SELECT expression tree. */
|
|
- pSelect = sqlite3SelectNew(pParse, pEList, pSelectSrc, pWhere, 0 ,0,
|
|
+ pSelect = sqlite3SelectNew(pParse, pEList, pSelectSrc, pWhere, 0 ,0,
|
|
pOrderBy,0,pLimit
|
|
);
|
|
|
|
@@ -114946,7 +124036,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
|
|
int addrEphOpen = 0; /* Instruction to open the Ephemeral table */
|
|
int bComplex; /* True if there are triggers or FKs or
|
|
** subqueries in the WHERE clause */
|
|
-
|
|
+
|
|
#ifndef SQLITE_OMIT_TRIGGER
|
|
int isView; /* True if attempting to delete from a view */
|
|
Trigger *pTrigger; /* List of table triggers, if required */
|
|
@@ -114954,12 +124044,13 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
|
|
|
|
memset(&sContext, 0, sizeof(sContext));
|
|
db = pParse->db;
|
|
- if( pParse->nErr || db->mallocFailed ){
|
|
+ assert( db->pParse==pParse );
|
|
+ if( pParse->nErr ){
|
|
goto delete_from_cleanup;
|
|
}
|
|
+ assert( db->mallocFailed==0 );
|
|
assert( pTabList->nSrc==1 );
|
|
|
|
-
|
|
/* Locate the table which we want to delete. This table has to be
|
|
** put in an SrcList structure because some of the subroutines we
|
|
** will be calling are designed to work with multiple tables and expect
|
|
@@ -114973,7 +124064,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
|
|
*/
|
|
#ifndef SQLITE_OMIT_TRIGGER
|
|
pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0);
|
|
- isView = pTab->pSelect!=0;
|
|
+ isView = IsView(pTab);
|
|
#else
|
|
# define pTrigger 0
|
|
# define isView 0
|
|
@@ -114984,6 +124075,14 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
|
|
# define isView 0
|
|
#endif
|
|
|
|
+#if TREETRACE_ENABLED
|
|
+ if( sqlite3TreeTrace & 0x10000 ){
|
|
+ sqlite3TreeViewLine(0, "In sqlite3Delete() at %s:%d", __FILE__, __LINE__);
|
|
+ sqlite3TreeViewDelete(pParse->pWith, pTabList, pWhere,
|
|
+ pOrderBy, pLimit, pTrigger);
|
|
+ }
|
|
+#endif
|
|
+
|
|
#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
|
|
if( !isView ){
|
|
pWhere = sqlite3LimitWhere(
|
|
@@ -115005,7 +124104,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
|
|
}
|
|
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
|
assert( iDb<db->nDb );
|
|
- rcauth = sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0,
|
|
+ rcauth = sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0,
|
|
db->aDb[iDb].zDbSName);
|
|
assert( rcauth==SQLITE_OK || rcauth==SQLITE_DENY || rcauth==SQLITE_IGNORE );
|
|
if( rcauth==SQLITE_DENY ){
|
|
@@ -115041,7 +124140,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
|
|
*/
|
|
#if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER)
|
|
if( isView ){
|
|
- sqlite3MaterializeView(pParse, pTab,
|
|
+ sqlite3MaterializeView(pParse, pTab,
|
|
pWhere, pOrderBy, pLimit, iTabCur
|
|
);
|
|
iDataCur = iIdxCur = iTabCur;
|
|
@@ -115065,6 +124164,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
|
|
if( (db->flags & SQLITE_CountRows)!=0
|
|
&& !pParse->nested
|
|
&& !pParse->pTriggerTab
|
|
+ && !pParse->bReturning
|
|
){
|
|
memCnt = ++pParse->nMem;
|
|
sqlite3VdbeAddOp2(v, OP_Integer, 0, memCnt);
|
|
@@ -115073,7 +124173,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
|
|
#ifndef SQLITE_OMIT_TRUNCATE_OPTIMIZATION
|
|
/* Special case: A DELETE without a WHERE clause deletes everything.
|
|
** It is easier just to erase the whole table. Prior to version 3.6.5,
|
|
- ** this optimization caused the row change count (the value returned by
|
|
+ ** this optimization caused the row change count (the value returned by
|
|
** API function sqlite3_count_changes) to be set incorrectly.
|
|
**
|
|
** The "rcauth==SQLITE_OK" terms is the
|
|
@@ -115098,13 +124198,17 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
|
|
}
|
|
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
|
assert( pIdx->pSchema==pTab->pSchema );
|
|
- sqlite3VdbeAddOp2(v, OP_Clear, pIdx->tnum, iDb);
|
|
+ if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){
|
|
+ sqlite3VdbeAddOp3(v, OP_Clear, pIdx->tnum, iDb, memCnt ? memCnt : -1);
|
|
+ }else{
|
|
+ sqlite3VdbeAddOp2(v, OP_Clear, pIdx->tnum, iDb);
|
|
+ }
|
|
}
|
|
}else
|
|
#endif /* SQLITE_OMIT_TRUNCATE_OPTIMIZATION */
|
|
{
|
|
- u16 wcf = WHERE_ONEPASS_DESIRED|WHERE_DUPLICATES_OK|WHERE_SEEK_TABLE;
|
|
- if( sNC.ncFlags & NC_VarSelect ) bComplex = 1;
|
|
+ u16 wcf = WHERE_ONEPASS_DESIRED|WHERE_DUPLICATES_OK;
|
|
+ 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 */
|
|
@@ -115124,7 +124228,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
|
|
addrEphOpen = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iEphCur, nPk);
|
|
sqlite3VdbeSetP4KeyInfo(pParse, pPk);
|
|
}
|
|
-
|
|
+
|
|
/* Construct a query to find the rowid or primary key for every row
|
|
** to be deleted, based on the WHERE clause. Set variable eOnePass
|
|
** to indicate the strategy used to implement this delete:
|
|
@@ -115133,18 +124237,21 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
|
|
** ONEPASS_SINGLE: One-pass approach - at most one row deleted.
|
|
** ONEPASS_MULTI: One-pass approach - any number of rows may be deleted.
|
|
*/
|
|
- pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0, wcf, iTabCur+1);
|
|
+ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0,0,wcf,iTabCur+1);
|
|
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 );
|
|
if( eOnePass!=ONEPASS_SINGLE ) sqlite3MultiWrite(pParse);
|
|
-
|
|
+ if( sqlite3WhereUsesDeferredSeek(pWInfo) ){
|
|
+ sqlite3VdbeAddOp1(v, OP_FinishSeek, iTabCur);
|
|
+ }
|
|
+
|
|
/* Keep track of the number of rows to be deleted */
|
|
if( memCnt ){
|
|
sqlite3VdbeAddOp2(v, OP_AddImm, memCnt, 1);
|
|
}
|
|
-
|
|
+
|
|
/* Extract the rowid or primary key for the current row */
|
|
if( pPk ){
|
|
for(i=0; i<nPk; i++){
|
|
@@ -115157,7 +124264,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
|
|
iKey = ++pParse->nMem;
|
|
sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, -1, iKey);
|
|
}
|
|
-
|
|
+
|
|
if( eOnePass!=ONEPASS_OFF ){
|
|
/* For ONEPASS, no need to store the rowid/primary-key. There is only
|
|
** one, so just keep it in its register(s) and fall through to the
|
|
@@ -115173,6 +124280,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
|
|
if( aiCurOnePass[0]>=0 ) aToOpen[aiCurOnePass[0]-iTabCur] = 0;
|
|
if( aiCurOnePass[1]>=0 ) aToOpen[aiCurOnePass[1]-iTabCur] = 0;
|
|
if( addrEphOpen ) sqlite3VdbeChangeToNoop(v, addrEphOpen);
|
|
+ addrBypass = sqlite3VdbeMakeLabel(pParse);
|
|
}else{
|
|
if( pPk ){
|
|
/* Add the PK key for this row to the temporary table */
|
|
@@ -115186,19 +124294,12 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
|
|
nKey = 1; /* OP_DeferredSeek always uses a single rowid */
|
|
sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, iKey);
|
|
}
|
|
- }
|
|
-
|
|
- /* If this DELETE cannot use the ONEPASS strategy, this is the
|
|
- ** end of the WHERE loop */
|
|
- if( eOnePass!=ONEPASS_OFF ){
|
|
- addrBypass = sqlite3VdbeMakeLabel(pParse);
|
|
- }else{
|
|
sqlite3WhereEnd(pWInfo);
|
|
}
|
|
-
|
|
- /* Unless this is a view, open cursors for the table we are
|
|
+
|
|
+ /* Unless this is a view, open cursors for the table we are
|
|
** deleting from and all its indices. If this is a view, then the
|
|
- ** only effect this statement has is to fire the INSTEAD OF
|
|
+ ** only effect this statement has is to fire the INSTEAD OF
|
|
** triggers.
|
|
*/
|
|
if( !isView ){
|
|
@@ -115211,16 +124312,18 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
|
|
iTabCur, aToOpen, &iDataCur, &iIdxCur);
|
|
assert( pPk || IsVirtual(pTab) || iDataCur==iTabCur );
|
|
assert( pPk || IsVirtual(pTab) || iIdxCur==iDataCur+1 );
|
|
- if( eOnePass==ONEPASS_MULTI ) sqlite3VdbeJumpHere(v, iAddrOnce);
|
|
+ if( eOnePass==ONEPASS_MULTI ){
|
|
+ sqlite3VdbeJumpHereOrPopInst(v, iAddrOnce);
|
|
+ }
|
|
}
|
|
-
|
|
+
|
|
/* Set up a loop over the rowids/primary-keys that were found in the
|
|
** where-clause loop above.
|
|
*/
|
|
if( eOnePass!=ONEPASS_OFF ){
|
|
assert( nKey==nPk ); /* OP_Found will use an unpacked key */
|
|
if( !IsVirtual(pTab) && aToOpen[iDataCur-iTabCur] ){
|
|
- assert( pPk!=0 || pTab->pSelect!=0 );
|
|
+ assert( pPk!=0 || IsView(pTab) );
|
|
sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, addrBypass, iKey, nKey);
|
|
VdbeCoverage(v);
|
|
}
|
|
@@ -115236,8 +124339,8 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
|
|
addrLoop = sqlite3VdbeAddOp3(v, OP_RowSetRead, iRowSet, 0, iKey);
|
|
VdbeCoverage(v);
|
|
assert( nKey==1 );
|
|
- }
|
|
-
|
|
+ }
|
|
+
|
|
/* Delete the row */
|
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
|
if( IsVirtual(pTab) ){
|
|
@@ -115260,7 +124363,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
|
|
sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
|
|
iKey, nKey, count, OE_Default, eOnePass, aiCurOnePass[1]);
|
|
}
|
|
-
|
|
+
|
|
/* End of the loop over all rowids/primary-keys. */
|
|
if( eOnePass!=ONEPASS_OFF ){
|
|
sqlite3VdbeResolveLabel(v, addrBypass);
|
|
@@ -115271,7 +124374,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
|
|
}else{
|
|
sqlite3VdbeGoto(v, addrLoop);
|
|
sqlite3VdbeJumpHere(v, addrLoop);
|
|
- }
|
|
+ }
|
|
} /* End non-truncate path */
|
|
|
|
/* Update the sqlite_sequence table by storing the content of the
|
|
@@ -115282,25 +124385,23 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
|
|
sqlite3AutoincrementEnd(pParse);
|
|
}
|
|
|
|
- /* Return the number of rows that were deleted. If this routine is
|
|
+ /* Return the number of rows that were deleted. If this routine is
|
|
** generating code because of a call to sqlite3NestedParse(), do not
|
|
** invoke the callback function.
|
|
*/
|
|
if( memCnt ){
|
|
- sqlite3VdbeAddOp2(v, OP_ResultRow, memCnt, 1);
|
|
- sqlite3VdbeSetNumCols(v, 1);
|
|
- sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows deleted", SQLITE_STATIC);
|
|
+ sqlite3CodeChangeCount(v, memCnt, "rows deleted");
|
|
}
|
|
|
|
delete_from_cleanup:
|
|
sqlite3AuthContextPop(&sContext);
|
|
sqlite3SrcListDelete(db, pTabList);
|
|
sqlite3ExprDelete(db, pWhere);
|
|
-#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT)
|
|
+#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT)
|
|
sqlite3ExprListDelete(db, pOrderBy);
|
|
sqlite3ExprDelete(db, pLimit);
|
|
#endif
|
|
- sqlite3DbFree(db, aToOpen);
|
|
+ if( aToOpen ) sqlite3DbNNFreeNN(db, aToOpen);
|
|
return;
|
|
}
|
|
/* Make sure "isView" and other macros defined above are undefined. Otherwise
|
|
@@ -115341,7 +124442,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
|
|
** and nPk before reading from it.
|
|
**
|
|
** If eMode is ONEPASS_MULTI, then this call is being made as part
|
|
-** of a ONEPASS delete that affects multiple rows. In this case, if
|
|
+** of a ONEPASS delete that affects multiple rows. In this case, if
|
|
** iIdxNoSeek is a valid cursor number (>=0) and is not the same as
|
|
** iDataCur, then its position should be preserved following the delete
|
|
** operation. Or, if iIdxNoSeek is not a valid cursor number, the
|
|
@@ -115377,7 +124478,7 @@ SQLITE_PRIVATE void sqlite3GenerateRowDelete(
|
|
VdbeModuleComment((v, "BEGIN: GenRowDel(%d,%d,%d,%d)",
|
|
iDataCur, iIdxCur, iPk, (int)nPk));
|
|
|
|
- /* Seek cursor iCur to the row to delete. If this row no longer exists
|
|
+ /* Seek cursor iCur to the row to delete. If this row no longer exists
|
|
** (this can happen if a trigger program has already deleted it), do
|
|
** not attempt to delete it or fire any DELETE triggers. */
|
|
iLabel = sqlite3VdbeMakeLabel(pParse);
|
|
@@ -115387,7 +124488,7 @@ SQLITE_PRIVATE void sqlite3GenerateRowDelete(
|
|
VdbeCoverageIf(v, opSeek==OP_NotExists);
|
|
VdbeCoverageIf(v, opSeek==OP_NotFound);
|
|
}
|
|
-
|
|
+
|
|
/* If there are any triggers to fire, allocate a range of registers to
|
|
** use for the old.* references in the triggers. */
|
|
if( sqlite3FkRequired(pParse, pTab, 0, 0) || pTrigger ){
|
|
@@ -115404,7 +124505,7 @@ SQLITE_PRIVATE void sqlite3GenerateRowDelete(
|
|
iOld = pParse->nMem+1;
|
|
pParse->nMem += (1 + pTab->nCol);
|
|
|
|
- /* Populate the OLD.* pseudo-table register array. These values will be
|
|
+ /* Populate the OLD.* pseudo-table register array. These values will be
|
|
** used by any BEFORE and AFTER triggers that exist. */
|
|
sqlite3VdbeAddOp2(v, OP_Copy, iPk, iOld);
|
|
for(iCol=0; iCol<pTab->nCol; iCol++){
|
|
@@ -115418,11 +124519,11 @@ SQLITE_PRIVATE void sqlite3GenerateRowDelete(
|
|
|
|
/* Invoke BEFORE DELETE trigger programs. */
|
|
addrStart = sqlite3VdbeCurrentAddr(v);
|
|
- sqlite3CodeRowTrigger(pParse, pTrigger,
|
|
+ sqlite3CodeRowTrigger(pParse, pTrigger,
|
|
TK_DELETE, 0, TRIGGER_BEFORE, pTab, iOld, onconf, iLabel
|
|
);
|
|
|
|
- /* If any BEFORE triggers were coded, then seek the cursor to the
|
|
+ /* If any BEFORE triggers were coded, then seek the cursor to the
|
|
** row to be deleted again. It may be that the BEFORE triggers moved
|
|
** the cursor or already deleted the row that the cursor was
|
|
** pointing to.
|
|
@@ -115439,22 +124540,22 @@ SQLITE_PRIVATE void sqlite3GenerateRowDelete(
|
|
}
|
|
|
|
/* Do FK processing. This call checks that any FK constraints that
|
|
- ** refer to this table (i.e. constraints attached to other tables)
|
|
+ ** refer to this table (i.e. constraints attached to other tables)
|
|
** are not violated by deleting this row. */
|
|
sqlite3FkCheck(pParse, pTab, iOld, 0, 0, 0);
|
|
}
|
|
|
|
/* Delete the index and table entries. Skip this step if pTab is really
|
|
** a view (in which case the only effect of the DELETE statement is to
|
|
- ** fire the INSTEAD OF triggers).
|
|
+ ** fire the INSTEAD OF triggers).
|
|
**
|
|
** If variable 'count' is non-zero, then this OP_Delete instruction should
|
|
** invoke the update-hook. The pre-update-hook, on the other hand should
|
|
** be invoked unless table pTab is a system table. The difference is that
|
|
- ** the update-hook is not invoked for rows removed by REPLACE, but the
|
|
+ ** the update-hook is not invoked for rows removed by REPLACE, but the
|
|
** pre-update-hook is.
|
|
- */
|
|
- if( pTab->pSelect==0 ){
|
|
+ */
|
|
+ if( !IsView(pTab) ){
|
|
u8 p5 = 0;
|
|
sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur,0,iIdxNoSeek);
|
|
sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, (count?OPFLAG_NCHANGE:0));
|
|
@@ -115473,16 +124574,16 @@ SQLITE_PRIVATE void sqlite3GenerateRowDelete(
|
|
|
|
/* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to
|
|
** handle rows (possibly in other tables) that refer via a foreign key
|
|
- ** to the row just deleted. */
|
|
+ ** to the row just deleted. */
|
|
sqlite3FkActions(pParse, pTab, 0, iOld, 0, 0);
|
|
|
|
/* Invoke AFTER DELETE trigger programs. */
|
|
- sqlite3CodeRowTrigger(pParse, 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
|
|
+ ** trigger programs were invoked. Or if a trigger program throws a
|
|
** RAISE(IGNORE) exception. */
|
|
sqlite3VdbeResolveLabel(v, iLabel);
|
|
VdbeModuleComment((v, "END: GenRowDel()"));
|
|
@@ -115534,6 +124635,7 @@ SQLITE_PRIVATE void sqlite3GenerateRowIndexDelete(
|
|
&iPartIdxLabel, pPrior, r1);
|
|
sqlite3VdbeAddOp3(v, OP_IdxDelete, iIdxCur+i, r1,
|
|
pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn);
|
|
+ sqlite3VdbeChangeP5(v, 1); /* Cause IdxDelete to error if no entry found */
|
|
sqlite3ResolvePartIdxLabel(pParse, iPartIdxLabel);
|
|
pPrior = pIdx;
|
|
}
|
|
@@ -115566,7 +124668,7 @@ SQLITE_PRIVATE void sqlite3GenerateRowIndexDelete(
|
|
** its key into the same sequence of registers and if pPrior and pIdx share
|
|
** a column in common, then the register corresponding to that column already
|
|
** holds the correct value and the loading of that register is skipped.
|
|
-** This optimization is helpful when doing a DELETE or an INTEGRITY_CHECK
|
|
+** This optimization is helpful when doing a DELETE or an INTEGRITY_CHECK
|
|
** on a table with multiple indices, and especially with the ROWID or
|
|
** PRIMARY KEY columns of the index.
|
|
*/
|
|
@@ -115589,7 +124691,7 @@ SQLITE_PRIVATE int sqlite3GenerateIndexKey(
|
|
if( pIdx->pPartIdxWhere ){
|
|
*piPartIdxLabel = sqlite3VdbeMakeLabel(pParse);
|
|
pParse->iSelfTab = iDataCur + 1;
|
|
- sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel,
|
|
+ sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel,
|
|
SQLITE_JUMPIFNULL);
|
|
pParse->iSelfTab = 0;
|
|
pPrior = 0; /* Ticket a9efb42811fa41ee 2019-11-02;
|
|
@@ -115610,20 +124712,18 @@ SQLITE_PRIVATE int sqlite3GenerateIndexKey(
|
|
continue;
|
|
}
|
|
sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iDataCur, j, regBase+j);
|
|
- /* If the column affinity is REAL but the number is an integer, then it
|
|
- ** might be stored in the table as an integer (using a compact
|
|
- ** representation) then converted to REAL by an OP_RealAffinity opcode.
|
|
- ** But we are getting ready to store this value back into an index, where
|
|
- ** it should be converted by to INTEGER again. So omit the OP_RealAffinity
|
|
- ** opcode if it is present */
|
|
- sqlite3VdbeDeletePriorOpcode(v, OP_RealAffinity);
|
|
+ if( pIdx->aiColumn[j]>=0 ){
|
|
+ /* If the column affinity is REAL but the number is an integer, then it
|
|
+ ** might be stored in the table as an integer (using a compact
|
|
+ ** representation) then converted to REAL by an OP_RealAffinity opcode.
|
|
+ ** But we are getting ready to store this value back into an index, where
|
|
+ ** it should be converted by to INTEGER again. So omit the
|
|
+ ** OP_RealAffinity opcode if it is present */
|
|
+ sqlite3VdbeDeletePriorOpcode(v, OP_RealAffinity);
|
|
+ }
|
|
}
|
|
if( regOut ){
|
|
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regOut);
|
|
- if( pIdx->pTable->pSelect ){
|
|
- const char *zAff = sqlite3IndexAffinityStr(pParse->db, pIdx);
|
|
- sqlite3VdbeChangeP4(v, -1, zAff, P4_TRANSIENT);
|
|
- }
|
|
}
|
|
sqlite3ReleaseTempRange(pParse, regBase, nCol);
|
|
return regBase;
|
|
@@ -115741,6 +124841,18 @@ static void typeofFunc(
|
|
sqlite3_result_text(context, azType[i], -1, SQLITE_STATIC);
|
|
}
|
|
|
|
+/* subtype(X)
|
|
+**
|
|
+** Return the subtype of X
|
|
+*/
|
|
+static void subtypeFunc(
|
|
+ sqlite3_context *context,
|
|
+ int argc,
|
|
+ sqlite3_value **argv
|
|
+){
|
|
+ UNUSED_PARAMETER(argc);
|
|
+ sqlite3_result_int(context, sqlite3_value_subtype(argv[0]));
|
|
+}
|
|
|
|
/*
|
|
** Implementation of the length() function
|
|
@@ -115785,7 +124897,7 @@ static void lengthFunc(
|
|
** Implementation of the abs() function.
|
|
**
|
|
** IMP: R-23979-26855 The abs(X) function returns the absolute value of
|
|
-** the numeric argument X.
|
|
+** the numeric argument X.
|
|
*/
|
|
static void absFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
|
|
assert( argc==1 );
|
|
@@ -115802,7 +124914,7 @@ static void absFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
|
|
return;
|
|
}
|
|
iVal = -iVal;
|
|
- }
|
|
+ }
|
|
sqlite3_result_int64(context, iVal);
|
|
break;
|
|
}
|
|
@@ -115902,7 +125014,7 @@ static void instrFunc(
|
|
}
|
|
|
|
/*
|
|
-** Implementation of the printf() function.
|
|
+** Implementation of the printf() (a.k.a. format()) SQL function.
|
|
*/
|
|
static void printfFunc(
|
|
sqlite3_context *context,
|
|
@@ -116054,7 +125166,7 @@ static void roundFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
|
|
*/
|
|
if( r<-4503599627370496.0 || r>+4503599627370496.0 ){
|
|
/* The value has no fractional part so there is nothing to round */
|
|
- }else if( n==0 ){
|
|
+ }else if( n==0 ){
|
|
r = (double)((sqlite_int64)(r+(r<0?-0.5:+0.5)));
|
|
}else{
|
|
zBuf = sqlite3_mprintf("%.*f",n,r);
|
|
@@ -116147,7 +125259,7 @@ static void lowerFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
|
|
#define noopFunc versionFunc /* Substitute function - never called */
|
|
|
|
/*
|
|
-** Implementation of random(). Return a random integer.
|
|
+** Implementation of random(). Return a random integer.
|
|
*/
|
|
static void randomFunc(
|
|
sqlite3_context *context,
|
|
@@ -116158,11 +125270,11 @@ static void randomFunc(
|
|
UNUSED_PARAMETER2(NotUsed, NotUsed2);
|
|
sqlite3_randomness(sizeof(r), &r);
|
|
if( r<0 ){
|
|
- /* We need to prevent a random number of 0x8000000000000000
|
|
+ /* We need to prevent a random number of 0x8000000000000000
|
|
** (or -9223372036854775808) since when you do abs() of that
|
|
** number of you get the same value back again. To do this
|
|
** in a way that is testable, mask the sign bit off of negative
|
|
- ** values, resulting in a positive value. Then take the
|
|
+ ** values, resulting in a positive value. Then take the
|
|
** 2s complement of that positive value. The end result can
|
|
** therefore be no less than -9223372036854775807.
|
|
*/
|
|
@@ -116200,8 +125312,8 @@ static void randomBlob(
|
|
** value is the same as the sqlite3_last_insert_rowid() API function.
|
|
*/
|
|
static void last_insert_rowid(
|
|
- sqlite3_context *context,
|
|
- int NotUsed,
|
|
+ sqlite3_context *context,
|
|
+ int NotUsed,
|
|
sqlite3_value **NotUsed2
|
|
){
|
|
sqlite3 *db = sqlite3_context_db_handle(context);
|
|
@@ -116215,9 +125327,9 @@ static void last_insert_rowid(
|
|
/*
|
|
** Implementation of the changes() SQL function.
|
|
**
|
|
-** IMP: R-62073-11209 The changes() SQL function is a wrapper
|
|
-** around the sqlite3_changes() C/C++ function and hence follows the same
|
|
-** rules for counting changes.
|
|
+** IMP: R-32760-32347 The changes() SQL function is a wrapper
|
|
+** around the sqlite3_changes64() C/C++ function and hence follows the
|
|
+** same rules for counting changes.
|
|
*/
|
|
static void changes(
|
|
sqlite3_context *context,
|
|
@@ -116226,12 +125338,12 @@ static void changes(
|
|
){
|
|
sqlite3 *db = sqlite3_context_db_handle(context);
|
|
UNUSED_PARAMETER2(NotUsed, NotUsed2);
|
|
- sqlite3_result_int(context, sqlite3_changes(db));
|
|
+ sqlite3_result_int64(context, sqlite3_changes64(db));
|
|
}
|
|
|
|
/*
|
|
** Implementation of the total_changes() SQL function. The return value is
|
|
-** the same as the sqlite3_total_changes() API function.
|
|
+** the same as the sqlite3_total_changes64() API function.
|
|
*/
|
|
static void total_changes(
|
|
sqlite3_context *context,
|
|
@@ -116240,9 +125352,9 @@ static void total_changes(
|
|
){
|
|
sqlite3 *db = sqlite3_context_db_handle(context);
|
|
UNUSED_PARAMETER2(NotUsed, NotUsed2);
|
|
- /* IMP: R-52756-41993 This function is a wrapper around the
|
|
- ** sqlite3_total_changes() C/C++ interface. */
|
|
- sqlite3_result_int(context, sqlite3_total_changes(db));
|
|
+ /* IMP: R-11217-42568 This function is a wrapper around the
|
|
+ ** sqlite3_total_changes64() C/C++ interface. */
|
|
+ sqlite3_result_int64(context, sqlite3_total_changes64(db));
|
|
}
|
|
|
|
/*
|
|
@@ -116309,7 +125421,7 @@ static const struct compareInfo likeInfoAlt = { '%', '_', 0, 0 };
|
|
** it the last character in the list.
|
|
**
|
|
** Like matching rules:
|
|
-**
|
|
+**
|
|
** '%' Matches any sequence of zero or more characters
|
|
**
|
|
*** '_' Matches any one character
|
|
@@ -116332,13 +125444,14 @@ static int patternCompare(
|
|
u32 matchAll = pInfo->matchAll; /* "*" or "%" */
|
|
u8 noCase = pInfo->noCase; /* True if uppercase==lowercase */
|
|
const u8 *zEscaped = 0; /* One past the last escaped input char */
|
|
-
|
|
+
|
|
while( (c = Utf8Read(zPattern))!=0 ){
|
|
if( c==matchAll ){ /* Match "*" */
|
|
/* Skip over multiple "*" characters in the pattern. If there
|
|
** are also "?" characters, skip those as well, but consume a
|
|
** single character of the input string for each "?" skipped */
|
|
- while( (c=Utf8Read(zPattern)) == matchAll || c == matchOne ){
|
|
+ while( (c=Utf8Read(zPattern)) == matchAll
|
|
+ || (c == matchOne && matchOne!=0) ){
|
|
if( c==matchOne && sqlite3Utf8Read(&zString)==0 ){
|
|
return SQLITE_NOWILDCARDMATCH;
|
|
}
|
|
@@ -116371,7 +125484,7 @@ static int patternCompare(
|
|
** c but in the other case and search the input string for either
|
|
** c or cx.
|
|
*/
|
|
- if( c<=0x80 ){
|
|
+ if( c<0x80 ){
|
|
char zStop[3];
|
|
int bMatch;
|
|
if( noCase ){
|
|
@@ -116454,7 +125567,13 @@ static int patternCompare(
|
|
** non-zero if there is no match.
|
|
*/
|
|
SQLITE_API int sqlite3_strglob(const char *zGlobPattern, const char *zString){
|
|
- return patternCompare((u8*)zGlobPattern, (u8*)zString, &globInfo, '[');
|
|
+ if( zString==0 ){
|
|
+ return zGlobPattern!=0;
|
|
+ }else if( zGlobPattern==0 ){
|
|
+ return 1;
|
|
+ }else {
|
|
+ return patternCompare((u8*)zGlobPattern, (u8*)zString, &globInfo, '[');
|
|
+ }
|
|
}
|
|
|
|
/*
|
|
@@ -116462,7 +125581,13 @@ SQLITE_API int sqlite3_strglob(const char *zGlobPattern, const char *zString){
|
|
** a miss - like strcmp().
|
|
*/
|
|
SQLITE_API int sqlite3_strlike(const char *zPattern, const char *zStr, unsigned int esc){
|
|
- return patternCompare((u8*)zPattern, (u8*)zStr, &likeInfoNorm, esc);
|
|
+ if( zStr==0 ){
|
|
+ return zPattern!=0;
|
|
+ }else if( zPattern==0 ){
|
|
+ return 1;
|
|
+ }else{
|
|
+ return patternCompare((u8*)zPattern, (u8*)zStr, &likeInfoNorm, esc);
|
|
+ }
|
|
}
|
|
|
|
/*
|
|
@@ -116488,8 +125613,8 @@ SQLITE_API int sqlite3_like_count = 0;
|
|
** the GLOB operator.
|
|
*/
|
|
static void likeFunc(
|
|
- sqlite3_context *context,
|
|
- int argc,
|
|
+ sqlite3_context *context,
|
|
+ int argc,
|
|
sqlite3_value **argv
|
|
){
|
|
const unsigned char *zA, *zB;
|
|
@@ -116497,6 +125622,7 @@ static void likeFunc(
|
|
int nPat;
|
|
sqlite3 *db = sqlite3_context_db_handle(context);
|
|
struct compareInfo *pInfo = sqlite3_user_data(context);
|
|
+ struct compareInfo backupInfo;
|
|
|
|
#ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS
|
|
if( sqlite3_value_type(argv[0])==SQLITE_BLOB
|
|
@@ -116527,11 +125653,17 @@ static void likeFunc(
|
|
const unsigned char *zEsc = sqlite3_value_text(argv[2]);
|
|
if( zEsc==0 ) return;
|
|
if( sqlite3Utf8CharLen((char*)zEsc, -1)!=1 ){
|
|
- sqlite3_result_error(context,
|
|
+ sqlite3_result_error(context,
|
|
"ESCAPE expression must be a single character", -1);
|
|
return;
|
|
}
|
|
escape = sqlite3Utf8Read(&zEsc);
|
|
+ if( escape==pInfo->matchAll || escape==pInfo->matchOne ){
|
|
+ memcpy(&backupInfo, pInfo, sizeof(backupInfo));
|
|
+ pInfo = &backupInfo;
|
|
+ if( escape==pInfo->matchAll ) pInfo->matchAll = 0;
|
|
+ if( escape==pInfo->matchOne ) pInfo->matchOne = 0;
|
|
+ }
|
|
}else{
|
|
escape = pInfo->matchSet;
|
|
}
|
|
@@ -116634,8 +125766,8 @@ static void compileoptionusedFunc(
|
|
#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
|
|
|
|
/*
|
|
-** Implementation of the sqlite_compileoption_get() function.
|
|
-** The result is a string that identifies the compiler options
|
|
+** Implementation of the sqlite_compileoption_get() function.
|
|
+** The result is a string that identifies the compiler options
|
|
** used to build SQLite.
|
|
*/
|
|
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
|
|
@@ -116659,43 +125791,46 @@ static void compileoptiongetFunc(
|
|
** digits. */
|
|
static const char hexdigits[] = {
|
|
'0', '1', '2', '3', '4', '5', '6', '7',
|
|
- '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
|
|
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
|
|
};
|
|
|
|
/*
|
|
-** Implementation of the QUOTE() function. This function takes a single
|
|
-** argument. If the argument is numeric, the return value is the same as
|
|
-** the argument. If the argument is NULL, the return value is the string
|
|
-** "NULL". Otherwise, the argument is enclosed in single quotes with
|
|
-** single-quote escapes.
|
|
+** Append to pStr text that is the SQL literal representation of the
|
|
+** value contained in pValue.
|
|
*/
|
|
-static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
|
|
- assert( argc==1 );
|
|
- UNUSED_PARAMETER(argc);
|
|
- switch( sqlite3_value_type(argv[0]) ){
|
|
+SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue){
|
|
+ /* As currently implemented, the string must be initially empty.
|
|
+ ** we might relax this requirement in the future, but that will
|
|
+ ** require enhancements to the implementation. */
|
|
+ assert( pStr!=0 && pStr->nChar==0 );
|
|
+
|
|
+ switch( sqlite3_value_type(pValue) ){
|
|
case SQLITE_FLOAT: {
|
|
double r1, r2;
|
|
- char zBuf[50];
|
|
- r1 = sqlite3_value_double(argv[0]);
|
|
- sqlite3_snprintf(sizeof(zBuf), zBuf, "%!.15g", r1);
|
|
- sqlite3AtoF(zBuf, &r2, 20, SQLITE_UTF8);
|
|
- if( r1!=r2 ){
|
|
- sqlite3_snprintf(sizeof(zBuf), zBuf, "%!.20e", r1);
|
|
+ const char *zVal;
|
|
+ r1 = sqlite3_value_double(pValue);
|
|
+ sqlite3_str_appendf(pStr, "%!.15g", r1);
|
|
+ zVal = sqlite3_str_value(pStr);
|
|
+ if( zVal ){
|
|
+ sqlite3AtoF(zVal, &r2, pStr->nChar, SQLITE_UTF8);
|
|
+ if( r1!=r2 ){
|
|
+ sqlite3_str_reset(pStr);
|
|
+ sqlite3_str_appendf(pStr, "%!.20e", r1);
|
|
+ }
|
|
}
|
|
- sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
|
|
break;
|
|
}
|
|
case SQLITE_INTEGER: {
|
|
- sqlite3_result_value(context, argv[0]);
|
|
+ sqlite3_str_appendf(pStr, "%lld", sqlite3_value_int64(pValue));
|
|
break;
|
|
}
|
|
case SQLITE_BLOB: {
|
|
- char *zText = 0;
|
|
- char const *zBlob = sqlite3_value_blob(argv[0]);
|
|
- int nBlob = sqlite3_value_bytes(argv[0]);
|
|
- assert( zBlob==sqlite3_value_blob(argv[0]) ); /* No encoding change */
|
|
- zText = (char *)contextMalloc(context, (2*(i64)nBlob)+4);
|
|
- if( zText ){
|
|
+ char const *zBlob = sqlite3_value_blob(pValue);
|
|
+ i64 nBlob = sqlite3_value_bytes(pValue);
|
|
+ assert( zBlob==sqlite3_value_blob(pValue) ); /* No encoding change */
|
|
+ sqlite3StrAccumEnlarge(pStr, nBlob*2 + 4);
|
|
+ if( pStr->accError==0 ){
|
|
+ char *zText = pStr->zText;
|
|
int i;
|
|
for(i=0; i<nBlob; i++){
|
|
zText[(i*2)+2] = hexdigits[(zBlob[i]>>4)&0x0F];
|
|
@@ -116705,45 +125840,51 @@ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
|
|
zText[(nBlob*2)+3] = '\0';
|
|
zText[0] = 'X';
|
|
zText[1] = '\'';
|
|
- sqlite3_result_text(context, zText, -1, SQLITE_TRANSIENT);
|
|
- sqlite3_free(zText);
|
|
+ pStr->nChar = nBlob*2 + 3;
|
|
}
|
|
break;
|
|
}
|
|
case SQLITE_TEXT: {
|
|
- int i,j;
|
|
- u64 n;
|
|
- const unsigned char *zArg = sqlite3_value_text(argv[0]);
|
|
- char *z;
|
|
-
|
|
- if( zArg==0 ) return;
|
|
- for(i=0, n=0; zArg[i]; i++){ if( zArg[i]=='\'' ) n++; }
|
|
- z = contextMalloc(context, ((i64)i)+((i64)n)+3);
|
|
- if( z ){
|
|
- z[0] = '\'';
|
|
- for(i=0, j=1; zArg[i]; i++){
|
|
- z[j++] = zArg[i];
|
|
- if( zArg[i]=='\'' ){
|
|
- z[j++] = '\'';
|
|
- }
|
|
- }
|
|
- z[j++] = '\'';
|
|
- z[j] = 0;
|
|
- sqlite3_result_text(context, z, j, sqlite3_free);
|
|
- }
|
|
+ const unsigned char *zArg = sqlite3_value_text(pValue);
|
|
+ sqlite3_str_appendf(pStr, "%Q", zArg);
|
|
break;
|
|
}
|
|
default: {
|
|
- assert( sqlite3_value_type(argv[0])==SQLITE_NULL );
|
|
- sqlite3_result_text(context, "NULL", 4, SQLITE_STATIC);
|
|
+ assert( sqlite3_value_type(pValue)==SQLITE_NULL );
|
|
+ sqlite3_str_append(pStr, "NULL", 4);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
+/*
|
|
+** Implementation of the QUOTE() function.
|
|
+**
|
|
+** The quote(X) function returns the text of an SQL literal which is the
|
|
+** value of its argument suitable for inclusion into an SQL statement.
|
|
+** Strings are surrounded by single-quotes with escapes on interior quotes
|
|
+** as needed. BLOBs are encoded as hexadecimal literals. Strings with
|
|
+** embedded NUL characters cannot be represented as string literals in SQL
|
|
+** and hence the returned string literal is truncated prior to the first NUL.
|
|
+*/
|
|
+static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
|
|
+ sqlite3_str str;
|
|
+ sqlite3 *db = sqlite3_context_db_handle(context);
|
|
+ assert( argc==1 );
|
|
+ UNUSED_PARAMETER(argc);
|
|
+ sqlite3StrAccumInit(&str, db, 0, 0, db->aLimit[SQLITE_LIMIT_LENGTH]);
|
|
+ sqlite3QuoteValue(&str,argv[0]);
|
|
+ sqlite3_result_text(context, sqlite3StrAccumFinish(&str), str.nChar,
|
|
+ SQLITE_DYNAMIC);
|
|
+ if( str.accError!=SQLITE_OK ){
|
|
+ sqlite3_result_null(context);
|
|
+ sqlite3_result_error_code(context, str.accError);
|
|
+ }
|
|
+}
|
|
+
|
|
/*
|
|
** The unicode() function. Return the integer unicode code-point value
|
|
-** for the first character of the input string.
|
|
+** for the first character of the input string.
|
|
*/
|
|
static void unicodeFunc(
|
|
sqlite3_context *context,
|
|
@@ -116826,6 +125967,96 @@ static void hexFunc(
|
|
}
|
|
}
|
|
|
|
+/*
|
|
+** Buffer zStr contains nStr bytes of utf-8 encoded text. Return 1 if zStr
|
|
+** contains character ch, or 0 if it does not.
|
|
+*/
|
|
+static int strContainsChar(const u8 *zStr, int nStr, u32 ch){
|
|
+ const u8 *zEnd = &zStr[nStr];
|
|
+ const u8 *z = zStr;
|
|
+ while( z<zEnd ){
|
|
+ u32 tst = Utf8Read(z);
|
|
+ if( tst==ch ) return 1;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*
|
|
+** The unhex() function. This function may be invoked with either one or
|
|
+** two arguments. In both cases the first argument is interpreted as text
|
|
+** a text value containing a set of pairs of hexadecimal digits which are
|
|
+** 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.
|
|
+**
|
|
+** 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
|
|
+** digits in the first argument. If any other character appears in the
|
|
+** first argument, or if one of the allowed characters appears between
|
|
+** two hexadecimal digits that make up a single byte, NULL is returned.
|
|
+**
|
|
+** The following expressions are all true:
|
|
+**
|
|
+** unhex('ABCD') IS x'ABCD'
|
|
+** unhex('AB CD') IS NULL
|
|
+** unhex('AB CD', ' ') IS x'ABCD'
|
|
+** unhex('A BCD', ' ') IS NULL
|
|
+*/
|
|
+static void unhexFunc(
|
|
+ sqlite3_context *pCtx,
|
|
+ int argc,
|
|
+ sqlite3_value **argv
|
|
+){
|
|
+ const u8 *zPass = (const u8*)"";
|
|
+ int nPass = 0;
|
|
+ const u8 *zHex = sqlite3_value_text(argv[0]);
|
|
+ int nHex = sqlite3_value_bytes(argv[0]);
|
|
+#ifdef SQLITE_DEBUG
|
|
+ const u8 *zEnd = zHex ? &zHex[nHex] : 0;
|
|
+#endif
|
|
+ u8 *pBlob = 0;
|
|
+ u8 *p = 0;
|
|
+
|
|
+ assert( argc==1 || argc==2 );
|
|
+ if( argc==2 ){
|
|
+ zPass = sqlite3_value_text(argv[1]);
|
|
+ nPass = sqlite3_value_bytes(argv[1]);
|
|
+ }
|
|
+ if( !zHex || !zPass ) return;
|
|
+
|
|
+ p = pBlob = contextMalloc(pCtx, (nHex/2)+1);
|
|
+ if( pBlob ){
|
|
+ u8 c; /* Most significant digit of next byte */
|
|
+ u8 d; /* Least significant digit of next byte */
|
|
+
|
|
+ while( (c = *zHex)!=0x00 ){
|
|
+ while( !sqlite3Isxdigit(c) ){
|
|
+ u32 ch = Utf8Read(zHex);
|
|
+ assert( zHex<=zEnd );
|
|
+ if( !strContainsChar(zPass, nPass, ch) ) goto unhex_null;
|
|
+ c = *zHex;
|
|
+ if( c==0x00 ) goto unhex_done;
|
|
+ }
|
|
+ zHex++;
|
|
+ assert( *zEnd==0x00 );
|
|
+ assert( zHex<=zEnd );
|
|
+ d = *(zHex++);
|
|
+ if( !sqlite3Isxdigit(d) ) goto unhex_null;
|
|
+ *(p++) = (sqlite3HexToInt(c)<<4) | sqlite3HexToInt(d);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ unhex_done:
|
|
+ sqlite3_result_blob(pCtx, pBlob, (p - pBlob), sqlite3_free);
|
|
+ return;
|
|
+
|
|
+ unhex_null:
|
|
+ sqlite3_free(pBlob);
|
|
+ return;
|
|
+}
|
|
+
|
|
+
|
|
/*
|
|
** The zeroblob(N) function returns a zero-filled blob of size N bytes.
|
|
*/
|
|
@@ -116899,7 +126130,7 @@ static void replaceFunc(
|
|
if( zOut==0 ){
|
|
return;
|
|
}
|
|
- loopLimit = nStr - nPattern;
|
|
+ loopLimit = nStr - nPattern;
|
|
cntExpand = 0;
|
|
for(i=j=0; i<=loopLimit; i++){
|
|
if( zStr[i]!=zPattern[0] || memcmp(&zStr[i], zPattern, nPattern) ){
|
|
@@ -116920,7 +126151,7 @@ static void replaceFunc(
|
|
** whose index is a power of two: 1, 2, 4, 8, 16, 32, ... */
|
|
u8 *zOld;
|
|
zOld = zOut;
|
|
- zOut = sqlite3_realloc64(zOut, (int)nOut + (nOut - nStr - 1));
|
|
+ zOut = sqlite3Realloc(zOut, (int)nOut + (nOut - nStr - 1));
|
|
if( zOut==0 ){
|
|
sqlite3_result_error_nomem(context);
|
|
sqlite3_free(zOld);
|
|
@@ -116952,10 +126183,10 @@ static void trimFunc(
|
|
){
|
|
const unsigned char *zIn; /* Input string */
|
|
const unsigned char *zCharSet; /* Set of characters to trim */
|
|
- int nIn; /* Number of bytes in input */
|
|
+ unsigned int nIn; /* Number of bytes in input */
|
|
int flags; /* 1: trimleft 2: trimright 3: trim */
|
|
int i; /* Loop counter */
|
|
- unsigned char *aLen = 0; /* Length of each character in zCharSet */
|
|
+ unsigned int *aLen = 0; /* Length of each character in zCharSet */
|
|
unsigned char **azChar = 0; /* Individual characters in zCharSet */
|
|
int nChar; /* Number of characters in zCharSet */
|
|
|
|
@@ -116964,13 +126195,13 @@ static void trimFunc(
|
|
}
|
|
zIn = sqlite3_value_text(argv[0]);
|
|
if( zIn==0 ) return;
|
|
- nIn = sqlite3_value_bytes(argv[0]);
|
|
+ nIn = (unsigned)sqlite3_value_bytes(argv[0]);
|
|
assert( zIn==sqlite3_value_text(argv[0]) );
|
|
if( argc==1 ){
|
|
- static const unsigned char lenOne[] = { 1 };
|
|
+ static const unsigned lenOne[] = { 1 };
|
|
static unsigned char * const azOne[] = { (u8*)" " };
|
|
nChar = 1;
|
|
- aLen = (u8*)lenOne;
|
|
+ aLen = (unsigned*)lenOne;
|
|
azChar = (unsigned char **)azOne;
|
|
zCharSet = 0;
|
|
}else if( (zCharSet = sqlite3_value_text(argv[1]))==0 ){
|
|
@@ -116981,15 +126212,16 @@ static void trimFunc(
|
|
SQLITE_SKIP_UTF8(z);
|
|
}
|
|
if( nChar>0 ){
|
|
- azChar = contextMalloc(context, ((i64)nChar)*(sizeof(char*)+1));
|
|
+ azChar = contextMalloc(context,
|
|
+ ((i64)nChar)*(sizeof(char*)+sizeof(unsigned)));
|
|
if( azChar==0 ){
|
|
return;
|
|
}
|
|
- aLen = (unsigned char*)&azChar[nChar];
|
|
+ aLen = (unsigned*)&azChar[nChar];
|
|
for(z=zCharSet, nChar=0; *z; nChar++){
|
|
azChar[nChar] = (unsigned char *)z;
|
|
SQLITE_SKIP_UTF8(z);
|
|
- aLen[nChar] = (u8)(z - azChar[nChar]);
|
|
+ aLen[nChar] = (unsigned)(z - azChar[nChar]);
|
|
}
|
|
}
|
|
}
|
|
@@ -116997,7 +126229,7 @@ static void trimFunc(
|
|
flags = SQLITE_PTR_TO_INT(sqlite3_user_data(context));
|
|
if( flags & 1 ){
|
|
while( nIn>0 ){
|
|
- int len = 0;
|
|
+ unsigned int len = 0;
|
|
for(i=0; i<nChar; i++){
|
|
len = aLen[i];
|
|
if( len<=nIn && memcmp(zIn, azChar[i], len)==0 ) break;
|
|
@@ -117009,7 +126241,7 @@ static void trimFunc(
|
|
}
|
|
if( flags & 2 ){
|
|
while( nIn>0 ){
|
|
- int len = 0;
|
|
+ unsigned int len = 0;
|
|
for(i=0; i<nChar; i++){
|
|
len = aLen[i];
|
|
if( len<=nIn && memcmp(&zIn[nIn-len],azChar[i],len)==0 ) break;
|
|
@@ -117042,6 +126274,9 @@ static void unknownFunc(
|
|
sqlite3_value **argv
|
|
){
|
|
/* no-op */
|
|
+ (void)context;
|
|
+ (void)argc;
|
|
+ (void)argv;
|
|
}
|
|
#endif /*SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION*/
|
|
|
|
@@ -117055,7 +126290,7 @@ static void unknownFunc(
|
|
** Compute the soundex encoding of a word.
|
|
**
|
|
** IMP: R-59782-00072 The soundex(X) function returns a string that is the
|
|
-** soundex encoding of the string X.
|
|
+** soundex encoding of the string X.
|
|
*/
|
|
static void soundexFunc(
|
|
sqlite3_context *context,
|
|
@@ -117144,7 +126379,7 @@ 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 */
|
|
+ i64 iSum; /* Integer sum */
|
|
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 */
|
|
@@ -117258,13 +126493,13 @@ static void countStep(sqlite3_context *context, int argc, sqlite3_value **argv){
|
|
|
|
#ifndef SQLITE_OMIT_DEPRECATED
|
|
/* The sqlite3_aggregate_count() function is deprecated. But just to make
|
|
- ** sure it still operates correctly, verify that its count agrees with our
|
|
+ ** sure it still operates correctly, verify that its count agrees with our
|
|
** internal count when using count(*) and when the total count can be
|
|
** expressed as a 32-bit integer. */
|
|
assert( argc==1 || p==0 || p->n>0x7fffffff || p->bInverse
|
|
|| p->n==sqlite3_aggregate_count(context) );
|
|
#endif
|
|
-}
|
|
+}
|
|
static void countFinalize(sqlite3_context *context){
|
|
CountCtx *p;
|
|
p = sqlite3_aggregate_context(context, 0);
|
|
@@ -117281,7 +126516,7 @@ static void countInverse(sqlite3_context *ctx, int argc, sqlite3_value **argv){
|
|
p->bInverse = 1;
|
|
#endif
|
|
}
|
|
-}
|
|
+}
|
|
#else
|
|
# define countInverse 0
|
|
#endif /* SQLITE_OMIT_WINDOWFUNC */
|
|
@@ -117290,8 +126525,8 @@ static void countInverse(sqlite3_context *ctx, int argc, sqlite3_value **argv){
|
|
** Routines to implement min() and max() aggregate functions.
|
|
*/
|
|
static void minmaxStep(
|
|
- sqlite3_context *context,
|
|
- int NotUsed,
|
|
+ sqlite3_context *context,
|
|
+ int NotUsed,
|
|
sqlite3_value **argv
|
|
){
|
|
Mem *pArg = (Mem *)argv[0];
|
|
@@ -117350,97 +126585,167 @@ static void minMaxFinalize(sqlite3_context *context){
|
|
|
|
/*
|
|
** group_concat(EXPR, ?SEPARATOR?)
|
|
+**
|
|
+** The SEPARATOR goes before the EXPR string. This is tragic. The
|
|
+** groupConcatInverse() implementation would have been easier if the
|
|
+** SEPARATOR were appended after EXPR. And the order is undocumented,
|
|
+** so we could change it, in theory. But the old behavior has been
|
|
+** around for so long that we dare not, for fear of breaking something.
|
|
*/
|
|
+typedef struct {
|
|
+ StrAccum str; /* The accumulated concatenation */
|
|
+#ifndef SQLITE_OMIT_WINDOWFUNC
|
|
+ int nAccum; /* Number of strings presently concatenated */
|
|
+ int nFirstSepLength; /* Used to detect separator length change */
|
|
+ /* If pnSepLengths!=0, refs an array of inter-string separator lengths,
|
|
+ ** stored as actually incorporated into presently accumulated result.
|
|
+ ** (Hence, its slots in use number nAccum-1 between method calls.)
|
|
+ ** If pnSepLengths==0, nFirstSepLength is the length used throughout.
|
|
+ */
|
|
+ int *pnSepLengths;
|
|
+#endif
|
|
+} GroupConcatCtx;
|
|
+
|
|
static void groupConcatStep(
|
|
sqlite3_context *context,
|
|
int argc,
|
|
sqlite3_value **argv
|
|
){
|
|
const char *zVal;
|
|
- StrAccum *pAccum;
|
|
+ GroupConcatCtx *pGCC;
|
|
const char *zSep;
|
|
int nVal, nSep;
|
|
assert( argc==1 || argc==2 );
|
|
if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
|
|
- pAccum = (StrAccum*)sqlite3_aggregate_context(context, sizeof(*pAccum));
|
|
-
|
|
- if( pAccum ){
|
|
+ pGCC = (GroupConcatCtx*)sqlite3_aggregate_context(context, sizeof(*pGCC));
|
|
+ if( pGCC ){
|
|
sqlite3 *db = sqlite3_context_db_handle(context);
|
|
- int firstTerm = pAccum->mxAlloc==0;
|
|
- pAccum->mxAlloc = db->aLimit[SQLITE_LIMIT_LENGTH];
|
|
- if( !firstTerm ){
|
|
- if( argc==2 ){
|
|
- zSep = (char*)sqlite3_value_text(argv[1]);
|
|
- nSep = sqlite3_value_bytes(argv[1]);
|
|
- }else{
|
|
- zSep = ",";
|
|
- nSep = 1;
|
|
+ int firstTerm = pGCC->str.mxAlloc==0;
|
|
+ pGCC->str.mxAlloc = db->aLimit[SQLITE_LIMIT_LENGTH];
|
|
+ if( argc==1 ){
|
|
+ if( !firstTerm ){
|
|
+ sqlite3_str_appendchar(&pGCC->str, 1, ',');
|
|
}
|
|
- if( zSep ) sqlite3_str_append(pAccum, zSep, nSep);
|
|
+#ifndef SQLITE_OMIT_WINDOWFUNC
|
|
+ else{
|
|
+ pGCC->nFirstSepLength = 1;
|
|
+ }
|
|
+#endif
|
|
+ }else if( !firstTerm ){
|
|
+ zSep = (char*)sqlite3_value_text(argv[1]);
|
|
+ nSep = sqlite3_value_bytes(argv[1]);
|
|
+ if( zSep ){
|
|
+ sqlite3_str_append(&pGCC->str, zSep, nSep);
|
|
+ }
|
|
+#ifndef SQLITE_OMIT_WINDOWFUNC
|
|
+ else{
|
|
+ nSep = 0;
|
|
+ }
|
|
+ if( nSep != pGCC->nFirstSepLength || pGCC->pnSepLengths != 0 ){
|
|
+ int *pnsl = pGCC->pnSepLengths;
|
|
+ if( pnsl == 0 ){
|
|
+ /* First separator length variation seen, start tracking them. */
|
|
+ pnsl = (int*)sqlite3_malloc64((pGCC->nAccum+1) * sizeof(int));
|
|
+ if( pnsl!=0 ){
|
|
+ int i = 0, nA = pGCC->nAccum-1;
|
|
+ while( i<nA ) pnsl[i++] = pGCC->nFirstSepLength;
|
|
+ }
|
|
+ }else{
|
|
+ pnsl = (int*)sqlite3_realloc64(pnsl, pGCC->nAccum * sizeof(int));
|
|
+ }
|
|
+ if( pnsl!=0 ){
|
|
+ if( ALWAYS(pGCC->nAccum>0) ){
|
|
+ pnsl[pGCC->nAccum-1] = nSep;
|
|
+ }
|
|
+ pGCC->pnSepLengths = pnsl;
|
|
+ }else{
|
|
+ sqlite3StrAccumSetError(&pGCC->str, SQLITE_NOMEM);
|
|
+ }
|
|
+ }
|
|
+#endif
|
|
+ }
|
|
+#ifndef SQLITE_OMIT_WINDOWFUNC
|
|
+ else{
|
|
+ pGCC->nFirstSepLength = sqlite3_value_bytes(argv[1]);
|
|
}
|
|
+ pGCC->nAccum += 1;
|
|
+#endif
|
|
zVal = (char*)sqlite3_value_text(argv[0]);
|
|
nVal = sqlite3_value_bytes(argv[0]);
|
|
- if( zVal ) sqlite3_str_append(pAccum, zVal, nVal);
|
|
+ if( zVal ) sqlite3_str_append(&pGCC->str, zVal, nVal);
|
|
}
|
|
}
|
|
+
|
|
#ifndef SQLITE_OMIT_WINDOWFUNC
|
|
static void groupConcatInverse(
|
|
sqlite3_context *context,
|
|
int argc,
|
|
sqlite3_value **argv
|
|
){
|
|
- int n;
|
|
- StrAccum *pAccum;
|
|
+ GroupConcatCtx *pGCC;
|
|
assert( argc==1 || argc==2 );
|
|
+ (void)argc; /* Suppress unused parameter warning */
|
|
if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
|
|
- pAccum = (StrAccum*)sqlite3_aggregate_context(context, sizeof(*pAccum));
|
|
- /* pAccum is always non-NULL since groupConcatStep() will have always
|
|
+ pGCC = (GroupConcatCtx*)sqlite3_aggregate_context(context, sizeof(*pGCC));
|
|
+ /* pGCC is always non-NULL since groupConcatStep() will have always
|
|
** run frist to initialize it */
|
|
- if( ALWAYS(pAccum) ){
|
|
- n = sqlite3_value_bytes(argv[0]);
|
|
- if( argc==2 ){
|
|
- n += sqlite3_value_bytes(argv[1]);
|
|
+ if( ALWAYS(pGCC) ){
|
|
+ int nVS;
|
|
+ /* Must call sqlite3_value_text() to convert the argument into text prior
|
|
+ ** to invoking sqlite3_value_bytes(), in case the text encoding is UTF16 */
|
|
+ (void)sqlite3_value_text(argv[0]);
|
|
+ nVS = sqlite3_value_bytes(argv[0]);
|
|
+ pGCC->nAccum -= 1;
|
|
+ if( pGCC->pnSepLengths!=0 ){
|
|
+ assert(pGCC->nAccum >= 0);
|
|
+ if( pGCC->nAccum>0 ){
|
|
+ nVS += *pGCC->pnSepLengths;
|
|
+ memmove(pGCC->pnSepLengths, pGCC->pnSepLengths+1,
|
|
+ (pGCC->nAccum-1)*sizeof(int));
|
|
+ }
|
|
}else{
|
|
- n++;
|
|
+ /* If removing single accumulated string, harmlessly over-do. */
|
|
+ nVS += pGCC->nFirstSepLength;
|
|
}
|
|
- if( n>=(int)pAccum->nChar ){
|
|
- pAccum->nChar = 0;
|
|
+ if( nVS>=(int)pGCC->str.nChar ){
|
|
+ pGCC->str.nChar = 0;
|
|
}else{
|
|
- pAccum->nChar -= n;
|
|
- memmove(pAccum->zText, &pAccum->zText[n], pAccum->nChar);
|
|
+ pGCC->str.nChar -= nVS;
|
|
+ memmove(pGCC->str.zText, &pGCC->str.zText[nVS], pGCC->str.nChar);
|
|
+ }
|
|
+ if( pGCC->str.nChar==0 ){
|
|
+ pGCC->str.mxAlloc = 0;
|
|
+ sqlite3_free(pGCC->pnSepLengths);
|
|
+ pGCC->pnSepLengths = 0;
|
|
}
|
|
- if( pAccum->nChar==0 ) pAccum->mxAlloc = 0;
|
|
}
|
|
}
|
|
#else
|
|
# define groupConcatInverse 0
|
|
#endif /* SQLITE_OMIT_WINDOWFUNC */
|
|
static void groupConcatFinalize(sqlite3_context *context){
|
|
- StrAccum *pAccum;
|
|
- pAccum = sqlite3_aggregate_context(context, 0);
|
|
- if( pAccum ){
|
|
- if( pAccum->accError==SQLITE_TOOBIG ){
|
|
- sqlite3_result_error_toobig(context);
|
|
- }else if( pAccum->accError==SQLITE_NOMEM ){
|
|
- sqlite3_result_error_nomem(context);
|
|
- }else{
|
|
- sqlite3_result_text(context, sqlite3StrAccumFinish(pAccum), -1,
|
|
- sqlite3_free);
|
|
- }
|
|
+ GroupConcatCtx *pGCC
|
|
+ = (GroupConcatCtx*)sqlite3_aggregate_context(context, 0);
|
|
+ if( pGCC ){
|
|
+ sqlite3ResultStrAccum(context, &pGCC->str);
|
|
+#ifndef SQLITE_OMIT_WINDOWFUNC
|
|
+ sqlite3_free(pGCC->pnSepLengths);
|
|
+#endif
|
|
}
|
|
}
|
|
#ifndef SQLITE_OMIT_WINDOWFUNC
|
|
static void groupConcatValue(sqlite3_context *context){
|
|
- sqlite3_str *pAccum;
|
|
- pAccum = (sqlite3_str*)sqlite3_aggregate_context(context, 0);
|
|
- if( pAccum ){
|
|
+ GroupConcatCtx *pGCC
|
|
+ = (GroupConcatCtx*)sqlite3_aggregate_context(context, 0);
|
|
+ if( pGCC ){
|
|
+ StrAccum *pAccum = &pGCC->str;
|
|
if( pAccum->accError==SQLITE_TOOBIG ){
|
|
sqlite3_result_error_toobig(context);
|
|
}else if( pAccum->accError==SQLITE_NOMEM ){
|
|
sqlite3_result_error_nomem(context);
|
|
- }else{
|
|
+ }else{
|
|
const char *zText = sqlite3_str_value(pAccum);
|
|
- sqlite3_result_text(context, zText, -1, SQLITE_TRANSIENT);
|
|
+ sqlite3_result_text(context, zText, pAccum->nChar, SQLITE_TRANSIENT);
|
|
}
|
|
}
|
|
}
|
|
@@ -117486,7 +126791,7 @@ SQLITE_PRIVATE void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive)
|
|
** pExpr points to an expression which implements a function. If
|
|
** it is appropriate to apply the LIKE optimization to that function
|
|
** then set aWc[0] through aWc[2] to the wildcard characters and the
|
|
-** escape character and then return TRUE. If the function is not a
|
|
+** escape character and then return TRUE. If the function is not a
|
|
** LIKE-style function then return FALSE.
|
|
**
|
|
** The expression "a LIKE b ESCAPE c" is only considered a valid LIKE
|
|
@@ -117502,11 +126807,14 @@ SQLITE_PRIVATE void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive)
|
|
SQLITE_PRIVATE int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){
|
|
FuncDef *pDef;
|
|
int nExpr;
|
|
- if( pExpr->op!=TK_FUNCTION || !pExpr->x.pList ){
|
|
+ assert( pExpr!=0 );
|
|
+ assert( pExpr->op==TK_FUNCTION );
|
|
+ assert( ExprUseXList(pExpr) );
|
|
+ if( !pExpr->x.pList ){
|
|
return 0;
|
|
}
|
|
- assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
|
|
nExpr = pExpr->x.pList->nExpr;
|
|
+ assert( !ExprHasProperty(pExpr, EP_IntValue) );
|
|
pDef = sqlite3FindFunction(db, pExpr->u.zToken, nExpr, SQLITE_UTF8, 0);
|
|
#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
|
|
if( pDef==0 ) return 0;
|
|
@@ -117514,29 +126822,240 @@ SQLITE_PRIVATE int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocas
|
|
if( NEVER(pDef==0) || (pDef->funcFlags & SQLITE_FUNC_LIKE)==0 ){
|
|
return 0;
|
|
}
|
|
+
|
|
+ /* The memcpy() statement assumes that the wildcard characters are
|
|
+ ** the first three statements in the compareInfo structure. The
|
|
+ ** asserts() that follow verify that assumption
|
|
+ */
|
|
+ memcpy(aWc, pDef->pUserData, 3);
|
|
+ assert( (char*)&likeInfoAlt == (char*)&likeInfoAlt.matchAll );
|
|
+ assert( &((char*)&likeInfoAlt)[1] == (char*)&likeInfoAlt.matchOne );
|
|
+ assert( &((char*)&likeInfoAlt)[2] == (char*)&likeInfoAlt.matchSet );
|
|
+
|
|
if( nExpr<3 ){
|
|
aWc[3] = 0;
|
|
}else{
|
|
Expr *pEscape = pExpr->x.pList->a[2].pExpr;
|
|
char *zEscape;
|
|
if( pEscape->op!=TK_STRING ) return 0;
|
|
+ assert( !ExprHasProperty(pEscape, EP_IntValue) );
|
|
zEscape = pEscape->u.zToken;
|
|
if( zEscape[0]==0 || zEscape[1]!=0 ) return 0;
|
|
+ if( zEscape[0]==aWc[0] ) return 0;
|
|
+ if( zEscape[0]==aWc[1] ) return 0;
|
|
aWc[3] = zEscape[0];
|
|
}
|
|
|
|
- /* The memcpy() statement assumes that the wildcard characters are
|
|
- ** the first three statements in the compareInfo structure. The
|
|
- ** asserts() that follow verify that assumption
|
|
- */
|
|
- memcpy(aWc, pDef->pUserData, 3);
|
|
- assert( (char*)&likeInfoAlt == (char*)&likeInfoAlt.matchAll );
|
|
- assert( &((char*)&likeInfoAlt)[1] == (char*)&likeInfoAlt.matchOne );
|
|
- assert( &((char*)&likeInfoAlt)[2] == (char*)&likeInfoAlt.matchSet );
|
|
*pIsNocase = (pDef->funcFlags & SQLITE_FUNC_CASE)==0;
|
|
return 1;
|
|
}
|
|
|
|
+/* Mathematical Constants */
|
|
+#ifndef M_PI
|
|
+# define M_PI 3.141592653589793238462643383279502884
|
|
+#endif
|
|
+#ifndef M_LN10
|
|
+# define M_LN10 2.302585092994045684017991454684364208
|
|
+#endif
|
|
+#ifndef M_LN2
|
|
+# define M_LN2 0.693147180559945309417232121458176568
|
|
+#endif
|
|
+
|
|
+
|
|
+/* Extra math functions that require linking with -lm
|
|
+*/
|
|
+#ifdef SQLITE_ENABLE_MATH_FUNCTIONS
|
|
+/*
|
|
+** Implementation SQL functions:
|
|
+**
|
|
+** ceil(X)
|
|
+** ceiling(X)
|
|
+** floor(X)
|
|
+**
|
|
+** The sqlite3_user_data() pointer is a pointer to the libm implementation
|
|
+** of the underlying C function.
|
|
+*/
|
|
+static void ceilingFunc(
|
|
+ sqlite3_context *context,
|
|
+ int argc,
|
|
+ sqlite3_value **argv
|
|
+){
|
|
+ assert( argc==1 );
|
|
+ switch( sqlite3_value_numeric_type(argv[0]) ){
|
|
+ case SQLITE_INTEGER: {
|
|
+ sqlite3_result_int64(context, sqlite3_value_int64(argv[0]));
|
|
+ break;
|
|
+ }
|
|
+ case SQLITE_FLOAT: {
|
|
+ double (*x)(double) = (double(*)(double))sqlite3_user_data(context);
|
|
+ sqlite3_result_double(context, x(sqlite3_value_double(argv[0])));
|
|
+ break;
|
|
+ }
|
|
+ default: {
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+** On some systems, ceil() and floor() are intrinsic function. You are
|
|
+** unable to take a pointer to these functions. Hence, we here wrap them
|
|
+** in our own actual functions.
|
|
+*/
|
|
+static double xCeil(double x){ return ceil(x); }
|
|
+static double xFloor(double x){ return floor(x); }
|
|
+
|
|
+/*
|
|
+** Some systems do not have log2() and log10() in their standard math
|
|
+** libraries.
|
|
+*/
|
|
+#if defined(HAVE_LOG10) && HAVE_LOG10==0
|
|
+# define log10(X) (0.4342944819032517867*log(X))
|
|
+#endif
|
|
+#if defined(HAVE_LOG2) && HAVE_LOG2==0
|
|
+# define log2(X) (1.442695040888963456*log(X))
|
|
+#endif
|
|
+
|
|
+
|
|
+/*
|
|
+** Implementation of SQL functions:
|
|
+**
|
|
+** ln(X) - natural logarithm
|
|
+** log(X) - log X base 10
|
|
+** log10(X) - log X base 10
|
|
+** log(B,X) - log X base B
|
|
+*/
|
|
+static void logFunc(
|
|
+ sqlite3_context *context,
|
|
+ int argc,
|
|
+ sqlite3_value **argv
|
|
+){
|
|
+ double x, b, ans;
|
|
+ assert( argc==1 || argc==2 );
|
|
+ switch( sqlite3_value_numeric_type(argv[0]) ){
|
|
+ case SQLITE_INTEGER:
|
|
+ case SQLITE_FLOAT:
|
|
+ x = sqlite3_value_double(argv[0]);
|
|
+ if( x<=0.0 ) return;
|
|
+ break;
|
|
+ default:
|
|
+ return;
|
|
+ }
|
|
+ if( argc==2 ){
|
|
+ switch( sqlite3_value_numeric_type(argv[0]) ){
|
|
+ case SQLITE_INTEGER:
|
|
+ case SQLITE_FLOAT:
|
|
+ b = log(x);
|
|
+ if( b<=0.0 ) return;
|
|
+ x = sqlite3_value_double(argv[1]);
|
|
+ if( x<=0.0 ) return;
|
|
+ break;
|
|
+ default:
|
|
+ return;
|
|
+ }
|
|
+ ans = log(x)/b;
|
|
+ }else{
|
|
+ switch( SQLITE_PTR_TO_INT(sqlite3_user_data(context)) ){
|
|
+ case 1:
|
|
+ ans = log10(x);
|
|
+ break;
|
|
+ case 2:
|
|
+ ans = log2(x);
|
|
+ break;
|
|
+ default:
|
|
+ ans = log(x);
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ sqlite3_result_double(context, ans);
|
|
+}
|
|
+
|
|
+/*
|
|
+** Functions to converts degrees to radians and radians to degrees.
|
|
+*/
|
|
+static double degToRad(double x){ return x*(M_PI/180.0); }
|
|
+static double radToDeg(double x){ return x*(180.0/M_PI); }
|
|
+
|
|
+/*
|
|
+** Implementation of 1-argument SQL math functions:
|
|
+**
|
|
+** exp(X) - Compute e to the X-th power
|
|
+*/
|
|
+static void math1Func(
|
|
+ sqlite3_context *context,
|
|
+ int argc,
|
|
+ sqlite3_value **argv
|
|
+){
|
|
+ int type0;
|
|
+ double v0, ans;
|
|
+ double (*x)(double);
|
|
+ assert( argc==1 );
|
|
+ type0 = sqlite3_value_numeric_type(argv[0]);
|
|
+ if( type0!=SQLITE_INTEGER && type0!=SQLITE_FLOAT ) return;
|
|
+ v0 = sqlite3_value_double(argv[0]);
|
|
+ x = (double(*)(double))sqlite3_user_data(context);
|
|
+ ans = x(v0);
|
|
+ sqlite3_result_double(context, ans);
|
|
+}
|
|
+
|
|
+/*
|
|
+** Implementation of 2-argument SQL math functions:
|
|
+**
|
|
+** power(X,Y) - Compute X to the Y-th power
|
|
+*/
|
|
+static void math2Func(
|
|
+ sqlite3_context *context,
|
|
+ int argc,
|
|
+ sqlite3_value **argv
|
|
+){
|
|
+ int type0, type1;
|
|
+ double v0, v1, ans;
|
|
+ double (*x)(double,double);
|
|
+ assert( argc==2 );
|
|
+ type0 = sqlite3_value_numeric_type(argv[0]);
|
|
+ if( type0!=SQLITE_INTEGER && type0!=SQLITE_FLOAT ) return;
|
|
+ type1 = sqlite3_value_numeric_type(argv[1]);
|
|
+ if( type1!=SQLITE_INTEGER && type1!=SQLITE_FLOAT ) return;
|
|
+ v0 = sqlite3_value_double(argv[0]);
|
|
+ v1 = sqlite3_value_double(argv[1]);
|
|
+ x = (double(*)(double,double))sqlite3_user_data(context);
|
|
+ ans = x(v0, v1);
|
|
+ sqlite3_result_double(context, ans);
|
|
+}
|
|
+
|
|
+/*
|
|
+** Implementation of 0-argument pi() function.
|
|
+*/
|
|
+static void piFunc(
|
|
+ sqlite3_context *context,
|
|
+ int argc,
|
|
+ sqlite3_value **argv
|
|
+){
|
|
+ assert( argc==0 );
|
|
+ (void)argv;
|
|
+ sqlite3_result_double(context, M_PI);
|
|
+}
|
|
+
|
|
+#endif /* SQLITE_ENABLE_MATH_FUNCTIONS */
|
|
+
|
|
+/*
|
|
+** Implementation of sign(X) function.
|
|
+*/
|
|
+static void signFunc(
|
|
+ sqlite3_context *context,
|
|
+ int argc,
|
|
+ sqlite3_value **argv
|
|
+){
|
|
+ int type0;
|
|
+ double x;
|
|
+ UNUSED_PARAMETER(argc);
|
|
+ assert( argc==1 );
|
|
+ type0 = sqlite3_value_numeric_type(argv[0]);
|
|
+ if( type0!=SQLITE_INTEGER && type0!=SQLITE_FLOAT ) return;
|
|
+ x = sqlite3_value_double(argv[0]);
|
|
+ sqlite3_result_int(context, x<0.0 ? -1 : x>0.0 ? +1 : 0);
|
|
+}
|
|
+
|
|
/*
|
|
** All of the FuncDef structures in the aBuiltinFunc[] array above
|
|
** to the global function hash table. This occurs at start-time (as
|
|
@@ -117557,12 +127076,12 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
|
|
*/
|
|
static FuncDef aBuiltinFunc[] = {
|
|
/***** Functions only available with SQLITE_TESTCTRL_INTERNAL_FUNCTIONS *****/
|
|
+#if !defined(SQLITE_UNTESTABLE)
|
|
TEST_FUNC(implies_nonnull_row, 2, INLINEFUNC_implies_nonnull_row, 0),
|
|
TEST_FUNC(expr_compare, 2, INLINEFUNC_expr_compare, 0),
|
|
TEST_FUNC(expr_implies_expr, 2, INLINEFUNC_expr_implies_expr, 0),
|
|
-#ifdef SQLITE_DEBUG
|
|
- TEST_FUNC(affinity, 1, INLINEFUNC_affinity, 0),
|
|
-#endif
|
|
+ TEST_FUNC(affinity, 1, INLINEFUNC_affinity, 0),
|
|
+#endif /* !defined(SQLITE_UNTESTABLE) */
|
|
/***** Regular functions *****/
|
|
#ifdef SQLITE_SOUNDEX
|
|
FUNCTION(soundex, 1, 0, 0, soundexFunc ),
|
|
@@ -117582,8 +127101,7 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
|
|
INLINE_FUNC(likelihood, 2, INLINEFUNC_unlikely, SQLITE_FUNC_UNLIKELY),
|
|
INLINE_FUNC(likely, 1, INLINEFUNC_unlikely, SQLITE_FUNC_UNLIKELY),
|
|
#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
|
|
- FUNCTION2(sqlite_offset, 1, 0, 0, noopFunc, SQLITE_FUNC_OFFSET|
|
|
- SQLITE_FUNC_TYPEOF),
|
|
+ INLINE_FUNC(sqlite_offset, 1, INLINEFUNC_sqlite_offset, 0 ),
|
|
#endif
|
|
FUNCTION(ltrim, 1, 1, 0, trimFunc ),
|
|
FUNCTION(ltrim, 2, 1, 0, trimFunc ),
|
|
@@ -117594,15 +127112,17 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
|
|
FUNCTION(min, -1, 0, 1, minmaxFunc ),
|
|
FUNCTION(min, 0, 0, 1, 0 ),
|
|
WAGGREGATE(min, 1, 0, 1, minmaxStep, minMaxFinalize, minMaxValue, 0,
|
|
- SQLITE_FUNC_MINMAX ),
|
|
+ SQLITE_FUNC_MINMAX|SQLITE_FUNC_ANYORDER ),
|
|
FUNCTION(max, -1, 1, 1, minmaxFunc ),
|
|
FUNCTION(max, 0, 1, 1, 0 ),
|
|
WAGGREGATE(max, 1, 1, 1, minmaxStep, minMaxFinalize, minMaxValue, 0,
|
|
- SQLITE_FUNC_MINMAX ),
|
|
+ SQLITE_FUNC_MINMAX|SQLITE_FUNC_ANYORDER ),
|
|
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),
|
|
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 ),
|
|
@@ -117613,7 +127133,9 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
|
|
FUNCTION(upper, 1, 0, 0, upperFunc ),
|
|
FUNCTION(lower, 1, 0, 0, lowerFunc ),
|
|
FUNCTION(hex, 1, 0, 0, hexFunc ),
|
|
- INLINE_FUNC(ifnull, 2, INLINEFUNC_coalesce, SQLITE_FUNC_COALESCE),
|
|
+ FUNCTION(unhex, 1, 0, 0, unhexFunc ),
|
|
+ FUNCTION(unhex, 2, 0, 0, unhexFunc ),
|
|
+ INLINE_FUNC(ifnull, 2, INLINEFUNC_coalesce, 0 ),
|
|
VFUNCTION(random, 0, 0, 0, randomFunc ),
|
|
VFUNCTION(randomblob, 1, 0, 0, randomBlob ),
|
|
FUNCTION(nullif, 2, 0, 1, nullifFunc ),
|
|
@@ -117628,18 +127150,21 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
|
|
FUNCTION(zeroblob, 1, 0, 0, zeroblobFunc ),
|
|
FUNCTION(substr, 2, 0, 0, substrFunc ),
|
|
FUNCTION(substr, 3, 0, 0, substrFunc ),
|
|
+ FUNCTION(substring, 2, 0, 0, substrFunc ),
|
|
+ FUNCTION(substring, 3, 0, 0, substrFunc ),
|
|
WAGGREGATE(sum, 1,0,0, sumStep, sumFinalize, sumFinalize, sumInverse, 0),
|
|
WAGGREGATE(total, 1,0,0, sumStep,totalFinalize,totalFinalize,sumInverse, 0),
|
|
WAGGREGATE(avg, 1,0,0, sumStep, avgFinalize, avgFinalize, sumInverse, 0),
|
|
- WAGGREGATE(count, 0,0,0, countStep,
|
|
- countFinalize, countFinalize, countInverse, SQLITE_FUNC_COUNT ),
|
|
- WAGGREGATE(count, 1,0,0, countStep,
|
|
- countFinalize, countFinalize, countInverse, 0 ),
|
|
- WAGGREGATE(group_concat, 1, 0, 0, groupConcatStep,
|
|
+ WAGGREGATE(count, 0,0,0, countStep,
|
|
+ countFinalize, countFinalize, countInverse,
|
|
+ SQLITE_FUNC_COUNT|SQLITE_FUNC_ANYORDER ),
|
|
+ WAGGREGATE(count, 1,0,0, countStep,
|
|
+ countFinalize, countFinalize, countInverse, SQLITE_FUNC_ANYORDER ),
|
|
+ WAGGREGATE(group_concat, 1, 0, 0, groupConcatStep,
|
|
groupConcatFinalize, groupConcatValue, groupConcatInverse, 0),
|
|
- WAGGREGATE(group_concat, 2, 0, 0, groupConcatStep,
|
|
+ WAGGREGATE(group_concat, 2, 0, 0, groupConcatStep,
|
|
groupConcatFinalize, groupConcatValue, groupConcatInverse, 0),
|
|
-
|
|
+
|
|
LIKEFUNC(glob, 2, &globInfo, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE),
|
|
#ifdef SQLITE_CASE_SENSITIVE_LIKE
|
|
LIKEFUNC(like, 2, &likeInfoAlt, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE),
|
|
@@ -117653,13 +127178,52 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
|
|
#endif
|
|
FUNCTION(coalesce, 1, 0, 0, 0 ),
|
|
FUNCTION(coalesce, 0, 0, 0, 0 ),
|
|
- INLINE_FUNC(coalesce, -1, INLINEFUNC_coalesce, SQLITE_FUNC_COALESCE),
|
|
+#ifdef SQLITE_ENABLE_MATH_FUNCTIONS
|
|
+ MFUNCTION(ceil, 1, xCeil, ceilingFunc ),
|
|
+ MFUNCTION(ceiling, 1, xCeil, ceilingFunc ),
|
|
+ MFUNCTION(floor, 1, xFloor, ceilingFunc ),
|
|
+#if SQLITE_HAVE_C99_MATH_FUNCS
|
|
+ MFUNCTION(trunc, 1, trunc, ceilingFunc ),
|
|
+#endif
|
|
+ FUNCTION(ln, 1, 0, 0, logFunc ),
|
|
+ FUNCTION(log, 1, 1, 0, logFunc ),
|
|
+ FUNCTION(log10, 1, 1, 0, logFunc ),
|
|
+ FUNCTION(log2, 1, 2, 0, logFunc ),
|
|
+ FUNCTION(log, 2, 0, 0, logFunc ),
|
|
+ MFUNCTION(exp, 1, exp, math1Func ),
|
|
+ MFUNCTION(pow, 2, pow, math2Func ),
|
|
+ MFUNCTION(power, 2, pow, math2Func ),
|
|
+ MFUNCTION(mod, 2, fmod, math2Func ),
|
|
+ MFUNCTION(acos, 1, acos, math1Func ),
|
|
+ MFUNCTION(asin, 1, asin, math1Func ),
|
|
+ MFUNCTION(atan, 1, atan, math1Func ),
|
|
+ MFUNCTION(atan2, 2, atan2, math2Func ),
|
|
+ MFUNCTION(cos, 1, cos, math1Func ),
|
|
+ MFUNCTION(sin, 1, sin, math1Func ),
|
|
+ MFUNCTION(tan, 1, tan, math1Func ),
|
|
+ MFUNCTION(cosh, 1, cosh, math1Func ),
|
|
+ MFUNCTION(sinh, 1, sinh, math1Func ),
|
|
+ MFUNCTION(tanh, 1, tanh, math1Func ),
|
|
+#if SQLITE_HAVE_C99_MATH_FUNCS
|
|
+ MFUNCTION(acosh, 1, acosh, math1Func ),
|
|
+ MFUNCTION(asinh, 1, asinh, math1Func ),
|
|
+ MFUNCTION(atanh, 1, atanh, math1Func ),
|
|
+#endif
|
|
+ MFUNCTION(sqrt, 1, sqrt, math1Func ),
|
|
+ MFUNCTION(radians, 1, degToRad, math1Func ),
|
|
+ MFUNCTION(degrees, 1, radToDeg, math1Func ),
|
|
+ FUNCTION(pi, 0, 0, 0, piFunc ),
|
|
+#endif /* SQLITE_ENABLE_MATH_FUNCTIONS */
|
|
+ FUNCTION(sign, 1, 0, 0, signFunc ),
|
|
+ INLINE_FUNC(coalesce, -1, INLINEFUNC_coalesce, 0 ),
|
|
+ INLINE_FUNC(iif, 3, INLINEFUNC_iif, 0 ),
|
|
};
|
|
#ifndef SQLITE_OMIT_ALTERTABLE
|
|
sqlite3AlterFunctions();
|
|
#endif
|
|
sqlite3WindowFunctions();
|
|
sqlite3RegisterDateTimeFunctions();
|
|
+ sqlite3RegisterJsonFunctions();
|
|
sqlite3InsertBuiltinFuncs(aBuiltinFunc, ArraySize(aBuiltinFunc));
|
|
|
|
#if 0 /* Enable to print out how the built-in functions are hashed */
|
|
@@ -117671,6 +127235,7 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
|
|
for(p=sqlite3BuiltinFunctions.a[i]; p; p=p->u.pHash){
|
|
int n = sqlite3Strlen30(p->zName);
|
|
int h = p->zName[0] + n;
|
|
+ assert( p->funcFlags & SQLITE_FUNC_BUILTIN );
|
|
printf(" %s(%d)", p->zName, h);
|
|
}
|
|
printf("\n");
|
|
@@ -117706,25 +127271,25 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
|
|
** Foreign keys in SQLite come in two flavours: deferred and immediate.
|
|
** If an immediate foreign key constraint is violated,
|
|
** SQLITE_CONSTRAINT_FOREIGNKEY is returned and the current
|
|
-** statement transaction rolled back. If a
|
|
-** deferred foreign key constraint is violated, no action is taken
|
|
-** immediately. However if the application attempts to commit the
|
|
+** statement transaction rolled back. If a
|
|
+** deferred foreign key constraint is violated, no action is taken
|
|
+** immediately. However if the application attempts to commit the
|
|
** transaction before fixing the constraint violation, the attempt fails.
|
|
**
|
|
** Deferred constraints are implemented using a simple counter associated
|
|
-** with the database handle. The counter is set to zero each time a
|
|
-** database transaction is opened. Each time a statement is executed
|
|
+** with the database handle. The counter is set to zero each time a
|
|
+** database transaction is opened. Each time a statement is executed
|
|
** that causes a foreign key violation, the counter is incremented. Each
|
|
** time a statement is executed that removes an existing violation from
|
|
** the database, the counter is decremented. When the transaction is
|
|
** committed, the commit fails if the current value of the counter is
|
|
** greater than zero. This scheme has two big drawbacks:
|
|
**
|
|
-** * When a commit fails due to a deferred foreign key constraint,
|
|
+** * When a commit fails due to a deferred foreign key constraint,
|
|
** there is no way to tell which foreign constraint is not satisfied,
|
|
** or which row it is not satisfied for.
|
|
**
|
|
-** * If the database contains foreign key violations when the
|
|
+** * If the database contains foreign key violations when the
|
|
** transaction is opened, this may cause the mechanism to malfunction.
|
|
**
|
|
** Despite these problems, this approach is adopted as it seems simpler
|
|
@@ -117736,26 +127301,26 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
|
|
** the parent table for a match. If none is found increment the
|
|
** constraint counter.
|
|
**
|
|
-** I.2) For each FK for which the table is the parent table,
|
|
+** I.2) For each FK for which the table is the parent table,
|
|
** search the child table for rows that correspond to the new
|
|
** row in the parent table. Decrement the counter for each row
|
|
** found (as the constraint is now satisfied).
|
|
**
|
|
** DELETE operations:
|
|
**
|
|
-** D.1) For each FK for which the table is the child table,
|
|
-** search the parent table for a row that corresponds to the
|
|
-** deleted row in the child table. If such a row is not found,
|
|
+** D.1) For each FK for which the table is the child table,
|
|
+** search the parent table for a row that corresponds to the
|
|
+** deleted row in the child table. If such a row is not found,
|
|
** decrement the counter.
|
|
**
|
|
-** D.2) For each FK for which the table is the parent table, search
|
|
-** the child table for rows that correspond to the deleted row
|
|
+** D.2) For each FK for which the table is the parent table, search
|
|
+** the child table for rows that correspond to the deleted row
|
|
** in the parent table. For each found increment the counter.
|
|
**
|
|
** UPDATE operations:
|
|
**
|
|
** An UPDATE command requires that all 4 steps above are taken, but only
|
|
-** for FK constraints for which the affected columns are actually
|
|
+** for FK constraints for which the affected columns are actually
|
|
** modified (values must be compared at runtime).
|
|
**
|
|
** Note that I.1 and D.1 are very similar operations, as are I.2 and D.2.
|
|
@@ -117764,10 +127329,10 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
|
|
** For the purposes of immediate FK constraints, the OR REPLACE conflict
|
|
** resolution is considered to delete rows before the new row is inserted.
|
|
** If a delete caused by OR REPLACE violates an FK constraint, an exception
|
|
-** is thrown, even if the FK constraint would be satisfied after the new
|
|
+** is thrown, even if the FK constraint would be satisfied after the new
|
|
** row is inserted.
|
|
**
|
|
-** Immediate constraints are usually handled similarly. The only difference
|
|
+** Immediate constraints are usually handled similarly. The only difference
|
|
** is that the counter used is stored as part of each individual statement
|
|
** object (struct Vdbe). If, after the statement has run, its immediate
|
|
** constraint counter is greater than zero,
|
|
@@ -117778,7 +127343,7 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
|
|
** INSERT violates a foreign key constraint. This is necessary as such
|
|
** an INSERT does not open a statement transaction.
|
|
**
|
|
-** TODO: How should dropping a table be handled? How should renaming a
|
|
+** TODO: How should dropping a table be handled? How should renaming a
|
|
** table be handled?
|
|
**
|
|
**
|
|
@@ -117789,7 +127354,7 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
|
|
** for those two operations needs to know whether or not the operation
|
|
** requires any FK processing and, if so, which columns of the original
|
|
** row are required by the FK processing VDBE code (i.e. if FKs were
|
|
-** implemented using triggers, which of the old.* columns would be
|
|
+** implemented using triggers, which of the old.* columns would be
|
|
** accessed). No information is required by the code-generator before
|
|
** coding an INSERT operation. The functions used by the UPDATE/DELETE
|
|
** generation code to query for this information are:
|
|
@@ -117826,13 +127391,13 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
|
|
/*
|
|
** A foreign key constraint requires that the key columns in the parent
|
|
** table are collectively subject to a UNIQUE or PRIMARY KEY constraint.
|
|
-** Given that pParent is the parent table for foreign key constraint pFKey,
|
|
-** search the schema for a unique index on the parent key columns.
|
|
+** Given that pParent is the parent table for foreign key constraint pFKey,
|
|
+** search the schema for a unique index on the parent key columns.
|
|
+**
|
|
+** If successful, zero is returned. If the parent key is an INTEGER PRIMARY
|
|
+** KEY column, then output variable *ppIdx is set to NULL. Otherwise, *ppIdx
|
|
+** is set to point to the unique index.
|
|
**
|
|
-** If successful, zero is returned. If the parent key is an INTEGER PRIMARY
|
|
-** KEY column, then output variable *ppIdx is set to NULL. Otherwise, *ppIdx
|
|
-** is set to point to the unique index.
|
|
-**
|
|
** If the parent key consists of a single column (the foreign key constraint
|
|
** is not a composite foreign key), output variable *paiCol is set to NULL.
|
|
** Otherwise, it is set to point to an allocated array of size N, where
|
|
@@ -117855,8 +127420,8 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
|
|
** PRIMARY KEY, or
|
|
**
|
|
** 4) No parent key columns were provided explicitly as part of the
|
|
-** foreign key definition, and the PRIMARY KEY of the parent table
|
|
-** consists of a different number of columns to the child key in
|
|
+** foreign key definition, and the PRIMARY KEY of the parent table
|
|
+** consists of a different number of columns to the child key in
|
|
** the child table.
|
|
**
|
|
** then non-zero is returned, and a "foreign key mismatch" error loaded
|
|
@@ -117880,9 +127445,9 @@ SQLITE_PRIVATE int sqlite3FkLocateIndex(
|
|
assert( !paiCol || *paiCol==0 );
|
|
assert( pParse );
|
|
|
|
- /* If this is a non-composite (single column) foreign key, check if it
|
|
- ** maps to the INTEGER PRIMARY KEY of table pParent. If so, leave *ppIdx
|
|
- ** and *paiCol set to zero and return early.
|
|
+ /* If this is a non-composite (single column) foreign key, check if it
|
|
+ ** maps to the INTEGER PRIMARY KEY of table pParent. If so, leave *ppIdx
|
|
+ ** and *paiCol set to zero and return early.
|
|
**
|
|
** Otherwise, for a composite foreign key (more than one column), allocate
|
|
** space for the aiCol array (returned via output parameter *paiCol).
|
|
@@ -117891,14 +127456,16 @@ SQLITE_PRIVATE int sqlite3FkLocateIndex(
|
|
if( nCol==1 ){
|
|
/* The FK maps to the IPK if any of the following are true:
|
|
**
|
|
- ** 1) There is an INTEGER PRIMARY KEY column and the FK is implicitly
|
|
+ ** 1) There is an INTEGER PRIMARY KEY column and the FK is implicitly
|
|
** mapped to the primary key of table pParent, or
|
|
** 2) The FK is explicitly mapped to a column declared as INTEGER
|
|
** PRIMARY KEY.
|
|
*/
|
|
if( pParent->iPKey>=0 ){
|
|
if( !zKey ) return 0;
|
|
- if( !sqlite3StrICmp(pParent->aCol[pParent->iPKey].zName, zKey) ) return 0;
|
|
+ if( !sqlite3StrICmp(pParent->aCol[pParent->iPKey].zCnName, zKey) ){
|
|
+ return 0;
|
|
+ }
|
|
}
|
|
}else if( paiCol ){
|
|
assert( nCol>1 );
|
|
@@ -117908,14 +127475,14 @@ SQLITE_PRIVATE int sqlite3FkLocateIndex(
|
|
}
|
|
|
|
for(pIdx=pParent->pIndex; pIdx; pIdx=pIdx->pNext){
|
|
- if( pIdx->nKeyCol==nCol && IsUniqueIndex(pIdx) && pIdx->pPartIdxWhere==0 ){
|
|
+ if( pIdx->nKeyCol==nCol && IsUniqueIndex(pIdx) && pIdx->pPartIdxWhere==0 ){
|
|
/* pIdx is a UNIQUE index (or a PRIMARY KEY) and has the right number
|
|
** of columns. If each indexed column corresponds to a foreign key
|
|
** column of pFKey, then this index is a winner. */
|
|
|
|
if( zKey==0 ){
|
|
- /* If zKey is NULL, then this foreign key is implicitly mapped to
|
|
- ** the PRIMARY KEY of table pParent. The PRIMARY KEY index may be
|
|
+ /* If zKey is NULL, then this foreign key is implicitly mapped to
|
|
+ ** the PRIMARY KEY of table pParent. The PRIMARY KEY index may be
|
|
** identified by the test. */
|
|
if( IsPrimaryKeyIndex(pIdx) ){
|
|
if( aiCol ){
|
|
@@ -117940,11 +127507,11 @@ SQLITE_PRIVATE int sqlite3FkLocateIndex(
|
|
/* If the index uses a collation sequence that is different from
|
|
** the default collation sequence for the column, this index is
|
|
** unusable. Bail out early in this case. */
|
|
- zDfltColl = pParent->aCol[iCol].zColl;
|
|
+ zDfltColl = sqlite3ColumnColl(&pParent->aCol[iCol]);
|
|
if( !zDfltColl ) zDfltColl = sqlite3StrBINARY;
|
|
if( sqlite3StrICmp(pIdx->azColl[i], zDfltColl) ) break;
|
|
|
|
- zIdxCol = pParent->aCol[iCol].zName;
|
|
+ zIdxCol = pParent->aCol[iCol].zCnName;
|
|
for(j=0; j<nCol; j++){
|
|
if( sqlite3StrICmp(pFKey->aCol[j].zCol, zIdxCol)==0 ){
|
|
if( aiCol ) aiCol[i] = pFKey->aCol[j].iFrom;
|
|
@@ -117973,15 +127540,15 @@ SQLITE_PRIVATE int sqlite3FkLocateIndex(
|
|
}
|
|
|
|
/*
|
|
-** This function is called when a row is inserted into or deleted from the
|
|
-** child table of foreign key constraint pFKey. If an SQL UPDATE is executed
|
|
+** This function is called when a row is inserted into or deleted from the
|
|
+** child table of foreign key constraint pFKey. If an SQL UPDATE is executed
|
|
** on the child table of pFKey, this function is invoked twice for each row
|
|
** affected - once to "delete" the old row, and then again to "insert" the
|
|
** new row.
|
|
**
|
|
** Each time it is called, this function generates VDBE code to locate the
|
|
-** row in the parent table that corresponds to the row being inserted into
|
|
-** or deleted from the child table. If the parent row can be found, no
|
|
+** row in the parent table that corresponds to the row being inserted into
|
|
+** or deleted from the child table. If the parent row can be found, no
|
|
** special action is taken. Otherwise, if the parent row can *not* be
|
|
** found in the parent table:
|
|
**
|
|
@@ -117995,7 +127562,7 @@ SQLITE_PRIVATE int sqlite3FkLocateIndex(
|
|
**
|
|
** DELETE deferred Decrement the "deferred constraint counter".
|
|
**
|
|
-** These operations are identified in the comment at the top of this file
|
|
+** These operations are identified in the comment at the top of this file
|
|
** (fkey.c) as "I.1" and "D.1".
|
|
*/
|
|
static void fkLookupParent(
|
|
@@ -118017,15 +127584,15 @@ static void fkLookupParent(
|
|
sqlite3VdbeVerifyAbortable(v,
|
|
(!pFKey->isDeferred
|
|
&& !(pParse->db->flags & SQLITE_DeferFKs)
|
|
- && !pParse->pToplevel
|
|
+ && !pParse->pToplevel
|
|
&& !pParse->isMultiWrite) ? OE_Abort : OE_Ignore);
|
|
|
|
/* If nIncr is less than zero, then check at runtime if there are any
|
|
** outstanding constraints to resolve. If there are not, there is no need
|
|
** to check if deleting this row resolves any outstanding violations.
|
|
**
|
|
- ** Check if any of the key columns in the child table row are NULL. If
|
|
- ** any are, then the constraint is considered satisfied. No need to
|
|
+ ** Check if any of the key columns in the child table row are NULL. If
|
|
+ ** any are, then the constraint is considered satisfied. No need to
|
|
** search for a matching row in the parent table. */
|
|
if( nIncr<0 ){
|
|
sqlite3VdbeAddOp2(v, OP_FkIfZero, pFKey->isDeferred, iOk);
|
|
@@ -118042,17 +127609,17 @@ static void fkLookupParent(
|
|
** column of the parent table (table pTab). */
|
|
int iMustBeInt; /* Address of MustBeInt instruction */
|
|
int regTemp = sqlite3GetTempReg(pParse);
|
|
-
|
|
- /* Invoke MustBeInt to coerce the child key value to an integer (i.e.
|
|
+
|
|
+ /* Invoke MustBeInt to coerce the child key value to an integer (i.e.
|
|
** apply the affinity of the parent key). If this fails, then there
|
|
** is no matching parent key. Before using MustBeInt, make a copy of
|
|
** the value. Otherwise, the value inserted into the child key column
|
|
** will have INTEGER affinity applied to it, which may not be correct. */
|
|
- sqlite3VdbeAddOp2(v, OP_SCopy,
|
|
+ sqlite3VdbeAddOp2(v, OP_SCopy,
|
|
sqlite3TableColumnToStorage(pFKey->pFrom,aiCol[0])+1+regData, regTemp);
|
|
iMustBeInt = sqlite3VdbeAddOp2(v, OP_MustBeInt, regTemp, 0);
|
|
VdbeCoverage(v);
|
|
-
|
|
+
|
|
/* If the parent table is the same as the child table, and we are about
|
|
** to increment the constraint-counter (i.e. this is an INSERT operation),
|
|
** then check if the row being inserted matches itself. If so, do not
|
|
@@ -118061,7 +127628,7 @@ static void fkLookupParent(
|
|
sqlite3VdbeAddOp3(v, OP_Eq, regData, iOk, regTemp); VdbeCoverage(v);
|
|
sqlite3VdbeChangeP5(v, SQLITE_NOTNULL);
|
|
}
|
|
-
|
|
+
|
|
sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead);
|
|
sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, regTemp); VdbeCoverage(v);
|
|
sqlite3VdbeGoto(v, iOk);
|
|
@@ -118071,22 +127638,21 @@ static void fkLookupParent(
|
|
}else{
|
|
int nCol = pFKey->nCol;
|
|
int regTemp = sqlite3GetTempRange(pParse, nCol);
|
|
- int regRec = sqlite3GetTempReg(pParse);
|
|
-
|
|
+
|
|
sqlite3VdbeAddOp3(v, OP_OpenRead, iCur, pIdx->tnum, iDb);
|
|
sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
|
|
for(i=0; i<nCol; i++){
|
|
- sqlite3VdbeAddOp2(v, OP_Copy,
|
|
+ sqlite3VdbeAddOp2(v, OP_Copy,
|
|
sqlite3TableColumnToStorage(pFKey->pFrom, aiCol[i])+1+regData,
|
|
regTemp+i);
|
|
}
|
|
-
|
|
+
|
|
/* If the parent table is the same as the child table, and we are about
|
|
** to increment the constraint-counter (i.e. this is an INSERT operation),
|
|
** then check if the row being inserted matches itself. If so, do not
|
|
- ** increment the constraint-counter.
|
|
+ ** increment the constraint-counter.
|
|
**
|
|
- ** If any of the parent-key values are NULL, then the row cannot match
|
|
+ ** If any of the parent-key values are NULL, then the row cannot match
|
|
** itself. So set JUMPIFNULL to make sure we do the OP_Found if any
|
|
** of the parent-key values are NULL (at this point it is known that
|
|
** none of the child key values are).
|
|
@@ -118110,19 +127676,18 @@ static void fkLookupParent(
|
|
}
|
|
sqlite3VdbeGoto(v, iOk);
|
|
}
|
|
-
|
|
- sqlite3VdbeAddOp4(v, OP_MakeRecord, regTemp, nCol, regRec,
|
|
+
|
|
+ sqlite3VdbeAddOp4(v, OP_Affinity, regTemp, nCol, 0,
|
|
sqlite3IndexAffinityStr(pParse->db,pIdx), nCol);
|
|
- sqlite3VdbeAddOp4Int(v, OP_Found, iCur, iOk, regRec, 0); VdbeCoverage(v);
|
|
-
|
|
- sqlite3ReleaseTempReg(pParse, regRec);
|
|
+ sqlite3VdbeAddOp4Int(v, OP_Found, iCur, iOk, regTemp, nCol);
|
|
+ VdbeCoverage(v);
|
|
sqlite3ReleaseTempRange(pParse, regTemp, nCol);
|
|
}
|
|
}
|
|
|
|
if( !pFKey->isDeferred && !(pParse->db->flags & SQLITE_DeferFKs)
|
|
- && !pParse->pToplevel
|
|
- && !pParse->isMultiWrite
|
|
+ && !pParse->pToplevel
|
|
+ && !pParse->isMultiWrite
|
|
){
|
|
/* Special case: If this is an INSERT statement that will insert exactly
|
|
** one row into the table, raise a constraint immediately instead of
|
|
@@ -118168,7 +127733,7 @@ static Expr *exprTableRegister(
|
|
pCol = &pTab->aCol[iCol];
|
|
pExpr->iTable = regBase + sqlite3TableColumnToStorage(pTab,iCol) + 1;
|
|
pExpr->affExpr = pCol->affinity;
|
|
- zColl = pCol->zColl;
|
|
+ zColl = sqlite3ColumnColl(pCol);
|
|
if( zColl==0 ) zColl = db->pDfltColl->zName;
|
|
pExpr = sqlite3ExprAddCollateString(pParse, pExpr, zColl);
|
|
}else{
|
|
@@ -118191,6 +127756,7 @@ static Expr *exprTableColumn(
|
|
){
|
|
Expr *pExpr = sqlite3Expr(db, TK_COLUMN, 0);
|
|
if( pExpr ){
|
|
+ assert( ExprUseYTab(pExpr) );
|
|
pExpr->y.pTab = pTab;
|
|
pExpr->iTable = iCursor;
|
|
pExpr->iColumn = iCol;
|
|
@@ -118200,7 +127766,7 @@ static Expr *exprTableColumn(
|
|
|
|
/*
|
|
** This function is called to generate code executed when a row is deleted
|
|
-** from the parent table of foreign key constraint pFKey and, if pFKey is
|
|
+** from the parent table of foreign key constraint pFKey and, if pFKey is
|
|
** deferred, when a row is inserted into the same table. When generating
|
|
** code for an SQL UPDATE operation, this function may be called twice -
|
|
** once to "delete" the old row and once to "insert" the new row.
|
|
@@ -118216,18 +127782,14 @@ static Expr *exprTableColumn(
|
|
** Operation | FK type | Action taken
|
|
** --------------------------------------------------------------------------
|
|
** DELETE immediate Increment the "immediate constraint counter".
|
|
-** Or, if the ON (UPDATE|DELETE) action is RESTRICT,
|
|
-** throw a "FOREIGN KEY constraint failed" exception.
|
|
**
|
|
** INSERT immediate Decrement the "immediate constraint counter".
|
|
**
|
|
** DELETE deferred Increment the "deferred constraint counter".
|
|
-** Or, if the ON (UPDATE|DELETE) action is RESTRICT,
|
|
-** throw a "FOREIGN KEY constraint failed" exception.
|
|
**
|
|
** INSERT deferred Decrement the "deferred constraint counter".
|
|
**
|
|
-** These operations are identified in the comment at the top of this file
|
|
+** These operations are identified in the comment at the top of this file
|
|
** (fkey.c) as "I.2" and "D.2".
|
|
*/
|
|
static void fkScanChildren(
|
|
@@ -118270,14 +127832,14 @@ static void fkScanChildren(
|
|
Expr *pLeft; /* Value from parent table row */
|
|
Expr *pRight; /* Column ref to child table */
|
|
Expr *pEq; /* Expression (pLeft = pRight) */
|
|
- i16 iCol; /* Index of column in child table */
|
|
+ i16 iCol; /* Index of column in child table */
|
|
const char *zCol; /* Name of column in child table */
|
|
|
|
iCol = pIdx ? pIdx->aiColumn[i] : -1;
|
|
pLeft = exprTableRegister(pParse, pTab, regData, iCol);
|
|
iCol = aiCol ? aiCol[i] : pFKey->aCol[0].iFrom;
|
|
assert( iCol>=0 );
|
|
- zCol = pFKey->pFrom->aCol[iCol].zName;
|
|
+ zCol = pFKey->pFrom->aCol[iCol].zCnName;
|
|
pRight = sqlite3Expr(db, TK_ID, zCol);
|
|
pEq = sqlite3PExpr(pParse, TK_EQ, pLeft, pRight);
|
|
pWhere = sqlite3ExprAnd(pParse, pWhere, pEq);
|
|
@@ -118292,7 +127854,7 @@ static void fkScanChildren(
|
|
**
|
|
** The first form is used for rowid tables. The second form is used
|
|
** for WITHOUT ROWID tables. In the second form, the *parent* key is
|
|
- ** (a,b,...). Either the parent or primary key could be used to
|
|
+ ** (a,b,...). Either the parent or primary key could be used to
|
|
** uniquely identify the current row, but the parent key is more convenient
|
|
** as the required values have already been loaded into registers
|
|
** by the caller.
|
|
@@ -118312,7 +127874,7 @@ static void fkScanChildren(
|
|
i16 iCol = pIdx->aiColumn[i];
|
|
assert( iCol>=0 );
|
|
pLeft = exprTableRegister(pParse, pTab, regData, iCol);
|
|
- pRight = sqlite3Expr(db, TK_ID, pTab->aCol[iCol].zName);
|
|
+ pRight = sqlite3Expr(db, TK_ID, pTab->aCol[iCol].zCnName);
|
|
pEq = sqlite3PExpr(pParse, TK_IS, pLeft, pRight);
|
|
pAll = sqlite3ExprAnd(pParse, pAll, pEq);
|
|
}
|
|
@@ -118331,7 +127893,7 @@ static void fkScanChildren(
|
|
** clause. For each row found, increment either the deferred or immediate
|
|
** foreign key constraint counter. */
|
|
if( pParse->nErr==0 ){
|
|
- pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0, 0, 0);
|
|
+ pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0, 0, 0, 0, 0);
|
|
sqlite3VdbeAddOp2(v, OP_FkCounter, pFKey->isDeferred, nIncr);
|
|
if( pWInfo ){
|
|
sqlite3WhereEnd(pWInfo);
|
|
@@ -118341,7 +127903,7 @@ static void fkScanChildren(
|
|
/* Clean up the WHERE clause constructed above. */
|
|
sqlite3ExprDelete(db, pWhere);
|
|
if( iFkIfZero ){
|
|
- sqlite3VdbeJumpHere(v, iFkIfZero);
|
|
+ sqlite3VdbeJumpHereOrPopInst(v, iFkIfZero);
|
|
}
|
|
}
|
|
|
|
@@ -118364,7 +127926,7 @@ SQLITE_PRIVATE FKey *sqlite3FkReferences(Table *pTab){
|
|
}
|
|
|
|
/*
|
|
-** The second argument is a Trigger structure allocated by the
|
|
+** The second argument is a Trigger structure allocated by the
|
|
** fkActionTrigger() routine. This function deletes the Trigger structure
|
|
** and all of its sub-components.
|
|
**
|
|
@@ -118382,6 +127944,25 @@ static void fkTriggerDelete(sqlite3 *dbMem, Trigger *p){
|
|
}
|
|
}
|
|
|
|
+/*
|
|
+** Clear the apTrigger[] cache of CASCADE triggers for all foreign keys
|
|
+** in a particular database. This needs to happen when the schema
|
|
+** changes.
|
|
+*/
|
|
+SQLITE_PRIVATE void sqlite3FkClearTriggerCache(sqlite3 *db, int iDb){
|
|
+ HashElem *k;
|
|
+ Hash *pHash = &db->aDb[iDb].pSchema->tblHash;
|
|
+ for(k=sqliteHashFirst(pHash); k; k=sqliteHashNext(k)){
|
|
+ Table *pTab = sqliteHashData(k);
|
|
+ FKey *pFKey;
|
|
+ if( !IsOrdinaryTable(pTab) ) continue;
|
|
+ for(pFKey=pTab->u.tab.pFKey; pFKey; pFKey=pFKey->pNextFrom){
|
|
+ fkTriggerDelete(db, pFKey->apTrigger[0]); pFKey->apTrigger[0] = 0;
|
|
+ fkTriggerDelete(db, pFKey->apTrigger[1]); pFKey->apTrigger[1] = 0;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
/*
|
|
** This function is called to generate code that runs when table pTab is
|
|
** being dropped from the database. The SrcList passed as the second argument
|
|
@@ -118392,7 +127973,7 @@ static void fkTriggerDelete(sqlite3 *dbMem, Trigger *p){
|
|
**
|
|
** (a) The table is the parent table of a FK constraint, or
|
|
** (b) The table is the child table of a deferred FK constraint and it is
|
|
-** determined at runtime that there are outstanding deferred FK
|
|
+** determined at runtime that there are outstanding deferred FK
|
|
** constraint violations in the database,
|
|
**
|
|
** then the equivalent of "DELETE FROM <tbl>" is executed before dropping
|
|
@@ -118401,20 +127982,20 @@ static void fkTriggerDelete(sqlite3 *dbMem, Trigger *p){
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTab){
|
|
sqlite3 *db = pParse->db;
|
|
- if( (db->flags&SQLITE_ForeignKeys) && !IsVirtual(pTab) ){
|
|
+ if( (db->flags&SQLITE_ForeignKeys) && IsOrdinaryTable(pTab) ){
|
|
int iSkip = 0;
|
|
Vdbe *v = sqlite3GetVdbe(pParse);
|
|
|
|
assert( v ); /* VDBE has already been allocated */
|
|
- assert( pTab->pSelect==0 ); /* Not a view */
|
|
+ assert( IsOrdinaryTable(pTab) );
|
|
if( sqlite3FkReferences(pTab)==0 ){
|
|
/* Search for a deferred foreign key constraint for which this table
|
|
- ** is the child table. If one cannot be found, return without
|
|
+ ** is the child table. If one cannot be found, return without
|
|
** generating any VDBE code. If one can be found, then jump over
|
|
** the entire DELETE if there are no outstanding deferred constraints
|
|
** when this statement is run. */
|
|
FKey *p;
|
|
- for(p=pTab->pFKey; p; p=p->pNextFrom){
|
|
+ for(p=pTab->u.tab.pFKey; p; p=p->pNextFrom){
|
|
if( p->isDeferred || (db->flags & SQLITE_DeferFKs) ) break;
|
|
}
|
|
if( !p ) return;
|
|
@@ -118426,10 +128007,10 @@ SQLITE_PRIVATE void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTa
|
|
sqlite3DeleteFrom(pParse, sqlite3SrcListDup(db, pName, 0), 0, 0, 0);
|
|
pParse->disableTriggers = 0;
|
|
|
|
- /* If the DELETE has generated immediate foreign key constraint
|
|
+ /* If the DELETE has generated immediate foreign key constraint
|
|
** violations, halt the VDBE and return an error at this point, before
|
|
** any modifications to the schema are made. This is because statement
|
|
- ** transactions are not able to rollback schema changes.
|
|
+ ** transactions are not able to rollback schema changes.
|
|
**
|
|
** If the SQLITE_DeferFKs flag is set, then this is not required, as
|
|
** the statement transaction will not be rolled back even if FK
|
|
@@ -118453,7 +128034,7 @@ SQLITE_PRIVATE void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTa
|
|
/*
|
|
** The second argument points to an FKey object representing a foreign key
|
|
** for which pTab is the child table. An UPDATE statement against pTab
|
|
-** is currently being processed. For each column of the table that is
|
|
+** is currently being processed. For each column of the table that is
|
|
** actually updated, the corresponding element in the aChange[] array
|
|
** is zero or greater (if a column is unmodified the corresponding element
|
|
** is set to -1). If the rowid column is modified by the UPDATE statement
|
|
@@ -118480,7 +128061,7 @@ static int fkChildIsModified(
|
|
/*
|
|
** The second argument points to an FKey object representing a foreign key
|
|
** for which pTab is the parent table. An UPDATE statement against pTab
|
|
-** is currently being processed. For each column of the table that is
|
|
+** is currently being processed. For each column of the table that is
|
|
** actually updated, the corresponding element in the aChange[] array
|
|
** is zero or greater (if a column is unmodified the corresponding element
|
|
** is set to -1). If the rowid column is modified by the UPDATE statement
|
|
@@ -118490,9 +128071,9 @@ static int fkChildIsModified(
|
|
** parent key for FK constraint *p are modified.
|
|
*/
|
|
static int fkParentIsModified(
|
|
- Table *pTab,
|
|
- FKey *p,
|
|
- int *aChange,
|
|
+ Table *pTab,
|
|
+ FKey *p,
|
|
+ int *aChange,
|
|
int bChngRowid
|
|
){
|
|
int i;
|
|
@@ -118503,7 +128084,7 @@ static int fkParentIsModified(
|
|
if( aChange[iKey]>=0 || (iKey==pTab->iPKey && bChngRowid) ){
|
|
Column *pCol = &pTab->aCol[iKey];
|
|
if( zKey ){
|
|
- if( 0==sqlite3StrICmp(pCol->zName, zKey) ) return 1;
|
|
+ if( 0==sqlite3StrICmp(pCol->zCnName, zKey) ) return 1;
|
|
}else if( pCol->colFlags & COLFLAG_PRIMKEY ){
|
|
return 1;
|
|
}
|
|
@@ -118533,7 +128114,7 @@ static int isSetNullAction(Parse *pParse, FKey *pFKey){
|
|
|
|
/*
|
|
** This function is called when inserting, deleting or updating a row of
|
|
-** table pTab to generate VDBE code to perform foreign key constraint
|
|
+** table pTab to generate VDBE code to perform foreign key constraint
|
|
** processing for the operation.
|
|
**
|
|
** For a DELETE operation, parameter regOld is passed the index of the
|
|
@@ -118549,11 +128130,11 @@ static int isSetNullAction(Parse *pParse, FKey *pFKey){
|
|
** For an UPDATE operation, this function is called twice. Once before
|
|
** the original record is deleted from the table using the calling convention
|
|
** described for DELETE. Then again after the original record is deleted
|
|
-** but before the new record is inserted using the INSERT convention.
|
|
+** but before the new record is inserted using the INSERT convention.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3FkCheck(
|
|
Parse *pParse, /* Parse context */
|
|
- Table *pTab, /* Row is being deleted from this table */
|
|
+ Table *pTab, /* Row is being deleted from this table */
|
|
int regOld, /* Previous row data is stored here */
|
|
int regNew, /* New row data is stored here */
|
|
int *aChange, /* Array indicating UPDATEd columns (or 0) */
|
|
@@ -118570,13 +128151,14 @@ SQLITE_PRIVATE void sqlite3FkCheck(
|
|
|
|
/* If foreign-keys are disabled, this function is a no-op. */
|
|
if( (db->flags&SQLITE_ForeignKeys)==0 ) return;
|
|
+ if( !IsOrdinaryTable(pTab) ) return;
|
|
|
|
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
|
zDb = db->aDb[iDb].zDbSName;
|
|
|
|
/* Loop through all the foreign key constraints for which pTab is the
|
|
** child table (the table that the foreign key definition is part of). */
|
|
- for(pFKey=pTab->pFKey; pFKey; pFKey=pFKey->pNextFrom){
|
|
+ for(pFKey=pTab->u.tab.pFKey; pFKey; pFKey=pFKey->pNextFrom){
|
|
Table *pTo; /* Parent table of foreign key pFKey */
|
|
Index *pIdx = 0; /* Index on key columns in pTo */
|
|
int *aiFree = 0;
|
|
@@ -118585,16 +128167,16 @@ SQLITE_PRIVATE void sqlite3FkCheck(
|
|
int i;
|
|
int bIgnore = 0;
|
|
|
|
- if( aChange
|
|
+ if( aChange
|
|
&& sqlite3_stricmp(pTab->zName, pFKey->zTo)!=0
|
|
- && fkChildIsModified(pTab, pFKey, aChange, bChngRowid)==0
|
|
+ && fkChildIsModified(pTab, pFKey, aChange, bChngRowid)==0
|
|
){
|
|
continue;
|
|
}
|
|
|
|
- /* Find the parent table of this foreign key. Also find a unique index
|
|
- ** on the parent key columns in the parent table. If either of these
|
|
- ** schema items cannot be located, set an error in pParse and return
|
|
+ /* Find the parent table of this foreign key. Also find a unique index
|
|
+ ** on the parent key columns in the parent table. If either of these
|
|
+ ** schema items cannot be located, set an error in pParse and return
|
|
** early. */
|
|
if( pParse->disableTriggers ){
|
|
pTo = sqlite3FindTable(db, pFKey->zTo, zDb);
|
|
@@ -118638,36 +128220,36 @@ SQLITE_PRIVATE void sqlite3FkCheck(
|
|
}
|
|
assert( pIdx==0 || pIdx->aiColumn[i]>=0 );
|
|
#ifndef SQLITE_OMIT_AUTHORIZATION
|
|
- /* Request permission to read the parent key columns. If the
|
|
+ /* Request permission to read the parent key columns. If the
|
|
** authorization callback returns SQLITE_IGNORE, behave as if any
|
|
** values read from the parent table are NULL. */
|
|
if( db->xAuth ){
|
|
int rcauth;
|
|
- char *zCol = pTo->aCol[pIdx ? pIdx->aiColumn[i] : pTo->iPKey].zName;
|
|
+ char *zCol = pTo->aCol[pIdx ? pIdx->aiColumn[i] : pTo->iPKey].zCnName;
|
|
rcauth = sqlite3AuthReadCol(pParse, pTo->zName, zCol, iDb);
|
|
bIgnore = (rcauth==SQLITE_IGNORE);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
- /* Take a shared-cache advisory read-lock on the parent table. Allocate
|
|
- ** a cursor to use to search the unique index on the parent key columns
|
|
+ /* Take a shared-cache advisory read-lock on the parent table. Allocate
|
|
+ ** a cursor to use to search the unique index on the parent key columns
|
|
** in the parent table. */
|
|
sqlite3TableLock(pParse, iDb, pTo->tnum, 0, pTo->zName);
|
|
pParse->nTab++;
|
|
|
|
if( regOld!=0 ){
|
|
/* A row is being removed from the child table. Search for the parent.
|
|
- ** If the parent does not exist, removing the child row resolves an
|
|
+ ** If the parent does not exist, removing the child row resolves an
|
|
** outstanding foreign key constraint violation. */
|
|
fkLookupParent(pParse, iDb, pTo, pIdx, pFKey, aiCol, regOld, -1, bIgnore);
|
|
}
|
|
if( regNew!=0 && !isSetNullAction(pParse, pFKey) ){
|
|
/* A row is being added to the child table. If a parent row cannot
|
|
- ** be found, adding the child row has violated the FK constraint.
|
|
+ ** be found, adding the child row has violated the FK constraint.
|
|
**
|
|
** If this operation is being performed as part of a trigger program
|
|
- ** that is actually a "SET NULL" action belonging to this very
|
|
+ ** that is actually a "SET NULL" action belonging to this very
|
|
** foreign key, then omit this scan altogether. As all child key
|
|
** values are guaranteed to be NULL, it is not possible for adding
|
|
** this row to cause an FK violation. */
|
|
@@ -118688,8 +128270,8 @@ SQLITE_PRIVATE void sqlite3FkCheck(
|
|
continue;
|
|
}
|
|
|
|
- if( !pFKey->isDeferred && !(db->flags & SQLITE_DeferFKs)
|
|
- && !pParse->pToplevel && !pParse->isMultiWrite
|
|
+ if( !pFKey->isDeferred && !(db->flags & SQLITE_DeferFKs)
|
|
+ && !pParse->pToplevel && !pParse->isMultiWrite
|
|
){
|
|
assert( regOld==0 && regNew!=0 );
|
|
/* Inserting a single row into a parent table cannot cause (or fix)
|
|
@@ -118707,12 +128289,12 @@ SQLITE_PRIVATE void sqlite3FkCheck(
|
|
** child table as a SrcList for sqlite3WhereBegin() */
|
|
pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
|
|
if( pSrc ){
|
|
- struct SrcList_item *pItem = pSrc->a;
|
|
+ SrcItem *pItem = pSrc->a;
|
|
pItem->pTab = pFKey->pFrom;
|
|
pItem->zName = pFKey->pFrom->zName;
|
|
pItem->pTab->nTabRef++;
|
|
pItem->iCursor = pParse->nTab++;
|
|
-
|
|
+
|
|
if( regNew!=0 ){
|
|
fkScanChildren(pParse, pSrc, pTab, pIdx, pFKey, aiCol, regNew, -1);
|
|
}
|
|
@@ -118731,10 +128313,10 @@ SQLITE_PRIVATE void sqlite3FkCheck(
|
|
**
|
|
** Note 2: At first glance it may seem like SQLite could simply omit
|
|
** all OP_FkCounter related scans when either CASCADE or SET NULL
|
|
- ** applies. The trouble starts if the CASCADE or SET NULL action
|
|
- ** trigger causes other triggers or action rules attached to the
|
|
+ ** applies. The trouble starts if the CASCADE or SET NULL action
|
|
+ ** trigger causes other triggers or action rules attached to the
|
|
** child table to fire. In these cases the fk constraint counters
|
|
- ** might be set incorrectly if any OP_FkCounter related scans are
|
|
+ ** might be set incorrectly if any OP_FkCounter related scans are
|
|
** omitted. */
|
|
if( !pFKey->isDeferred && eAction!=OE_Cascade && eAction!=OE_SetNull ){
|
|
sqlite3MayAbort(pParse);
|
|
@@ -118750,7 +128332,7 @@ SQLITE_PRIVATE void sqlite3FkCheck(
|
|
#define COLUMN_MASK(x) (((x)>31) ? 0xffffffff : ((u32)1<<(x)))
|
|
|
|
/*
|
|
-** This function is called before generating code to update or delete a
|
|
+** This function is called before generating code to update or delete a
|
|
** row contained in table pTab.
|
|
*/
|
|
SQLITE_PRIVATE u32 sqlite3FkOldmask(
|
|
@@ -118758,10 +128340,10 @@ SQLITE_PRIVATE u32 sqlite3FkOldmask(
|
|
Table *pTab /* Table being modified */
|
|
){
|
|
u32 mask = 0;
|
|
- if( pParse->db->flags&SQLITE_ForeignKeys ){
|
|
+ if( pParse->db->flags&SQLITE_ForeignKeys && IsOrdinaryTable(pTab) ){
|
|
FKey *p;
|
|
int i;
|
|
- for(p=pTab->pFKey; p; p=p->pNextFrom){
|
|
+ for(p=pTab->u.tab.pFKey; p; p=p->pNextFrom){
|
|
for(i=0; i<p->nCol; i++) mask |= COLUMN_MASK(p->aCol[i].iFrom);
|
|
}
|
|
for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){
|
|
@@ -118780,22 +128362,24 @@ SQLITE_PRIVATE u32 sqlite3FkOldmask(
|
|
|
|
|
|
/*
|
|
-** This function is called before generating code to update or delete a
|
|
+** This function is called before generating code to update or delete a
|
|
** row contained in table pTab. If the operation is a DELETE, then
|
|
** parameter aChange is passed a NULL value. For an UPDATE, aChange points
|
|
** to an array of size N, where N is the number of columns in table pTab.
|
|
-** If the i'th column is not modified by the UPDATE, then the corresponding
|
|
+** If the i'th column is not modified by the UPDATE, then the corresponding
|
|
** entry in the aChange[] array is set to -1. If the column is modified,
|
|
** the value is 0 or greater. Parameter chngRowid is set to true if the
|
|
** UPDATE statement modifies the rowid fields of the table.
|
|
**
|
|
** If any foreign key processing will be required, this function returns
|
|
-** non-zero. If there is no foreign key related processing, this function
|
|
+** non-zero. If there is no foreign key related processing, this function
|
|
** returns zero.
|
|
**
|
|
** For an UPDATE, this function returns 2 if:
|
|
**
|
|
-** * There are any FKs for which pTab is the child and the parent table, or
|
|
+** * There are any FKs for which pTab is the child and the parent table
|
|
+** and any FK processing at all is required (even of a different FK), or
|
|
+**
|
|
** * the UPDATE modifies one or more parent keys for which the action is
|
|
** not "NO ACTION" (i.e. is CASCADE, SET DEFAULT or SET NULL).
|
|
**
|
|
@@ -118807,23 +128391,24 @@ SQLITE_PRIVATE int sqlite3FkRequired(
|
|
int *aChange, /* Non-NULL for UPDATE operations */
|
|
int chngRowid /* True for UPDATE that affects rowid */
|
|
){
|
|
- int eRet = 0;
|
|
- if( pParse->db->flags&SQLITE_ForeignKeys ){
|
|
+ int eRet = 1; /* Value to return if bHaveFK is true */
|
|
+ int bHaveFK = 0; /* If FK processing is required */
|
|
+ if( pParse->db->flags&SQLITE_ForeignKeys && IsOrdinaryTable(pTab) ){
|
|
if( !aChange ){
|
|
- /* A DELETE operation. Foreign key processing is required if the
|
|
- ** table in question is either the child or parent table for any
|
|
+ /* A DELETE operation. Foreign key processing is required if the
|
|
+ ** table in question is either the child or parent table for any
|
|
** foreign key constraint. */
|
|
- eRet = (sqlite3FkReferences(pTab) || pTab->pFKey);
|
|
+ bHaveFK = (sqlite3FkReferences(pTab) || pTab->u.tab.pFKey);
|
|
}else{
|
|
/* This is an UPDATE. Foreign key processing is only required if the
|
|
** operation modifies one or more child or parent key columns. */
|
|
FKey *p;
|
|
|
|
/* Check if any child key columns are being modified. */
|
|
- for(p=pTab->pFKey; p; p=p->pNextFrom){
|
|
- if( 0==sqlite3_stricmp(pTab->zName, p->zTo) ) return 2;
|
|
+ for(p=pTab->u.tab.pFKey; p; p=p->pNextFrom){
|
|
if( fkChildIsModified(pTab, p, aChange, chngRowid) ){
|
|
- eRet = 1;
|
|
+ if( 0==sqlite3_stricmp(pTab->zName, p->zTo) ) eRet = 2;
|
|
+ bHaveFK = 1;
|
|
}
|
|
}
|
|
|
|
@@ -118831,16 +128416,16 @@ SQLITE_PRIVATE int sqlite3FkRequired(
|
|
for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){
|
|
if( fkParentIsModified(pTab, p, aChange, chngRowid) ){
|
|
if( p->aAction[1]!=OE_None ) return 2;
|
|
- eRet = 1;
|
|
+ bHaveFK = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- return eRet;
|
|
+ return bHaveFK ? eRet : 0;
|
|
}
|
|
|
|
/*
|
|
-** This function is called when an UPDATE or DELETE operation is being
|
|
+** This function is called when an UPDATE or DELETE operation is being
|
|
** compiled on table pTab, which is the parent table of foreign-key pFKey.
|
|
** If the current operation is an UPDATE, then the pChanges parameter is
|
|
** passed a pointer to the list of columns being modified. If it is a
|
|
@@ -118848,11 +128433,11 @@ SQLITE_PRIVATE int sqlite3FkRequired(
|
|
**
|
|
** It returns a pointer to a Trigger structure containing a trigger
|
|
** equivalent to the ON UPDATE or ON DELETE action specified by pFKey.
|
|
-** If the action is "NO ACTION" or "RESTRICT", then a NULL pointer is
|
|
-** returned (these actions require no special handling by the triggers
|
|
-** sub-system, code for them is created by fkScanChildren()).
|
|
+** If the action is "NO ACTION" then a NULL pointer is returned (these actions
|
|
+** require no special handling by the triggers sub-system, code for them is
|
|
+** created by fkScanChildren()).
|
|
**
|
|
-** For example, if pFKey is the foreign key and pTab is table "p" in
|
|
+** For example, if pFKey is the foreign key and pTab is table "p" in
|
|
** the following schema:
|
|
**
|
|
** CREATE TABLE p(pk PRIMARY KEY);
|
|
@@ -118865,7 +128450,7 @@ SQLITE_PRIVATE int sqlite3FkRequired(
|
|
** END;
|
|
**
|
|
** The returned pointer is cached as part of the foreign key object. It
|
|
-** is eventually freed along with the rest of the foreign key object by
|
|
+** is eventually freed along with the rest of the foreign key object by
|
|
** sqlite3FkDelete().
|
|
*/
|
|
static Trigger *fkActionTrigger(
|
|
@@ -118913,15 +128498,15 @@ static Trigger *fkActionTrigger(
|
|
assert( pIdx!=0 || (pTab->iPKey>=0 && pTab->iPKey<pTab->nCol) );
|
|
assert( pIdx==0 || pIdx->aiColumn[i]>=0 );
|
|
sqlite3TokenInit(&tToCol,
|
|
- pTab->aCol[pIdx ? pIdx->aiColumn[i] : pTab->iPKey].zName);
|
|
- sqlite3TokenInit(&tFromCol, pFKey->pFrom->aCol[iFromCol].zName);
|
|
+ pTab->aCol[pIdx ? pIdx->aiColumn[i] : pTab->iPKey].zCnName);
|
|
+ sqlite3TokenInit(&tFromCol, pFKey->pFrom->aCol[iFromCol].zCnName);
|
|
|
|
/* Create the expression "OLD.zToCol = zFromCol". It is important
|
|
** that the "OLD.zToCol" term is on the LHS of the = operator, so
|
|
** that the affinity and collation sequence associated with the
|
|
** parent table are used for the comparison. */
|
|
pEq = sqlite3PExpr(pParse, TK_EQ,
|
|
- sqlite3PExpr(pParse, TK_DOT,
|
|
+ sqlite3PExpr(pParse, TK_DOT,
|
|
sqlite3ExprAlloc(db, TK_ID, &tOld, 0),
|
|
sqlite3ExprAlloc(db, TK_ID, &tToCol, 0)),
|
|
sqlite3ExprAlloc(db, TK_ID, &tFromCol, 0)
|
|
@@ -118935,20 +128520,20 @@ static Trigger *fkActionTrigger(
|
|
*/
|
|
if( pChanges ){
|
|
pEq = sqlite3PExpr(pParse, TK_IS,
|
|
- sqlite3PExpr(pParse, TK_DOT,
|
|
+ sqlite3PExpr(pParse, TK_DOT,
|
|
sqlite3ExprAlloc(db, TK_ID, &tOld, 0),
|
|
sqlite3ExprAlloc(db, TK_ID, &tToCol, 0)),
|
|
- sqlite3PExpr(pParse, TK_DOT,
|
|
+ sqlite3PExpr(pParse, TK_DOT,
|
|
sqlite3ExprAlloc(db, TK_ID, &tNew, 0),
|
|
sqlite3ExprAlloc(db, TK_ID, &tToCol, 0))
|
|
);
|
|
pWhen = sqlite3ExprAnd(pParse, pWhen, pEq);
|
|
}
|
|
-
|
|
+
|
|
if( action!=OE_Restrict && (action!=OE_Cascade || pChanges) ){
|
|
Expr *pNew;
|
|
if( action==OE_Cascade ){
|
|
- pNew = sqlite3PExpr(pParse, TK_DOT,
|
|
+ pNew = sqlite3PExpr(pParse, TK_DOT,
|
|
sqlite3ExprAlloc(db, TK_ID, &tNew, 0),
|
|
sqlite3ExprAlloc(db, TK_ID, &tToCol, 0));
|
|
}else if( action==OE_SetDflt ){
|
|
@@ -118959,7 +128544,7 @@ static Trigger *fkActionTrigger(
|
|
testcase( pCol->colFlags & COLFLAG_STORED );
|
|
pDflt = 0;
|
|
}else{
|
|
- pDflt = pCol->pDflt;
|
|
+ pDflt = sqlite3ColumnExpr(pFKey->pFrom, pCol);
|
|
}
|
|
if( pDflt ){
|
|
pNew = sqlite3ExprDup(db, pDflt, 0);
|
|
@@ -118979,18 +128564,23 @@ static Trigger *fkActionTrigger(
|
|
nFrom = sqlite3Strlen30(zFrom);
|
|
|
|
if( action==OE_Restrict ){
|
|
+ int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
|
Token tFrom;
|
|
- Expr *pRaise;
|
|
+ Token tDb;
|
|
+ Expr *pRaise;
|
|
|
|
tFrom.z = zFrom;
|
|
tFrom.n = nFrom;
|
|
+ tDb.z = db->aDb[iDb].zDbSName;
|
|
+ tDb.n = sqlite3Strlen30(tDb.z);
|
|
+
|
|
pRaise = sqlite3Expr(db, TK_RAISE, "FOREIGN KEY constraint failed");
|
|
if( pRaise ){
|
|
pRaise->affExpr = OE_Abort;
|
|
}
|
|
- pSelect = sqlite3SelectNew(pParse,
|
|
+ pSelect = sqlite3SelectNew(pParse,
|
|
sqlite3ExprListAppend(pParse, 0, pRaise),
|
|
- sqlite3SrcListAppend(pParse, 0, &tFrom, 0),
|
|
+ sqlite3SrcListAppend(pParse, 0, &tDb, &tFrom),
|
|
pWhere,
|
|
0, 0, 0, 0, 0
|
|
);
|
|
@@ -119000,7 +128590,7 @@ static Trigger *fkActionTrigger(
|
|
/* Disable lookaside memory allocation */
|
|
DisableLookaside;
|
|
|
|
- pTrigger = (Trigger *)sqlite3DbMallocZero(db,
|
|
+ pTrigger = (Trigger *)sqlite3DbMallocZero(db,
|
|
sizeof(Trigger) + /* struct Trigger */
|
|
sizeof(TriggerStep) + /* Single step in trigger program */
|
|
nFrom + 1 /* Space for pStep->zTarget */
|
|
@@ -119009,7 +128599,7 @@ static Trigger *fkActionTrigger(
|
|
pStep = pTrigger->step_list = (TriggerStep *)&pTrigger[1];
|
|
pStep->zTarget = (char *)&pStep[1];
|
|
memcpy((char *)pStep->zTarget, zFrom, nFrom);
|
|
-
|
|
+
|
|
pStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE);
|
|
pStep->pExprList = sqlite3ExprListDup(db, pList, EXPRDUP_REDUCE);
|
|
pStep->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE);
|
|
@@ -119035,13 +128625,14 @@ static Trigger *fkActionTrigger(
|
|
|
|
switch( action ){
|
|
case OE_Restrict:
|
|
- pStep->op = TK_SELECT;
|
|
+ pStep->op = TK_SELECT;
|
|
break;
|
|
- case OE_Cascade:
|
|
- if( !pChanges ){
|
|
- pStep->op = TK_DELETE;
|
|
- break;
|
|
+ case OE_Cascade:
|
|
+ if( !pChanges ){
|
|
+ pStep->op = TK_DELETE;
|
|
+ break;
|
|
}
|
|
+ /* no break */ deliberate_fall_through
|
|
default:
|
|
pStep->op = TK_UPDATE;
|
|
}
|
|
@@ -119067,9 +128658,9 @@ SQLITE_PRIVATE void sqlite3FkActions(
|
|
int *aChange, /* Array indicating UPDATEd columns (or 0) */
|
|
int bChngRowid /* True if rowid is UPDATEd */
|
|
){
|
|
- /* If foreign-key support is enabled, iterate through all FKs that
|
|
- ** refer to table pTab. If there is an action associated with the FK
|
|
- ** for this operation (either update or delete), invoke the associated
|
|
+ /* If foreign-key support is enabled, iterate through all FKs that
|
|
+ ** refer to table pTab. If there is an action associated with the FK
|
|
+ ** for this operation (either update or delete), invoke the associated
|
|
** trigger sub-program. */
|
|
if( pParse->db->flags&SQLITE_ForeignKeys ){
|
|
FKey *pFKey; /* Iterator variable */
|
|
@@ -119095,12 +128686,13 @@ SQLITE_PRIVATE void sqlite3FkDelete(sqlite3 *db, Table *pTab){
|
|
FKey *pFKey; /* Iterator variable */
|
|
FKey *pNext; /* Copy of pFKey->pNextFrom */
|
|
|
|
- assert( db==0 || IsVirtual(pTab)
|
|
- || sqlite3SchemaMutexHeld(db, 0, pTab->pSchema) );
|
|
- for(pFKey=pTab->pFKey; pFKey; pFKey=pNext){
|
|
+ assert( IsOrdinaryTable(pTab) );
|
|
+ assert( db!=0 );
|
|
+ for(pFKey=pTab->u.tab.pFKey; pFKey; pFKey=pNext){
|
|
+ assert( db==0 || sqlite3SchemaMutexHeld(db, 0, pTab->pSchema) );
|
|
|
|
/* Remove the FK from the fkeyHash hash table. */
|
|
- if( !db || db->pnBytesFreed==0 ){
|
|
+ if( db->pnBytesFreed==0 ){
|
|
if( pFKey->pPrevTo ){
|
|
pFKey->pPrevTo->pNextTo = pFKey->pNextTo;
|
|
}else{
|
|
@@ -119149,7 +128741,7 @@ SQLITE_PRIVATE void sqlite3FkDelete(sqlite3 *db, Table *pTab){
|
|
/* #include "sqliteInt.h" */
|
|
|
|
/*
|
|
-** Generate code that will
|
|
+** Generate code that will
|
|
**
|
|
** (1) acquire a lock for table pTab then
|
|
** (2) open pTab as cursor iCur.
|
|
@@ -119166,9 +128758,10 @@ SQLITE_PRIVATE void sqlite3OpenTable(
|
|
){
|
|
Vdbe *v;
|
|
assert( !IsVirtual(pTab) );
|
|
- v = sqlite3GetVdbe(pParse);
|
|
+ assert( pParse->pVdbe!=0 );
|
|
+ v = pParse->pVdbe;
|
|
assert( opcode==OP_OpenWrite || opcode==OP_OpenRead );
|
|
- sqlite3TableLock(pParse, iDb, pTab->tnum,
|
|
+ sqlite3TableLock(pParse, iDb, pTab->tnum,
|
|
(opcode==OP_OpenWrite)?1:0, pTab->zName);
|
|
if( HasRowid(pTab) ){
|
|
sqlite3VdbeAddOp4Int(v, opcode, iCur, pTab->tnum, iDb, pTab->nNVCol);
|
|
@@ -119176,7 +128769,7 @@ SQLITE_PRIVATE void sqlite3OpenTable(
|
|
}else{
|
|
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
|
|
assert( pPk!=0 );
|
|
- assert( pPk->tnum==pTab->tnum );
|
|
+ assert( pPk->tnum==pTab->tnum || CORRUPT_DB );
|
|
sqlite3VdbeAddOp3(v, opcode, iCur, pPk->tnum, iDb);
|
|
sqlite3VdbeSetP4KeyInfo(pParse, pPk);
|
|
VdbeComment((v, "%s", pTab->zName));
|
|
@@ -119185,7 +128778,7 @@ SQLITE_PRIVATE void sqlite3OpenTable(
|
|
|
|
/*
|
|
** Return a pointer to the column affinity string associated with index
|
|
-** pIdx. A column affinity string has one character for each column in
|
|
+** pIdx. A column affinity string has one character for each column in
|
|
** the table, according to the affinity of the column:
|
|
**
|
|
** Character Column affinity
|
|
@@ -119229,6 +128822,7 @@ SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(sqlite3 *db, Index *pIdx){
|
|
aff = SQLITE_AFF_INTEGER;
|
|
}else{
|
|
assert( x==XN_EXPR );
|
|
+ assert( pIdx->bHasExpr );
|
|
assert( pIdx->aColExpr!=0 );
|
|
aff = sqlite3ExprAffinity(pIdx->aColExpr->a[n].pExpr);
|
|
}
|
|
@@ -119238,50 +128832,101 @@ SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(sqlite3 *db, Index *pIdx){
|
|
}
|
|
pIdx->zColAff[n] = 0;
|
|
}
|
|
-
|
|
+
|
|
return pIdx->zColAff;
|
|
}
|
|
|
|
/*
|
|
+** Compute an affinity string for a table. Space is obtained
|
|
+** from sqlite3DbMalloc(). The caller is responsible for freeing
|
|
+** the space when done.
|
|
+*/
|
|
+SQLITE_PRIVATE char *sqlite3TableAffinityStr(sqlite3 *db, const Table *pTab){
|
|
+ char *zColAff;
|
|
+ zColAff = (char *)sqlite3DbMallocRaw(db, pTab->nCol+1);
|
|
+ if( zColAff ){
|
|
+ int i, j;
|
|
+ for(i=j=0; i<pTab->nCol; i++){
|
|
+ if( (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ){
|
|
+ zColAff[j++] = pTab->aCol[i].affinity;
|
|
+ }
|
|
+ }
|
|
+ do{
|
|
+ zColAff[j--] = 0;
|
|
+ }while( j>=0 && zColAff[j]<=SQLITE_AFF_BLOB );
|
|
+ }
|
|
+ return zColAff;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Make changes to the evolving bytecode to do affinity transformations
|
|
+** of values that are about to be gathered into a row for table pTab.
|
|
+**
|
|
+** For ordinary (legacy, non-strict) tables:
|
|
+** -----------------------------------------
|
|
+**
|
|
** Compute the affinity string for table pTab, if it has not already been
|
|
** computed. As an optimization, omit trailing SQLITE_AFF_BLOB affinities.
|
|
**
|
|
-** If the affinity exists (if it is no entirely SQLITE_AFF_BLOB values) and
|
|
-** if iReg>0 then code an OP_Affinity opcode that will set the affinities
|
|
-** for register iReg and following. Or if affinities exists and iReg==0,
|
|
+** If the affinity string is empty (because it was all SQLITE_AFF_BLOB entries
|
|
+** which were then optimized out) then this routine becomes a no-op.
|
|
+**
|
|
+** Otherwise if iReg>0 then code an OP_Affinity opcode that will set the
|
|
+** affinities for register iReg and following. Or if iReg==0,
|
|
** then just set the P4 operand of the previous opcode (which should be
|
|
** an OP_MakeRecord) to the affinity string.
|
|
**
|
|
** A column affinity string has one character per column:
|
|
**
|
|
-** Character Column affinity
|
|
-** ------------------------------
|
|
-** 'A' BLOB
|
|
-** 'B' TEXT
|
|
-** 'C' NUMERIC
|
|
-** 'D' INTEGER
|
|
-** 'E' REAL
|
|
+** Character Column affinity
|
|
+** --------- ---------------
|
|
+** 'A' BLOB
|
|
+** 'B' TEXT
|
|
+** 'C' NUMERIC
|
|
+** 'D' INTEGER
|
|
+** 'E' REAL
|
|
+**
|
|
+** For STRICT tables:
|
|
+** ------------------
|
|
+**
|
|
+** Generate an appropropriate OP_TypeCheck opcode that will verify the
|
|
+** datatypes against the column definitions in pTab. If iReg==0, that
|
|
+** means an OP_MakeRecord opcode has already been generated and should be
|
|
+** the last opcode generated. The new OP_TypeCheck needs to be inserted
|
|
+** before the OP_MakeRecord. The new OP_TypeCheck should use the same
|
|
+** register set as the OP_MakeRecord. If iReg>0 then register iReg is
|
|
+** the first of a series of registers that will form the new record.
|
|
+** Apply the type checking to that array of registers.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){
|
|
- int i, j;
|
|
- char *zColAff = pTab->zColAff;
|
|
+ int i;
|
|
+ char *zColAff;
|
|
+ if( pTab->tabFlags & TF_Strict ){
|
|
+ if( iReg==0 ){
|
|
+ /* Move the previous opcode (which should be OP_MakeRecord) forward
|
|
+ ** by one slot and insert a new OP_TypeCheck where the current
|
|
+ ** OP_MakeRecord is found */
|
|
+ VdbeOp *pPrev;
|
|
+ sqlite3VdbeAppendP4(v, pTab, P4_TABLE);
|
|
+ pPrev = sqlite3VdbeGetLastOp(v);
|
|
+ assert( pPrev!=0 );
|
|
+ assert( pPrev->opcode==OP_MakeRecord || sqlite3VdbeDb(v)->mallocFailed );
|
|
+ pPrev->opcode = OP_TypeCheck;
|
|
+ sqlite3VdbeAddOp3(v, OP_MakeRecord, pPrev->p1, pPrev->p2, pPrev->p3);
|
|
+ }else{
|
|
+ /* Insert an isolated OP_Typecheck */
|
|
+ sqlite3VdbeAddOp2(v, OP_TypeCheck, iReg, pTab->nNVCol);
|
|
+ sqlite3VdbeAppendP4(v, pTab, P4_TABLE);
|
|
+ }
|
|
+ return;
|
|
+ }
|
|
+ zColAff = pTab->zColAff;
|
|
if( zColAff==0 ){
|
|
- sqlite3 *db = sqlite3VdbeDb(v);
|
|
- zColAff = (char *)sqlite3DbMallocRaw(0, pTab->nCol+1);
|
|
+ zColAff = sqlite3TableAffinityStr(0, pTab);
|
|
if( !zColAff ){
|
|
- sqlite3OomFault(db);
|
|
+ sqlite3OomFault(sqlite3VdbeDb(v));
|
|
return;
|
|
}
|
|
-
|
|
- for(i=j=0; i<pTab->nCol; i++){
|
|
- assert( pTab->aCol[i].affinity!=0 );
|
|
- if( (pTab->aCol[i].colFlags & COLFLAG_VIRTUAL)==0 ){
|
|
- zColAff[j++] = pTab->aCol[i].affinity;
|
|
- }
|
|
- }
|
|
- do{
|
|
- zColAff[j--] = 0;
|
|
- }while( j>=0 && zColAff[j]<=SQLITE_AFF_BLOB );
|
|
pTab->zColAff = zColAff;
|
|
}
|
|
assert( zColAff!=0 );
|
|
@@ -119290,6 +128935,8 @@ SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){
|
|
if( iReg ){
|
|
sqlite3VdbeAddOp4(v, OP_Affinity, iReg, i, 0, zColAff, i);
|
|
}else{
|
|
+ assert( sqlite3VdbeGetLastOp(v)->opcode==OP_MakeRecord
|
|
+ || sqlite3VdbeDb(v)->mallocFailed );
|
|
sqlite3VdbeChangeP4(v, -1, zColAff, i);
|
|
}
|
|
}
|
|
@@ -119297,9 +128944,9 @@ SQLITE_PRIVATE void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){
|
|
|
|
/*
|
|
** Return non-zero if the table pTab in database iDb or any of its indices
|
|
-** have been opened at any point in the VDBE program. This is used to see if
|
|
-** a statement of the form "INSERT INTO <iDb, pTab> SELECT ..." can
|
|
-** run without using a temporary table for the results of the SELECT.
|
|
+** have been opened at any point in the VDBE program. This is used to see if
|
|
+** a statement of the form "INSERT INTO <iDb, pTab> SELECT ..." can
|
|
+** run without using a temporary table for the results of the SELECT.
|
|
*/
|
|
static int readsTable(Parse *p, int iDb, Table *pTab){
|
|
Vdbe *v = sqlite3GetVdbe(p);
|
|
@@ -119314,7 +128961,7 @@ static int readsTable(Parse *p, int iDb, Table *pTab){
|
|
assert( pOp!=0 );
|
|
if( pOp->opcode==OP_OpenRead && pOp->p3==iDb ){
|
|
Index *pIndex;
|
|
- int tnum = pOp->p2;
|
|
+ Pgno tnum = pOp->p2;
|
|
if( tnum==pTab->tnum ){
|
|
return 1;
|
|
}
|
|
@@ -119373,24 +129020,30 @@ SQLITE_PRIVATE void sqlite3ComputeGeneratedColumns(
|
|
** that appropriate affinity has been applied to the regular columns
|
|
*/
|
|
sqlite3TableAffinity(pParse->pVdbe, pTab, iRegStore);
|
|
- if( (pTab->tabFlags & TF_HasStored)!=0
|
|
- && (pOp = sqlite3VdbeGetOp(pParse->pVdbe,-1))->opcode==OP_Affinity
|
|
- ){
|
|
- /* Change the OP_Affinity argument to '@' (NONE) for all stored
|
|
- ** columns. '@' is the no-op affinity and those columns have not
|
|
- ** yet been computed. */
|
|
- int ii, jj;
|
|
- char *zP4 = pOp->p4.z;
|
|
- assert( zP4!=0 );
|
|
- assert( pOp->p4type==P4_DYNAMIC );
|
|
- for(ii=jj=0; zP4[jj]; ii++){
|
|
- if( pTab->aCol[ii].colFlags & COLFLAG_VIRTUAL ){
|
|
- continue;
|
|
- }
|
|
- if( pTab->aCol[ii].colFlags & COLFLAG_STORED ){
|
|
- zP4[jj] = SQLITE_AFF_NONE;
|
|
+ if( (pTab->tabFlags & TF_HasStored)!=0 ){
|
|
+ pOp = sqlite3VdbeGetLastOp(pParse->pVdbe);
|
|
+ if( pOp->opcode==OP_Affinity ){
|
|
+ /* Change the OP_Affinity argument to '@' (NONE) for all stored
|
|
+ ** columns. '@' is the no-op affinity and those columns have not
|
|
+ ** yet been computed. */
|
|
+ int ii, jj;
|
|
+ char *zP4 = pOp->p4.z;
|
|
+ assert( zP4!=0 );
|
|
+ assert( pOp->p4type==P4_DYNAMIC );
|
|
+ for(ii=jj=0; zP4[jj]; ii++){
|
|
+ if( pTab->aCol[ii].colFlags & COLFLAG_VIRTUAL ){
|
|
+ continue;
|
|
+ }
|
|
+ if( pTab->aCol[ii].colFlags & COLFLAG_STORED ){
|
|
+ zP4[jj] = SQLITE_AFF_NONE;
|
|
+ }
|
|
+ jj++;
|
|
}
|
|
- jj++;
|
|
+ }else if( pOp->opcode==OP_TypeCheck ){
|
|
+ /* If an OP_TypeCheck was generated because the table is STRICT,
|
|
+ ** then set the P3 operand to indicate that generated columns should
|
|
+ ** not be checked */
|
|
+ pOp->p3 = 1;
|
|
}
|
|
}
|
|
|
|
@@ -119426,7 +129079,7 @@ SQLITE_PRIVATE void sqlite3ComputeGeneratedColumns(
|
|
int x;
|
|
pCol->colFlags |= COLFLAG_BUSY;
|
|
w.eCode = 0;
|
|
- sqlite3WalkExpr(&w, pCol->pDflt);
|
|
+ sqlite3WalkExpr(&w, sqlite3ColumnExpr(pTab, pCol));
|
|
pCol->colFlags &= ~COLFLAG_BUSY;
|
|
if( w.eCode & COLFLAG_NOTAVAIL ){
|
|
pRedo = pCol;
|
|
@@ -119435,13 +129088,13 @@ SQLITE_PRIVATE void sqlite3ComputeGeneratedColumns(
|
|
eProgress = 1;
|
|
assert( pCol->colFlags & COLFLAG_GENERATED );
|
|
x = sqlite3TableColumnToStorage(pTab, i) + iRegStore;
|
|
- sqlite3ExprCodeGeneratedColumn(pParse, pCol, x);
|
|
+ sqlite3ExprCodeGeneratedColumn(pParse, pTab, pCol, x);
|
|
pCol->colFlags &= ~COLFLAG_NOTAVAIL;
|
|
}
|
|
}
|
|
}while( pRedo && eProgress );
|
|
if( pRedo ){
|
|
- sqlite3ErrorMsg(pParse, "generated column loop on \"%s\"", pRedo->zName);
|
|
+ sqlite3ErrorMsg(pParse, "generated column loop on \"%s\"", pRedo->zCnName);
|
|
}
|
|
pParse->iSelfTab = 0;
|
|
}
|
|
@@ -119491,7 +129144,7 @@ static int autoIncBegin(
|
|
** Ticket d8dc2b3a58cd5dc2918a1d4acb 2018-05-23 */
|
|
if( pSeqTab==0
|
|
|| !HasRowid(pSeqTab)
|
|
- || IsVirtual(pSeqTab)
|
|
+ || NEVER(IsVirtual(pSeqTab))
|
|
|| pSeqTab->nCol!=2
|
|
){
|
|
pParse->nErr++;
|
|
@@ -119503,7 +129156,9 @@ static int autoIncBegin(
|
|
while( pInfo && pInfo->pTab!=pTab ){ pInfo = pInfo->pNext; }
|
|
if( pInfo==0 ){
|
|
pInfo = sqlite3DbMallocRawNN(pParse->db, sizeof(*pInfo));
|
|
- if( pInfo==0 ) return 0;
|
|
+ sqlite3ParserAddCleanup(pToplevel, sqlite3DbFree, pInfo);
|
|
+ testcase( pParse->earlyCleanup );
|
|
+ if( pParse->db->mallocFailed ) return 0;
|
|
pInfo->pNext = pToplevel->pAinc;
|
|
pToplevel->pAinc = pInfo;
|
|
pInfo->pTab = pTab;
|
|
@@ -119519,7 +129174,7 @@ static int autoIncBegin(
|
|
|
|
/*
|
|
** This routine generates code that will initialize all of the
|
|
-** register used by the autoincrement tracker.
|
|
+** register used by the autoincrement tracker.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3AutoincrementBegin(Parse *pParse){
|
|
AutoincInfo *p; /* Information about an AUTOINCREMENT */
|
|
@@ -119548,7 +129203,7 @@ SQLITE_PRIVATE void sqlite3AutoincrementBegin(Parse *pParse){
|
|
/* 8 */ {OP_Goto, 0, 11, 0},
|
|
/* 9 */ {OP_Next, 0, 2, 0},
|
|
/* 10 */ {OP_Integer, 0, 0, 0},
|
|
- /* 11 */ {OP_Close, 0, 0, 0}
|
|
+ /* 11 */ {OP_Close, 0, 0, 0}
|
|
};
|
|
VdbeOp *aOp;
|
|
pDb = &db->aDb[p->iDb];
|
|
@@ -119798,9 +129453,11 @@ SQLITE_PRIVATE void sqlite3Insert(
|
|
#endif
|
|
|
|
db = pParse->db;
|
|
- if( pParse->nErr || db->mallocFailed ){
|
|
+ assert( db->pParse==pParse );
|
|
+ if( pParse->nErr ){
|
|
goto insert_cleanup;
|
|
}
|
|
+ assert( db->mallocFailed==0 );
|
|
dest.iSDParm = 0; /* Suppress a harmless compiler warning */
|
|
|
|
/* If the Select object is really just a simple VALUES() list with a
|
|
@@ -119834,7 +129491,7 @@ SQLITE_PRIVATE void sqlite3Insert(
|
|
*/
|
|
#ifndef SQLITE_OMIT_TRIGGER
|
|
pTrigger = sqlite3TriggersExist(pParse, pTab, TK_INSERT, 0, &tmask);
|
|
- isView = pTab->pSelect!=0;
|
|
+ isView = IsView(pTab);
|
|
#else
|
|
# define pTrigger 0
|
|
# define tmask 0
|
|
@@ -119846,6 +129503,14 @@ SQLITE_PRIVATE void sqlite3Insert(
|
|
#endif
|
|
assert( (pTrigger && tmask) || (pTrigger==0 && tmask==0) );
|
|
|
|
+#if TREETRACE_ENABLED
|
|
+ if( sqlite3TreeTrace & 0x10000 ){
|
|
+ sqlite3TreeViewLine(0, "In sqlite3Insert() at %s:%d", __FILE__, __LINE__);
|
|
+ sqlite3TreeViewInsert(pParse->pWith, pTabList, pColumn, pSelect, pList,
|
|
+ onError, pUpsert, pTrigger);
|
|
+ }
|
|
+#endif
|
|
+
|
|
/* If pTab is really a view, make sure it has been initialized.
|
|
** ViewGetColumnNames() is a no-op if pTab is not a view.
|
|
*/
|
|
@@ -119876,7 +129541,11 @@ SQLITE_PRIVATE void sqlite3Insert(
|
|
**
|
|
** This is the 2nd template.
|
|
*/
|
|
- if( pColumn==0 && xferOptimization(pParse, pTab, pSelect, onError, iDb) ){
|
|
+ if( pColumn==0
|
|
+ && pSelect!=0
|
|
+ && pTrigger==0
|
|
+ && xferOptimization(pParse, pTab, pSelect, onError, iDb)
|
|
+ ){
|
|
assert( !pTrigger );
|
|
assert( pList==0 );
|
|
goto insert_end;
|
|
@@ -119900,7 +129569,7 @@ SQLITE_PRIVATE void sqlite3Insert(
|
|
regData = regRowid+1;
|
|
|
|
/* If the INSERT statement included an IDLIST term, then make sure
|
|
- ** all elements of the IDLIST really are columns of the table and
|
|
+ ** all elements of the IDLIST really are columns of the table and
|
|
** remember the column indices.
|
|
**
|
|
** If the table has an INTEGER PRIMARY KEY column and that column
|
|
@@ -119920,22 +129589,24 @@ SQLITE_PRIVATE void sqlite3Insert(
|
|
*/
|
|
bIdListInOrder = (pTab->tabFlags & (TF_OOOHidden|TF_HasStored))==0;
|
|
if( pColumn ){
|
|
+ assert( pColumn->eU4!=EU4_EXPR );
|
|
+ pColumn->eU4 = EU4_IDX;
|
|
for(i=0; i<pColumn->nId; i++){
|
|
- pColumn->a[i].idx = -1;
|
|
+ pColumn->a[i].u4.idx = -1;
|
|
}
|
|
for(i=0; i<pColumn->nId; i++){
|
|
for(j=0; j<pTab->nCol; j++){
|
|
- if( sqlite3StrICmp(pColumn->a[i].zName, pTab->aCol[j].zName)==0 ){
|
|
- pColumn->a[i].idx = j;
|
|
+ if( sqlite3StrICmp(pColumn->a[i].zName, pTab->aCol[j].zCnName)==0 ){
|
|
+ pColumn->a[i].u4.idx = j;
|
|
if( i!=j ) bIdListInOrder = 0;
|
|
if( j==pTab->iPKey ){
|
|
ipkColumn = i; assert( !withoutRowid );
|
|
}
|
|
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
|
|
if( pTab->aCol[j].colFlags & (COLFLAG_STORED|COLFLAG_VIRTUAL) ){
|
|
- sqlite3ErrorMsg(pParse,
|
|
+ sqlite3ErrorMsg(pParse,
|
|
"cannot INSERT into generated column \"%s\"",
|
|
- pTab->aCol[j].zName);
|
|
+ pTab->aCol[j].zCnName);
|
|
goto insert_cleanup;
|
|
}
|
|
#endif
|
|
@@ -119948,7 +129619,7 @@ SQLITE_PRIVATE void sqlite3Insert(
|
|
bIdListInOrder = 0;
|
|
}else{
|
|
sqlite3ErrorMsg(pParse, "table %S has no column named %s",
|
|
- pTabList, 0, pColumn->a[i].zName);
|
|
+ pTabList->a, pColumn->a[i].zName);
|
|
pParse->checkSchema = 1;
|
|
goto insert_cleanup;
|
|
}
|
|
@@ -119976,7 +129647,9 @@ SQLITE_PRIVATE void sqlite3Insert(
|
|
dest.nSdst = pTab->nCol;
|
|
rc = sqlite3Select(pParse, pSelect, &dest);
|
|
regFromSelect = dest.iSdst;
|
|
- if( rc || db->mallocFailed || pParse->nErr ) goto insert_cleanup;
|
|
+ assert( db->pParse==pParse );
|
|
+ if( rc || pParse->nErr ) goto insert_cleanup;
|
|
+ assert( db->mallocFailed==0 );
|
|
sqlite3VdbeEndCoroutine(v, regYield);
|
|
sqlite3VdbeJumpHere(v, addrTop - 1); /* label B: */
|
|
assert( pSelect->pEList );
|
|
@@ -119988,7 +129661,7 @@ SQLITE_PRIVATE void sqlite3Insert(
|
|
** the destination table (template 3).
|
|
**
|
|
** A temp table must be used if the table being updated is also one
|
|
- ** of the tables being read by the SELECT statement. Also use a
|
|
+ ** of the tables being read by the SELECT statement. Also use a
|
|
** temp table in the case of row triggers.
|
|
*/
|
|
if( pTrigger || readsTable(pParse, iDb, pTab) ){
|
|
@@ -120024,7 +129697,7 @@ SQLITE_PRIVATE void sqlite3Insert(
|
|
sqlite3ReleaseTempReg(pParse, regTempRowid);
|
|
}
|
|
}else{
|
|
- /* This is the case if the data for the INSERT is coming from a
|
|
+ /* This is the case if the data for the INSERT is coming from a
|
|
** single-row VALUES clause
|
|
*/
|
|
NameContext sNC;
|
|
@@ -120043,7 +129716,7 @@ SQLITE_PRIVATE void sqlite3Insert(
|
|
}
|
|
|
|
/* If there is no IDLIST term but the table has an integer primary
|
|
- ** key, the set the ipkColumn variable to the integer primary key
|
|
+ ** key, the set the ipkColumn variable to the integer primary key
|
|
** column index in the original table definition.
|
|
*/
|
|
if( pColumn==0 && nColumn>0 ){
|
|
@@ -120061,30 +129734,36 @@ SQLITE_PRIVATE void sqlite3Insert(
|
|
}
|
|
}
|
|
#endif
|
|
- }
|
|
|
|
- /* Make sure the number of columns in the source data matches the number
|
|
- ** of columns to be inserted into the table.
|
|
- */
|
|
- for(i=0; i<pTab->nCol; i++){
|
|
- if( pTab->aCol[i].colFlags & COLFLAG_NOINSERT ) nHidden++;
|
|
- }
|
|
- if( pColumn==0 && nColumn && nColumn!=(pTab->nCol-nHidden) ){
|
|
- sqlite3ErrorMsg(pParse,
|
|
- "table %S has %d columns but %d values were supplied",
|
|
- pTabList, 0, pTab->nCol-nHidden, nColumn);
|
|
- goto insert_cleanup;
|
|
+ /* Make sure the number of columns in the source data matches the number
|
|
+ ** of columns to be inserted into the table.
|
|
+ */
|
|
+ assert( TF_HasHidden==COLFLAG_HIDDEN );
|
|
+ assert( TF_HasGenerated==COLFLAG_GENERATED );
|
|
+ assert( COLFLAG_NOINSERT==(COLFLAG_GENERATED|COLFLAG_HIDDEN) );
|
|
+ if( (pTab->tabFlags & (TF_HasGenerated|TF_HasHidden))!=0 ){
|
|
+ for(i=0; i<pTab->nCol; i++){
|
|
+ if( pTab->aCol[i].colFlags & COLFLAG_NOINSERT ) nHidden++;
|
|
+ }
|
|
+ }
|
|
+ if( nColumn!=(pTab->nCol-nHidden) ){
|
|
+ sqlite3ErrorMsg(pParse,
|
|
+ "table %S has %d columns but %d values were supplied",
|
|
+ pTabList->a, pTab->nCol-nHidden, nColumn);
|
|
+ goto insert_cleanup;
|
|
+ }
|
|
}
|
|
if( pColumn!=0 && nColumn!=pColumn->nId ){
|
|
sqlite3ErrorMsg(pParse, "%d values for %d columns", nColumn, pColumn->nId);
|
|
goto insert_cleanup;
|
|
}
|
|
-
|
|
+
|
|
/* Initialize the count of rows to be inserted
|
|
*/
|
|
if( (db->flags & SQLITE_CountRows)!=0
|
|
&& !pParse->nested
|
|
&& !pParse->pTriggerTab
|
|
+ && !pParse->bReturning
|
|
){
|
|
regRowCount = ++pParse->nMem;
|
|
sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount);
|
|
@@ -120108,12 +129787,13 @@ SQLITE_PRIVATE void sqlite3Insert(
|
|
}
|
|
#ifndef SQLITE_OMIT_UPSERT
|
|
if( pUpsert ){
|
|
+ Upsert *pNx;
|
|
if( IsVirtual(pTab) ){
|
|
sqlite3ErrorMsg(pParse, "UPSERT not implemented for virtual table \"%s\"",
|
|
pTab->zName);
|
|
goto insert_cleanup;
|
|
}
|
|
- if( pTab->pSelect ){
|
|
+ if( IsView(pTab) ){
|
|
sqlite3ErrorMsg(pParse, "cannot UPSERT a view");
|
|
goto insert_cleanup;
|
|
}
|
|
@@ -120121,13 +129801,19 @@ SQLITE_PRIVATE void sqlite3Insert(
|
|
goto insert_cleanup;
|
|
}
|
|
pTabList->a[0].iCursor = iDataCur;
|
|
- pUpsert->pUpsertSrc = pTabList;
|
|
- pUpsert->regData = regData;
|
|
- pUpsert->iDataCur = iDataCur;
|
|
- pUpsert->iIdxCur = iIdxCur;
|
|
- if( pUpsert->pUpsertTarget ){
|
|
- sqlite3UpsertAnalyzeTarget(pParse, pTabList, pUpsert);
|
|
- }
|
|
+ pNx = pUpsert;
|
|
+ do{
|
|
+ pNx->pUpsertSrc = pTabList;
|
|
+ pNx->regData = regData;
|
|
+ pNx->iDataCur = iDataCur;
|
|
+ pNx->iIdxCur = iIdxCur;
|
|
+ if( pNx->pUpsertTarget ){
|
|
+ if( sqlite3UpsertAnalyzeTarget(pParse, pTabList, pNx) ){
|
|
+ goto insert_cleanup;
|
|
+ }
|
|
+ }
|
|
+ pNx = pNx->pNextUpsert;
|
|
+ }while( pNx!=0 );
|
|
}
|
|
#endif
|
|
|
|
@@ -120206,35 +129892,47 @@ SQLITE_PRIVATE void sqlite3Insert(
|
|
}else if( pColumn==0 ){
|
|
/* Hidden columns that are not explicitly named in the INSERT
|
|
** get there default value */
|
|
- sqlite3ExprCodeFactorable(pParse, pTab->aCol[i].pDflt, iRegStore);
|
|
+ sqlite3ExprCodeFactorable(pParse,
|
|
+ sqlite3ColumnExpr(pTab, &pTab->aCol[i]),
|
|
+ iRegStore);
|
|
continue;
|
|
}
|
|
}
|
|
if( pColumn ){
|
|
- for(j=0; j<pColumn->nId && pColumn->a[j].idx!=i; j++){}
|
|
+ assert( pColumn->eU4==EU4_IDX );
|
|
+ for(j=0; j<pColumn->nId && pColumn->a[j].u4.idx!=i; j++){}
|
|
if( j>=pColumn->nId ){
|
|
/* A column not named in the insert column list gets its
|
|
** default value */
|
|
- sqlite3ExprCodeFactorable(pParse, pTab->aCol[i].pDflt, iRegStore);
|
|
+ sqlite3ExprCodeFactorable(pParse,
|
|
+ sqlite3ColumnExpr(pTab, &pTab->aCol[i]),
|
|
+ iRegStore);
|
|
continue;
|
|
}
|
|
k = j;
|
|
}else if( nColumn==0 ){
|
|
/* This is INSERT INTO ... DEFAULT VALUES. Load the default value. */
|
|
- sqlite3ExprCodeFactorable(pParse, pTab->aCol[i].pDflt, iRegStore);
|
|
+ sqlite3ExprCodeFactorable(pParse,
|
|
+ sqlite3ColumnExpr(pTab, &pTab->aCol[i]),
|
|
+ iRegStore);
|
|
continue;
|
|
}else{
|
|
k = i - nHidden;
|
|
}
|
|
|
|
if( useTempTable ){
|
|
- sqlite3VdbeAddOp3(v, OP_Column, srcTab, k, iRegStore);
|
|
+ sqlite3VdbeAddOp3(v, OP_Column, srcTab, k, iRegStore);
|
|
}else if( pSelect ){
|
|
if( regFromSelect!=regData ){
|
|
sqlite3VdbeAddOp2(v, OP_SCopy, regFromSelect+k, iRegStore);
|
|
}
|
|
}else{
|
|
- sqlite3ExprCode(pParse, pList->a[k].pExpr, iRegStore);
|
|
+ Expr *pX = pList->a[k].pExpr;
|
|
+ int y = sqlite3ExprCodeTarget(pParse, pX, iRegStore);
|
|
+ if( y!=iRegStore ){
|
|
+ sqlite3VdbeAddOp2(v,
|
|
+ ExprHasProperty(pX, EP_Subquery) ? OP_Copy : OP_SCopy, y, iRegStore);
|
|
+ }
|
|
}
|
|
}
|
|
|
|
@@ -120268,11 +129966,6 @@ SQLITE_PRIVATE void sqlite3Insert(
|
|
sqlite3VdbeAddOp1(v, OP_MustBeInt, regCols); VdbeCoverage(v);
|
|
}
|
|
|
|
- /* Cannot have triggers on a virtual table. If it were possible,
|
|
- ** this block would have to account for hidden column.
|
|
- */
|
|
- assert( !IsVirtual(pTab) );
|
|
-
|
|
/* Copy the new data already generated. */
|
|
assert( pTab->nNVCol>0 );
|
|
sqlite3VdbeAddOp3(v, OP_Copy, regRowid+1, regCols+1, pTab->nNVCol-1);
|
|
@@ -120299,7 +129992,7 @@ SQLITE_PRIVATE void sqlite3Insert(
|
|
}
|
|
|
|
/* Fire BEFORE or INSTEAD OF triggers */
|
|
- sqlite3CodeRowTrigger(pParse, pTrigger, TK_INSERT, 0, TRIGGER_BEFORE,
|
|
+ sqlite3CodeRowTrigger(pParse, pTrigger, TK_INSERT, 0, TRIGGER_BEFORE,
|
|
pTab, regCols-pTab->nCol-1, onError, endOfLoop);
|
|
|
|
sqlite3ReleaseTempRange(pParse, regCols, pTab->nCol+1);
|
|
@@ -120371,18 +130064,20 @@ SQLITE_PRIVATE void sqlite3Insert(
|
|
}else
|
|
#endif
|
|
{
|
|
- int isReplace; /* Set to true if constraints may cause a replace */
|
|
+ int isReplace = 0;/* Set to true if constraints may cause a replace */
|
|
int bUseSeek; /* True to use OPFLAG_SEEKRESULT */
|
|
sqlite3GenerateConstraintChecks(pParse, pTab, aRegIdx, iDataCur, iIdxCur,
|
|
regIns, 0, ipkColumn>=0, onError, endOfLoop, &isReplace, 0, pUpsert
|
|
);
|
|
- sqlite3FkCheck(pParse, pTab, 0, regIns, 0, 0);
|
|
+ if( db->flags & SQLITE_ForeignKeys ){
|
|
+ sqlite3FkCheck(pParse, pTab, 0, regIns, 0, 0);
|
|
+ }
|
|
|
|
/* Set the OPFLAG_USESEEKRESULT flag if either (a) there are no REPLACE
|
|
** constraints or (b) there are no triggers and this table is not a
|
|
** parent table in a foreign key constraint. It is safe to set the
|
|
** flag in the second case as if any REPLACE constraint is hit, an
|
|
- ** OP_Delete or OP_IdxDelete instruction will be executed on each
|
|
+ ** OP_Delete or OP_IdxDelete instruction will be executed on each
|
|
** cursor that is disturbed. And these instructions both clear the
|
|
** VdbeCursor.seekResult variable, disabling the OPFLAG_USESEEKRESULT
|
|
** functionality. */
|
|
@@ -120391,6 +130086,13 @@ SQLITE_PRIVATE void sqlite3Insert(
|
|
regIns, aRegIdx, 0, appendFlag, bUseSeek
|
|
);
|
|
}
|
|
+#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
|
|
+ }else if( pParse->bReturning ){
|
|
+ /* If there is a RETURNING clause, populate the rowid register with
|
|
+ ** constant value -1, in case one or more of the returned expressions
|
|
+ ** refer to the "rowid" of the view. */
|
|
+ sqlite3VdbeAddOp2(v, OP_Integer, -1, regRowid);
|
|
+#endif
|
|
}
|
|
|
|
/* Update the count of rows that are inserted
|
|
@@ -120401,7 +130103,7 @@ SQLITE_PRIVATE void sqlite3Insert(
|
|
|
|
if( pTrigger ){
|
|
/* Code AFTER triggers */
|
|
- sqlite3CodeRowTrigger(pParse, pTrigger, TK_INSERT, 0, TRIGGER_AFTER,
|
|
+ sqlite3CodeRowTrigger(pParse, pTrigger, TK_INSERT, 0, TRIGGER_AFTER,
|
|
pTab, regData-2-pTab->nCol, onError, endOfLoop);
|
|
}
|
|
|
|
@@ -120427,7 +130129,9 @@ SQLITE_PRIVATE void sqlite3Insert(
|
|
sqlite3VdbeJumpHere(v, addrInsTop);
|
|
}
|
|
|
|
+#ifndef SQLITE_OMIT_XFER_OPT
|
|
insert_end:
|
|
+#endif /* SQLITE_OMIT_XFER_OPT */
|
|
/* Update the sqlite_sequence table by storing the content of the
|
|
** maximum rowid counter values recorded while inserting into
|
|
** autoincrement tables.
|
|
@@ -120437,14 +130141,12 @@ SQLITE_PRIVATE void sqlite3Insert(
|
|
}
|
|
|
|
/*
|
|
- ** Return the number of rows inserted. If this routine is
|
|
+ ** Return the number of rows inserted. If this routine is
|
|
** generating code because of a call to sqlite3NestedParse(), do not
|
|
** invoke the callback function.
|
|
*/
|
|
if( regRowCount ){
|
|
- sqlite3VdbeAddOp2(v, OP_ResultRow, regRowCount, 1);
|
|
- sqlite3VdbeSetNumCols(v, 1);
|
|
- sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows inserted", SQLITE_STATIC);
|
|
+ sqlite3CodeChangeCount(v, regRowCount, "rows inserted");
|
|
}
|
|
|
|
insert_cleanup:
|
|
@@ -120453,7 +130155,7 @@ SQLITE_PRIVATE void sqlite3Insert(
|
|
sqlite3UpsertDelete(db, pUpsert);
|
|
sqlite3SelectDelete(db, pSelect);
|
|
sqlite3IdListDelete(db, pColumn);
|
|
- sqlite3DbFree(db, aRegIdx);
|
|
+ if( aRegIdx ) sqlite3DbNNFreeNN(db, aRegIdx);
|
|
}
|
|
|
|
/* Make sure "isView" and other macros defined above are undefined. Otherwise
|
|
@@ -120470,7 +130172,7 @@ SQLITE_PRIVATE void sqlite3Insert(
|
|
#endif
|
|
|
|
/*
|
|
-** Meanings of bits in of pWalker->eCode for
|
|
+** Meanings of bits in of pWalker->eCode for
|
|
** sqlite3ExprReferencesUpdatedColumn()
|
|
*/
|
|
#define CKCNSTRNT_COLUMN 0x01 /* CHECK constraint uses a changing column */
|
|
@@ -120532,6 +130234,70 @@ SQLITE_PRIVATE int sqlite3ExprReferencesUpdatedColumn(
|
|
return w.eCode!=0;
|
|
}
|
|
|
|
+/*
|
|
+** The sqlite3GenerateConstraintChecks() routine usually wants to visit
|
|
+** the indexes of a table in the order provided in the Table->pIndex list.
|
|
+** However, sometimes (rarely - when there is an upsert) it wants to visit
|
|
+** the indexes in a different order. The following data structures accomplish
|
|
+** this.
|
|
+**
|
|
+** The IndexIterator object is used to walk through all of the indexes
|
|
+** of a table in either Index.pNext order, or in some other order established
|
|
+** by an array of IndexListTerm objects.
|
|
+*/
|
|
+typedef struct IndexListTerm IndexListTerm;
|
|
+typedef struct IndexIterator IndexIterator;
|
|
+struct IndexIterator {
|
|
+ int eType; /* 0 for Index.pNext list. 1 for an array of IndexListTerm */
|
|
+ int i; /* Index of the current item from the list */
|
|
+ union {
|
|
+ struct { /* Use this object for eType==0: A Index.pNext list */
|
|
+ Index *pIdx; /* The current Index */
|
|
+ } lx;
|
|
+ struct { /* Use this object for eType==1; Array of IndexListTerm */
|
|
+ int nIdx; /* Size of the array */
|
|
+ IndexListTerm *aIdx; /* Array of IndexListTerms */
|
|
+ } ax;
|
|
+ } u;
|
|
+};
|
|
+
|
|
+/* When IndexIterator.eType==1, then each index is an array of instances
|
|
+** of the following object
|
|
+*/
|
|
+struct IndexListTerm {
|
|
+ Index *p; /* The index */
|
|
+ int ix; /* Which entry in the original Table.pIndex list is this index*/
|
|
+};
|
|
+
|
|
+/* Return the first index on the list */
|
|
+static Index *indexIteratorFirst(IndexIterator *pIter, int *pIx){
|
|
+ assert( pIter->i==0 );
|
|
+ if( pIter->eType ){
|
|
+ *pIx = pIter->u.ax.aIdx[0].ix;
|
|
+ return pIter->u.ax.aIdx[0].p;
|
|
+ }else{
|
|
+ *pIx = 0;
|
|
+ return pIter->u.lx.pIdx;
|
|
+ }
|
|
+}
|
|
+
|
|
+/* Return the next index from the list. Return NULL when out of indexes */
|
|
+static Index *indexIteratorNext(IndexIterator *pIter, int *pIx){
|
|
+ if( pIter->eType ){
|
|
+ int i = ++pIter->i;
|
|
+ if( i>=pIter->u.ax.nIdx ){
|
|
+ *pIx = i;
|
|
+ return 0;
|
|
+ }
|
|
+ *pIx = pIter->u.ax.aIdx[i].ix;
|
|
+ return pIter->u.ax.aIdx[i].p;
|
|
+ }else{
|
|
+ ++(*pIx);
|
|
+ pIter->u.lx.pIdx = pIter->u.lx.pIdx->pNext;
|
|
+ return pIter->u.lx.pIdx;
|
|
+ }
|
|
+}
|
|
+
|
|
/*
|
|
** Generate code to do constraint checks prior to an INSERT or an UPDATE
|
|
** on table pTab.
|
|
@@ -120640,7 +130406,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
|
|
){
|
|
Vdbe *v; /* VDBE under constrution */
|
|
Index *pIdx; /* Pointer to one of the indices */
|
|
- Index *pPk = 0; /* The PRIMARY KEY index */
|
|
+ Index *pPk = 0; /* The PRIMARY KEY index for WITHOUT ROWID tables */
|
|
sqlite3 *db; /* Database connection */
|
|
int i; /* loop counter */
|
|
int ix; /* Index loop counter */
|
|
@@ -120648,11 +130414,11 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
|
|
int onError; /* Conflict resolution strategy */
|
|
int seenReplace = 0; /* True if REPLACE is used to resolve INT PK conflict */
|
|
int nPkField; /* Number of fields in PRIMARY KEY. 1 for ROWID tables */
|
|
- Index *pUpIdx = 0; /* Index to which to apply the upsert */
|
|
- u8 isUpdate; /* True if this is an UPDATE operation */
|
|
+ Upsert *pUpsertClause = 0; /* The specific ON CONFLICT clause for pIdx */
|
|
+ u8 isUpdate; /* True if this is an UPDATE operation */
|
|
u8 bAffinityDone = 0; /* True if the OP_Affinity operation has been run */
|
|
- int upsertBypass = 0; /* Address of Goto to bypass upsert subroutine */
|
|
- int upsertJump = 0; /* Address of Goto that jumps into upsert subroutine */
|
|
+ int upsertIpkReturn = 0; /* Address of Goto at end of IPK uniqueness check */
|
|
+ int upsertIpkDelay = 0; /* Address of Goto to bypass initial IPK check */
|
|
int ipkTop = 0; /* Top of the IPK uniqueness check */
|
|
int ipkBottom = 0; /* OP_Goto at the end of the IPK uniqueness check */
|
|
/* Variables associated with retesting uniqueness constraints after
|
|
@@ -120662,16 +130428,17 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
|
|
int lblRecheckOk = 0; /* Each recheck jumps to this label if it passes */
|
|
Trigger *pTrigger; /* List of DELETE triggers on the table pTab */
|
|
int nReplaceTrig = 0; /* Number of replace triggers coded */
|
|
+ IndexIterator sIdxIter; /* Index iterator */
|
|
|
|
isUpdate = regOldData!=0;
|
|
db = pParse->db;
|
|
- v = sqlite3GetVdbe(pParse);
|
|
+ v = pParse->pVdbe;
|
|
assert( v!=0 );
|
|
- assert( pTab->pSelect==0 ); /* This table is not a VIEW */
|
|
+ assert( !IsView(pTab) ); /* This table is not a VIEW */
|
|
nCol = pTab->nCol;
|
|
-
|
|
+
|
|
/* pPk is the PRIMARY KEY index for WITHOUT ROWID tables and NULL for
|
|
- ** normal rowid tables. nPkField is the number of key fields in the
|
|
+ ** normal rowid tables. nPkField is the number of key fields in the
|
|
** pPk index or 1 for a rowid table. In other words, nPkField is the
|
|
** number of fields in the true primary key of the table. */
|
|
if( HasRowid(pTab) ){
|
|
@@ -120718,7 +130485,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
|
|
}
|
|
if( onError==OE_Replace ){
|
|
if( b2ndPass /* REPLACE becomes ABORT on the 2nd pass */
|
|
- || pCol->pDflt==0 /* REPLACE is ABORT if no DEFAULT value */
|
|
+ || pCol->iDflt==0 /* REPLACE is ABORT if no DEFAULT value */
|
|
){
|
|
testcase( pCol->colFlags & COLFLAG_VIRTUAL );
|
|
testcase( pCol->colFlags & COLFLAG_STORED );
|
|
@@ -120740,17 +130507,19 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
|
|
VdbeCoverage(v);
|
|
assert( (pCol->colFlags & COLFLAG_GENERATED)==0 );
|
|
nSeenReplace++;
|
|
- sqlite3ExprCode(pParse, pCol->pDflt, iReg);
|
|
+ sqlite3ExprCodeCopy(pParse,
|
|
+ sqlite3ColumnExpr(pTab, pCol), iReg);
|
|
sqlite3VdbeJumpHere(v, addr1);
|
|
break;
|
|
}
|
|
case OE_Abort:
|
|
sqlite3MayAbort(pParse);
|
|
- /* Fall through */
|
|
+ /* no break */ deliberate_fall_through
|
|
case OE_Rollback:
|
|
case OE_Fail: {
|
|
char *zMsg = sqlite3MPrintf(db, "%s.%s", pTab->zName,
|
|
- pCol->zName);
|
|
+ pCol->zCnName);
|
|
+ testcase( zMsg==0 && db->mallocFailed==0 );
|
|
sqlite3VdbeAddOp3(v, OP_HaltIfNull, SQLITE_CONSTRAINT_NOTNULL,
|
|
onError, iReg);
|
|
sqlite3VdbeAppendP4(v, zMsg, P4_DYNAMIC);
|
|
@@ -120795,6 +130564,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
|
|
onError = overrideError!=OE_Default ? overrideError : OE_Abort;
|
|
for(i=0; i<pCheck->nExpr; i++){
|
|
int allOk;
|
|
+ Expr *pCopy;
|
|
Expr *pExpr = pCheck->a[i].pExpr;
|
|
if( aiChng
|
|
&& !sqlite3ExprReferencesUpdatedColumn(pExpr, aiChng, pkChng)
|
|
@@ -120803,14 +130573,22 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
|
|
** updated so there is no point it verifying the check constraint */
|
|
continue;
|
|
}
|
|
+ if( bAffinityDone==0 ){
|
|
+ sqlite3TableAffinity(v, pTab, regNewData+1);
|
|
+ bAffinityDone = 1;
|
|
+ }
|
|
allOk = sqlite3VdbeMakeLabel(pParse);
|
|
sqlite3VdbeVerifyAbortable(v, onError);
|
|
- sqlite3ExprIfTrue(pParse, pExpr, allOk, SQLITE_JUMPIFNULL);
|
|
+ pCopy = sqlite3ExprDup(db, pExpr, 0);
|
|
+ if( !db->mallocFailed ){
|
|
+ sqlite3ExprIfTrue(pParse, pCopy, allOk, SQLITE_JUMPIFNULL);
|
|
+ }
|
|
+ sqlite3ExprDelete(db, pCopy);
|
|
if( onError==OE_Ignore ){
|
|
sqlite3VdbeGoto(v, ignoreDest);
|
|
}else{
|
|
char *zName = pCheck->a[i].zEName;
|
|
- if( zName==0 ) zName = pTab->zName;
|
|
+ assert( zName!=0 || pParse->db->mallocFailed );
|
|
if( onError==OE_Replace ) onError = OE_Abort; /* IMP: R-26383-51744 */
|
|
sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_CHECK,
|
|
onError, zName, P4_TRANSIENT,
|
|
@@ -120850,19 +130628,63 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
|
|
** list of indexes attached to a table puts all OE_Replace indexes last
|
|
** in the list. See sqlite3CreateIndex() for where that happens.
|
|
*/
|
|
-
|
|
+ sIdxIter.eType = 0;
|
|
+ sIdxIter.i = 0;
|
|
+ sIdxIter.u.ax.aIdx = 0; /* Silence harmless compiler warning */
|
|
+ sIdxIter.u.lx.pIdx = pTab->pIndex;
|
|
if( pUpsert ){
|
|
if( pUpsert->pUpsertTarget==0 ){
|
|
- /* An ON CONFLICT DO NOTHING clause, without a constraint-target.
|
|
- ** Make all unique constraint resolution be OE_Ignore */
|
|
- assert( pUpsert->pUpsertSet==0 );
|
|
- overrideError = OE_Ignore;
|
|
- pUpsert = 0;
|
|
- }else if( (pUpIdx = pUpsert->pUpsertIdx)!=0 ){
|
|
- /* If the constraint-target uniqueness check must be run first.
|
|
- ** Jump to that uniqueness check now */
|
|
- upsertJump = sqlite3VdbeAddOp0(v, OP_Goto);
|
|
- VdbeComment((v, "UPSERT constraint goes first"));
|
|
+ /* There is just on ON CONFLICT clause and it has no constraint-target */
|
|
+ assert( pUpsert->pNextUpsert==0 );
|
|
+ if( pUpsert->isDoUpdate==0 ){
|
|
+ /* A single ON CONFLICT DO NOTHING clause, without a constraint-target.
|
|
+ ** Make all unique constraint resolution be OE_Ignore */
|
|
+ overrideError = OE_Ignore;
|
|
+ pUpsert = 0;
|
|
+ }else{
|
|
+ /* A single ON CONFLICT DO UPDATE. Make all resolutions OE_Update */
|
|
+ overrideError = OE_Update;
|
|
+ }
|
|
+ }else if( pTab->pIndex!=0 ){
|
|
+ /* Otherwise, we'll need to run the IndexListTerm array version of the
|
|
+ ** iterator to ensure that all of the ON CONFLICT conditions are
|
|
+ ** checked first and in order. */
|
|
+ int nIdx, jj;
|
|
+ u64 nByte;
|
|
+ Upsert *pTerm;
|
|
+ u8 *bUsed;
|
|
+ for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){
|
|
+ assert( aRegIdx[nIdx]>0 );
|
|
+ }
|
|
+ sIdxIter.eType = 1;
|
|
+ sIdxIter.u.ax.nIdx = nIdx;
|
|
+ nByte = (sizeof(IndexListTerm)+1)*nIdx + nIdx;
|
|
+ sIdxIter.u.ax.aIdx = sqlite3DbMallocZero(db, nByte);
|
|
+ if( sIdxIter.u.ax.aIdx==0 ) return; /* OOM */
|
|
+ bUsed = (u8*)&sIdxIter.u.ax.aIdx[nIdx];
|
|
+ pUpsert->pToFree = sIdxIter.u.ax.aIdx;
|
|
+ for(i=0, pTerm=pUpsert; pTerm; pTerm=pTerm->pNextUpsert){
|
|
+ if( pTerm->pUpsertTarget==0 ) break;
|
|
+ if( pTerm->pUpsertIdx==0 ) continue; /* Skip ON CONFLICT for the IPK */
|
|
+ jj = 0;
|
|
+ pIdx = pTab->pIndex;
|
|
+ while( ALWAYS(pIdx!=0) && pIdx!=pTerm->pUpsertIdx ){
|
|
+ pIdx = pIdx->pNext;
|
|
+ jj++;
|
|
+ }
|
|
+ if( bUsed[jj] ) continue; /* Duplicate ON CONFLICT clause ignored */
|
|
+ bUsed[jj] = 1;
|
|
+ sIdxIter.u.ax.aIdx[i].p = pIdx;
|
|
+ sIdxIter.u.ax.aIdx[i].ix = jj;
|
|
+ i++;
|
|
+ }
|
|
+ for(jj=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, jj++){
|
|
+ if( bUsed[jj] ) continue;
|
|
+ sIdxIter.u.ax.aIdx[i].p = pIdx;
|
|
+ sIdxIter.u.ax.aIdx[i].ix = jj;
|
|
+ i++;
|
|
+ }
|
|
+ assert( i==nIdx );
|
|
}
|
|
}
|
|
|
|
@@ -120925,11 +130747,20 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
|
|
}
|
|
|
|
/* figure out whether or not upsert applies in this case */
|
|
- if( pUpsert && pUpsert->pUpsertIdx==0 ){
|
|
- if( pUpsert->pUpsertSet==0 ){
|
|
- onError = OE_Ignore; /* DO NOTHING is the same as INSERT OR IGNORE */
|
|
- }else{
|
|
- onError = OE_Update; /* DO UPDATE */
|
|
+ if( pUpsert ){
|
|
+ pUpsertClause = sqlite3UpsertOfIndex(pUpsert,0);
|
|
+ if( pUpsertClause!=0 ){
|
|
+ if( pUpsertClause->isDoUpdate==0 ){
|
|
+ onError = OE_Ignore; /* DO NOTHING is the same as INSERT OR IGNORE */
|
|
+ }else{
|
|
+ onError = OE_Update; /* DO UPDATE */
|
|
+ }
|
|
+ }
|
|
+ if( pUpsertClause!=pUpsert ){
|
|
+ /* The first ON CONFLICT clause has a conflict target other than
|
|
+ ** the IPK. We have to jump ahead to that first ON CONFLICT clause
|
|
+ ** and then come back here and deal with the IPK afterwards */
|
|
+ upsertIpkDelay = sqlite3VdbeAddOp0(v, OP_Goto);
|
|
}
|
|
}
|
|
|
|
@@ -120939,8 +130770,9 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
|
|
** the UNIQUE constraints have run.
|
|
*/
|
|
if( onError==OE_Replace /* IPK rule is REPLACE */
|
|
- && onError!=overrideError /* Rules for other contraints are different */
|
|
+ && onError!=overrideError /* Rules for other constraints are different */
|
|
&& pTab->pIndex /* There exist other constraints */
|
|
+ && !upsertIpkDelay /* IPK check already deferred by UPSERT */
|
|
){
|
|
ipkTop = sqlite3VdbeAddOp0(v, OP_Goto)+1;
|
|
VdbeComment((v, "defer IPK REPLACE until last"));
|
|
@@ -120965,7 +130797,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
|
|
switch( onError ){
|
|
default: {
|
|
onError = OE_Abort;
|
|
- /* Fall thru into the next case */
|
|
+ /* no break */ deliberate_fall_through
|
|
}
|
|
case OE_Rollback:
|
|
case OE_Abort:
|
|
@@ -120983,10 +130815,10 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
|
|
** the triggers and remove both the table and index b-tree entries.
|
|
**
|
|
** Otherwise, if there are no triggers or the recursive-triggers
|
|
- ** flag is not set, but the table has one or more indexes, call
|
|
- ** GenerateRowIndexDelete(). This removes the index b-tree entries
|
|
- ** only. The table b-tree entry will be replaced by the new entry
|
|
- ** when it is inserted.
|
|
+ ** flag is not set, but the table has one or more indexes, call
|
|
+ ** GenerateRowIndexDelete(). This removes the index b-tree entries
|
|
+ ** only. The table b-tree entry will be replaced by the new entry
|
|
+ ** when it is inserted.
|
|
**
|
|
** If either GenerateRowDelete() or GenerateRowIndexDelete() is called,
|
|
** also invoke MultiWrite() to indicate that this VDBE may require
|
|
@@ -121026,7 +130858,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
|
|
#ifndef SQLITE_OMIT_UPSERT
|
|
case OE_Update: {
|
|
sqlite3UpsertDoUpdate(pParse, pUpsert, pTab, 0, iDataCur);
|
|
- /* Fall through */
|
|
+ /* no break */ deliberate_fall_through
|
|
}
|
|
#endif
|
|
case OE_Ignore: {
|
|
@@ -121036,7 +130868,9 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
|
|
}
|
|
}
|
|
sqlite3VdbeResolveLabel(v, addrRowidOk);
|
|
- if( ipkTop ){
|
|
+ if( pUpsert && pUpsertClause!=pUpsert ){
|
|
+ upsertIpkReturn = sqlite3VdbeAddOp0(v, OP_Goto);
|
|
+ }else if( ipkTop ){
|
|
ipkBottom = sqlite3VdbeAddOp0(v, OP_Goto);
|
|
sqlite3VdbeJumpHere(v, ipkTop-1);
|
|
}
|
|
@@ -121049,7 +130883,10 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
|
|
** This loop also handles the case of the PRIMARY KEY index for a
|
|
** WITHOUT ROWID table.
|
|
*/
|
|
- for(ix=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, ix++){
|
|
+ for(pIdx = indexIteratorFirst(&sIdxIter, &ix);
|
|
+ pIdx;
|
|
+ pIdx = indexIteratorNext(&sIdxIter, &ix)
|
|
+ ){
|
|
int regIdx; /* Range of registers hold conent for pIdx */
|
|
int regR; /* Range of registers holding conflicting PK */
|
|
int iThisCur; /* Cursor for this UNIQUE index */
|
|
@@ -121057,19 +130894,18 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
|
|
int addrConflictCk; /* First opcode in the conflict check logic */
|
|
|
|
if( aRegIdx[ix]==0 ) continue; /* Skip indices that do not change */
|
|
- if( pUpIdx==pIdx ){
|
|
- addrUniqueOk = upsertJump+1;
|
|
- upsertBypass = sqlite3VdbeGoto(v, 0);
|
|
- VdbeComment((v, "Skip upsert subroutine"));
|
|
- sqlite3VdbeJumpHere(v, upsertJump);
|
|
- }else{
|
|
- addrUniqueOk = sqlite3VdbeMakeLabel(pParse);
|
|
+ if( pUpsert ){
|
|
+ pUpsertClause = sqlite3UpsertOfIndex(pUpsert, pIdx);
|
|
+ if( upsertIpkDelay && pUpsertClause==pUpsert ){
|
|
+ sqlite3VdbeJumpHere(v, upsertIpkDelay);
|
|
+ }
|
|
}
|
|
- if( bAffinityDone==0 && (pUpIdx==0 || pUpIdx==pIdx) ){
|
|
+ addrUniqueOk = sqlite3VdbeMakeLabel(pParse);
|
|
+ if( bAffinityDone==0 ){
|
|
sqlite3TableAffinity(v, pTab, regNewData+1);
|
|
bAffinityDone = 1;
|
|
}
|
|
- VdbeNoopComment((v, "uniqueness check for %s", pIdx->zName));
|
|
+ VdbeNoopComment((v, "prep index %s", pIdx->zName));
|
|
iThisCur = iIdxCur+ix;
|
|
|
|
|
|
@@ -121102,7 +130938,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
|
|
testcase( sqlite3TableColumnToStorage(pTab, iField)!=iField );
|
|
x = sqlite3TableColumnToStorage(pTab, iField) + regNewData + 1;
|
|
sqlite3VdbeAddOp2(v, OP_SCopy, x, regIdx+i);
|
|
- VdbeComment((v, "%s", pTab->aCol[iField].zName));
|
|
+ VdbeComment((v, "%s", pTab->aCol[iField].zCnName));
|
|
}
|
|
}
|
|
sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn, aRegIdx[ix]);
|
|
@@ -121114,7 +130950,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
|
|
#endif
|
|
sqlite3VdbeReleaseRegisters(pParse, regIdx, pIdx->nColumn, 0, 0);
|
|
|
|
- /* In an UPDATE operation, if this index is the PRIMARY KEY index
|
|
+ /* In an UPDATE operation, if this index is the PRIMARY KEY index
|
|
** of a WITHOUT ROWID table and there has been no change the
|
|
** primary key, then no collision is possible. The collision detection
|
|
** logic below can all be skipped. */
|
|
@@ -121125,7 +130961,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
|
|
|
|
/* Find out what action to take in case there is a uniqueness conflict */
|
|
onError = pIdx->onError;
|
|
- if( onError==OE_None ){
|
|
+ if( onError==OE_None ){
|
|
sqlite3VdbeResolveLabel(v, addrUniqueOk);
|
|
continue; /* pIdx is not a UNIQUE index */
|
|
}
|
|
@@ -121136,8 +130972,8 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
|
|
}
|
|
|
|
/* Figure out if the upsert clause applies to this index */
|
|
- if( pUpIdx==pIdx ){
|
|
- if( pUpsert->pUpsertSet==0 ){
|
|
+ if( pUpsertClause ){
|
|
+ if( pUpsertClause->isDoUpdate==0 ){
|
|
onError = OE_Ignore; /* DO NOTHING is the same as INSERT OR IGNORE */
|
|
}else{
|
|
onError = OE_Update; /* DO UPDATE */
|
|
@@ -121153,7 +130989,8 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
|
|
**
|
|
** This is not possible for ENABLE_PREUPDATE_HOOK builds, as the row
|
|
** must be explicitly deleted in order to ensure any pre-update hook
|
|
- ** is invoked. */
|
|
+ ** is invoked. */
|
|
+ assert( IsOrdinaryTable(pTab) );
|
|
#ifndef SQLITE_ENABLE_PREUPDATE_HOOK
|
|
if( (ix==0 && pIdx->pNext==0) /* Condition 3 */
|
|
&& pPk==pIdx /* Condition 2 */
|
|
@@ -121161,7 +130998,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
|
|
&& ( 0==(db->flags&SQLITE_RecTriggers) || /* Condition 4 */
|
|
0==sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0))
|
|
&& ( 0==(db->flags&SQLITE_ForeignKeys) || /* Condition 5 */
|
|
- (0==pTab->pFKey && 0==sqlite3FkReferences(pTab)))
|
|
+ (0==pTab->u.tab.pFKey && 0==sqlite3FkReferences(pTab)))
|
|
){
|
|
sqlite3VdbeResolveLabel(v, addrUniqueOk);
|
|
continue;
|
|
@@ -121170,12 +131007,12 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
|
|
|
|
/* Check to see if the new index entry will be unique */
|
|
sqlite3VdbeVerifyAbortable(v, onError);
|
|
- addrConflictCk =
|
|
+ addrConflictCk =
|
|
sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, addrUniqueOk,
|
|
regIdx, pIdx->nKeyCol); VdbeCoverage(v);
|
|
|
|
/* Generate code to handle collisions */
|
|
- regR = (pIdx==pPk) ? regIdx : sqlite3GetTempRange(pParse, nPkField);
|
|
+ regR = pIdx==pPk ? regIdx : sqlite3GetTempRange(pParse, nPkField);
|
|
if( isUpdate || onError==OE_Replace ){
|
|
if( HasRowid(pTab) ){
|
|
sqlite3VdbeAddOp2(v, OP_IdxRowid, iThisCur, regR);
|
|
@@ -121196,13 +131033,13 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
|
|
x = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[i]);
|
|
sqlite3VdbeAddOp3(v, OP_Column, iThisCur, x, regR+i);
|
|
VdbeComment((v, "%s.%s", pTab->zName,
|
|
- pTab->aCol[pPk->aiColumn[i]].zName));
|
|
+ pTab->aCol[pPk->aiColumn[i]].zCnName));
|
|
}
|
|
}
|
|
if( isUpdate ){
|
|
- /* If currently processing the PRIMARY KEY of a WITHOUT ROWID
|
|
+ /* If currently processing the PRIMARY KEY of a WITHOUT ROWID
|
|
** table, only conflict if the new PRIMARY KEY values are actually
|
|
- ** different from the old.
|
|
+ ** different from the old. See TH3 withoutrowid04.test.
|
|
**
|
|
** For a UNIQUE index, only conflict if the PRIMARY KEY values
|
|
** of the matched index row are different from the original PRIMARY
|
|
@@ -121210,7 +131047,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
|
|
int addrJump = sqlite3VdbeCurrentAddr(v)+pPk->nKeyCol;
|
|
int op = OP_Ne;
|
|
int regCmp = (IsPrimaryKeyIndex(pIdx) ? regIdx : regR);
|
|
-
|
|
+
|
|
for(i=0; i<pPk->nKeyCol; i++){
|
|
char *p4 = (char*)sqlite3LocateCollSeq(pParse, pPk->azColl[i]);
|
|
x = pPk->aiColumn[i];
|
|
@@ -121220,7 +131057,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
|
|
op = OP_Eq;
|
|
}
|
|
x = sqlite3TableColumnToStorage(pTab, x);
|
|
- sqlite3VdbeAddOp4(v, op,
|
|
+ sqlite3VdbeAddOp4(v, op,
|
|
regOldData+1+x, addrJump, regCmp+i, p4, P4_COLLSEQ
|
|
);
|
|
sqlite3VdbeChangeP5(v, SQLITE_NOTNULL);
|
|
@@ -121247,7 +131084,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
|
|
#ifndef SQLITE_OMIT_UPSERT
|
|
case OE_Update: {
|
|
sqlite3UpsertDoUpdate(pParse, pUpsert, pTab, pIdx, iIdxCur+ix);
|
|
- /* Fall through */
|
|
+ /* no break */ deliberate_fall_through
|
|
}
|
|
#endif
|
|
case OE_Ignore: {
|
|
@@ -121260,7 +131097,8 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
|
|
|
|
assert( onError==OE_Replace );
|
|
nConflictCk = sqlite3VdbeCurrentAddr(v) - addrConflictCk;
|
|
- assert( nConflictCk>0 );
|
|
+ assert( nConflictCk>0 || db->mallocFailed );
|
|
+ testcase( nConflictCk<=0 );
|
|
testcase( nConflictCk>1 );
|
|
if( regTrigCnt ){
|
|
sqlite3MultiWrite(pParse);
|
|
@@ -121304,12 +131142,14 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
|
|
x = *sqlite3VdbeGetOp(v, addrConflictCk);
|
|
if( x.opcode!=OP_IdxRowid ){
|
|
int p2; /* New P2 value for copied conflict check opcode */
|
|
+ const char *zP4;
|
|
if( sqlite3OpcodeProperty[x.opcode]&OPFLG_JUMP ){
|
|
p2 = lblRecheckOk;
|
|
}else{
|
|
p2 = x.p2;
|
|
}
|
|
- sqlite3VdbeAddOp4(v, x.opcode, x.p1, p2, x.p3, x.p4.z, x.p4type);
|
|
+ zP4 = x.p4type==P4_INT32 ? SQLITE_INT_TO_PTR(x.p4.i) : x.p4.z;
|
|
+ sqlite3VdbeAddOp4(v, x.opcode, x.p1, p2, x.p3, zP4, x.p4type);
|
|
sqlite3VdbeChangeP5(v, x.p5);
|
|
VdbeCoverageIf(v, p2!=x.p2);
|
|
}
|
|
@@ -121325,19 +131165,23 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
|
|
break;
|
|
}
|
|
}
|
|
- if( pUpIdx==pIdx ){
|
|
- sqlite3VdbeGoto(v, upsertJump+1);
|
|
- sqlite3VdbeJumpHere(v, upsertBypass);
|
|
- }else{
|
|
- sqlite3VdbeResolveLabel(v, addrUniqueOk);
|
|
- }
|
|
+ sqlite3VdbeResolveLabel(v, addrUniqueOk);
|
|
if( regR!=regIdx ) sqlite3ReleaseTempRange(pParse, regR, nPkField);
|
|
+ if( pUpsertClause
|
|
+ && upsertIpkReturn
|
|
+ && sqlite3UpsertNextIsIPK(pUpsertClause)
|
|
+ ){
|
|
+ sqlite3VdbeGoto(v, upsertIpkDelay+1);
|
|
+ sqlite3VdbeJumpHere(v, upsertIpkReturn);
|
|
+ upsertIpkReturn = 0;
|
|
+ }
|
|
}
|
|
|
|
/* If the IPK constraint is a REPLACE, run it last */
|
|
if( ipkTop ){
|
|
sqlite3VdbeGoto(v, ipkTop);
|
|
VdbeComment((v, "Do IPK REPLACE"));
|
|
+ assert( ipkBottom>0 );
|
|
sqlite3VdbeJumpHere(v, ipkBottom);
|
|
}
|
|
|
|
@@ -121390,13 +131234,39 @@ SQLITE_PRIVATE void sqlite3SetMakeRecordP5(Vdbe *v, Table *pTab){
|
|
if( pTab->pSchema->file_format<2 ) return;
|
|
|
|
for(i=pTab->nCol-1; i>0; i--){
|
|
- if( pTab->aCol[i].pDflt!=0 ) break;
|
|
+ if( pTab->aCol[i].iDflt!=0 ) break;
|
|
if( pTab->aCol[i].colFlags & COLFLAG_PRIMKEY ) break;
|
|
}
|
|
sqlite3VdbeChangeP5(v, i+1);
|
|
}
|
|
#endif
|
|
|
|
+/*
|
|
+** Table pTab is a WITHOUT ROWID table that is being written to. The cursor
|
|
+** number is iCur, and register regData contains the new record for the
|
|
+** PK index. This function adds code to invoke the pre-update hook,
|
|
+** if one is registered.
|
|
+*/
|
|
+#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
|
|
+static void codeWithoutRowidPreupdate(
|
|
+ Parse *pParse, /* Parse context */
|
|
+ Table *pTab, /* Table being updated */
|
|
+ int iCur, /* Cursor number for table */
|
|
+ int regData /* Data containing new record */
|
|
+){
|
|
+ Vdbe *v = pParse->pVdbe;
|
|
+ int r = sqlite3GetTempReg(pParse);
|
|
+ assert( !HasRowid(pTab) );
|
|
+ assert( 0==(pParse->db->mDbFlags & DBFLAG_Vacuum) || CORRUPT_DB );
|
|
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, r);
|
|
+ sqlite3VdbeAddOp4(v, OP_Insert, iCur, regData, r, (char*)pTab, P4_TABLE);
|
|
+ sqlite3VdbeChangeP5(v, OPFLAG_ISNOOP);
|
|
+ sqlite3ReleaseTempReg(pParse, r);
|
|
+}
|
|
+#else
|
|
+# define codeWithoutRowidPreupdate(a,b,c,d)
|
|
+#endif
|
|
+
|
|
/*
|
|
** This routine generates code to finish the INSERT or UPDATE operation
|
|
** that was started by a prior call to sqlite3GenerateConstraintChecks.
|
|
@@ -121427,9 +131297,9 @@ SQLITE_PRIVATE void sqlite3CompleteInsertion(
|
|
|| update_flags==(OPFLAG_ISUPDATE|OPFLAG_SAVEPOSITION)
|
|
);
|
|
|
|
- v = sqlite3GetVdbe(pParse);
|
|
+ v = pParse->pVdbe;
|
|
assert( v!=0 );
|
|
- assert( pTab->pSelect==0 ); /* This table is not a VIEW */
|
|
+ assert( !IsView(pTab) ); /* This table is not a VIEW */
|
|
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
|
|
/* All REPLACE indexes are at the end of the list */
|
|
assert( pIdx->onError!=OE_Replace
|
|
@@ -121442,20 +131312,11 @@ SQLITE_PRIVATE void sqlite3CompleteInsertion(
|
|
}
|
|
pik_flags = (useSeekResult ? OPFLAG_USESEEKRESULT : 0);
|
|
if( IsPrimaryKeyIndex(pIdx) && !HasRowid(pTab) ){
|
|
- assert( pParse->nested==0 );
|
|
pik_flags |= OPFLAG_NCHANGE;
|
|
pik_flags |= (update_flags & OPFLAG_SAVEPOSITION);
|
|
-#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
|
|
if( update_flags==0 ){
|
|
- int r = sqlite3GetTempReg(pParse);
|
|
- sqlite3VdbeAddOp2(v, OP_Integer, 0, r);
|
|
- sqlite3VdbeAddOp4(v, OP_Insert,
|
|
- iIdxCur+i, aRegIdx[i], r, (char*)pTab, P4_TABLE
|
|
- );
|
|
- sqlite3VdbeChangeP5(v, OPFLAG_ISNOOP);
|
|
- sqlite3ReleaseTempReg(pParse, r);
|
|
+ codeWithoutRowidPreupdate(pParse, pTab, iIdxCur+i, aRegIdx[i]);
|
|
}
|
|
-#endif
|
|
}
|
|
sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iIdxCur+i, aRegIdx[i],
|
|
aRegIdx[i]+1,
|
|
@@ -121523,12 +131384,13 @@ SQLITE_PRIVATE int sqlite3OpenTableAndIndices(
|
|
assert( op==OP_OpenWrite || p5==0 );
|
|
if( IsVirtual(pTab) ){
|
|
/* This routine is a no-op for virtual tables. Leave the output
|
|
- ** variables *piDataCur and *piIdxCur uninitialized so that valgrind
|
|
- ** can detect if they are used by mistake in the caller. */
|
|
+ ** variables *piDataCur and *piIdxCur set to illegal cursor numbers
|
|
+ ** for improved error detection. */
|
|
+ *piDataCur = *piIdxCur = -999;
|
|
return 0;
|
|
}
|
|
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
|
|
- v = sqlite3GetVdbe(pParse);
|
|
+ v = pParse->pVdbe;
|
|
assert( v!=0 );
|
|
if( iBase<0 ) iBase = pParse->nTab;
|
|
iDataCur = iBase++;
|
|
@@ -121622,7 +131484,7 @@ static int xferCompatibleIndex(Index *pDest, Index *pSrc){
|
|
**
|
|
** INSERT INTO tab1 SELECT * FROM tab2;
|
|
**
|
|
-** The xfer optimization transfers raw records from tab2 over to tab1.
|
|
+** The xfer optimization transfers raw records from tab2 over to tab1.
|
|
** Columns are not decoded and reassembled, which greatly improves
|
|
** performance. Raw index records are transferred in the same way.
|
|
**
|
|
@@ -121653,7 +131515,7 @@ static int xferOptimization(
|
|
ExprList *pEList; /* The result set of the SELECT */
|
|
Table *pSrc; /* The table in the FROM clause of SELECT */
|
|
Index *pSrcIdx, *pDestIdx; /* Source and destination indices */
|
|
- struct SrcList_item *pItem; /* An element of pSelect->pSrc */
|
|
+ SrcItem *pItem; /* An element of pSelect->pSrc */
|
|
int i; /* Loop counter */
|
|
int iDbSrc; /* The database of pSrc */
|
|
int iSrc, iDest; /* Cursors from source and destination */
|
|
@@ -121665,18 +131527,13 @@ static int xferOptimization(
|
|
int destHasUniqueIdx = 0; /* True if pDest has a UNIQUE index */
|
|
int regData, regRowid; /* Registers holding data and rowid */
|
|
|
|
- if( pSelect==0 ){
|
|
- return 0; /* Must be of the form INSERT INTO ... SELECT ... */
|
|
- }
|
|
+ assert( pSelect!=0 );
|
|
if( pParse->pWith || pSelect->pWith ){
|
|
/* Do not attempt to process this query if there are an WITH clauses
|
|
** attached to it. Proceeding may generate a false "no such table: xxx"
|
|
** error if pSelect reads from a CTE named "xxx". */
|
|
return 0;
|
|
}
|
|
- if( sqlite3TriggerList(pParse, pDest) ){
|
|
- return 0; /* tab1 must not have triggers */
|
|
- }
|
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
|
if( IsVirtual(pDest) ){
|
|
return 0; /* tab1 must not be a virtual table */
|
|
@@ -121733,19 +131590,14 @@ static int xferOptimization(
|
|
return 0; /* FROM clause does not contain a real table */
|
|
}
|
|
if( pSrc->tnum==pDest->tnum && pSrc->pSchema==pDest->pSchema ){
|
|
- testcase( pSrc!=pDest ); /* Possible due to bad sqlite_master.rootpage */
|
|
+ testcase( pSrc!=pDest ); /* Possible due to bad sqlite_schema.rootpage */
|
|
return 0; /* tab1 and tab2 may not be the same table */
|
|
}
|
|
if( HasRowid(pDest)!=HasRowid(pSrc) ){
|
|
return 0; /* source and destination must both be WITHOUT ROWID or not */
|
|
}
|
|
-#ifndef SQLITE_OMIT_VIRTUALTABLE
|
|
- if( IsVirtual(pSrc) ){
|
|
- return 0; /* tab2 must not be a virtual table */
|
|
- }
|
|
-#endif
|
|
- if( pSrc->pSelect ){
|
|
- return 0; /* tab2 may not be a view */
|
|
+ if( !IsOrdinaryTable(pSrc) ){
|
|
+ return 0; /* tab2 may not be a view or virtual table */
|
|
}
|
|
if( pDest->nCol!=pSrc->nCol ){
|
|
return 0; /* Number of columns must be the same in tab1 and tab2 */
|
|
@@ -121753,12 +131605,15 @@ static int xferOptimization(
|
|
if( pDest->iPKey!=pSrc->iPKey ){
|
|
return 0; /* Both tables must have the same INTEGER PRIMARY KEY */
|
|
}
|
|
+ if( (pDest->tabFlags & TF_Strict)!=0 && (pSrc->tabFlags & TF_Strict)==0 ){
|
|
+ return 0; /* Cannot feed from a non-strict into a strict table */
|
|
+ }
|
|
for(i=0; i<pDest->nCol; i++){
|
|
Column *pDestCol = &pDest->aCol[i];
|
|
Column *pSrcCol = &pSrc->aCol[i];
|
|
#ifdef SQLITE_ENABLE_HIDDEN_COLUMNS
|
|
- if( (db->mDbFlags & DBFLAG_Vacuum)==0
|
|
- && (pDestCol->colFlags | pSrcCol->colFlags) & COLFLAG_HIDDEN
|
|
+ if( (db->mDbFlags & DBFLAG_Vacuum)==0
|
|
+ && (pDestCol->colFlags | pSrcCol->colFlags) & COLFLAG_HIDDEN
|
|
){
|
|
return 0; /* Neither table may have __hidden__ columns */
|
|
}
|
|
@@ -121775,7 +131630,7 @@ static int xferOptimization(
|
|
**
|
|
** Nevertheless, this is a useful notational shorthand to tell SQLite
|
|
** to do a bulk transfer all of the content from t1 over to t2.
|
|
- **
|
|
+ **
|
|
** We could, in theory, disable this (except for internal use by the
|
|
** VACUUM command where it is actually needed). But why do that? It
|
|
** seems harmless enough, and provides a useful service.
|
|
@@ -121789,7 +131644,9 @@ static int xferOptimization(
|
|
** This requirement could be relaxed for VIRTUAL columns, I suppose.
|
|
*/
|
|
if( (pDestCol->colFlags & COLFLAG_GENERATED)!=0 ){
|
|
- if( sqlite3ExprCompare(0, pSrcCol->pDflt, pDestCol->pDflt, -1)!=0 ){
|
|
+ if( sqlite3ExprCompare(0,
|
|
+ sqlite3ColumnExpr(pSrc, pSrcCol),
|
|
+ sqlite3ColumnExpr(pDest, pDestCol), -1)!=0 ){
|
|
testcase( pDestCol->colFlags & COLFLAG_VIRTUAL );
|
|
testcase( pDestCol->colFlags & COLFLAG_STORED );
|
|
return 0; /* Different generator expressions */
|
|
@@ -121799,7 +131656,8 @@ static int xferOptimization(
|
|
if( pDestCol->affinity!=pSrcCol->affinity ){
|
|
return 0; /* Affinity must be the same on all columns */
|
|
}
|
|
- if( sqlite3_stricmp(pDestCol->zColl, pSrcCol->zColl)!=0 ){
|
|
+ if( sqlite3_stricmp(sqlite3ColumnColl(pDestCol),
|
|
+ sqlite3ColumnColl(pSrcCol))!=0 ){
|
|
return 0; /* Collating sequence must be the same on all columns */
|
|
}
|
|
if( pDestCol->notNull && !pSrcCol->notNull ){
|
|
@@ -121807,11 +131665,15 @@ static int xferOptimization(
|
|
}
|
|
/* Default values for second and subsequent columns need to match. */
|
|
if( (pDestCol->colFlags & COLFLAG_GENERATED)==0 && i>0 ){
|
|
- assert( pDestCol->pDflt==0 || pDestCol->pDflt->op==TK_SPAN );
|
|
- assert( pSrcCol->pDflt==0 || pSrcCol->pDflt->op==TK_SPAN );
|
|
- if( (pDestCol->pDflt==0)!=(pSrcCol->pDflt==0)
|
|
- || (pDestCol->pDflt && strcmp(pDestCol->pDflt->u.zToken,
|
|
- pSrcCol->pDflt->u.zToken)!=0)
|
|
+ Expr *pDestExpr = sqlite3ColumnExpr(pDest, pDestCol);
|
|
+ Expr *pSrcExpr = sqlite3ColumnExpr(pSrc, pSrcCol);
|
|
+ assert( pDestExpr==0 || pDestExpr->op==TK_SPAN );
|
|
+ assert( pDestExpr==0 || !ExprHasProperty(pDestExpr, EP_IntValue) );
|
|
+ assert( pSrcExpr==0 || pSrcExpr->op==TK_SPAN );
|
|
+ assert( pSrcExpr==0 || !ExprHasProperty(pSrcExpr, EP_IntValue) );
|
|
+ if( (pDestExpr==0)!=(pSrcExpr==0)
|
|
+ || (pDestExpr!=0 && strcmp(pDestExpr->u.zToken,
|
|
+ pSrcExpr->u.zToken)!=0)
|
|
){
|
|
return 0; /* Default values must be the same for all columns */
|
|
}
|
|
@@ -121843,12 +131705,13 @@ static int xferOptimization(
|
|
#ifndef SQLITE_OMIT_FOREIGN_KEY
|
|
/* Disallow the transfer optimization if the destination table constains
|
|
** any foreign key constraints. This is more restrictive than necessary.
|
|
- ** But the main beneficiary of the transfer optimization is the VACUUM
|
|
+ ** But the main beneficiary of the transfer optimization is the VACUUM
|
|
** command, and the VACUUM command disables foreign key constraints. So
|
|
** the extra complication to make this rule less restrictive is probably
|
|
** not worth the effort. Ticket [6284df89debdfa61db8073e062908af0c9b6118e]
|
|
*/
|
|
- if( (db->flags & SQLITE_ForeignKeys)!=0 && pDest->pFKey!=0 ){
|
|
+ assert( IsOrdinaryTable(pDest) );
|
|
+ if( (db->flags & SQLITE_ForeignKeys)!=0 && pDest->u.tab.pFKey!=0 ){
|
|
return 0;
|
|
}
|
|
#endif
|
|
@@ -121870,6 +131733,7 @@ static int xferOptimization(
|
|
iDest = pParse->nTab++;
|
|
regAutoinc = autoIncBegin(pParse, iDbDest, pDest);
|
|
regData = sqlite3GetTempReg(pParse);
|
|
+ sqlite3VdbeAddOp2(v, OP_Null, 0, regData);
|
|
regRowid = sqlite3GetTempReg(pParse);
|
|
sqlite3OpenTable(pParse, iDest, iDbDest, pDest, OP_OpenWrite);
|
|
assert( HasRowid(pDest) || destHasUniqueIdx );
|
|
@@ -121890,7 +131754,7 @@ static int xferOptimization(
|
|
** (If the destination is not initially empty, the rowid fields
|
|
** of index entries might need to change.)
|
|
**
|
|
- ** (2) The destination has a unique index. (The xfer optimization
|
|
+ ** (2) The destination has a unique index. (The xfer optimization
|
|
** is unable to test uniqueness.)
|
|
**
|
|
** (3) onError is something other than OE_Abort and OE_Rollback.
|
|
@@ -121905,11 +131769,13 @@ static int xferOptimization(
|
|
emptySrcTest = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v);
|
|
if( pDest->iPKey>=0 ){
|
|
addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid);
|
|
- sqlite3VdbeVerifyAbortable(v, onError);
|
|
- addr2 = sqlite3VdbeAddOp3(v, OP_NotExists, iDest, 0, regRowid);
|
|
- VdbeCoverage(v);
|
|
- sqlite3RowidConstraint(pParse, onError, pDest);
|
|
- sqlite3VdbeJumpHere(v, addr2);
|
|
+ if( (db->mDbFlags & DBFLAG_Vacuum)==0 ){
|
|
+ sqlite3VdbeVerifyAbortable(v, onError);
|
|
+ addr2 = sqlite3VdbeAddOp3(v, OP_NotExists, iDest, 0, regRowid);
|
|
+ VdbeCoverage(v);
|
|
+ sqlite3RowidConstraint(pParse, onError, pDest);
|
|
+ sqlite3VdbeJumpHere(v, addr2);
|
|
+ }
|
|
autoIncStep(pParse, regAutoinc, regRowid);
|
|
}else if( pDest->pIndex==0 && !(db->mDbFlags & DBFLAG_VacuumInto) ){
|
|
addr1 = sqlite3VdbeAddOp2(v, OP_NewRowid, iDest, regRowid);
|
|
@@ -121917,17 +131783,28 @@ static int xferOptimization(
|
|
addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid);
|
|
assert( (pDest->tabFlags & TF_Autoincrement)==0 );
|
|
}
|
|
- sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1);
|
|
+
|
|
if( db->mDbFlags & DBFLAG_Vacuum ){
|
|
sqlite3VdbeAddOp1(v, OP_SeekEnd, iDest);
|
|
- insFlags = OPFLAG_NCHANGE|OPFLAG_LASTROWID|
|
|
- OPFLAG_APPEND|OPFLAG_USESEEKRESULT;
|
|
+ insFlags = OPFLAG_APPEND|OPFLAG_USESEEKRESULT|OPFLAG_PREFORMAT;
|
|
}else{
|
|
- insFlags = OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND;
|
|
+ insFlags = OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND|OPFLAG_PREFORMAT;
|
|
+ }
|
|
+#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
|
|
+ if( (db->mDbFlags & DBFLAG_Vacuum)==0 ){
|
|
+ sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1);
|
|
+ insFlags &= ~OPFLAG_PREFORMAT;
|
|
+ }else
|
|
+#endif
|
|
+ {
|
|
+ sqlite3VdbeAddOp3(v, OP_RowCell, iDest, iSrc, regRowid);
|
|
+ }
|
|
+ sqlite3VdbeAddOp3(v, OP_Insert, iDest, regData, regRowid);
|
|
+ if( (db->mDbFlags & DBFLAG_Vacuum)==0 ){
|
|
+ sqlite3VdbeChangeP4(v, -1, (char*)pDest, P4_TABLE);
|
|
}
|
|
- sqlite3VdbeAddOp4(v, OP_Insert, iDest, regData, regRowid,
|
|
- (char*)pDest, P4_TABLE);
|
|
sqlite3VdbeChangeP5(v, insFlags);
|
|
+
|
|
sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1); VdbeCoverage(v);
|
|
sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);
|
|
sqlite3VdbeAddOp2(v, OP_Close, iDest, 0);
|
|
@@ -121949,19 +131826,18 @@ static int xferOptimization(
|
|
sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR);
|
|
VdbeComment((v, "%s", pDestIdx->zName));
|
|
addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v);
|
|
- sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1);
|
|
if( db->mDbFlags & DBFLAG_Vacuum ){
|
|
/* This INSERT command is part of a VACUUM operation, which guarantees
|
|
** that the destination table is empty. If all indexed columns use
|
|
** collation sequence BINARY, then it can also be assumed that the
|
|
- ** index will be populated by inserting keys in strictly sorted
|
|
+ ** index will be populated by inserting keys in strictly sorted
|
|
** order. In this case, instead of seeking within the b-tree as part
|
|
** of every OP_IdxInsert opcode, an OP_SeekEnd is added before the
|
|
- ** OP_IdxInsert to seek to the point within the b-tree where each key
|
|
+ ** OP_IdxInsert to seek to the point within the b-tree where each key
|
|
** should be inserted. This is faster.
|
|
**
|
|
** If any of the indexed columns use a collation sequence other than
|
|
- ** BINARY, this optimization is disabled. This is because the user
|
|
+ ** BINARY, this optimization is disabled. This is because the user
|
|
** might change the definition of a collation sequence and then run
|
|
** a VACUUM command. In that case keys may not be written in strictly
|
|
** sorted order. */
|
|
@@ -121970,13 +131846,22 @@ static int xferOptimization(
|
|
if( sqlite3_stricmp(sqlite3StrBINARY, zColl) ) break;
|
|
}
|
|
if( i==pSrcIdx->nColumn ){
|
|
- idxInsFlags = OPFLAG_USESEEKRESULT;
|
|
+ idxInsFlags = OPFLAG_USESEEKRESULT|OPFLAG_PREFORMAT;
|
|
sqlite3VdbeAddOp1(v, OP_SeekEnd, iDest);
|
|
+ sqlite3VdbeAddOp2(v, OP_RowCell, iDest, iSrc);
|
|
}
|
|
- }
|
|
- if( !HasRowid(pSrc) && pDestIdx->idxType==SQLITE_IDXTYPE_PRIMARYKEY ){
|
|
+ }else if( !HasRowid(pSrc) && pDestIdx->idxType==SQLITE_IDXTYPE_PRIMARYKEY ){
|
|
idxInsFlags |= OPFLAG_NCHANGE;
|
|
}
|
|
+ if( idxInsFlags!=(OPFLAG_USESEEKRESULT|OPFLAG_PREFORMAT) ){
|
|
+ sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1);
|
|
+ if( (db->mDbFlags & DBFLAG_Vacuum)==0
|
|
+ && !HasRowid(pDest)
|
|
+ && IsPrimaryKeyIndex(pDestIdx)
|
|
+ ){
|
|
+ codeWithoutRowidPreupdate(pParse, pDest, iDest, regData);
|
|
+ }
|
|
+ }
|
|
sqlite3VdbeAddOp2(v, OP_IdxInsert, iDest, regData);
|
|
sqlite3VdbeChangeP5(v, idxInsFlags|OPFLAG_APPEND);
|
|
sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1+1); VdbeCoverage(v);
|
|
@@ -122070,7 +131955,7 @@ SQLITE_API int sqlite3_exec(
|
|
rc = sqlite3_step(pStmt);
|
|
|
|
/* Invoke the callback function if required */
|
|
- if( xCallback && (SQLITE_ROW==rc ||
|
|
+ if( xCallback && (SQLITE_ROW==rc ||
|
|
(SQLITE_DONE==rc && !callbackIsInit
|
|
&& db->flags&SQLITE_NullCallback)) ){
|
|
if( !callbackIsInit ){
|
|
@@ -122179,7 +132064,7 @@ SQLITE_API int sqlite3_exec(
|
|
** This header file defines the SQLite interface for use by
|
|
** shared libraries that want to be imported as extensions into
|
|
** an SQLite instance. Shared libraries that intend to be loaded
|
|
-** as extensions by SQLite should #include this file instead of
|
|
+** as extensions by SQLite should #include this file instead of
|
|
** sqlite3.h.
|
|
*/
|
|
#ifndef SQLITE3EXT_H
|
|
@@ -122497,6 +132382,37 @@ struct sqlite3_api_routines {
|
|
const char *(*filename_database)(const char*);
|
|
const char *(*filename_journal)(const char*);
|
|
const char *(*filename_wal)(const char*);
|
|
+ /* Version 3.32.0 and later */
|
|
+ const char *(*create_filename)(const char*,const char*,const char*,
|
|
+ int,const char**);
|
|
+ void (*free_filename)(const char*);
|
|
+ sqlite3_file *(*database_file_object)(const char*);
|
|
+ /* Version 3.34.0 and later */
|
|
+ int (*txn_state)(sqlite3*,const char*);
|
|
+ /* Version 3.36.1 and later */
|
|
+ sqlite3_int64 (*changes64)(sqlite3*);
|
|
+ sqlite3_int64 (*total_changes64)(sqlite3*);
|
|
+ /* Version 3.37.0 and later */
|
|
+ int (*autovacuum_pages)(sqlite3*,
|
|
+ unsigned int(*)(void*,const char*,unsigned int,unsigned int,unsigned int),
|
|
+ void*, void(*)(void*));
|
|
+ /* Version 3.38.0 and later */
|
|
+ int (*error_offset)(sqlite3*);
|
|
+ int (*vtab_rhs_value)(sqlite3_index_info*,int,sqlite3_value**);
|
|
+ int (*vtab_distinct)(sqlite3_index_info*);
|
|
+ int (*vtab_in)(sqlite3_index_info*,int,int);
|
|
+ int (*vtab_in_first)(sqlite3_value*,sqlite3_value**);
|
|
+ int (*vtab_in_next)(sqlite3_value*,sqlite3_value**);
|
|
+ /* Version 3.39.0 and later */
|
|
+ int (*deserialize)(sqlite3*,const char*,unsigned char*,
|
|
+ sqlite3_int64,sqlite3_int64,unsigned);
|
|
+ unsigned char *(*serialize)(sqlite3*,const char *,sqlite3_int64*,
|
|
+ unsigned int);
|
|
+ const char *(*db_name)(sqlite3*,int);
|
|
+ /* Version 3.40.0 and later */
|
|
+ int (*value_encoding)(sqlite3_value*);
|
|
+ /* Version 3.41.0 and later */
|
|
+ int (*is_interrupted)(sqlite3*);
|
|
};
|
|
|
|
/*
|
|
@@ -122797,17 +132713,45 @@ typedef int (*sqlite3_loadext_entry)(
|
|
#define sqlite3_filename_database sqlite3_api->filename_database
|
|
#define sqlite3_filename_journal sqlite3_api->filename_journal
|
|
#define sqlite3_filename_wal sqlite3_api->filename_wal
|
|
+/* Version 3.32.0 and later */
|
|
+#define sqlite3_create_filename sqlite3_api->create_filename
|
|
+#define sqlite3_free_filename sqlite3_api->free_filename
|
|
+#define sqlite3_database_file_object sqlite3_api->database_file_object
|
|
+/* Version 3.34.0 and later */
|
|
+#define sqlite3_txn_state sqlite3_api->txn_state
|
|
+/* Version 3.36.1 and later */
|
|
+#define sqlite3_changes64 sqlite3_api->changes64
|
|
+#define sqlite3_total_changes64 sqlite3_api->total_changes64
|
|
+/* Version 3.37.0 and later */
|
|
+#define sqlite3_autovacuum_pages sqlite3_api->autovacuum_pages
|
|
+/* Version 3.38.0 and later */
|
|
+#define sqlite3_error_offset sqlite3_api->error_offset
|
|
+#define sqlite3_vtab_rhs_value sqlite3_api->vtab_rhs_value
|
|
+#define sqlite3_vtab_distinct sqlite3_api->vtab_distinct
|
|
+#define sqlite3_vtab_in sqlite3_api->vtab_in
|
|
+#define sqlite3_vtab_in_first sqlite3_api->vtab_in_first
|
|
+#define sqlite3_vtab_in_next sqlite3_api->vtab_in_next
|
|
+/* Version 3.39.0 and later */
|
|
+#ifndef SQLITE_OMIT_DESERIALIZE
|
|
+#define sqlite3_deserialize sqlite3_api->deserialize
|
|
+#define sqlite3_serialize sqlite3_api->serialize
|
|
+#endif
|
|
+#define sqlite3_db_name sqlite3_api->db_name
|
|
+/* Version 3.40.0 and later */
|
|
+#define sqlite3_value_encoding sqlite3_api->value_encoding
|
|
+/* Version 3.41.0 and later */
|
|
+#define sqlite3_is_interrupted sqlite3_api->is_interrupted
|
|
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
|
|
|
|
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
|
|
- /* This case when the file really is being compiled as a loadable
|
|
+ /* This case when the file really is being compiled as a loadable
|
|
** extension */
|
|
# define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0;
|
|
# define SQLITE_EXTENSION_INIT2(v) sqlite3_api=v;
|
|
# define SQLITE_EXTENSION_INIT3 \
|
|
extern const sqlite3_api_routines *sqlite3_api;
|
|
#else
|
|
- /* This case when the file is being statically linked into the
|
|
+ /* This case when the file is being statically linked into the
|
|
** application */
|
|
# define SQLITE_EXTENSION_INIT1 /*no-op*/
|
|
# define SQLITE_EXTENSION_INIT2(v) (void)v; /* unused parameter */
|
|
@@ -123099,8 +133043,8 @@ static const sqlite3_api_routines sqlite3Apis = {
|
|
sqlite3_memory_highwater,
|
|
sqlite3_memory_used,
|
|
#ifdef SQLITE_MUTEX_OMIT
|
|
- 0,
|
|
- 0,
|
|
+ 0,
|
|
+ 0,
|
|
0,
|
|
0,
|
|
0,
|
|
@@ -123275,8 +133219,55 @@ static const sqlite3_api_routines sqlite3Apis = {
|
|
sqlite3_filename_database,
|
|
sqlite3_filename_journal,
|
|
sqlite3_filename_wal,
|
|
+ /* Version 3.32.0 and later */
|
|
+ sqlite3_create_filename,
|
|
+ sqlite3_free_filename,
|
|
+ sqlite3_database_file_object,
|
|
+ /* Version 3.34.0 and later */
|
|
+ sqlite3_txn_state,
|
|
+ /* Version 3.36.1 and later */
|
|
+ sqlite3_changes64,
|
|
+ sqlite3_total_changes64,
|
|
+ /* Version 3.37.0 and later */
|
|
+ sqlite3_autovacuum_pages,
|
|
+ /* Version 3.38.0 and later */
|
|
+ sqlite3_error_offset,
|
|
+#ifndef SQLITE_OMIT_VIRTUALTABLE
|
|
+ sqlite3_vtab_rhs_value,
|
|
+ sqlite3_vtab_distinct,
|
|
+ sqlite3_vtab_in,
|
|
+ sqlite3_vtab_in_first,
|
|
+ sqlite3_vtab_in_next,
|
|
+#else
|
|
+ 0,
|
|
+ 0,
|
|
+ 0,
|
|
+ 0,
|
|
+ 0,
|
|
+#endif
|
|
+ /* Version 3.39.0 and later */
|
|
+#ifndef SQLITE_OMIT_DESERIALIZE
|
|
+ sqlite3_deserialize,
|
|
+ sqlite3_serialize,
|
|
+#else
|
|
+ 0,
|
|
+ 0,
|
|
+#endif
|
|
+ sqlite3_db_name,
|
|
+ /* Version 3.40.0 and later */
|
|
+ sqlite3_value_encoding,
|
|
+ /* Version 3.41.0 and later */
|
|
+ sqlite3_is_interrupted
|
|
};
|
|
|
|
+/* True if x is the directory separator character
|
|
+*/
|
|
+#if SQLITE_OS_WIN
|
|
+# define DirSep(X) ((X)=='/'||(X)=='\\')
|
|
+#else
|
|
+# define DirSep(X) ((X)=='/')
|
|
+#endif
|
|
+
|
|
/*
|
|
** Attempt to load an SQLite extension library contained in the file
|
|
** zFile. The entry point is zProc. zProc may be 0 in which case a
|
|
@@ -123285,7 +133276,7 @@ static const sqlite3_api_routines sqlite3Apis = {
|
|
**
|
|
** Return SQLITE_OK on success and SQLITE_ERROR if something goes wrong.
|
|
**
|
|
-** If an error occurs and pzErrMsg is not 0, then fill *pzErrMsg with
|
|
+** If an error occurs and pzErrMsg is not 0, then fill *pzErrMsg with
|
|
** error message text. The calling function should free this memory
|
|
** by calling sqlite3DbFree(db, ).
|
|
*/
|
|
@@ -123302,14 +133293,14 @@ static int sqlite3LoadExtension(
|
|
const char *zEntry;
|
|
char *zAltEntry = 0;
|
|
void **aHandle;
|
|
- u64 nMsg = 300 + sqlite3Strlen30(zFile);
|
|
+ u64 nMsg = strlen(zFile);
|
|
int ii;
|
|
int rc;
|
|
|
|
/* Shared library endings to try if zFile cannot be loaded as written */
|
|
static const char *azEndings[] = {
|
|
#if SQLITE_OS_WIN
|
|
- "dll"
|
|
+ "dll"
|
|
#elif defined(__APPLE__)
|
|
"dylib"
|
|
#else
|
|
@@ -123336,6 +133327,12 @@ static int sqlite3LoadExtension(
|
|
|
|
zEntry = zProc ? zProc : "sqlite3_extension_init";
|
|
|
|
+ /* 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 */
|
|
+ if( nMsg>SQLITE_MAX_PATHLEN ) goto extension_not_found;
|
|
+
|
|
handle = sqlite3OsDlOpen(pVfs, zFile);
|
|
#if SQLITE_OS_UNIX || SQLITE_OS_WIN
|
|
for(ii=0; ii<ArraySize(azEndings) && handle==0; ii++){
|
|
@@ -123345,25 +133342,15 @@ static int sqlite3LoadExtension(
|
|
sqlite3_free(zAltFile);
|
|
}
|
|
#endif
|
|
- if( handle==0 ){
|
|
- if( pzErrMsg ){
|
|
- *pzErrMsg = zErrmsg = sqlite3_malloc64(nMsg);
|
|
- if( zErrmsg ){
|
|
- sqlite3_snprintf(nMsg, zErrmsg,
|
|
- "unable to open shared library [%s]", zFile);
|
|
- sqlite3OsDlError(pVfs, nMsg-1, zErrmsg);
|
|
- }
|
|
- }
|
|
- return SQLITE_ERROR;
|
|
- }
|
|
+ if( handle==0 ) goto extension_not_found;
|
|
xInit = (sqlite3_loadext_entry)sqlite3OsDlSym(pVfs, handle, zEntry);
|
|
|
|
/* If no entry point was specified and the default legacy
|
|
** entry point name "sqlite3_extension_init" was not found, then
|
|
** construct an entry point name "sqlite3_X_init" where the X is
|
|
- ** replaced by the lowercase value of every ASCII alphabetic
|
|
+ ** replaced by the lowercase value of every ASCII alphabetic
|
|
** character in the filename after the last "/" upto the first ".",
|
|
- ** and eliding the first three characters if they are "lib".
|
|
+ ** and eliding the first three characters if they are "lib".
|
|
** Examples:
|
|
**
|
|
** /usr/local/lib/libExample5.4.3.so ==> sqlite3_example_init
|
|
@@ -123378,7 +133365,7 @@ static int sqlite3LoadExtension(
|
|
return SQLITE_NOMEM_BKPT;
|
|
}
|
|
memcpy(zAltEntry, "sqlite3_", 8);
|
|
- for(iFile=ncFile-1; iFile>=0 && zFile[iFile]!='/'; iFile--){}
|
|
+ for(iFile=ncFile-1; iFile>=0 && !DirSep(zFile[iFile]); iFile--){}
|
|
iFile++;
|
|
if( sqlite3_strnicmp(zFile+iFile, "lib", 3)==0 ) iFile += 3;
|
|
for(iEntry=8; (c = zFile[iFile])!=0 && c!='.'; iFile++){
|
|
@@ -123392,10 +133379,11 @@ static int sqlite3LoadExtension(
|
|
}
|
|
if( xInit==0 ){
|
|
if( pzErrMsg ){
|
|
- nMsg += sqlite3Strlen30(zEntry);
|
|
+ nMsg += strlen(zEntry) + 300;
|
|
*pzErrMsg = zErrmsg = sqlite3_malloc64(nMsg);
|
|
if( zErrmsg ){
|
|
- sqlite3_snprintf(nMsg, zErrmsg,
|
|
+ assert( nMsg<0x7fffffff ); /* zErrmsg would be NULL if not so */
|
|
+ sqlite3_snprintf((int)nMsg, zErrmsg,
|
|
"no entry point [%s] in shared library [%s]", zEntry, zFile);
|
|
sqlite3OsDlError(pVfs, nMsg-1, zErrmsg);
|
|
}
|
|
@@ -123429,6 +133417,19 @@ static int sqlite3LoadExtension(
|
|
|
|
db->aExtension[db->nExtension++] = handle;
|
|
return SQLITE_OK;
|
|
+
|
|
+extension_not_found:
|
|
+ if( pzErrMsg ){
|
|
+ nMsg += 300;
|
|
+ *pzErrMsg = zErrmsg = sqlite3_malloc64(nMsg);
|
|
+ if( zErrmsg ){
|
|
+ assert( nMsg<0x7fffffff ); /* zErrmsg would be NULL if not so */
|
|
+ sqlite3_snprintf((int)nMsg, zErrmsg,
|
|
+ "unable to open shared library [%.*s]", SQLITE_MAX_PATHLEN, zFile);
|
|
+ sqlite3OsDlError(pVfs, nMsg-1, zErrmsg);
|
|
+ }
|
|
+ }
|
|
+ return SQLITE_ERROR;
|
|
}
|
|
SQLITE_API int sqlite3_load_extension(
|
|
sqlite3 *db, /* Load the extension into this database connection */
|
|
@@ -123478,12 +133479,12 @@ SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff){
|
|
** The following object holds the list of automatically loaded
|
|
** extensions.
|
|
**
|
|
-** This list is shared across threads. The SQLITE_MUTEX_STATIC_MASTER
|
|
+** This list is shared across threads. The SQLITE_MUTEX_STATIC_MAIN
|
|
** mutex must be held while accessing this list.
|
|
*/
|
|
typedef struct sqlite3AutoExtList sqlite3AutoExtList;
|
|
static SQLITE_WSD struct sqlite3AutoExtList {
|
|
- u32 nExt; /* Number of entries in aExt[] */
|
|
+ u32 nExt; /* Number of entries in aExt[] */
|
|
void (**aExt)(void); /* Pointers to the extension init functions */
|
|
} sqlite3Autoext = { 0, 0 };
|
|
|
|
@@ -123520,7 +133521,7 @@ SQLITE_API int sqlite3_auto_extension(
|
|
{
|
|
u32 i;
|
|
#if SQLITE_THREADSAFE
|
|
- sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
|
|
+ sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN);
|
|
#endif
|
|
wsdAutoextInit;
|
|
sqlite3_mutex_enter(mutex);
|
|
@@ -123558,7 +133559,7 @@ SQLITE_API int sqlite3_cancel_auto_extension(
|
|
void (*xInit)(void)
|
|
){
|
|
#if SQLITE_THREADSAFE
|
|
- sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
|
|
+ sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN);
|
|
#endif
|
|
int i;
|
|
int n = 0;
|
|
@@ -123585,7 +133586,7 @@ SQLITE_API void sqlite3_reset_auto_extension(void){
|
|
#endif
|
|
{
|
|
#if SQLITE_THREADSAFE
|
|
- sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
|
|
+ sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN);
|
|
#endif
|
|
wsdAutoextInit;
|
|
sqlite3_mutex_enter(mutex);
|
|
@@ -123615,7 +133616,7 @@ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){
|
|
for(i=0; go; i++){
|
|
char *zErrmsg;
|
|
#if SQLITE_THREADSAFE
|
|
- sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
|
|
+ sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN);
|
|
#endif
|
|
#ifdef SQLITE_OMIT_LOAD_EXTENSION
|
|
const sqlite3_api_routines *pThunk = 0;
|
|
@@ -123670,7 +133671,7 @@ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){
|
|
** that includes the PragType_XXXX macro definitions and the aPragmaName[]
|
|
** object. This ensures that the aPragmaName[] table is arranged in
|
|
** lexicographical order to facility a binary search of the pragma name.
|
|
-** Do not edit pragma.h directly. Edit and rerun the script in at
|
|
+** Do not edit pragma.h directly. Edit and rerun the script in at
|
|
** ../tool/mkpragmatab.tcl. */
|
|
/************** Include pragma.h in the middle of pragma.c *******************/
|
|
/************** Begin file pragma.h ******************************************/
|
|
@@ -123681,51 +133682,52 @@ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){
|
|
*/
|
|
|
|
/* The various pragma types */
|
|
-#define PragTyp_HEADER_VALUE 0
|
|
-#define PragTyp_AUTO_VACUUM 1
|
|
-#define PragTyp_FLAG 2
|
|
-#define PragTyp_BUSY_TIMEOUT 3
|
|
-#define PragTyp_CACHE_SIZE 4
|
|
-#define PragTyp_CACHE_SPILL 5
|
|
-#define PragTyp_CASE_SENSITIVE_LIKE 6
|
|
-#define PragTyp_COLLATION_LIST 7
|
|
-#define PragTyp_COMPILE_OPTIONS 8
|
|
-#define PragTyp_DATA_STORE_DIRECTORY 9
|
|
-#define PragTyp_DATABASE_LIST 10
|
|
-#define PragTyp_DEFAULT_CACHE_SIZE 11
|
|
-#define PragTyp_ENCODING 12
|
|
-#define PragTyp_FOREIGN_KEY_CHECK 13
|
|
-#define PragTyp_FOREIGN_KEY_LIST 14
|
|
-#define PragTyp_FUNCTION_LIST 15
|
|
-#define PragTyp_HARD_HEAP_LIMIT 16
|
|
-#define PragTyp_INCREMENTAL_VACUUM 17
|
|
-#define PragTyp_INDEX_INFO 18
|
|
-#define PragTyp_INDEX_LIST 19
|
|
-#define PragTyp_INTEGRITY_CHECK 20
|
|
-#define PragTyp_JOURNAL_MODE 21
|
|
-#define PragTyp_JOURNAL_SIZE_LIMIT 22
|
|
-#define PragTyp_LOCK_PROXY_FILE 23
|
|
-#define PragTyp_LOCKING_MODE 24
|
|
-#define PragTyp_PAGE_COUNT 25
|
|
-#define PragTyp_MMAP_SIZE 26
|
|
-#define PragTyp_MODULE_LIST 27
|
|
-#define PragTyp_OPTIMIZE 28
|
|
-#define PragTyp_PAGE_SIZE 29
|
|
-#define PragTyp_PRAGMA_LIST 30
|
|
-#define PragTyp_SECURE_DELETE 31
|
|
-#define PragTyp_SHRINK_MEMORY 32
|
|
-#define PragTyp_SOFT_HEAP_LIMIT 33
|
|
-#define PragTyp_SYNCHRONOUS 34
|
|
-#define PragTyp_TABLE_INFO 35
|
|
-#define PragTyp_TEMP_STORE 36
|
|
-#define PragTyp_TEMP_STORE_DIRECTORY 37
|
|
-#define PragTyp_THREADS 38
|
|
-#define PragTyp_WAL_AUTOCHECKPOINT 39
|
|
-#define PragTyp_WAL_CHECKPOINT 40
|
|
-#define PragTyp_ACTIVATE_EXTENSIONS 41
|
|
-#define PragTyp_KEY 42
|
|
-#define PragTyp_LOCK_STATUS 43
|
|
-#define PragTyp_STATS 44
|
|
+#define PragTyp_ACTIVATE_EXTENSIONS 0
|
|
+#define PragTyp_ANALYSIS_LIMIT 1
|
|
+#define PragTyp_HEADER_VALUE 2
|
|
+#define PragTyp_AUTO_VACUUM 3
|
|
+#define PragTyp_FLAG 4
|
|
+#define PragTyp_BUSY_TIMEOUT 5
|
|
+#define PragTyp_CACHE_SIZE 6
|
|
+#define PragTyp_CACHE_SPILL 7
|
|
+#define PragTyp_CASE_SENSITIVE_LIKE 8
|
|
+#define PragTyp_COLLATION_LIST 9
|
|
+#define PragTyp_COMPILE_OPTIONS 10
|
|
+#define PragTyp_DATA_STORE_DIRECTORY 11
|
|
+#define PragTyp_DATABASE_LIST 12
|
|
+#define PragTyp_DEFAULT_CACHE_SIZE 13
|
|
+#define PragTyp_ENCODING 14
|
|
+#define PragTyp_FOREIGN_KEY_CHECK 15
|
|
+#define PragTyp_FOREIGN_KEY_LIST 16
|
|
+#define PragTyp_FUNCTION_LIST 17
|
|
+#define PragTyp_HARD_HEAP_LIMIT 18
|
|
+#define PragTyp_INCREMENTAL_VACUUM 19
|
|
+#define PragTyp_INDEX_INFO 20
|
|
+#define PragTyp_INDEX_LIST 21
|
|
+#define PragTyp_INTEGRITY_CHECK 22
|
|
+#define PragTyp_JOURNAL_MODE 23
|
|
+#define PragTyp_JOURNAL_SIZE_LIMIT 24
|
|
+#define PragTyp_LOCK_PROXY_FILE 25
|
|
+#define PragTyp_LOCKING_MODE 26
|
|
+#define PragTyp_PAGE_COUNT 27
|
|
+#define PragTyp_MMAP_SIZE 28
|
|
+#define PragTyp_MODULE_LIST 29
|
|
+#define PragTyp_OPTIMIZE 30
|
|
+#define PragTyp_PAGE_SIZE 31
|
|
+#define PragTyp_PRAGMA_LIST 32
|
|
+#define PragTyp_SECURE_DELETE 33
|
|
+#define PragTyp_SHRINK_MEMORY 34
|
|
+#define PragTyp_SOFT_HEAP_LIMIT 35
|
|
+#define PragTyp_SYNCHRONOUS 36
|
|
+#define PragTyp_TABLE_INFO 37
|
|
+#define PragTyp_TABLE_LIST 38
|
|
+#define PragTyp_TEMP_STORE 39
|
|
+#define PragTyp_TEMP_STORE_DIRECTORY 40
|
|
+#define PragTyp_THREADS 41
|
|
+#define PragTyp_WAL_AUTOCHECKPOINT 42
|
|
+#define PragTyp_WAL_CHECKPOINT 43
|
|
+#define PragTyp_LOCK_STATUS 44
|
|
+#define PragTyp_STATS 45
|
|
|
|
/* Property flags associated with various pragma. */
|
|
#define PragFlg_NeedSchema 0x01 /* Force schema load before running */
|
|
@@ -123743,60 +133745,66 @@ SQLITE_PRIVATE void sqlite3AutoLoadExtensions(sqlite3 *db){
|
|
*/
|
|
static const char *const pragCName[] = {
|
|
/* 0 */ "id", /* Used by: foreign_key_list */
|
|
- /* 1 */ "seq",
|
|
- /* 2 */ "table",
|
|
- /* 3 */ "from",
|
|
- /* 4 */ "to",
|
|
- /* 5 */ "on_update",
|
|
- /* 6 */ "on_delete",
|
|
- /* 7 */ "match",
|
|
+ /* 1 */ "seq",
|
|
+ /* 2 */ "table",
|
|
+ /* 3 */ "from",
|
|
+ /* 4 */ "to",
|
|
+ /* 5 */ "on_update",
|
|
+ /* 6 */ "on_delete",
|
|
+ /* 7 */ "match",
|
|
/* 8 */ "cid", /* Used by: table_xinfo */
|
|
- /* 9 */ "name",
|
|
- /* 10 */ "type",
|
|
- /* 11 */ "notnull",
|
|
- /* 12 */ "dflt_value",
|
|
- /* 13 */ "pk",
|
|
- /* 14 */ "hidden",
|
|
+ /* 9 */ "name",
|
|
+ /* 10 */ "type",
|
|
+ /* 11 */ "notnull",
|
|
+ /* 12 */ "dflt_value",
|
|
+ /* 13 */ "pk",
|
|
+ /* 14 */ "hidden",
|
|
/* table_info reuses 8 */
|
|
- /* 15 */ "seqno", /* Used by: index_xinfo */
|
|
- /* 16 */ "cid",
|
|
- /* 17 */ "name",
|
|
- /* 18 */ "desc",
|
|
- /* 19 */ "coll",
|
|
- /* 20 */ "key",
|
|
- /* 21 */ "name", /* Used by: function_list */
|
|
- /* 22 */ "builtin",
|
|
- /* 23 */ "type",
|
|
- /* 24 */ "enc",
|
|
- /* 25 */ "narg",
|
|
- /* 26 */ "flags",
|
|
- /* 27 */ "tbl", /* Used by: stats */
|
|
- /* 28 */ "idx",
|
|
- /* 29 */ "wdth",
|
|
- /* 30 */ "hght",
|
|
- /* 31 */ "flgs",
|
|
- /* 32 */ "seq", /* Used by: index_list */
|
|
- /* 33 */ "name",
|
|
- /* 34 */ "unique",
|
|
- /* 35 */ "origin",
|
|
- /* 36 */ "partial",
|
|
- /* 37 */ "table", /* Used by: foreign_key_check */
|
|
- /* 38 */ "rowid",
|
|
- /* 39 */ "parent",
|
|
- /* 40 */ "fkid",
|
|
- /* index_info reuses 15 */
|
|
- /* 41 */ "seq", /* Used by: database_list */
|
|
- /* 42 */ "name",
|
|
- /* 43 */ "file",
|
|
- /* 44 */ "busy", /* Used by: wal_checkpoint */
|
|
- /* 45 */ "log",
|
|
- /* 46 */ "checkpointed",
|
|
- /* collation_list reuses 32 */
|
|
- /* 47 */ "database", /* Used by: lock_status */
|
|
- /* 48 */ "status",
|
|
- /* 49 */ "cache_size", /* Used by: default_cache_size */
|
|
+ /* 15 */ "schema", /* Used by: table_list */
|
|
+ /* 16 */ "name",
|
|
+ /* 17 */ "type",
|
|
+ /* 18 */ "ncol",
|
|
+ /* 19 */ "wr",
|
|
+ /* 20 */ "strict",
|
|
+ /* 21 */ "seqno", /* Used by: index_xinfo */
|
|
+ /* 22 */ "cid",
|
|
+ /* 23 */ "name",
|
|
+ /* 24 */ "desc",
|
|
+ /* 25 */ "coll",
|
|
+ /* 26 */ "key",
|
|
+ /* 27 */ "name", /* Used by: function_list */
|
|
+ /* 28 */ "builtin",
|
|
+ /* 29 */ "type",
|
|
+ /* 30 */ "enc",
|
|
+ /* 31 */ "narg",
|
|
+ /* 32 */ "flags",
|
|
+ /* 33 */ "tbl", /* Used by: stats */
|
|
+ /* 34 */ "idx",
|
|
+ /* 35 */ "wdth",
|
|
+ /* 36 */ "hght",
|
|
+ /* 37 */ "flgs",
|
|
+ /* 38 */ "seq", /* Used by: index_list */
|
|
+ /* 39 */ "name",
|
|
+ /* 40 */ "unique",
|
|
+ /* 41 */ "origin",
|
|
+ /* 42 */ "partial",
|
|
+ /* 43 */ "table", /* Used by: foreign_key_check */
|
|
+ /* 44 */ "rowid",
|
|
+ /* 45 */ "parent",
|
|
+ /* 46 */ "fkid",
|
|
+ /* index_info reuses 21 */
|
|
+ /* 47 */ "seq", /* Used by: database_list */
|
|
+ /* 48 */ "name",
|
|
+ /* 49 */ "file",
|
|
+ /* 50 */ "busy", /* Used by: wal_checkpoint */
|
|
+ /* 51 */ "log",
|
|
+ /* 52 */ "checkpointed",
|
|
+ /* collation_list reuses 38 */
|
|
+ /* 53 */ "database", /* Used by: lock_status */
|
|
+ /* 54 */ "status",
|
|
+ /* 55 */ "cache_size", /* Used by: default_cache_size */
|
|
/* module_list pragma_list reuses 9 */
|
|
- /* 50 */ "timeout", /* Used by: busy_timeout */
|
|
+ /* 56 */ "timeout", /* Used by: busy_timeout */
|
|
};
|
|
|
|
/* Definitions of all built-in pragmas */
|
|
@@ -123809,13 +133817,18 @@ typedef struct PragmaName {
|
|
u64 iArg; /* Extra argument */
|
|
} PragmaName;
|
|
static const PragmaName aPragmaName[] = {
|
|
-#if defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD)
|
|
+#if defined(SQLITE_ENABLE_CEROD)
|
|
{/* zName: */ "activate_extensions",
|
|
/* ePragTyp: */ PragTyp_ACTIVATE_EXTENSIONS,
|
|
/* ePragFlg: */ 0,
|
|
/* ColNames: */ 0, 0,
|
|
/* iArg: */ 0 },
|
|
#endif
|
|
+ {/* zName: */ "analysis_limit",
|
|
+ /* ePragTyp: */ PragTyp_ANALYSIS_LIMIT,
|
|
+ /* ePragFlg: */ PragFlg_Result0,
|
|
+ /* ColNames: */ 0, 0,
|
|
+ /* iArg: */ 0 },
|
|
#if !defined(SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS)
|
|
{/* zName: */ "application_id",
|
|
/* ePragTyp: */ PragTyp_HEADER_VALUE,
|
|
@@ -123842,7 +133855,7 @@ static const PragmaName aPragmaName[] = {
|
|
{/* zName: */ "busy_timeout",
|
|
/* ePragTyp: */ PragTyp_BUSY_TIMEOUT,
|
|
/* ePragFlg: */ PragFlg_Result0,
|
|
- /* ColNames: */ 50, 1,
|
|
+ /* ColNames: */ 56, 1,
|
|
/* iArg: */ 0 },
|
|
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
|
|
{/* zName: */ "cache_size",
|
|
@@ -123881,7 +133894,7 @@ static const PragmaName aPragmaName[] = {
|
|
{/* zName: */ "collation_list",
|
|
/* ePragTyp: */ PragTyp_COLLATION_LIST,
|
|
/* ePragFlg: */ PragFlg_Result0,
|
|
- /* ColNames: */ 32, 2,
|
|
+ /* ColNames: */ 38, 2,
|
|
/* iArg: */ 0 },
|
|
#endif
|
|
#if !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS)
|
|
@@ -123915,15 +133928,15 @@ static const PragmaName aPragmaName[] = {
|
|
#if !defined(SQLITE_OMIT_SCHEMA_PRAGMAS)
|
|
{/* zName: */ "database_list",
|
|
/* ePragTyp: */ PragTyp_DATABASE_LIST,
|
|
- /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0,
|
|
- /* ColNames: */ 41, 3,
|
|
+ /* ePragFlg: */ PragFlg_Result0,
|
|
+ /* ColNames: */ 47, 3,
|
|
/* iArg: */ 0 },
|
|
#endif
|
|
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)
|
|
{/* zName: */ "default_cache_size",
|
|
/* ePragTyp: */ PragTyp_DEFAULT_CACHE_SIZE,
|
|
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
|
|
- /* ColNames: */ 49, 1,
|
|
+ /* ColNames: */ 55, 1,
|
|
/* iArg: */ 0 },
|
|
#endif
|
|
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
|
|
@@ -123952,8 +133965,8 @@ static const PragmaName aPragmaName[] = {
|
|
#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
|
|
{/* zName: */ "foreign_key_check",
|
|
/* ePragTyp: */ PragTyp_FOREIGN_KEY_CHECK,
|
|
- /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0,
|
|
- /* ColNames: */ 37, 4,
|
|
+ /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1|PragFlg_SchemaOpt,
|
|
+ /* ColNames: */ 43, 4,
|
|
/* iArg: */ 0 },
|
|
#endif
|
|
#if !defined(SQLITE_OMIT_FOREIGN_KEY)
|
|
@@ -123996,7 +134009,7 @@ static const PragmaName aPragmaName[] = {
|
|
{/* zName: */ "function_list",
|
|
/* ePragTyp: */ PragTyp_FUNCTION_LIST,
|
|
/* ePragFlg: */ PragFlg_Result0,
|
|
- /* ColNames: */ 21, 6,
|
|
+ /* ColNames: */ 27, 6,
|
|
/* iArg: */ 0 },
|
|
#endif
|
|
#endif
|
|
@@ -124005,18 +134018,6 @@ static const PragmaName aPragmaName[] = {
|
|
/* ePragFlg: */ PragFlg_Result0,
|
|
/* ColNames: */ 0, 0,
|
|
/* iArg: */ 0 },
|
|
-#if defined(SQLITE_HAS_CODEC)
|
|
- {/* zName: */ "hexkey",
|
|
- /* ePragTyp: */ PragTyp_KEY,
|
|
- /* ePragFlg: */ 0,
|
|
- /* ColNames: */ 0, 0,
|
|
- /* iArg: */ 2 },
|
|
- {/* zName: */ "hexrekey",
|
|
- /* ePragTyp: */ PragTyp_KEY,
|
|
- /* ePragFlg: */ 0,
|
|
- /* ColNames: */ 0, 0,
|
|
- /* iArg: */ 3 },
|
|
-#endif
|
|
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
|
|
#if !defined(SQLITE_OMIT_CHECK)
|
|
{/* zName: */ "ignore_check_constraints",
|
|
@@ -124037,23 +134038,23 @@ static const PragmaName aPragmaName[] = {
|
|
{/* zName: */ "index_info",
|
|
/* ePragTyp: */ PragTyp_INDEX_INFO,
|
|
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
|
|
- /* ColNames: */ 15, 3,
|
|
+ /* ColNames: */ 21, 3,
|
|
/* iArg: */ 0 },
|
|
{/* zName: */ "index_list",
|
|
/* ePragTyp: */ PragTyp_INDEX_LIST,
|
|
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
|
|
- /* ColNames: */ 32, 5,
|
|
+ /* ColNames: */ 38, 5,
|
|
/* iArg: */ 0 },
|
|
{/* zName: */ "index_xinfo",
|
|
/* ePragTyp: */ PragTyp_INDEX_INFO,
|
|
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
|
|
- /* ColNames: */ 15, 6,
|
|
+ /* ColNames: */ 21, 6,
|
|
/* iArg: */ 1 },
|
|
#endif
|
|
#if !defined(SQLITE_OMIT_INTEGRITY_CHECK)
|
|
{/* zName: */ "integrity_check",
|
|
/* ePragTyp: */ PragTyp_INTEGRITY_CHECK,
|
|
- /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1,
|
|
+ /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1|PragFlg_SchemaOpt,
|
|
/* ColNames: */ 0, 0,
|
|
/* iArg: */ 0 },
|
|
#endif
|
|
@@ -124069,13 +134070,6 @@ static const PragmaName aPragmaName[] = {
|
|
/* ColNames: */ 0, 0,
|
|
/* iArg: */ 0 },
|
|
#endif
|
|
-#if defined(SQLITE_HAS_CODEC)
|
|
- {/* zName: */ "key",
|
|
- /* ePragTyp: */ PragTyp_KEY,
|
|
- /* ePragFlg: */ 0,
|
|
- /* ColNames: */ 0, 0,
|
|
- /* iArg: */ 0 },
|
|
-#endif
|
|
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
|
|
{/* zName: */ "legacy_alter_table",
|
|
/* ePragTyp: */ PragTyp_FLAG,
|
|
@@ -124094,7 +134088,7 @@ static const PragmaName aPragmaName[] = {
|
|
{/* zName: */ "lock_status",
|
|
/* ePragTyp: */ PragTyp_LOCK_STATUS,
|
|
/* ePragFlg: */ PragFlg_Result0,
|
|
- /* ColNames: */ 47, 2,
|
|
+ /* ColNames: */ 53, 2,
|
|
/* iArg: */ 0 },
|
|
#endif
|
|
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
|
|
@@ -124168,7 +134162,7 @@ static const PragmaName aPragmaName[] = {
|
|
#if !defined(SQLITE_OMIT_INTEGRITY_CHECK)
|
|
{/* zName: */ "quick_check",
|
|
/* ePragTyp: */ PragTyp_INTEGRITY_CHECK,
|
|
- /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1,
|
|
+ /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1|PragFlg_SchemaOpt,
|
|
/* ColNames: */ 0, 0,
|
|
/* iArg: */ 0 },
|
|
#endif
|
|
@@ -124183,15 +134177,6 @@ static const PragmaName aPragmaName[] = {
|
|
/* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1,
|
|
/* ColNames: */ 0, 0,
|
|
/* iArg: */ SQLITE_RecTriggers },
|
|
-#endif
|
|
-#if defined(SQLITE_HAS_CODEC)
|
|
- {/* zName: */ "rekey",
|
|
- /* ePragTyp: */ PragTyp_KEY,
|
|
- /* ePragFlg: */ 0,
|
|
- /* ColNames: */ 0, 0,
|
|
- /* iArg: */ 1 },
|
|
-#endif
|
|
-#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
|
|
{/* zName: */ "reverse_unordered_selects",
|
|
/* ePragTyp: */ PragTyp_FLAG,
|
|
/* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1,
|
|
@@ -124242,7 +134227,7 @@ static const PragmaName aPragmaName[] = {
|
|
{/* zName: */ "stats",
|
|
/* ePragTyp: */ PragTyp_STATS,
|
|
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq,
|
|
- /* ColNames: */ 27, 5,
|
|
+ /* ColNames: */ 33, 5,
|
|
/* iArg: */ 0 },
|
|
#endif
|
|
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
|
|
@@ -124258,6 +134243,11 @@ static const PragmaName aPragmaName[] = {
|
|
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
|
|
/* ColNames: */ 8, 6,
|
|
/* iArg: */ 0 },
|
|
+ {/* zName: */ "table_list",
|
|
+ /* ePragTyp: */ PragTyp_TABLE_LIST,
|
|
+ /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1,
|
|
+ /* ColNames: */ 15, 6,
|
|
+ /* iArg: */ 0 },
|
|
{/* zName: */ "table_xinfo",
|
|
/* ePragTyp: */ PragTyp_TABLE_INFO,
|
|
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
|
|
@@ -124275,18 +134265,6 @@ static const PragmaName aPragmaName[] = {
|
|
/* ePragFlg: */ PragFlg_NoColumns1,
|
|
/* ColNames: */ 0, 0,
|
|
/* iArg: */ 0 },
|
|
-#endif
|
|
-#if defined(SQLITE_HAS_CODEC)
|
|
- {/* zName: */ "textkey",
|
|
- /* ePragTyp: */ PragTyp_KEY,
|
|
- /* ePragFlg: */ 0,
|
|
- /* ColNames: */ 0, 0,
|
|
- /* iArg: */ 4 },
|
|
- {/* zName: */ "textrekey",
|
|
- /* ePragTyp: */ PragTyp_KEY,
|
|
- /* ePragFlg: */ 0,
|
|
- /* ColNames: */ 0, 0,
|
|
- /* iArg: */ 5 },
|
|
#endif
|
|
{/* zName: */ "threads",
|
|
/* ePragTyp: */ PragTyp_THREADS,
|
|
@@ -124345,7 +134323,7 @@ static const PragmaName aPragmaName[] = {
|
|
{/* zName: */ "wal_checkpoint",
|
|
/* ePragTyp: */ PragTyp_WAL_CHECKPOINT,
|
|
/* ePragFlg: */ PragFlg_NeedSchema,
|
|
- /* ColNames: */ 44, 3,
|
|
+ /* ColNames: */ 50, 3,
|
|
/* iArg: */ 0 },
|
|
#endif
|
|
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
|
|
@@ -124356,14 +134334,14 @@ static const PragmaName aPragmaName[] = {
|
|
/* iArg: */ SQLITE_WriteSchema|SQLITE_NoSchemaError },
|
|
#endif
|
|
};
|
|
-/* Number of pragmas: 66 on by default, 82 total. */
|
|
+/* Number of pragmas: 68 on by default, 78 total. */
|
|
|
|
/************** End of pragma.h **********************************************/
|
|
/************** Continuing where we left off in pragma.c *********************/
|
|
|
|
/*
|
|
** Interpret the given string as a safety level. Return 0 for OFF,
|
|
-** 1 for ON or NORMAL, 2 for FULL, and 3 for EXTRA. Return 1 for an empty or
|
|
+** 1 for ON or NORMAL, 2 for FULL, and 3 for EXTRA. Return 1 for an empty or
|
|
** unrecognized string argument. The FULL and EXTRA option is disallowed
|
|
** if the omitFull parameter it 1.
|
|
**
|
|
@@ -124422,7 +134400,7 @@ static int getLockingMode(const char *z){
|
|
/*
|
|
** Interpret the given string as an auto-vacuum mode value.
|
|
**
|
|
-** The following strings, "none", "full" and "incremental" are
|
|
+** The following strings, "none", "full" and "incremental" are
|
|
** acceptable, as are their numeric equivalents: 0, 1 and 2 respectively.
|
|
*/
|
|
static int getAutoVacuum(const char *z){
|
|
@@ -124462,7 +134440,9 @@ static int getTempStore(const char *z){
|
|
static int invalidateTempStorage(Parse *pParse){
|
|
sqlite3 *db = pParse->db;
|
|
if( db->aDb[1].pBt!=0 ){
|
|
- if( !db->autoCommit || sqlite3BtreeIsInReadTrans(db->aDb[1].pBt) ){
|
|
+ if( !db->autoCommit
|
|
+ || sqlite3BtreeTxnState(db->aDb[1].pBt)!=SQLITE_TXN_NONE
|
|
+ ){
|
|
sqlite3ErrorMsg(pParse, "temporary storage cannot be changed "
|
|
"from within a transaction");
|
|
return SQLITE_ERROR;
|
|
@@ -124574,7 +134554,7 @@ static const char *actionName(u8 action){
|
|
case OE_SetDflt: zName = "SET DEFAULT"; break;
|
|
case OE_Cascade: zName = "CASCADE"; break;
|
|
case OE_Restrict: zName = "RESTRICT"; break;
|
|
- default: zName = "NO ACTION";
|
|
+ default: zName = "NO ACTION";
|
|
assert( action==OE_None ); break;
|
|
}
|
|
return zName;
|
|
@@ -124636,15 +134616,16 @@ static void pragmaFunclistLine(
|
|
int isBuiltin, /* True if this is a built-in function */
|
|
int showInternFuncs /* True if showing internal functions */
|
|
){
|
|
+ u32 mask =
|
|
+ SQLITE_DETERMINISTIC |
|
|
+ SQLITE_DIRECTONLY |
|
|
+ SQLITE_SUBTYPE |
|
|
+ SQLITE_INNOCUOUS |
|
|
+ SQLITE_FUNC_INTERNAL
|
|
+ ;
|
|
+ if( showInternFuncs ) mask = 0xffffffff;
|
|
for(; p; p=p->pNext){
|
|
const char *zType;
|
|
- static const u32 mask =
|
|
- SQLITE_DETERMINISTIC |
|
|
- SQLITE_DIRECTONLY |
|
|
- SQLITE_SUBTYPE |
|
|
- SQLITE_INNOCUOUS |
|
|
- SQLITE_FUNC_INTERNAL
|
|
- ;
|
|
static const char *azEnc[] = { 0, "utf8", "utf16le", "utf16be" };
|
|
|
|
assert( SQLITE_FUNC_ENCMASK==0x3 );
|
|
@@ -124657,7 +134638,7 @@ static void pragmaFunclistLine(
|
|
&& showInternFuncs==0
|
|
){
|
|
continue;
|
|
- }
|
|
+ }
|
|
if( p->xValue!=0 ){
|
|
zType = "w";
|
|
}else if( p->xFinalize!=0 ){
|
|
@@ -124692,7 +134673,7 @@ static int integrityCheckResultRow(Vdbe *v){
|
|
}
|
|
|
|
/*
|
|
-** Process a pragma statement.
|
|
+** Process a pragma statement.
|
|
**
|
|
** Pragmas are of this form:
|
|
**
|
|
@@ -124707,7 +134688,7 @@ static int integrityCheckResultRow(Vdbe *v){
|
|
** id and pId2 is any empty string.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3Pragma(
|
|
- Parse *pParse,
|
|
+ Parse *pParse,
|
|
Token *pId1, /* First part of [schema.]id field */
|
|
Token *pId2, /* Second part of [schema.]id field, or NULL */
|
|
Token *pValue, /* Token for <value>, or NULL */
|
|
@@ -124735,8 +134716,8 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
if( iDb<0 ) return;
|
|
pDb = &db->aDb[iDb];
|
|
|
|
- /* If the temp database has been explicitly named as part of the
|
|
- ** pragma, make sure it is open.
|
|
+ /* If the temp database has been explicitly named as part of the
|
|
+ ** pragma, make sure it is open.
|
|
*/
|
|
if( iDb==1 && sqlite3OpenTempDatabase(pParse) ){
|
|
return;
|
|
@@ -124796,7 +134777,11 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
|
|
/* Locate the pragma in the lookup table */
|
|
pPragma = pragmaLocate(zLeft);
|
|
- if( pPragma==0 ) goto pragma_out;
|
|
+ if( pPragma==0 ){
|
|
+ /* IMP: R-43042-22504 No error messages are generated if an
|
|
+ ** unknown pragma is issued. */
|
|
+ goto pragma_out;
|
|
+ }
|
|
|
|
/* Make sure the database schema is loaded if the pragma requires that */
|
|
if( (pPragma->mPragFlg & PragFlg_NeedSchema)!=0 ){
|
|
@@ -124804,7 +134789,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
}
|
|
|
|
/* Register the result column names for pragmas that return results */
|
|
- if( (pPragma->mPragFlg & PragFlg_NoColumns)==0
|
|
+ if( (pPragma->mPragFlg & PragFlg_NoColumns)==0
|
|
&& ((pPragma->mPragFlg & PragFlg_NoColumns1)==0 || zRight==0)
|
|
){
|
|
setPragmaResultColumnNames(v, pPragma);
|
|
@@ -124812,7 +134797,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
|
|
/* Jump to the appropriate pragma handler */
|
|
switch( pPragma->ePragTyp ){
|
|
-
|
|
+
|
|
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)
|
|
/*
|
|
** PRAGMA [schema.]default_cache_size
|
|
@@ -124886,7 +134871,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
** buffer that the pager module resizes using sqlite3_realloc().
|
|
*/
|
|
db->nextPagesize = sqlite3Atoi(zRight);
|
|
- if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize,-1,0) ){
|
|
+ if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize,0,0) ){
|
|
sqlite3OomFault(db);
|
|
}
|
|
}
|
|
@@ -124928,7 +134913,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
** PRAGMA [schema.]max_page_count=N
|
|
**
|
|
** The first form reports the current setting for the
|
|
- ** maximum number of pages in the database file. The
|
|
+ ** maximum number of pages in the database file. The
|
|
** second form attempts to change this setting. Both
|
|
** forms return the current setting.
|
|
**
|
|
@@ -124942,13 +134927,19 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
*/
|
|
case PragTyp_PAGE_COUNT: {
|
|
int iReg;
|
|
+ i64 x = 0;
|
|
sqlite3CodeVerifySchema(pParse, iDb);
|
|
iReg = ++pParse->nMem;
|
|
if( sqlite3Tolower(zLeft[0])=='p' ){
|
|
sqlite3VdbeAddOp2(v, OP_Pagecount, iDb, iReg);
|
|
}else{
|
|
- sqlite3VdbeAddOp3(v, OP_MaxPgcnt, iDb, iReg,
|
|
- sqlite3AbsInt32(sqlite3Atoi(zRight)));
|
|
+ if( zRight && sqlite3DecOrHexToI64(zRight,&x)==0 ){
|
|
+ if( x<0 ) x = 0;
|
|
+ else if( x>0xfffffffe ) x = 0xfffffffe;
|
|
+ }else{
|
|
+ x = 0;
|
|
+ }
|
|
+ sqlite3VdbeAddOp3(v, OP_MaxPgcnt, iDb, iReg, (int)x);
|
|
}
|
|
sqlite3VdbeAddOp2(v, OP_ResultRow, iReg, 1);
|
|
break;
|
|
@@ -125089,7 +135080,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
*/
|
|
rc = sqlite3BtreeSetAutoVacuum(pBt, eAuto);
|
|
if( rc==SQLITE_OK && (eAuto==1 || eAuto==2) ){
|
|
- /* When setting the auto_vacuum mode to either "full" or
|
|
+ /* When setting the auto_vacuum mode to either "full" or
|
|
** "incremental", write the value of meta[6] in the database
|
|
** file. Before writing to meta[6], check that meta[3] indicates
|
|
** that this really is an auto-vacuum capable database.
|
|
@@ -125126,7 +135117,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
*/
|
|
#ifndef SQLITE_OMIT_AUTOVACUUM
|
|
case PragTyp_INCREMENTAL_VACUUM: {
|
|
- int iLimit, addr;
|
|
+ int iLimit = 0, addr;
|
|
if( zRight==0 || !sqlite3GetInt32(zRight, &iLimit) || iLimit<=0 ){
|
|
iLimit = 0x7fffffff;
|
|
}
|
|
@@ -125191,7 +135182,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
|
if( !zRight ){
|
|
returnSingleInt(v,
|
|
- (db->flags & SQLITE_CacheSpill)==0 ? 0 :
|
|
+ (db->flags & SQLITE_CacheSpill)==0 ? 0 :
|
|
sqlite3BtreeSetSpillSize(pDb->pBt,0));
|
|
}else{
|
|
int size = 1;
|
|
@@ -125283,6 +135274,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
**
|
|
*/
|
|
case PragTyp_TEMP_STORE_DIRECTORY: {
|
|
+ sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
|
|
if( !zRight ){
|
|
returnSingleText(v, sqlite3_temp_directory);
|
|
}else{
|
|
@@ -125292,6 +135284,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
rc = sqlite3OsAccess(db->pVfs, zRight, SQLITE_ACCESS_READWRITE, &res);
|
|
if( rc!=SQLITE_OK || res==0 ){
|
|
sqlite3ErrorMsg(pParse, "not a writable directory");
|
|
+ sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
|
|
goto pragma_out;
|
|
}
|
|
}
|
|
@@ -125309,6 +135302,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
}
|
|
#endif /* SQLITE_OMIT_WSD */
|
|
}
|
|
+ sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
|
|
break;
|
|
}
|
|
|
|
@@ -125327,6 +135321,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
**
|
|
*/
|
|
case PragTyp_DATA_STORE_DIRECTORY: {
|
|
+ sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
|
|
if( !zRight ){
|
|
returnSingleText(v, sqlite3_data_directory);
|
|
}else{
|
|
@@ -125336,6 +135331,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
rc = sqlite3OsAccess(db->pVfs, zRight, SQLITE_ACCESS_READWRITE, &res);
|
|
if( rc!=SQLITE_OK || res==0 ){
|
|
sqlite3ErrorMsg(pParse, "not a writable directory");
|
|
+ sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
|
|
goto pragma_out;
|
|
}
|
|
}
|
|
@@ -125347,6 +135343,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
}
|
|
#endif /* SQLITE_OMIT_WSD */
|
|
}
|
|
+ sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_TEMPDIR));
|
|
break;
|
|
}
|
|
#endif
|
|
@@ -125365,7 +135362,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
Pager *pPager = sqlite3BtreePager(pDb->pBt);
|
|
char *proxy_file_path = NULL;
|
|
sqlite3_file *pFile = sqlite3PagerFile(pPager);
|
|
- sqlite3OsFileControlHint(pFile, SQLITE_GET_LOCKPROXYFILE,
|
|
+ sqlite3OsFileControlHint(pFile, SQLITE_GET_LOCKPROXYFILE,
|
|
&proxy_file_path);
|
|
returnSingleText(v, proxy_file_path);
|
|
}else{
|
|
@@ -125373,10 +135370,10 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
sqlite3_file *pFile = sqlite3PagerFile(pPager);
|
|
int res;
|
|
if( zRight[0] ){
|
|
- res=sqlite3OsFileControl(pFile, SQLITE_SET_LOCKPROXYFILE,
|
|
+ res=sqlite3OsFileControl(pFile, SQLITE_SET_LOCKPROXYFILE,
|
|
zRight);
|
|
} else {
|
|
- res=sqlite3OsFileControl(pFile, SQLITE_SET_LOCKPROXYFILE,
|
|
+ res=sqlite3OsFileControl(pFile, SQLITE_SET_LOCKPROXYFILE,
|
|
NULL);
|
|
}
|
|
if( res!=SQLITE_OK ){
|
|
@@ -125386,8 +135383,8 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
}
|
|
break;
|
|
}
|
|
-#endif /* SQLITE_ENABLE_LOCKING_STYLE */
|
|
-
|
|
+#endif /* SQLITE_ENABLE_LOCKING_STYLE */
|
|
+
|
|
/*
|
|
** PRAGMA [schema.]synchronous
|
|
** PRAGMA [schema.]synchronous=OFF|ON|NORMAL|FULL|EXTRA
|
|
@@ -125402,7 +135399,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
returnSingleInt(v, pDb->safety_level-1);
|
|
}else{
|
|
if( !db->autoCommit ){
|
|
- sqlite3ErrorMsg(pParse,
|
|
+ sqlite3ErrorMsg(pParse,
|
|
"Safety level may not be changed inside a transaction");
|
|
}else if( iDb!=1 ){
|
|
int iLevel = (getSafetyLevel(zRight,0,1)+1) & PAGER_SYNCHRONOUS_MASK;
|
|
@@ -125440,9 +135437,17 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
}else{
|
|
db->flags &= ~mask;
|
|
if( mask==SQLITE_DeferFKs ) db->nDeferredImmCons = 0;
|
|
+ if( (mask & SQLITE_WriteSchema)!=0
|
|
+ && sqlite3_stricmp(zRight, "reset")==0
|
|
+ ){
|
|
+ /* IMP: R-60817-01178 If the argument is "RESET" then schema
|
|
+ ** writing is disabled (as with "PRAGMA writable_schema=OFF") and,
|
|
+ ** in addition, the schema is reloaded. */
|
|
+ sqlite3ResetAllSchemasOfConnection(db);
|
|
+ }
|
|
}
|
|
|
|
- /* Many of the flag-pragmas modify the code generated by the SQL
|
|
+ /* Many of the flag-pragmas modify the code generated by the SQL
|
|
** compiler (eg. count_changes). So add an opcode to expire all
|
|
** compiled SQL statements after modifying a pragma value.
|
|
*/
|
|
@@ -125469,18 +135474,18 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
*/
|
|
case PragTyp_TABLE_INFO: if( zRight ){
|
|
Table *pTab;
|
|
+ sqlite3CodeVerifyNamedSchema(pParse, zDb);
|
|
pTab = sqlite3LocateTable(pParse, LOCATE_NOERR, zRight, zDb);
|
|
if( pTab ){
|
|
- int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
|
int i, k;
|
|
int nHidden = 0;
|
|
Column *pCol;
|
|
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
|
|
pParse->nMem = 7;
|
|
- sqlite3CodeVerifySchema(pParse, iTabDb);
|
|
sqlite3ViewGetColumnNames(pParse, pTab);
|
|
for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
|
|
int isHidden = 0;
|
|
+ const Expr *pColExpr;
|
|
if( pCol->colFlags & COLFLAG_NOINSERT ){
|
|
if( pPragma->iArg==0 ){
|
|
nHidden++;
|
|
@@ -125501,13 +135506,16 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
}else{
|
|
for(k=1; k<=pTab->nCol && pPk->aiColumn[k-1]!=i; k++){}
|
|
}
|
|
- assert( pCol->pDflt==0 || pCol->pDflt->op==TK_SPAN || isHidden>=2 );
|
|
+ pColExpr = sqlite3ColumnExpr(pTab,pCol);
|
|
+ assert( pColExpr==0 || pColExpr->op==TK_SPAN || isHidden>=2 );
|
|
+ assert( pColExpr==0 || !ExprHasProperty(pColExpr, EP_IntValue)
|
|
+ || isHidden>=2 );
|
|
sqlite3VdbeMultiLoad(v, 1, pPragma->iArg ? "issisii" : "issisi",
|
|
i-nHidden,
|
|
- pCol->zName,
|
|
+ pCol->zCnName,
|
|
sqlite3ColumnType(pCol,""),
|
|
pCol->notNull ? 1 : 0,
|
|
- pCol->pDflt && isHidden<2 ? pCol->pDflt->u.zToken : 0,
|
|
+ (isHidden>=2 || pColExpr==0) ? 0 : pColExpr->u.zToken,
|
|
k,
|
|
isHidden);
|
|
}
|
|
@@ -125515,6 +135523,85 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
}
|
|
break;
|
|
|
|
+ /*
|
|
+ ** PRAGMA table_list
|
|
+ **
|
|
+ ** Return a single row for each table, virtual table, or view in the
|
|
+ ** entire schema.
|
|
+ **
|
|
+ ** schema: Name of attached database hold this table
|
|
+ ** name: Name of the table itself
|
|
+ ** type: "table", "view", "virtual", "shadow"
|
|
+ ** ncol: Number of columns
|
|
+ ** wr: True for a WITHOUT ROWID table
|
|
+ ** strict: True for a STRICT table
|
|
+ */
|
|
+ case PragTyp_TABLE_LIST: {
|
|
+ int ii;
|
|
+ pParse->nMem = 6;
|
|
+ sqlite3CodeVerifyNamedSchema(pParse, zDb);
|
|
+ for(ii=0; ii<db->nDb; ii++){
|
|
+ HashElem *k;
|
|
+ Hash *pHash;
|
|
+ int initNCol;
|
|
+ if( zDb && sqlite3_stricmp(zDb, db->aDb[ii].zDbSName)!=0 ) continue;
|
|
+
|
|
+ /* Ensure that the Table.nCol field is initialized for all views
|
|
+ ** and virtual tables. Each time we initialize a Table.nCol value
|
|
+ ** for a table, that can potentially disrupt the hash table, so restart
|
|
+ ** the initialization scan.
|
|
+ */
|
|
+ pHash = &db->aDb[ii].pSchema->tblHash;
|
|
+ initNCol = sqliteHashCount(pHash);
|
|
+ while( initNCol-- ){
|
|
+ for(k=sqliteHashFirst(pHash); 1; k=sqliteHashNext(k) ){
|
|
+ Table *pTab;
|
|
+ if( k==0 ){ initNCol = 0; break; }
|
|
+ pTab = sqliteHashData(k);
|
|
+ if( pTab->nCol==0 ){
|
|
+ char *zSql = sqlite3MPrintf(db, "SELECT*FROM\"%w\"", pTab->zName);
|
|
+ if( zSql ){
|
|
+ sqlite3_stmt *pDummy = 0;
|
|
+ (void)sqlite3_prepare(db, zSql, -1, &pDummy, 0);
|
|
+ (void)sqlite3_finalize(pDummy);
|
|
+ sqlite3DbFree(db, zSql);
|
|
+ }
|
|
+ if( db->mallocFailed ){
|
|
+ sqlite3ErrorMsg(db->pParse, "out of memory");
|
|
+ db->pParse->rc = SQLITE_NOMEM_BKPT;
|
|
+ }
|
|
+ pHash = &db->aDb[ii].pSchema->tblHash;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ for(k=sqliteHashFirst(pHash); k; k=sqliteHashNext(k) ){
|
|
+ Table *pTab = sqliteHashData(k);
|
|
+ const char *zType;
|
|
+ if( zRight && sqlite3_stricmp(zRight, pTab->zName)!=0 ) continue;
|
|
+ if( IsView(pTab) ){
|
|
+ zType = "view";
|
|
+ }else if( IsVirtual(pTab) ){
|
|
+ zType = "virtual";
|
|
+ }else if( pTab->tabFlags & TF_Shadow ){
|
|
+ zType = "shadow";
|
|
+ }else{
|
|
+ zType = "table";
|
|
+ }
|
|
+ sqlite3VdbeMultiLoad(v, 1, "sssiii",
|
|
+ db->aDb[ii].zDbSName,
|
|
+ sqlite3PreferredTableName(pTab->zName),
|
|
+ zType,
|
|
+ pTab->nCol,
|
|
+ (pTab->tabFlags & TF_WithoutRowid)!=0,
|
|
+ (pTab->tabFlags & TF_Strict)!=0
|
|
+ );
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ break;
|
|
+
|
|
#ifdef SQLITE_DEBUG
|
|
case PragTyp_STATS: {
|
|
Index *pIdx;
|
|
@@ -125524,7 +135611,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
for(i=sqliteHashFirst(&pDb->pSchema->tblHash); i; i=sqliteHashNext(i)){
|
|
Table *pTab = sqliteHashData(i);
|
|
sqlite3VdbeMultiLoad(v, 1, "ssiii",
|
|
- pTab->zName,
|
|
+ sqlite3PreferredTableName(pTab->zName),
|
|
0,
|
|
pTab->szTabRow,
|
|
pTab->nRowLogEst,
|
|
@@ -125574,7 +135661,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
for(i=0; i<mx; i++){
|
|
i16 cnum = pIdx->aiColumn[i];
|
|
sqlite3VdbeMultiLoad(v, 1, "iisX", i, cnum,
|
|
- cnum<0 ? 0 : pTab->aCol[cnum].zName);
|
|
+ cnum<0 ? 0 : pTab->aCol[cnum].zCnName);
|
|
if( pPragma->iArg ){
|
|
sqlite3VdbeMultiLoad(v, 4, "isiX",
|
|
pIdx->aSortOrder[i],
|
|
@@ -125643,11 +135730,13 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
pParse->nMem = 6;
|
|
for(i=0; i<SQLITE_FUNC_HASH_SZ; i++){
|
|
for(p=sqlite3BuiltinFunctions.a[i]; p; p=p->u.pHash ){
|
|
+ assert( p->funcFlags & SQLITE_FUNC_BUILTIN );
|
|
pragmaFunclistLine(v, p, 1, showInternFunc);
|
|
}
|
|
}
|
|
for(j=sqliteHashFirst(&db->aFunc); j; j=sqliteHashNext(j)){
|
|
p = (FuncDef*)sqliteHashData(j);
|
|
+ assert( (p->funcFlags & SQLITE_FUNC_BUILTIN)==0 );
|
|
pragmaFunclistLine(v, p, 0, showInternFunc);
|
|
}
|
|
}
|
|
@@ -125681,11 +135770,11 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
FKey *pFK;
|
|
Table *pTab;
|
|
pTab = sqlite3FindTable(db, zRight, zDb);
|
|
- if( pTab ){
|
|
- pFK = pTab->pFKey;
|
|
+ if( pTab && IsOrdinaryTable(pTab) ){
|
|
+ pFK = pTab->u.tab.pFKey;
|
|
if( pFK ){
|
|
int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
|
- int i = 0;
|
|
+ int i = 0;
|
|
pParse->nMem = 8;
|
|
sqlite3CodeVerifySchema(pParse, iTabDb);
|
|
while(pFK){
|
|
@@ -125695,7 +135784,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
i,
|
|
j,
|
|
pFK->zTo,
|
|
- pTab->aCol[pFK->aCol[j].iFrom].zName,
|
|
+ pTab->aCol[pFK->aCol[j].iFrom].zCnName,
|
|
pFK->aCol[j].zCol,
|
|
actionName(pFK->aAction[1]), /* ON UPDATE */
|
|
actionName(pFK->aAction[0]), /* ON DELETE */
|
|
@@ -125722,7 +135811,6 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
HashElem *k; /* Loop counter: Next table in schema */
|
|
int x; /* result variable */
|
|
int regResult; /* 3 registers to hold a result row */
|
|
- int regKey; /* Register to hold key for checking the FK */
|
|
int regRow; /* Registers to hold a row from pTab */
|
|
int addrTop; /* Top of a loop checking foreign keys */
|
|
int addrOk; /* Jump here if the key is OK */
|
|
@@ -125730,11 +135818,9 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
|
|
regResult = pParse->nMem+1;
|
|
pParse->nMem += 4;
|
|
- regKey = ++pParse->nMem;
|
|
regRow = ++pParse->nMem;
|
|
k = sqliteHashFirst(&db->aDb[iDb].pSchema->tblHash);
|
|
while( k ){
|
|
- int iTabDb;
|
|
if( zRight ){
|
|
pTab = sqlite3LocateTable(pParse, 0, zRight, zDb);
|
|
k = 0;
|
|
@@ -125742,24 +135828,26 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
pTab = (Table*)sqliteHashData(k);
|
|
k = sqliteHashNext(k);
|
|
}
|
|
- if( pTab==0 || pTab->pFKey==0 ) continue;
|
|
- iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
|
- sqlite3CodeVerifySchema(pParse, iTabDb);
|
|
- sqlite3TableLock(pParse, iTabDb, pTab->tnum, 0, pTab->zName);
|
|
+ if( pTab==0 || !IsOrdinaryTable(pTab) || pTab->u.tab.pFKey==0 ) continue;
|
|
+ iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
|
+ 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;
|
|
- sqlite3OpenTable(pParse, 0, iTabDb, pTab, OP_OpenRead);
|
|
+ sqlite3OpenTable(pParse, 0, iDb, pTab, OP_OpenRead);
|
|
sqlite3VdbeLoadString(v, regResult, pTab->zName);
|
|
- for(i=1, pFK=pTab->pFKey; pFK; i++, pFK=pFK->pNextFrom){
|
|
+ assert( IsOrdinaryTable(pTab) );
|
|
+ for(i=1, pFK=pTab->u.tab.pFKey; pFK; i++, pFK=pFK->pNextFrom){
|
|
pParent = sqlite3FindTable(db, pFK->zTo, zDb);
|
|
if( pParent==0 ) continue;
|
|
pIdx = 0;
|
|
- sqlite3TableLock(pParse, iTabDb, pParent->tnum, 0, pParent->zName);
|
|
+ sqlite3TableLock(pParse, iDb, pParent->tnum, 0, pParent->zName);
|
|
x = sqlite3FkLocateIndex(pParse, pParent, pFK, &pIdx, 0);
|
|
if( x==0 ){
|
|
if( pIdx==0 ){
|
|
- sqlite3OpenTable(pParse, i, iTabDb, pParent, OP_OpenRead);
|
|
+ sqlite3OpenTable(pParse, i, iDb, pParent, OP_OpenRead);
|
|
}else{
|
|
- sqlite3VdbeAddOp3(v, OP_OpenRead, i, pIdx->tnum, iTabDb);
|
|
+ sqlite3VdbeAddOp3(v, OP_OpenRead, i, pIdx->tnum, iDb);
|
|
sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
|
|
}
|
|
}else{
|
|
@@ -125771,20 +135859,22 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
if( pFK ) break;
|
|
if( pParse->nTab<i ) pParse->nTab = i;
|
|
addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, 0); VdbeCoverage(v);
|
|
- for(i=1, pFK=pTab->pFKey; pFK; i++, pFK=pFK->pNextFrom){
|
|
+ assert( IsOrdinaryTable(pTab) );
|
|
+ for(i=1, pFK=pTab->u.tab.pFKey; pFK; i++, pFK=pFK->pNextFrom){
|
|
pParent = sqlite3FindTable(db, pFK->zTo, zDb);
|
|
pIdx = 0;
|
|
aiCols = 0;
|
|
if( pParent ){
|
|
x = sqlite3FkLocateIndex(pParse, pParent, pFK, &pIdx, &aiCols);
|
|
- assert( x==0 );
|
|
+ assert( x==0 || db->mallocFailed );
|
|
}
|
|
addrOk = sqlite3VdbeMakeLabel(pParse);
|
|
|
|
/* Generate code to read the child key values into registers
|
|
- ** regRow..regRow+n. If any of the child key values are NULL, this
|
|
- ** row cannot cause an FK violation. Jump directly to addrOk in
|
|
+ ** 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;
|
|
for(j=0; j<pFK->nCol; j++){
|
|
int iCol = aiCols ? aiCols[j] : pFK->aCol[j].iFrom;
|
|
sqlite3ExprCodeGetColumnOfTable(v, pTab, 0, iCol, regRow+j);
|
|
@@ -125794,15 +135884,15 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
/* Generate code to query the parent index for a matching parent
|
|
** key. If a match is found, jump to addrOk. */
|
|
if( pIdx ){
|
|
- sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, pFK->nCol, regKey,
|
|
+ sqlite3VdbeAddOp4(v, OP_Affinity, regRow, pFK->nCol, 0,
|
|
sqlite3IndexAffinityStr(db,pIdx), pFK->nCol);
|
|
- sqlite3VdbeAddOp4Int(v, OP_Found, i, addrOk, regKey, 0);
|
|
+ sqlite3VdbeAddOp4Int(v, OP_Found, i, addrOk, regRow, pFK->nCol);
|
|
VdbeCoverage(v);
|
|
}else if( pParent ){
|
|
int jmp = sqlite3VdbeCurrentAddr(v)+2;
|
|
sqlite3VdbeAddOp3(v, OP_SeekRowid, i, jmp, regRow); VdbeCoverage(v);
|
|
sqlite3VdbeGoto(v, addrOk);
|
|
- assert( pFK->nCol==1 );
|
|
+ assert( pFK->nCol==1 || db->mallocFailed );
|
|
}
|
|
|
|
/* Generate code to report an FK violation to the caller. */
|
|
@@ -125848,13 +135938,26 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
**
|
|
** Verify the integrity of the database.
|
|
**
|
|
- ** The "quick_check" is reduced version of
|
|
+ ** 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).
|
|
+ **
|
|
+ ** The maximum nubmer of errors is 100 by default. A different default
|
|
+ ** can be specified using a numeric parameter N.
|
|
+ **
|
|
+ ** Or, the parameter N can be the name of a table. In that case, only
|
|
+ ** the one table named is verified. The freelist is only verified if
|
|
+ ** the named table is "sqlite_schema" (or one of its aliases).
|
|
+ **
|
|
+ ** All schemas are checked by default. To check just a single
|
|
+ ** schema, use the form:
|
|
+ **
|
|
+ ** PRAGMA schema.integrity_check;
|
|
*/
|
|
case PragTyp_INTEGRITY_CHECK: {
|
|
int i, j, addr, mxErr;
|
|
+ Table *pObjTab = 0; /* Check only this one table, if not NULL */
|
|
|
|
int isQuick = (sqlite3Tolower(zLeft[0])=='q');
|
|
|
|
@@ -125877,9 +135980,13 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
/* Set the maximum error count */
|
|
mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
|
|
if( zRight ){
|
|
- sqlite3GetInt32(zRight, &mxErr);
|
|
- if( mxErr<=0 ){
|
|
- mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
|
|
+ if( sqlite3GetInt32(zRight, &mxErr) ){
|
|
+ if( mxErr<=0 ){
|
|
+ mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
|
|
+ }
|
|
+ }else{
|
|
+ pObjTab = sqlite3LocateTable(pParse, 0, zRight,
|
|
+ iDb>=0 ? db->aDb[iDb].zDbSName : 0);
|
|
}
|
|
}
|
|
sqlite3VdbeAddOp2(v, OP_Integer, mxErr-1, 1); /* reg[1] holds errors left */
|
|
@@ -125908,15 +136015,21 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
Table *pTab = sqliteHashData(x); /* Current table */
|
|
Index *pIdx; /* An index on pTab */
|
|
int nIdx; /* Number of indexes on pTab */
|
|
+ if( pObjTab && pObjTab!=pTab ) continue;
|
|
if( HasRowid(pTab) ) cnt++;
|
|
for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){ cnt++; }
|
|
if( nIdx>mxIdx ) mxIdx = nIdx;
|
|
}
|
|
+ if( cnt==0 ) continue;
|
|
+ if( pObjTab ) cnt++;
|
|
aRoot = sqlite3DbMallocRawNN(db, sizeof(int)*(cnt+1));
|
|
if( aRoot==0 ) break;
|
|
- for(cnt=0, x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
|
|
+ cnt = 0;
|
|
+ if( pObjTab ) aRoot[++cnt] = 0;
|
|
+ for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
|
|
Table *pTab = sqliteHashData(x);
|
|
Index *pIdx;
|
|
+ if( pObjTab && pObjTab!=pTab ) continue;
|
|
if( HasRowid(pTab) ) aRoot[++cnt] = pTab->tnum;
|
|
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
|
aRoot[++cnt] = pIdx->tnum;
|
|
@@ -125944,17 +136057,28 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
|
|
Table *pTab = sqliteHashData(x);
|
|
Index *pIdx, *pPk;
|
|
- Index *pPrior = 0;
|
|
+ Index *pPrior = 0; /* Previous index */
|
|
int loopTop;
|
|
int iDataCur, iIdxCur;
|
|
int r1 = -1;
|
|
-
|
|
- if( pTab->tnum<1 ) continue; /* Skip VIEWs or VIRTUAL TABLEs */
|
|
- pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab);
|
|
+ int bStrict; /* True for a STRICT table */
|
|
+ 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( isQuick || HasRowid(pTab) ){
|
|
+ pPk = 0;
|
|
+ r2 = 0;
|
|
+ }else{
|
|
+ pPk = sqlite3PrimaryKeyIndex(pTab);
|
|
+ r2 = sqlite3GetTempRange(pParse, pPk->nKeyCol);
|
|
+ sqlite3VdbeAddOp3(v, OP_Null, 1, r2, r2+pPk->nKeyCol-1);
|
|
+ }
|
|
sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenRead, 0,
|
|
1, 0, &iDataCur, &iIdxCur);
|
|
/* reg[7] counts the number of entries in the table.
|
|
- ** reg[8+i] counts the number of entries in the i-th index
|
|
+ ** reg[8+i] counts the number of entries in the i-th index
|
|
*/
|
|
sqlite3VdbeAddOp2(v, OP_Integer, 0, 7);
|
|
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
|
|
@@ -125964,27 +136088,166 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
assert( sqlite3NoTempsInRange(pParse,1,7+j) );
|
|
sqlite3VdbeAddOp2(v, OP_Rewind, iDataCur, 0); VdbeCoverage(v);
|
|
loopTop = sqlite3VdbeAddOp2(v, OP_AddImm, 7, 1);
|
|
+
|
|
+ /* Fetch the right-most column from the table. This will cause
|
|
+ ** the entire record header to be parsed and sanity checked. It
|
|
+ ** will also prepopulate the cursor column cache that is used
|
|
+ ** by the OP_IsType code, so it is a required step.
|
|
+ */
|
|
+ assert( !IsVirtual(pTab) );
|
|
+ if( HasRowid(pTab) ){
|
|
+ mxCol = -1;
|
|
+ for(j=0; j<pTab->nCol; j++){
|
|
+ if( (pTab->aCol[j].colFlags & COLFLAG_VIRTUAL)==0 ) mxCol++;
|
|
+ }
|
|
+ if( mxCol==pTab->iPKey ) mxCol--;
|
|
+ }else{
|
|
+ /* COLFLAG_VIRTUAL columns are not included in the WITHOUT ROWID
|
|
+ ** PK index column-count, so there is no need to account for them
|
|
+ ** in this case. */
|
|
+ mxCol = sqlite3PrimaryKeyIndex(pTab)->nColumn-1;
|
|
+ }
|
|
+ if( mxCol>=0 ){
|
|
+ sqlite3VdbeAddOp3(v, OP_Column, iDataCur, mxCol, 3);
|
|
+ sqlite3VdbeTypeofColumn(v, 3);
|
|
+ }
|
|
+
|
|
if( !isQuick ){
|
|
- /* Sanity check on record header decoding */
|
|
- sqlite3VdbeAddOp3(v, OP_Column, iDataCur, pTab->nNVCol-1,3);
|
|
- sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG);
|
|
+ if( pPk ){
|
|
+ /* Verify WITHOUT ROWID keys are in ascending order */
|
|
+ int a1;
|
|
+ char *zErr;
|
|
+ a1 = sqlite3VdbeAddOp4Int(v, OP_IdxGT, iDataCur, 0,r2,pPk->nKeyCol);
|
|
+ VdbeCoverage(v);
|
|
+ sqlite3VdbeAddOp1(v, OP_IsNull, r2); VdbeCoverage(v);
|
|
+ zErr = sqlite3MPrintf(db,
|
|
+ "row not in PRIMARY KEY order for %s",
|
|
+ pTab->zName);
|
|
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
|
|
+ integrityCheckResultRow(v);
|
|
+ sqlite3VdbeJumpHere(v, a1);
|
|
+ sqlite3VdbeJumpHere(v, a1+1);
|
|
+ for(j=0; j<pPk->nKeyCol; j++){
|
|
+ sqlite3ExprCodeLoadIndexColumn(pParse, pPk, iDataCur, j, r2+j);
|
|
+ }
|
|
+ }
|
|
}
|
|
- /* Verify that all NOT NULL columns really are NOT NULL */
|
|
+ /* Verify datatypes for all columns:
|
|
+ **
|
|
+ ** (1) NOT NULL columns may not contain a NULL
|
|
+ ** (2) Datatype must be exact for non-ANY columns in STRICT tables
|
|
+ ** (3) Datatype for TEXT columns in non-STRICT tables must be
|
|
+ ** NULL, TEXT, or BLOB.
|
|
+ ** (4) Datatype for numeric columns in non-STRICT tables must not
|
|
+ ** be a TEXT value that can be losslessly converted to numeric.
|
|
+ */
|
|
+ bStrict = (pTab->tabFlags & TF_Strict)!=0;
|
|
for(j=0; j<pTab->nCol; j++){
|
|
char *zErr;
|
|
- int jmp2;
|
|
+ Column *pCol = pTab->aCol + j; /* The column to be checked */
|
|
+ int labelError; /* Jump here to report an error */
|
|
+ int labelOk; /* Jump here if all looks ok */
|
|
+ int p1, p3, p4; /* Operands to the OP_IsType opcode */
|
|
+ int doTypeCheck; /* Check datatypes (besides NOT NULL) */
|
|
+
|
|
if( j==pTab->iPKey ) continue;
|
|
- if( pTab->aCol[j].notNull==0 ) continue;
|
|
- sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, j, 3);
|
|
- if( sqlite3VdbeGetOp(v,-1)->opcode==OP_Column ){
|
|
- sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG);
|
|
+ if( bStrict ){
|
|
+ doTypeCheck = pCol->eCType>COLTYPE_ANY;
|
|
+ }else{
|
|
+ doTypeCheck = pCol->affinity>SQLITE_AFF_BLOB;
|
|
+ }
|
|
+ if( pCol->notNull==0 && !doTypeCheck ) continue;
|
|
+
|
|
+ /* Compute the operands that will be needed for OP_IsType */
|
|
+ p4 = SQLITE_NULL;
|
|
+ if( pCol->colFlags & COLFLAG_VIRTUAL ){
|
|
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, j, 3);
|
|
+ p1 = -1;
|
|
+ p3 = 3;
|
|
+ }else{
|
|
+ if( pCol->iDflt ){
|
|
+ sqlite3_value *pDfltValue = 0;
|
|
+ sqlite3ValueFromExpr(db, sqlite3ColumnExpr(pTab,pCol), ENC(db),
|
|
+ pCol->affinity, &pDfltValue);
|
|
+ if( pDfltValue ){
|
|
+ p4 = sqlite3_value_type(pDfltValue);
|
|
+ sqlite3ValueFree(pDfltValue);
|
|
+ }
|
|
+ }
|
|
+ p1 = iDataCur;
|
|
+ if( !HasRowid(pTab) ){
|
|
+ testcase( j!=sqlite3TableColumnToStorage(pTab, j) );
|
|
+ p3 = sqlite3TableColumnToIndex(sqlite3PrimaryKeyIndex(pTab), j);
|
|
+ }else{
|
|
+ p3 = sqlite3TableColumnToStorage(pTab,j);
|
|
+ testcase( p3!=j);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ labelError = sqlite3VdbeMakeLabel(pParse);
|
|
+ labelOk = sqlite3VdbeMakeLabel(pParse);
|
|
+ if( pCol->notNull ){
|
|
+ /* (1) NOT NULL columns may not contain a NULL */
|
|
+ int jmp2 = sqlite3VdbeAddOp4Int(v, OP_IsType, p1, labelOk, p3, p4);
|
|
+ sqlite3VdbeChangeP5(v, 0x0f);
|
|
+ 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);
|
|
+ }else{
|
|
+ /* VDBE byte code will fall thru */
|
|
+ }
|
|
+ }
|
|
+ if( bStrict && doTypeCheck ){
|
|
+ /* (2) Datatype must be exact for non-ANY columns in STRICT tables*/
|
|
+ static unsigned char aStdTypeMask[] = {
|
|
+ 0x1f, /* ANY */
|
|
+ 0x18, /* BLOB */
|
|
+ 0x11, /* INT */
|
|
+ 0x11, /* INTEGER */
|
|
+ 0x13, /* REAL */
|
|
+ 0x14 /* TEXT */
|
|
+ };
|
|
+ sqlite3VdbeAddOp4Int(v, OP_IsType, p1, labelOk, p3, p4);
|
|
+ assert( pCol->eCType>=1 && pCol->eCType<=sizeof(aStdTypeMask) );
|
|
+ sqlite3VdbeChangeP5(v, aStdTypeMask[pCol->eCType-1]);
|
|
+ VdbeCoverage(v);
|
|
+ zErr = sqlite3MPrintf(db, "non-%s value in %s.%s",
|
|
+ sqlite3StdType[pCol->eCType-1],
|
|
+ pTab->zName, pTab->aCol[j].zCnName);
|
|
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
|
|
+ }else if( !bStrict && pCol->affinity==SQLITE_AFF_TEXT ){
|
|
+ /* (3) Datatype for TEXT columns in non-STRICT tables must be
|
|
+ ** NULL, TEXT, or BLOB. */
|
|
+ sqlite3VdbeAddOp4Int(v, OP_IsType, p1, labelOk, p3, p4);
|
|
+ sqlite3VdbeChangeP5(v, 0x1c); /* NULL, TEXT, or BLOB */
|
|
+ VdbeCoverage(v);
|
|
+ zErr = sqlite3MPrintf(db, "NUMERIC value in %s.%s",
|
|
+ pTab->zName, pTab->aCol[j].zCnName);
|
|
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
|
|
+ }else if( !bStrict && pCol->affinity>=SQLITE_AFF_NUMERIC ){
|
|
+ /* (4) Datatype for numeric columns in non-STRICT tables must not
|
|
+ ** be a TEXT value that can be converted to numeric. */
|
|
+ sqlite3VdbeAddOp4Int(v, OP_IsType, p1, labelOk, p3, p4);
|
|
+ sqlite3VdbeChangeP5(v, 0x1b); /* NULL, INT, FLOAT, or BLOB */
|
|
+ VdbeCoverage(v);
|
|
+ if( p1>=0 ){
|
|
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, j, 3);
|
|
+ }
|
|
+ sqlite3VdbeAddOp4(v, OP_Affinity, 3, 1, 0, "C", P4_STATIC);
|
|
+ sqlite3VdbeAddOp4Int(v, OP_IsType, -1, labelOk, 3, p4);
|
|
+ sqlite3VdbeChangeP5(v, 0x1c); /* NULL, TEXT, or BLOB */
|
|
+ VdbeCoverage(v);
|
|
+ zErr = sqlite3MPrintf(db, "TEXT value in %s.%s",
|
|
+ pTab->zName, pTab->aCol[j].zCnName);
|
|
+ sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
|
|
}
|
|
- jmp2 = sqlite3VdbeAddOp1(v, OP_NotNull, 3); VdbeCoverage(v);
|
|
- zErr = sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName,
|
|
- pTab->aCol[j].zName);
|
|
- sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
|
|
+ sqlite3VdbeResolveLabel(v, labelError);
|
|
integrityCheckResultRow(v);
|
|
- sqlite3VdbeJumpHere(v, jmp2);
|
|
+ sqlite3VdbeResolveLabel(v, labelOk);
|
|
}
|
|
/* Verify CHECK constraints */
|
|
if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){
|
|
@@ -125998,7 +136261,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
for(k=pCheck->nExpr-1; k>0; k--){
|
|
sqlite3ExprIfFalse(pParse, pCheck->a[k].pExpr, addrCkFault, 0);
|
|
}
|
|
- sqlite3ExprIfTrue(pParse, pCheck->a[0].pExpr, addrCkOk,
|
|
+ sqlite3ExprIfTrue(pParse, pCheck->a[0].pExpr, addrCkOk,
|
|
SQLITE_JUMPIFNULL);
|
|
sqlite3VdbeResolveLabel(v, addrCkFault);
|
|
pParse->iSelfTab = 0;
|
|
@@ -126013,7 +136276,8 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
if( !isQuick ){ /* Omit the remaining tests for quick_check */
|
|
/* Validate index entries for the current row */
|
|
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
|
|
- int jmp2, jmp3, jmp4, jmp5;
|
|
+ int jmp2, jmp3, jmp4, jmp5, label6;
|
|
+ int kk;
|
|
int ckUniq = sqlite3VdbeMakeLabel(pParse);
|
|
if( pPk==pIdx ) continue;
|
|
r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 0, &jmp3,
|
|
@@ -126031,13 +136295,49 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
|
|
jmp4 = integrityCheckResultRow(v);
|
|
sqlite3VdbeJumpHere(v, jmp2);
|
|
+
|
|
+ /* The OP_IdxRowid opcode is an optimized version of OP_Column
|
|
+ ** that extracts the rowid off the end of the index record.
|
|
+ ** But it only works correctly if index record does not have
|
|
+ ** any extra bytes at the end. Verify that this is the case. */
|
|
+ if( HasRowid(pTab) ){
|
|
+ int jmp7;
|
|
+ sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur+j, 3);
|
|
+ jmp7 = sqlite3VdbeAddOp3(v, OP_Eq, 3, 0, r1+pIdx->nColumn-1);
|
|
+ VdbeCoverage(v);
|
|
+ sqlite3VdbeLoadString(v, 3,
|
|
+ "rowid not at end-of-record for row ");
|
|
+ sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3);
|
|
+ sqlite3VdbeLoadString(v, 4, " of index ");
|
|
+ sqlite3VdbeGoto(v, jmp5-1);
|
|
+ sqlite3VdbeJumpHere(v, jmp7);
|
|
+ }
|
|
+
|
|
+ /* Any indexed columns with non-BINARY collations must still hold
|
|
+ ** the exact same text value as the table. */
|
|
+ label6 = 0;
|
|
+ for(kk=0; kk<pIdx->nKeyCol; kk++){
|
|
+ if( pIdx->azColl[kk]==sqlite3StrBINARY ) continue;
|
|
+ if( label6==0 ) label6 = sqlite3VdbeMakeLabel(pParse);
|
|
+ sqlite3VdbeAddOp3(v, OP_Column, iIdxCur+j, kk, 3);
|
|
+ sqlite3VdbeAddOp3(v, OP_Ne, 3, label6, r1+kk); VdbeCoverage(v);
|
|
+ }
|
|
+ if( label6 ){
|
|
+ int jmp6 = sqlite3VdbeAddOp0(v, OP_Goto);
|
|
+ sqlite3VdbeResolveLabel(v, label6);
|
|
+ sqlite3VdbeLoadString(v, 3, "row ");
|
|
+ sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3);
|
|
+ sqlite3VdbeLoadString(v, 4, " values differ from index ");
|
|
+ sqlite3VdbeGoto(v, jmp5-1);
|
|
+ sqlite3VdbeJumpHere(v, jmp6);
|
|
+ }
|
|
+
|
|
/* For UNIQUE indexes, verify that only one entry exists with the
|
|
** current key. The entry is unique if (1) any column is NULL
|
|
** or (2) the next entry has a different key */
|
|
if( IsUniqueIndex(pIdx) ){
|
|
int uniqOk = sqlite3VdbeMakeLabel(pParse);
|
|
int jmp6;
|
|
- int kk;
|
|
for(kk=0; kk<pIdx->nKeyCol; kk++){
|
|
int iCol = pIdx->aiColumn[kk];
|
|
assert( iCol!=XN_ROWID && iCol<pTab->nCol );
|
|
@@ -126060,7 +136360,6 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
}
|
|
sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v);
|
|
sqlite3VdbeJumpHere(v, loopTop-1);
|
|
-#ifndef SQLITE_OMIT_BTREECOUNT
|
|
if( !isQuick ){
|
|
sqlite3VdbeLoadString(v, 2, "wrong # of entries in index ");
|
|
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
|
|
@@ -126073,9 +136372,11 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
integrityCheckResultRow(v);
|
|
sqlite3VdbeJumpHere(v, addr);
|
|
}
|
|
+ if( pPk ){
|
|
+ sqlite3ReleaseTempRange(pParse, r2, pPk->nKeyCol);
|
|
+ }
|
|
}
|
|
-#endif /* SQLITE_OMIT_BTREECOUNT */
|
|
- }
|
|
+ }
|
|
}
|
|
{
|
|
static const int iLn = VDBE_OFFSET_LINENO(2);
|
|
@@ -126117,7 +136418,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
** encoding that will be used for the main database file if a new file
|
|
** is created. If an existing main database file is opened, then the
|
|
** default text encoding for the existing database is used.
|
|
- **
|
|
+ **
|
|
** In all cases new databases created using the ATTACH command are
|
|
** created to use the same default text encoding as the main database. If
|
|
** the main database has not been initialized and/or created when ATTACH
|
|
@@ -126155,21 +136456,12 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
** will be overwritten when the schema is next loaded. If it does not
|
|
** already exists, it will be created to use the new encoding value.
|
|
*/
|
|
- int canChangeEnc = 1; /* True if allowed to change the encoding */
|
|
- int i; /* For looping over all attached databases */
|
|
- for(i=0; i<db->nDb; i++){
|
|
- if( db->aDb[i].pBt!=0
|
|
- && DbHasProperty(db,i,DB_SchemaLoaded)
|
|
- && !DbHasProperty(db,i,DB_Empty)
|
|
- ){
|
|
- canChangeEnc = 0;
|
|
- }
|
|
- }
|
|
- if( canChangeEnc ){
|
|
+ if( (db->mDbFlags & DBFLAG_EncodingFixed)==0 ){
|
|
for(pEnc=&encnames[0]; pEnc->zName; pEnc++){
|
|
if( 0==sqlite3StrICmp(zRight, pEnc->zName) ){
|
|
- SCHEMA_ENC(db) = ENC(db) =
|
|
- pEnc->enc ? pEnc->enc : SQLITE_UTF16NATIVE;
|
|
+ u8 enc = pEnc->enc ? pEnc->enc : SQLITE_UTF16NATIVE;
|
|
+ SCHEMA_ENC(db) = enc;
|
|
+ sqlite3SetTextEncoding(db, enc);
|
|
break;
|
|
}
|
|
}
|
|
@@ -126232,6 +136524,12 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
aOp[1].p1 = iDb;
|
|
aOp[1].p2 = iCookie;
|
|
aOp[1].p3 = sqlite3Atoi(zRight);
|
|
+ aOp[1].p5 = 1;
|
|
+ if( iCookie==BTREE_SCHEMA_VERSION && (db->flags & SQLITE_Defensive)!=0 ){
|
|
+ /* Do not allow the use of PRAGMA schema_version=VALUE in defensive
|
|
+ ** mode. Change the OP_SetCookie opcode into a no-op. */
|
|
+ aOp[1].opcode = OP_Noop;
|
|
+ }
|
|
}else{
|
|
/* Read the specified cookie value */
|
|
static const VdbeOpList readCookie[] = {
|
|
@@ -126279,7 +136577,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
** Checkpoint the database.
|
|
*/
|
|
case PragTyp_WAL_CHECKPOINT: {
|
|
- int iBt = (pId2->z?iDb:SQLITE_MAX_ATTACHED);
|
|
+ int iBt = (pId2->z?iDb:SQLITE_MAX_DB);
|
|
int eMode = SQLITE_CHECKPOINT_PASSIVE;
|
|
if( zRight ){
|
|
if( sqlite3StrICmp(zRight, "full")==0 ){
|
|
@@ -126308,8 +136606,8 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
if( zRight ){
|
|
sqlite3_wal_autocheckpoint(db, sqlite3Atoi(zRight));
|
|
}
|
|
- returnSingleInt(v,
|
|
- db->xWalCallback==sqlite3WalDefaultHook ?
|
|
+ returnSingleInt(v,
|
|
+ db->xWalCallback==sqlite3WalDefaultHook ?
|
|
SQLITE_PTR_TO_INT(db->pWalArg) : 0);
|
|
}
|
|
break;
|
|
@@ -126349,7 +136647,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
** 0x0002 Run ANALYZE on tables that might benefit. On by default.
|
|
** See below for additional information.
|
|
**
|
|
- ** 0x0004 (Not yet implemented) Record usage and performance
|
|
+ ** 0x0004 (Not yet implemented) Record usage and performance
|
|
** information from the current session in the
|
|
** database file so that it will be available to "optimize"
|
|
** pragmas run by future database connections.
|
|
@@ -126360,7 +136658,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
** The default MASK is and always shall be 0xfffe. 0xfffe means perform all
|
|
** of the optimizations listed above except Debug Mode, including new
|
|
** optimizations that have not yet been invented. If new optimizations are
|
|
- ** ever added that should be off by default, those off-by-default
|
|
+ ** ever added that should be off by default, those off-by-default
|
|
** optimizations will have bitmasks of 0x10000 or larger.
|
|
**
|
|
** DETERMINATION OF WHEN TO RUN ANALYZE
|
|
@@ -126421,7 +136719,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
}
|
|
if( szThreshold ){
|
|
sqlite3OpenTable(pParse, iTabCur, iDb, pTab, OP_OpenRead);
|
|
- sqlite3VdbeAddOp3(v, OP_IfSmaller, iTabCur,
|
|
+ sqlite3VdbeAddOp3(v, OP_IfSmaller, iTabCur,
|
|
sqlite3VdbeCurrentAddr(v)+2+(opMask&1), szThreshold);
|
|
VdbeCoverage(v);
|
|
}
|
|
@@ -126518,6 +136816,25 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
break;
|
|
}
|
|
|
|
+ /*
|
|
+ ** PRAGMA analysis_limit
|
|
+ ** PRAGMA analysis_limit = N
|
|
+ **
|
|
+ ** Configure the maximum number of rows that ANALYZE will examine
|
|
+ ** in each index that it looks at. Return the new limit.
|
|
+ */
|
|
+ case PragTyp_ANALYSIS_LIMIT: {
|
|
+ sqlite3_int64 N;
|
|
+ if( zRight
|
|
+ && sqlite3DecOrHexToI64(zRight, &N)==SQLITE_OK /* IMP: R-40975-20399 */
|
|
+ && N>=0
|
|
+ ){
|
|
+ db->nAnalysisLimit = (int)(N&0x7fffffff);
|
|
+ }
|
|
+ returnSingleInt(v, db->nAnalysisLimit); /* IMP: R-57594-65522 */
|
|
+ break;
|
|
+ }
|
|
+
|
|
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
|
|
/*
|
|
** Report the current state of file logs for all databases
|
|
@@ -126536,7 +136853,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
pBt = db->aDb[i].pBt;
|
|
if( pBt==0 || sqlite3BtreePager(pBt)==0 ){
|
|
zState = "closed";
|
|
- }else if( sqlite3_file_control(db, i ? db->aDb[i].zDbSName : 0,
|
|
+ }else if( sqlite3_file_control(db, i ? db->aDb[i].zDbSName : 0,
|
|
SQLITE_FCNTL_LOCKSTATE, &j)==SQLITE_OK ){
|
|
zState = azLockName[j];
|
|
}
|
|
@@ -126546,59 +136863,11 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
}
|
|
#endif
|
|
|
|
-#ifdef SQLITE_HAS_CODEC
|
|
- /* Pragma iArg
|
|
- ** ---------- ------
|
|
- ** key 0
|
|
- ** rekey 1
|
|
- ** hexkey 2
|
|
- ** hexrekey 3
|
|
- ** textkey 4
|
|
- ** textrekey 5
|
|
- */
|
|
- case PragTyp_KEY: {
|
|
- if( zRight ){
|
|
- char zBuf[40];
|
|
- const char *zKey = zRight;
|
|
- int n;
|
|
- if( pPragma->iArg==2 || pPragma->iArg==3 ){
|
|
- u8 iByte;
|
|
- int i;
|
|
- for(i=0, iByte=0; i<sizeof(zBuf)*2 && sqlite3Isxdigit(zRight[i]); i++){
|
|
- iByte = (iByte<<4) + sqlite3HexToInt(zRight[i]);
|
|
- if( (i&1)!=0 ) zBuf[i/2] = iByte;
|
|
- }
|
|
- zKey = zBuf;
|
|
- n = i/2;
|
|
- }else{
|
|
- n = pPragma->iArg<4 ? sqlite3Strlen30(zRight) : -1;
|
|
- }
|
|
- if( (pPragma->iArg & 1)==0 ){
|
|
- rc = sqlite3_key_v2(db, zDb, zKey, n);
|
|
- }else{
|
|
- rc = sqlite3_rekey_v2(db, zDb, zKey, n);
|
|
- }
|
|
- if( rc==SQLITE_OK && n!=0 ){
|
|
- sqlite3VdbeSetNumCols(v, 1);
|
|
- sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "ok", SQLITE_STATIC);
|
|
- returnSingleText(v, "ok");
|
|
- }
|
|
- }
|
|
- break;
|
|
- }
|
|
-#endif
|
|
-#if defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD)
|
|
+#if defined(SQLITE_ENABLE_CEROD)
|
|
case PragTyp_ACTIVATE_EXTENSIONS: if( zRight ){
|
|
-#ifdef SQLITE_HAS_CODEC
|
|
- if( sqlite3StrNICmp(zRight, "see-", 4)==0 ){
|
|
- sqlite3_activate_see(&zRight[4]);
|
|
- }
|
|
-#endif
|
|
-#ifdef SQLITE_ENABLE_CEROD
|
|
if( sqlite3StrNICmp(zRight, "cerod-", 6)==0 ){
|
|
sqlite3_activate_cerod(&zRight[6]);
|
|
}
|
|
-#endif
|
|
}
|
|
break;
|
|
#endif
|
|
@@ -126608,7 +136877,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
/* The following block is a no-op unless SQLITE_DEBUG is defined. Its only
|
|
** purpose is to execute assert() statements to verify that if the
|
|
** PragFlg_NoColumns1 flag is set and the caller specified an argument
|
|
- ** to the PRAGMA, the implementation has not added any OP_ResultRow
|
|
+ ** to the PRAGMA, the implementation has not added any OP_ResultRow
|
|
** instructions to the VM. */
|
|
if( (pPragma->mPragFlg & PragFlg_NoColumns1) && zRight ){
|
|
sqlite3VdbeVerifyNoResultRow(v);
|
|
@@ -126639,7 +136908,7 @@ struct PragmaVtabCursor {
|
|
char *azArg[2]; /* Value of the argument and schema */
|
|
};
|
|
|
|
-/*
|
|
+/*
|
|
** Pragma virtual table module xConnect method.
|
|
*/
|
|
static int pragmaVtabConnect(
|
|
@@ -126701,7 +136970,7 @@ static int pragmaVtabConnect(
|
|
return rc;
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** Pragma virtual table module xDisconnect method.
|
|
*/
|
|
static int pragmaVtabDisconnect(sqlite3_vtab *pVtab){
|
|
@@ -126799,11 +137068,11 @@ static int pragmaVtabNext(sqlite3_vtab_cursor *pVtabCursor){
|
|
return rc;
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** Pragma virtual table module xFilter method.
|
|
*/
|
|
static int pragmaVtabFilter(
|
|
- sqlite3_vtab_cursor *pVtabCursor,
|
|
+ sqlite3_vtab_cursor *pVtabCursor,
|
|
int idxNum, const char *idxStr,
|
|
int argc, sqlite3_value **argv
|
|
){
|
|
@@ -126858,11 +137127,11 @@ static int pragmaVtabEof(sqlite3_vtab_cursor *pVtabCursor){
|
|
}
|
|
|
|
/* The xColumn method simply returns the corresponding column from
|
|
-** the PRAGMA.
|
|
+** the PRAGMA.
|
|
*/
|
|
static int pragmaVtabColumn(
|
|
- sqlite3_vtab_cursor *pVtabCursor,
|
|
- sqlite3_context *ctx,
|
|
+ sqlite3_vtab_cursor *pVtabCursor,
|
|
+ sqlite3_context *ctx,
|
|
int i
|
|
){
|
|
PragmaVtabCursor *pCsr = (PragmaVtabCursor*)pVtabCursor;
|
|
@@ -126875,7 +137144,7 @@ static int pragmaVtabColumn(
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** Pragma virtual table module xRowid method.
|
|
*/
|
|
static int pragmaVtabRowid(sqlite3_vtab_cursor *pVtabCursor, sqlite_int64 *p){
|
|
@@ -126956,7 +137225,7 @@ SQLITE_PRIVATE Module *sqlite3PragmaVtabRegister(sqlite3 *db, const char *zName)
|
|
*/
|
|
static void corruptSchema(
|
|
InitData *pData, /* Initialization context */
|
|
- const char *zObj, /* Object being parsed at the point of error */
|
|
+ char **azObj, /* Type and name of object being parsed */
|
|
const char *zExtra /* Error information */
|
|
){
|
|
sqlite3 *db = pData->db;
|
|
@@ -126964,14 +137233,23 @@ static void corruptSchema(
|
|
pData->rc = SQLITE_NOMEM_BKPT;
|
|
}else if( pData->pzErrMsg[0]!=0 ){
|
|
/* A error message has already been generated. Do not overwrite it */
|
|
- }else if( pData->mInitFlags & INITFLAG_AlterTable ){
|
|
- *pData->pzErrMsg = sqlite3DbStrDup(db, zExtra);
|
|
+ }else if( pData->mInitFlags & (INITFLAG_AlterMask) ){
|
|
+ static const char *azAlterType[] = {
|
|
+ "rename",
|
|
+ "drop column",
|
|
+ "add column"
|
|
+ };
|
|
+ *pData->pzErrMsg = sqlite3MPrintf(db,
|
|
+ "error in %s %s after %s: %s", azObj[0], azObj[1],
|
|
+ azAlterType[(pData->mInitFlags&INITFLAG_AlterMask)-1],
|
|
+ zExtra
|
|
+ );
|
|
pData->rc = SQLITE_ERROR;
|
|
}else if( db->flags & SQLITE_WriteSchema ){
|
|
pData->rc = SQLITE_CORRUPT_BKPT;
|
|
}else{
|
|
char *z;
|
|
- if( zObj==0 ) zObj = "?";
|
|
+ const char *zObj = azObj[1] ? azObj[1] : "?";
|
|
z = sqlite3MPrintf(db, "malformed database schema (%s)", zObj);
|
|
if( zExtra && zExtra[0] ) z = sqlite3MPrintf(db, "%z - %s", z, zExtra);
|
|
*pData->pzErrMsg = z;
|
|
@@ -127026,22 +137304,29 @@ SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char
|
|
assert( argc==5 );
|
|
UNUSED_PARAMETER2(NotUsed, argc);
|
|
assert( sqlite3_mutex_held(db->mutex) );
|
|
- DbClearProperty(db, iDb, DB_Empty);
|
|
+ db->mDbFlags |= DBFLAG_EncodingFixed;
|
|
+ if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */
|
|
pData->nInitRow++;
|
|
if( db->mallocFailed ){
|
|
- corruptSchema(pData, argv[1], 0);
|
|
+ corruptSchema(pData, argv, 0);
|
|
return 1;
|
|
}
|
|
|
|
assert( iDb>=0 && iDb<db->nDb );
|
|
- if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */
|
|
if( argv[3]==0 ){
|
|
- corruptSchema(pData, argv[1], 0);
|
|
- }else if( sqlite3_strnicmp(argv[4],"create ",7)==0 ){
|
|
+ corruptSchema(pData, argv, 0);
|
|
+ }else if( argv[4]
|
|
+ && 'c'==sqlite3UpperToLower[(unsigned char)argv[4][0]]
|
|
+ && 'r'==sqlite3UpperToLower[(unsigned char)argv[4][1]] ){
|
|
/* Call the parser to process a CREATE TABLE, INDEX or VIEW.
|
|
** But because db->init.busy is set to 1, no VDBE code is generated
|
|
** or executed. All the parser does is build the internal data
|
|
** structures that describe the table, index, or view.
|
|
+ **
|
|
+ ** No other valid SQL statement, other than the variable CREATE statements,
|
|
+ ** can begin with the letters "C" and "R". Thus, it is not possible run
|
|
+ ** any other kind of statement while parsing the schema, even a corrupt
|
|
+ ** schema.
|
|
*/
|
|
int rc;
|
|
u8 saved_iDb = db->init.iDb;
|
|
@@ -127050,9 +137335,15 @@ SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char
|
|
|
|
assert( db->init.busy );
|
|
db->init.iDb = iDb;
|
|
- db->init.newTnum = sqlite3Atoi(argv[3]);
|
|
+ if( sqlite3GetUInt32(argv[3], &db->init.newTnum)==0
|
|
+ || (db->init.newTnum>pData->mxPage && pData->mxPage>0)
|
|
+ ){
|
|
+ if( sqlite3Config.bExtraSchemaChecks ){
|
|
+ corruptSchema(pData, argv, "invalid rootpage");
|
|
+ }
|
|
+ }
|
|
db->init.orphanTrigger = 0;
|
|
- db->init.azInit = argv;
|
|
+ db->init.azInit = (const char**)argv;
|
|
pStmt = 0;
|
|
TESTONLY(rcp = ) sqlite3Prepare(db, argv[4], -1, 0, 0, &pStmt, 0);
|
|
rc = db->errCode;
|
|
@@ -127067,13 +137358,14 @@ SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char
|
|
if( rc==SQLITE_NOMEM ){
|
|
sqlite3OomFault(db);
|
|
}else if( rc!=SQLITE_INTERRUPT && (rc&0xFF)!=SQLITE_LOCKED ){
|
|
- corruptSchema(pData, argv[1], sqlite3_errmsg(db));
|
|
+ corruptSchema(pData, argv, sqlite3_errmsg(db));
|
|
}
|
|
}
|
|
}
|
|
+ db->init.azInit = sqlite3StdType; /* Any array of string ptrs will do */
|
|
sqlite3_finalize(pStmt);
|
|
}else if( argv[1]==0 || (argv[4]!=0 && argv[4][0]!=0) ){
|
|
- corruptSchema(pData, argv[1], 0);
|
|
+ corruptSchema(pData, argv, 0);
|
|
}else{
|
|
/* If the SQL column is blank it means this is an index that
|
|
** was created to be the PRIMARY KEY or to fulfill a UNIQUE
|
|
@@ -127083,12 +137375,17 @@ SQLITE_PRIVATE int sqlite3InitCallback(void *pInit, int argc, char **argv, char
|
|
*/
|
|
Index *pIndex;
|
|
pIndex = sqlite3FindIndex(db, argv[1], db->aDb[iDb].zDbSName);
|
|
- if( pIndex==0
|
|
- || sqlite3GetInt32(argv[3],&pIndex->tnum)==0
|
|
+ if( pIndex==0 ){
|
|
+ corruptSchema(pData, argv, "orphan index");
|
|
+ }else
|
|
+ if( sqlite3GetUInt32(argv[3],&pIndex->tnum)==0
|
|
|| pIndex->tnum<2
|
|
+ || pIndex->tnum>pData->mxPage
|
|
|| sqlite3IndexHasDuplicateRootPage(pIndex)
|
|
){
|
|
- corruptSchema(pData, argv[1], pIndex?"invalid rootpage":"orphan index");
|
|
+ if( sqlite3Config.bExtraSchemaChecks ){
|
|
+ corruptSchema(pData, argv, "invalid rootpage");
|
|
+ }
|
|
}
|
|
}
|
|
return 0;
|
|
@@ -127112,8 +137409,9 @@ SQLITE_PRIVATE int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFl
|
|
char const *azArg[6];
|
|
int meta[5];
|
|
InitData initData;
|
|
- const char *zMasterName;
|
|
+ const char *zSchemaTabName;
|
|
int openedTransaction = 0;
|
|
+ int mask = ((db->mDbFlags & DBFLAG_EncodingFixed) | ~DBFLAG_EncodingFixed);
|
|
|
|
assert( (db->mDbFlags & DBFLAG_SchemaKnownOk)==0 );
|
|
assert( iDb>=0 && iDb<db->nDb );
|
|
@@ -127123,13 +137421,13 @@ SQLITE_PRIVATE int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFl
|
|
|
|
db->init.busy = 1;
|
|
|
|
- /* Construct the in-memory representation schema tables (sqlite_master or
|
|
- ** sqlite_temp_master) by invoking the parser directly. The appropriate
|
|
+ /* Construct the in-memory representation schema tables (sqlite_schema or
|
|
+ ** sqlite_temp_schema) by invoking the parser directly. The appropriate
|
|
** table name will be inserted automatically by the parser so we can just
|
|
** use the abbreviation "x" here. The parser will also automatically tag
|
|
** the schema table as read-only. */
|
|
azArg[0] = "table";
|
|
- azArg[1] = zMasterName = SCHEMA_TABLE(iDb);
|
|
+ azArg[1] = zSchemaTabName = SCHEMA_TABLE(iDb);
|
|
azArg[2] = azArg[1];
|
|
azArg[3] = "1";
|
|
azArg[4] = "CREATE TABLE x(type text,name text,tbl_name text,"
|
|
@@ -127141,7 +137439,9 @@ SQLITE_PRIVATE int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFl
|
|
initData.pzErrMsg = pzErrMsg;
|
|
initData.mInitFlags = mFlags;
|
|
initData.nInitRow = 0;
|
|
+ initData.mxPage = 0;
|
|
sqlite3InitCallback(&initData, 5, (char **)azArg, 0);
|
|
+ db->mDbFlags &= mask;
|
|
if( initData.rc ){
|
|
rc = initData.rc;
|
|
goto error_out;
|
|
@@ -127158,10 +137458,10 @@ SQLITE_PRIVATE int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFl
|
|
}
|
|
|
|
/* If there is not already a read-only (or read-write) transaction opened
|
|
- ** on the b-tree database, open one now. If a transaction is opened, it
|
|
+ ** on the b-tree database, open one now. If a transaction is opened, it
|
|
** will be closed before this function returns. */
|
|
sqlite3BtreeEnter(pDb->pBt);
|
|
- if( !sqlite3BtreeIsInReadTrans(pDb->pBt) ){
|
|
+ if( sqlite3BtreeTxnState(pDb->pBt)==SQLITE_TXN_NONE ){
|
|
rc = sqlite3BtreeBeginTrans(pDb->pBt, 0, 0);
|
|
if( rc!=SQLITE_OK ){
|
|
sqlite3SetString(pzErrMsg, db, sqlite3ErrStr(rc));
|
|
@@ -127201,27 +137501,30 @@ SQLITE_PRIVATE int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFl
|
|
** as sqlite3.enc.
|
|
*/
|
|
if( meta[BTREE_TEXT_ENCODING-1] ){ /* text encoding */
|
|
- if( iDb==0 ){
|
|
-#ifndef SQLITE_OMIT_UTF16
|
|
+ if( iDb==0 && (db->mDbFlags & DBFLAG_EncodingFixed)==0 ){
|
|
u8 encoding;
|
|
+#ifndef SQLITE_OMIT_UTF16
|
|
/* If opening the main database, set ENC(db). */
|
|
encoding = (u8)meta[BTREE_TEXT_ENCODING-1] & 3;
|
|
if( encoding==0 ) encoding = SQLITE_UTF8;
|
|
- ENC(db) = encoding;
|
|
#else
|
|
- ENC(db) = SQLITE_UTF8;
|
|
+ encoding = SQLITE_UTF8;
|
|
#endif
|
|
+ if( db->nVdbeActive>0 && encoding!=ENC(db) ){
|
|
+ rc = SQLITE_LOCKED;
|
|
+ goto initone_error_out;
|
|
+ }else{
|
|
+ sqlite3SetTextEncoding(db, encoding);
|
|
+ }
|
|
}else{
|
|
/* If opening an attached database, the encoding much match ENC(db) */
|
|
- if( meta[BTREE_TEXT_ENCODING-1]!=ENC(db) ){
|
|
+ if( (meta[BTREE_TEXT_ENCODING-1] & 3)!=ENC(db) ){
|
|
sqlite3SetString(pzErrMsg, db, "attached databases must use the same"
|
|
" text encoding as main database");
|
|
rc = SQLITE_ERROR;
|
|
goto initone_error_out;
|
|
}
|
|
}
|
|
- }else{
|
|
- DbSetProperty(db, iDb, DB_Empty);
|
|
}
|
|
pDb->pSchema->enc = ENC(db);
|
|
|
|
@@ -127264,11 +137567,12 @@ SQLITE_PRIVATE int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFl
|
|
/* Read the schema information out of the schema tables
|
|
*/
|
|
assert( db->init.busy );
|
|
+ initData.mxPage = sqlite3BtreeLastPage(pDb->pBt);
|
|
{
|
|
char *zSql;
|
|
- zSql = sqlite3MPrintf(db,
|
|
+ zSql = sqlite3MPrintf(db,
|
|
"SELECT*FROM\"%w\".%s ORDER BY rowid",
|
|
- db->aDb[iDb].zDbSName, zMasterName);
|
|
+ db->aDb[iDb].zDbSName, zSchemaTabName);
|
|
#ifndef SQLITE_OMIT_AUTHORIZATION
|
|
{
|
|
sqlite3_xauth xAuth;
|
|
@@ -127288,18 +137592,22 @@ SQLITE_PRIVATE int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFl
|
|
}
|
|
#endif
|
|
}
|
|
+ assert( pDb == &(db->aDb[iDb]) );
|
|
if( db->mallocFailed ){
|
|
rc = SQLITE_NOMEM_BKPT;
|
|
sqlite3ResetAllSchemasOfConnection(db);
|
|
- }
|
|
- if( rc==SQLITE_OK || (db->flags&SQLITE_NoSchemaError)){
|
|
- /* Black magic: If the SQLITE_NoSchemaError flag is set, then consider
|
|
- ** the schema loaded, even if errors occurred. In this situation the
|
|
- ** current sqlite3_prepare() operation will fail, but the following one
|
|
- ** will attempt to compile the supplied statement against whatever subset
|
|
- ** of the schema was loaded before the error occurred. The primary
|
|
- ** purpose of this is to allow access to the sqlite_master table
|
|
- ** even when its contents have been corrupted.
|
|
+ pDb = &db->aDb[iDb];
|
|
+ }else
|
|
+ if( rc==SQLITE_OK || ((db->flags&SQLITE_NoSchemaError) && rc!=SQLITE_NOMEM)){
|
|
+ /* Hack: If the SQLITE_NoSchemaError flag is set, then consider
|
|
+ ** the schema loaded, even if errors (other than OOM) occurred. In
|
|
+ ** this situation the current sqlite3_prepare() operation will fail,
|
|
+ ** but the following one will attempt to compile the supplied statement
|
|
+ ** against whatever subset of the schema was loaded before the error
|
|
+ ** occurred.
|
|
+ **
|
|
+ ** The primary purpose of this is to allow access to the sqlite_schema
|
|
+ ** table even when its contents have been corrupted.
|
|
*/
|
|
DbSetProperty(db, iDb, DB_SchemaLoaded);
|
|
rc = SQLITE_OK;
|
|
@@ -127333,13 +137641,12 @@ SQLITE_PRIVATE int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFl
|
|
** error occurs, write an error message into *pzErrMsg.
|
|
**
|
|
** After a database is initialized, the DB_SchemaLoaded bit is set
|
|
-** bit is set in the flags field of the Db structure. If the database
|
|
-** file was of zero-length, then the DB_Empty flag is also set.
|
|
+** bit is set in the flags field of the Db structure.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3Init(sqlite3 *db, char **pzErrMsg){
|
|
int i, rc;
|
|
int commit_internal = !(db->mDbFlags&DBFLAG_SchemaChange);
|
|
-
|
|
+
|
|
assert( sqlite3_mutex_held(db->mutex) );
|
|
assert( sqlite3BtreeHoldsMutex(db->aDb[0].pBt) );
|
|
assert( db->init.busy==0 );
|
|
@@ -127404,25 +137711,26 @@ static void schemaIsValid(Parse *pParse){
|
|
if( pBt==0 ) continue;
|
|
|
|
/* If there is not already a read-only (or read-write) transaction opened
|
|
- ** on the b-tree database, open one now. If a transaction is opened, it
|
|
+ ** on the b-tree database, open one now. If a transaction is opened, it
|
|
** will be closed immediately after reading the meta-value. */
|
|
- if( !sqlite3BtreeIsInReadTrans(pBt) ){
|
|
+ if( sqlite3BtreeTxnState(pBt)==SQLITE_TXN_NONE ){
|
|
rc = sqlite3BtreeBeginTrans(pBt, 0, 0);
|
|
if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){
|
|
sqlite3OomFault(db);
|
|
+ pParse->rc = SQLITE_NOMEM;
|
|
}
|
|
if( rc!=SQLITE_OK ) return;
|
|
openedTransaction = 1;
|
|
}
|
|
|
|
- /* Read the schema cookie from the database. If it does not match the
|
|
+ /* Read the schema cookie from the database. If it does not match the
|
|
** value stored as part of the in-memory schema representation,
|
|
** set Parse.rc to SQLITE_SCHEMA. */
|
|
sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&cookie);
|
|
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
|
if( cookie!=db->aDb[iDb].pSchema->schema_cookie ){
|
|
+ if( DbHasProperty(db, iDb, DB_SchemaLoaded) ) pParse->rc = SQLITE_SCHEMA;
|
|
sqlite3ResetOneSchema(db, iDb);
|
|
- pParse->rc = SQLITE_SCHEMA;
|
|
}
|
|
|
|
/* Close the transaction, if one was opened. */
|
|
@@ -127440,17 +137748,18 @@ static void schemaIsValid(Parse *pParse){
|
|
** attached database is returned.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){
|
|
- int i = -1000000;
|
|
+ int i = -32768;
|
|
|
|
- /* If pSchema is NULL, then return -1000000. This happens when code in
|
|
+ /* If pSchema is NULL, then return -32768. This happens when code in
|
|
** expr.c is trying to resolve a reference to a transient table (i.e. one
|
|
- ** created by a sub-select). In this case the return value of this
|
|
+ ** created by a sub-select). In this case the return value of this
|
|
** function should never be used.
|
|
**
|
|
- ** We return -1000000 instead of the more usual -1 simply because using
|
|
- ** -1000000 as the incorrect index into db->aDb[] is much
|
|
+ ** We return -32768 instead of the more usual -1 simply because using
|
|
+ ** -32768 as the incorrect index into db->aDb[] is much
|
|
** more likely to cause a segfault than -1 (of course there are assert()
|
|
- ** statements too, but it never hurts to play the odds).
|
|
+ ** statements too, but it never hurts to play the odds) and
|
|
+ ** -32768 will still fit into a 16-bit signed integer.
|
|
*/
|
|
assert( sqlite3_mutex_held(db->mutex) );
|
|
if( pSchema ){
|
|
@@ -127468,18 +137777,109 @@ SQLITE_PRIVATE int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){
|
|
/*
|
|
** Free all memory allocations in the pParse object
|
|
*/
|
|
-SQLITE_PRIVATE void sqlite3ParserReset(Parse *pParse){
|
|
+SQLITE_PRIVATE void sqlite3ParseObjectReset(Parse *pParse){
|
|
sqlite3 *db = pParse->db;
|
|
- sqlite3DbFree(db, pParse->aLabel);
|
|
- sqlite3ExprListDelete(db, pParse->pConstExpr);
|
|
- if( db ){
|
|
- assert( db->lookaside.bDisable >= pParse->disableLookaside );
|
|
- db->lookaside.bDisable -= pParse->disableLookaside;
|
|
- db->lookaside.sz = db->lookaside.bDisable ? 0 : db->lookaside.szTrue;
|
|
- }
|
|
+ assert( db!=0 );
|
|
+ assert( db->pParse==pParse );
|
|
+ assert( pParse->nested==0 );
|
|
+#ifndef SQLITE_OMIT_SHARED_CACHE
|
|
+ if( pParse->aTableLock ) sqlite3DbNNFreeNN(db, pParse->aTableLock);
|
|
+#endif
|
|
+ while( pParse->pCleanup ){
|
|
+ ParseCleanup *pCleanup = pParse->pCleanup;
|
|
+ pParse->pCleanup = pCleanup->pNext;
|
|
+ pCleanup->xCleanup(db, pCleanup->pPtr);
|
|
+ sqlite3DbNNFreeNN(db, pCleanup);
|
|
+ }
|
|
+ if( pParse->aLabel ) sqlite3DbNNFreeNN(db, pParse->aLabel);
|
|
+ if( pParse->pConstExpr ){
|
|
+ sqlite3ExprListDelete(db, pParse->pConstExpr);
|
|
+ }
|
|
+ assert( db->lookaside.bDisable >= pParse->disableLookaside );
|
|
+ db->lookaside.bDisable -= pParse->disableLookaside;
|
|
+ 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;
|
|
}
|
|
|
|
+/*
|
|
+** Add a new cleanup operation to a Parser. The cleanup should happen when
|
|
+** the parser object is destroyed. But, beware: the cleanup might happen
|
|
+** 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
|
|
+** 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.
|
|
+**
|
|
+** If a memory allocation error occurs, then the cleanup happens immediately.
|
|
+** When either SQLITE_DEBUG or SQLITE_COVERAGE_TEST are defined, the
|
|
+** pParse->earlyCleanup flag is set in that case. Calling code show verify
|
|
+** that test cases exist for which this happens, to guard against possible
|
|
+** use-after-free errors following an OOM. The preferred way to do this is
|
|
+** to immediately follow the call to this routine with:
|
|
+**
|
|
+** testcase( pParse->earlyCleanup );
|
|
+**
|
|
+** This routine returns a copy of its pPtr input (the third parameter)
|
|
+** except if an early cleanup occurs, in which case it returns NULL. So
|
|
+** another way to check for early cleanup is to check the return value.
|
|
+** Or, stop using the pPtr parameter with this call and use only its
|
|
+** return value thereafter. Something like this:
|
|
+**
|
|
+** pObj = sqlite3ParserAddCleanup(pParse, destructor, pObj);
|
|
+*/
|
|
+SQLITE_PRIVATE void *sqlite3ParserAddCleanup(
|
|
+ Parse *pParse, /* Destroy when this Parser finishes */
|
|
+ void (*xCleanup)(sqlite3*,void*), /* The cleanup routine */
|
|
+ void *pPtr /* Pointer to object to be cleaned up */
|
|
+){
|
|
+ ParseCleanup *pCleanup = sqlite3DbMallocRaw(pParse->db, sizeof(*pCleanup));
|
|
+ if( pCleanup ){
|
|
+ pCleanup->pNext = pParse->pCleanup;
|
|
+ pParse->pCleanup = pCleanup;
|
|
+ pCleanup->pPtr = pPtr;
|
|
+ pCleanup->xCleanup = xCleanup;
|
|
+ }else{
|
|
+ xCleanup(pParse->db, pPtr);
|
|
+ pPtr = 0;
|
|
+#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST)
|
|
+ pParse->earlyCleanup = 1;
|
|
+#endif
|
|
+ }
|
|
+ return pPtr;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Turn bulk memory into a valid Parse object and link that Parse object
|
|
+** into database connection db.
|
|
+**
|
|
+** Call sqlite3ParseObjectReset() to undo this operation.
|
|
+**
|
|
+** Caution: Do not confuse this routine with sqlite3ParseObjectInit() which
|
|
+** is generated by Lemon.
|
|
+*/
|
|
+SQLITE_PRIVATE void sqlite3ParseObjectInit(Parse *pParse, sqlite3 *db){
|
|
+ memset(PARSE_HDR(pParse), 0, PARSE_HDR_SZ);
|
|
+ memset(PARSE_TAIL(pParse), 0, PARSE_TAIL_SZ);
|
|
+ assert( db->pParse!=pParse );
|
|
+ pParse->pOuterParse = db->pParse;
|
|
+ db->pParse = pParse;
|
|
+ pParse->db = db;
|
|
+ if( db->mallocFailed ) sqlite3ErrorMsg(pParse, "out of memory");
|
|
+}
|
|
+
|
|
+/*
|
|
+** Maximum number of times that we will try again to prepare a statement
|
|
+** that returns SQLITE_ERROR_RETRY.
|
|
+*/
|
|
+#ifndef SQLITE_MAX_PREPARE_RETRY
|
|
+# define SQLITE_MAX_PREPARE_RETRY 25
|
|
+#endif
|
|
+
|
|
/*
|
|
** Compile the UTF-8 encoded SQL statement zSql into a statement handle.
|
|
*/
|
|
@@ -127492,16 +137892,19 @@ static int sqlite3Prepare(
|
|
sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
|
|
const char **pzTail /* OUT: End of parsed string */
|
|
){
|
|
- char *zErrMsg = 0; /* Error message */
|
|
int rc = SQLITE_OK; /* Result code */
|
|
int i; /* Loop counter */
|
|
Parse sParse; /* Parsing context */
|
|
|
|
- memset(&sParse, 0, PARSE_HDR_SZ);
|
|
+ /* sqlite3ParseObjectInit(&sParse, db); // inlined for performance */
|
|
+ memset(PARSE_HDR(&sParse), 0, PARSE_HDR_SZ);
|
|
memset(PARSE_TAIL(&sParse), 0, PARSE_TAIL_SZ);
|
|
+ sParse.pOuterParse = db->pParse;
|
|
+ db->pParse = &sParse;
|
|
+ sParse.db = db;
|
|
sParse.pReprepare = pReprepare;
|
|
assert( ppStmt && *ppStmt==0 );
|
|
- /* assert( !db->mallocFailed ); // not true with SQLITE_USE_ALLOCA */
|
|
+ if( db->mallocFailed ) sqlite3ErrorMsg(&sParse, "out of memory");
|
|
assert( sqlite3_mutex_held(db->mutex) );
|
|
|
|
/* For a long-term use prepared statement avoid the use of
|
|
@@ -127511,7 +137914,7 @@ static int sqlite3Prepare(
|
|
sParse.disableLookaside++;
|
|
DisableLookaside;
|
|
}
|
|
- sParse.disableVtab = (prepFlags & SQLITE_PREPARE_NO_VTAB)!=0;
|
|
+ sParse.prepFlags = prepFlags & 0xff;
|
|
|
|
/* Check to verify that it is possible to get a read lock on all
|
|
** database schemas. The inability to get a read lock indicates that
|
|
@@ -127528,8 +137931,8 @@ static int sqlite3Prepare(
|
|
** This thread is currently holding mutexes on all Btrees (because
|
|
** of the sqlite3BtreeEnterAll() in sqlite3LockAndPrepare()) so it
|
|
** is not possible for another thread to start a new schema change
|
|
- ** while this routine is running. Hence, we do not need to hold
|
|
- ** locks on the schema, we just need to make sure nobody else is
|
|
+ ** while this routine is running. Hence, we do not need to hold
|
|
+ ** locks on the schema, we just need to make sure nobody else is
|
|
** holding them.
|
|
**
|
|
** Note that setting READ_UNCOMMITTED overrides most lock detection,
|
|
@@ -127552,9 +137955,10 @@ static int sqlite3Prepare(
|
|
}
|
|
}
|
|
|
|
- sqlite3VtabUnlockList(db);
|
|
+#ifndef SQLITE_OMIT_VIRTUALTABLE
|
|
+ if( db->pDisconnect ) sqlite3VtabUnlockList(db);
|
|
+#endif
|
|
|
|
- sParse.db = db;
|
|
if( nBytes>=0 && (nBytes==0 || zSql[nBytes-1]!=0) ){
|
|
char *zSqlCopy;
|
|
int mxLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH];
|
|
@@ -127567,23 +137971,17 @@ static int sqlite3Prepare(
|
|
}
|
|
zSqlCopy = sqlite3DbStrNDup(db, zSql, nBytes);
|
|
if( zSqlCopy ){
|
|
- sqlite3RunParser(&sParse, zSqlCopy, &zErrMsg);
|
|
+ sqlite3RunParser(&sParse, zSqlCopy);
|
|
sParse.zTail = &zSql[sParse.zTail-zSqlCopy];
|
|
sqlite3DbFree(db, zSqlCopy);
|
|
}else{
|
|
sParse.zTail = &zSql[nBytes];
|
|
}
|
|
}else{
|
|
- sqlite3RunParser(&sParse, zSql, &zErrMsg);
|
|
+ sqlite3RunParser(&sParse, zSql);
|
|
}
|
|
assert( 0==sParse.nQueryLoop );
|
|
|
|
- if( sParse.rc==SQLITE_DONE ){
|
|
- sParse.rc = SQLITE_OK;
|
|
- }
|
|
- if( sParse.checkSchema ){
|
|
- schemaIsValid(&sParse);
|
|
- }
|
|
if( pzTail ){
|
|
*pzTail = sParse.zTail;
|
|
}
|
|
@@ -127593,21 +137991,30 @@ static int sqlite3Prepare(
|
|
}
|
|
if( db->mallocFailed ){
|
|
sParse.rc = SQLITE_NOMEM_BKPT;
|
|
+ sParse.checkSchema = 0;
|
|
}
|
|
- rc = sParse.rc;
|
|
- if( rc!=SQLITE_OK ){
|
|
- if( sParse.pVdbe ) sqlite3VdbeFinalize(sParse.pVdbe);
|
|
- assert(!(*ppStmt));
|
|
+ if( sParse.rc!=SQLITE_OK && sParse.rc!=SQLITE_DONE ){
|
|
+ if( sParse.checkSchema && db->init.busy==0 ){
|
|
+ schemaIsValid(&sParse);
|
|
+ }
|
|
+ if( sParse.pVdbe ){
|
|
+ sqlite3VdbeFinalize(sParse.pVdbe);
|
|
+ }
|
|
+ assert( 0==(*ppStmt) );
|
|
+ rc = sParse.rc;
|
|
+ if( sParse.zErrMsg ){
|
|
+ sqlite3ErrorWithMsg(db, rc, "%s", sParse.zErrMsg);
|
|
+ sqlite3DbFree(db, sParse.zErrMsg);
|
|
+ }else{
|
|
+ sqlite3Error(db, rc);
|
|
+ }
|
|
}else{
|
|
+ assert( sParse.zErrMsg==0 );
|
|
*ppStmt = (sqlite3_stmt*)sParse.pVdbe;
|
|
+ rc = SQLITE_OK;
|
|
+ sqlite3ErrorClear(db);
|
|
}
|
|
|
|
- if( zErrMsg ){
|
|
- sqlite3ErrorWithMsg(db, rc, "%s", zErrMsg);
|
|
- sqlite3DbFree(db, zErrMsg);
|
|
- }else{
|
|
- sqlite3Error(db, rc);
|
|
- }
|
|
|
|
/* Delete any TriggerPrg structures allocated while parsing this statement. */
|
|
while( sParse.pTriggerPrg ){
|
|
@@ -127618,7 +138025,7 @@ static int sqlite3Prepare(
|
|
|
|
end_prepare:
|
|
|
|
- sqlite3ParserReset(&sParse);
|
|
+ sqlite3ParseObjectReset(&sParse);
|
|
return rc;
|
|
}
|
|
static int sqlite3LockAndPrepare(
|
|
@@ -127648,11 +138055,13 @@ static int sqlite3LockAndPrepare(
|
|
** reset is considered a permanent error. */
|
|
rc = sqlite3Prepare(db, zSql, nBytes, prepFlags, pOld, ppStmt, pzTail);
|
|
assert( rc==SQLITE_OK || *ppStmt==0 );
|
|
- }while( rc==SQLITE_ERROR_RETRY
|
|
+ if( rc==SQLITE_OK || db->mallocFailed ) break;
|
|
+ }while( (rc==SQLITE_ERROR_RETRY && (cnt++)<SQLITE_MAX_PREPARE_RETRY)
|
|
|| (rc==SQLITE_SCHEMA && (sqlite3ResetOneSchema(db,-1), cnt++)==0) );
|
|
sqlite3BtreeLeaveAll(db);
|
|
rc = sqlite3ApiExit(db, rc);
|
|
assert( (rc&db->errMask)==rc );
|
|
+ db->busyHandler.nBusy = 0;
|
|
sqlite3_mutex_leave(db->mutex);
|
|
return rc;
|
|
}
|
|
@@ -127663,7 +138072,7 @@ static int sqlite3LockAndPrepare(
|
|
**
|
|
** If the statement is successfully recompiled, return SQLITE_OK. Otherwise,
|
|
** if the statement cannot be recompiled because another connection has
|
|
-** locked the sqlite3_master table, return SQLITE_LOCKED. If any other error
|
|
+** locked the sqlite3_schema table, return SQLITE_LOCKED. If any other error
|
|
** occurs, return SQLITE_SCHEMA.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3Reprepare(Vdbe *p){
|
|
@@ -127764,7 +138173,7 @@ SQLITE_API int sqlite3_prepare_v3(
|
|
** Compile the UTF-16 encoded SQL statement zSql into a statement handle.
|
|
*/
|
|
static int sqlite3Prepare16(
|
|
- sqlite3 *db, /* Database handle. */
|
|
+ sqlite3 *db, /* Database handle. */
|
|
const void *zSql, /* UTF-16 encoded SQL statement. */
|
|
int nBytes, /* Length of zSql in bytes. */
|
|
u32 prepFlags, /* Zero or more SQLITE_PREPARE_* flags */
|
|
@@ -127807,7 +138216,7 @@ static int sqlite3Prepare16(
|
|
int chars_parsed = sqlite3Utf8CharLen(zSql8, (int)(zTail8-zSql8));
|
|
*pzTail = (u8 *)zSql + sqlite3Utf16ByteLen(zSql, chars_parsed);
|
|
}
|
|
- sqlite3DbFree(db, zSql8);
|
|
+ sqlite3DbFree(db, zSql8);
|
|
rc = sqlite3ApiExit(db, rc);
|
|
sqlite3_mutex_leave(db->mutex);
|
|
return rc;
|
|
@@ -127822,7 +138231,7 @@ static int sqlite3Prepare16(
|
|
** occurs.
|
|
*/
|
|
SQLITE_API int sqlite3_prepare16(
|
|
- sqlite3 *db, /* Database handle. */
|
|
+ sqlite3 *db, /* Database handle. */
|
|
const void *zSql, /* UTF-16 encoded SQL statement. */
|
|
int nBytes, /* Length of zSql in bytes. */
|
|
sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
|
|
@@ -127834,7 +138243,7 @@ SQLITE_API int sqlite3_prepare16(
|
|
return rc;
|
|
}
|
|
SQLITE_API int sqlite3_prepare16_v2(
|
|
- sqlite3 *db, /* Database handle. */
|
|
+ sqlite3 *db, /* Database handle. */
|
|
const void *zSql, /* UTF-16 encoded SQL statement. */
|
|
int nBytes, /* Length of zSql in bytes. */
|
|
sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
|
|
@@ -127846,7 +138255,7 @@ SQLITE_API int sqlite3_prepare16_v2(
|
|
return rc;
|
|
}
|
|
SQLITE_API int sqlite3_prepare16_v3(
|
|
- sqlite3 *db, /* Database handle. */
|
|
+ sqlite3 *db, /* Database handle. */
|
|
const void *zSql, /* UTF-16 encoded SQL statement. */
|
|
int nBytes, /* Length of zSql in bytes. */
|
|
unsigned int prepFlags, /* Zero or more SQLITE_PREPARE_* flags */
|
|
@@ -127881,20 +138290,6 @@ SQLITE_API int sqlite3_prepare16_v3(
|
|
*/
|
|
/* #include "sqliteInt.h" */
|
|
|
|
-/*
|
|
-** Trace output macros
|
|
-*/
|
|
-#if SELECTTRACE_ENABLED
|
|
-/***/ int sqlite3SelectTrace = 0;
|
|
-# define SELECTTRACE(K,P,S,X) \
|
|
- if(sqlite3SelectTrace&(K)) \
|
|
- sqlite3DebugPrintf("%u/%d/%p: ",(S)->selId,(P)->addrExplain,(S)),\
|
|
- sqlite3DebugPrintf X
|
|
-#else
|
|
-# define SELECTTRACE(K,P,S,X)
|
|
-#endif
|
|
-
|
|
-
|
|
/*
|
|
** An instance of the following object is used to record information about
|
|
** how to process the DISTINCT keyword, to simplify passing that information
|
|
@@ -127902,7 +138297,7 @@ SQLITE_API int sqlite3_prepare16_v3(
|
|
*/
|
|
typedef struct DistinctCtx DistinctCtx;
|
|
struct DistinctCtx {
|
|
- u8 isTnct; /* True if the DISTINCT keyword is present */
|
|
+ u8 isTnct; /* 0: Not distinct. 1: DISTICT 2: DISTINCT and ORDER BY */
|
|
u8 eTnctType; /* One of the WHERE_DISTINCT_* operators */
|
|
int tabTnct; /* Ephemeral table used for DISTINCT processing */
|
|
int addrTnct; /* Address of OP_OpenEphemeral opcode for tabTnct */
|
|
@@ -127946,6 +138341,10 @@ struct SortCtx {
|
|
} aDefer[4];
|
|
#endif
|
|
struct RowLoadInfo *pDeferredRowLoad; /* Deferred row loading info or NULL */
|
|
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
|
|
+ int addrPush; /* First instruction to push data into sorter */
|
|
+ int addrPushEnd; /* Last instruction that pushes data into sorter */
|
|
+#endif
|
|
};
|
|
#define SORTFLAG_UseSorter 0x01 /* Use SorterOpen instead of OpenEphemeral */
|
|
|
|
@@ -127957,6 +138356,7 @@ struct SortCtx {
|
|
** If bFree==0, Leave the first Select object unfreed
|
|
*/
|
|
static void clearSelect(sqlite3 *db, Select *p, int bFree){
|
|
+ assert( db!=0 );
|
|
while( p ){
|
|
Select *pPrior = p->pPrior;
|
|
sqlite3ExprListDelete(db, p->pEList);
|
|
@@ -127966,14 +138366,17 @@ static void clearSelect(sqlite3 *db, Select *p, int bFree){
|
|
sqlite3ExprDelete(db, p->pHaving);
|
|
sqlite3ExprListDelete(db, p->pOrderBy);
|
|
sqlite3ExprDelete(db, p->pLimit);
|
|
+ if( OK_IF_ALWAYS_TRUE(p->pWith) ) sqlite3WithDelete(db, p->pWith);
|
|
#ifndef SQLITE_OMIT_WINDOWFUNC
|
|
if( OK_IF_ALWAYS_TRUE(p->pWinDefn) ){
|
|
sqlite3WindowListDelete(db, p->pWinDefn);
|
|
}
|
|
- assert( p->pWin==0 );
|
|
+ while( p->pWin ){
|
|
+ assert( p->pWin->ppThis==&p->pWin );
|
|
+ sqlite3WindowUnlinkFromSelect(p->pWin);
|
|
+ }
|
|
#endif
|
|
- if( OK_IF_ALWAYS_TRUE(p->pWith) ) sqlite3WithDelete(db, p->pWith);
|
|
- if( bFree ) sqlite3DbFreeNN(db, p);
|
|
+ if( bFree ) sqlite3DbNNFreeNN(db, p);
|
|
p = pPrior;
|
|
bFree = 1;
|
|
}
|
|
@@ -127985,6 +138388,7 @@ static void clearSelect(sqlite3 *db, Select *p, int bFree){
|
|
SQLITE_PRIVATE void sqlite3SelectDestInit(SelectDest *pDest, int eDest, int iParm){
|
|
pDest->eDest = (u8)eDest;
|
|
pDest->iSDParm = iParm;
|
|
+ pDest->iSDParm2 = 0;
|
|
pDest->zAffSdst = 0;
|
|
pDest->iSdst = 0;
|
|
pDest->nSdst = 0;
|
|
@@ -128006,9 +138410,9 @@ SQLITE_PRIVATE Select *sqlite3SelectNew(
|
|
u32 selFlags, /* Flag parameters, such as SF_Distinct */
|
|
Expr *pLimit /* LIMIT value. NULL means not used */
|
|
){
|
|
- Select *pNew;
|
|
+ Select *pNew, *pAllocated;
|
|
Select standin;
|
|
- pNew = sqlite3DbMallocRawNN(pParse->db, sizeof(*pNew) );
|
|
+ pAllocated = pNew = sqlite3DbMallocRawNN(pParse->db, sizeof(*pNew) );
|
|
if( pNew==0 ){
|
|
assert( pParse->db->mallocFailed );
|
|
pNew = &standin;
|
|
@@ -128042,12 +138446,11 @@ SQLITE_PRIVATE Select *sqlite3SelectNew(
|
|
#endif
|
|
if( pParse->db->mallocFailed ) {
|
|
clearSelect(pParse->db, pNew, pNew!=&standin);
|
|
- pNew = 0;
|
|
+ pAllocated = 0;
|
|
}else{
|
|
assert( pNew->pSrc!=0 || pParse->nErr>0 );
|
|
}
|
|
- assert( pNew!=&standin );
|
|
- return pNew;
|
|
+ return pAllocated;
|
|
}
|
|
|
|
|
|
@@ -128058,21 +138461,6 @@ SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3 *db, Select *p){
|
|
if( OK_IF_ALWAYS_TRUE(p) ) clearSelect(db, p, 1);
|
|
}
|
|
|
|
-/*
|
|
-** Delete all the substructure for p, but keep p allocated. Redefine
|
|
-** p to be a single SELECT where every column of the result set has a
|
|
-** value of NULL.
|
|
-*/
|
|
-SQLITE_PRIVATE void sqlite3SelectReset(Parse *pParse, Select *p){
|
|
- if( ALWAYS(p) ){
|
|
- clearSelect(pParse->db, p, 0);
|
|
- memset(&p->iLimit, 0, sizeof(Select) - offsetof(Select,iLimit));
|
|
- p->pEList = sqlite3ExprListAppend(pParse, 0,
|
|
- sqlite3ExprAlloc(pParse->db,TK_NULL,0,0));
|
|
- p->pSrc = sqlite3DbMallocZero(pParse->db, sizeof(SrcList));
|
|
- }
|
|
-}
|
|
-
|
|
/*
|
|
** Return a pointer to the right-most SELECT statement in a compound.
|
|
*/
|
|
@@ -128097,6 +138485,52 @@ static Select *findRightmost(Select *p){
|
|
**
|
|
** If an illegal or unsupported join type is seen, then still return
|
|
** a join type, but put an error in the pParse structure.
|
|
+**
|
|
+** These are the valid join types:
|
|
+**
|
|
+**
|
|
+** pA pB pC Return Value
|
|
+** ------- ----- ----- ------------
|
|
+** CROSS - - JT_CROSS
|
|
+** INNER - - JT_INNER
|
|
+** LEFT - - JT_LEFT|JT_OUTER
|
|
+** LEFT OUTER - JT_LEFT|JT_OUTER
|
|
+** RIGHT - - JT_RIGHT|JT_OUTER
|
|
+** RIGHT OUTER - JT_RIGHT|JT_OUTER
|
|
+** FULL - - JT_LEFT|JT_RIGHT|JT_OUTER
|
|
+** FULL OUTER - JT_LEFT|JT_RIGHT|JT_OUTER
|
|
+** NATURAL INNER - JT_NATURAL|JT_INNER
|
|
+** NATURAL LEFT - JT_NATURAL|JT_LEFT|JT_OUTER
|
|
+** NATURAL LEFT OUTER JT_NATURAL|JT_LEFT|JT_OUTER
|
|
+** NATURAL RIGHT - JT_NATURAL|JT_RIGHT|JT_OUTER
|
|
+** NATURAL RIGHT OUTER JT_NATURAL|JT_RIGHT|JT_OUTER
|
|
+** NATURAL FULL - JT_NATURAL|JT_LEFT|JT_RIGHT
|
|
+** 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.
|
|
+** 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:
|
|
+**
|
|
+** INNER CROSS JOIN -> same as JOIN
|
|
+** NATURAL CROSS JOIN -> same as NATURAL JOIN
|
|
+** OUTER LEFT JOIN -> same as LEFT JOIN
|
|
+** LEFT NATURAL JOIN -> same as NATURAL LEFT JOIN
|
|
+** LEFT RIGHT JOIN -> same as FULL JOIN
|
|
+** RIGHT OUTER FULL JOIN -> same as FULL JOIN
|
|
+** CROSS CROSS CROSS JOIN -> same as JOIN
|
|
+**
|
|
+** The only restrictions on the join type name are:
|
|
+**
|
|
+** * "INNER" cannot appear together with "OUTER", "LEFT", "RIGHT",
|
|
+** or "FULL".
|
|
+**
|
|
+** * "CROSS" cannot appear together with "OUTER", "LEFT", "RIGHT,
|
|
+** or "FULL".
|
|
+**
|
|
+** * If "OUTER" is present then there must also be one of
|
|
+** "LEFT", "RIGHT", or "FULL"
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3JoinType(Parse *pParse, Token *pA, Token *pB, Token *pC){
|
|
int jointype = 0;
|
|
@@ -128109,13 +138543,13 @@ SQLITE_PRIVATE int sqlite3JoinType(Parse *pParse, Token *pA, Token *pB, Token *p
|
|
u8 nChar; /* Length of the keyword in characters */
|
|
u8 code; /* Join type mask */
|
|
} aKeyword[] = {
|
|
- /* natural */ { 0, 7, JT_NATURAL },
|
|
- /* left */ { 6, 4, JT_LEFT|JT_OUTER },
|
|
- /* outer */ { 10, 5, JT_OUTER },
|
|
- /* right */ { 14, 5, JT_RIGHT|JT_OUTER },
|
|
- /* full */ { 19, 4, JT_LEFT|JT_RIGHT|JT_OUTER },
|
|
- /* inner */ { 23, 5, JT_INNER },
|
|
- /* cross */ { 28, 5, JT_INNER|JT_CROSS },
|
|
+ /* (0) natural */ { 0, 7, JT_NATURAL },
|
|
+ /* (1) left */ { 6, 4, JT_LEFT|JT_OUTER },
|
|
+ /* (2) outer */ { 10, 5, JT_OUTER },
|
|
+ /* (3) right */ { 14, 5, JT_RIGHT|JT_OUTER },
|
|
+ /* (4) full */ { 19, 4, JT_LEFT|JT_RIGHT|JT_OUTER },
|
|
+ /* (5) inner */ { 23, 5, JT_INNER },
|
|
+ /* (6) cross */ { 28, 5, JT_INNER|JT_CROSS },
|
|
};
|
|
int i, j;
|
|
apAll[0] = pA;
|
|
@@ -128124,7 +138558,7 @@ SQLITE_PRIVATE int sqlite3JoinType(Parse *pParse, Token *pA, Token *pB, Token *p
|
|
for(i=0; i<3 && apAll[i]; i++){
|
|
p = apAll[i];
|
|
for(j=0; j<ArraySize(aKeyword); j++){
|
|
- if( p->n==aKeyword[j].nChar
|
|
+ if( p->n==aKeyword[j].nChar
|
|
&& sqlite3StrNICmp((char*)p->z, &zKeyText[aKeyword[j].i], p->n)==0 ){
|
|
jointype |= aKeyword[j].code;
|
|
break;
|
|
@@ -128138,18 +138572,15 @@ SQLITE_PRIVATE int sqlite3JoinType(Parse *pParse, Token *pA, Token *pB, Token *p
|
|
}
|
|
if(
|
|
(jointype & (JT_INNER|JT_OUTER))==(JT_INNER|JT_OUTER) ||
|
|
- (jointype & JT_ERROR)!=0
|
|
+ (jointype & JT_ERROR)!=0 ||
|
|
+ (jointype & (JT_OUTER|JT_LEFT|JT_RIGHT))==JT_OUTER
|
|
){
|
|
- const char *zSp = " ";
|
|
- assert( pB!=0 );
|
|
- if( pC==0 ){ zSp++; }
|
|
- sqlite3ErrorMsg(pParse, "unknown or unsupported join type: "
|
|
- "%T %T%s%T", pA, pB, zSp, pC);
|
|
- jointype = JT_INNER;
|
|
- }else if( (jointype & JT_OUTER)!=0
|
|
- && (jointype & (JT_LEFT|JT_RIGHT))!=JT_LEFT ){
|
|
- sqlite3ErrorMsg(pParse,
|
|
- "RIGHT and FULL OUTER JOINs are not currently supported");
|
|
+ const char *zSp1 = " ";
|
|
+ const char *zSp2 = " ";
|
|
+ if( pB==0 ){ zSp1++; }
|
|
+ if( pC==0 ){ zSp2++; }
|
|
+ sqlite3ErrorMsg(pParse, "unknown join type: "
|
|
+ "%T%s%T%s%T", pA, zSp1, pB, zSp2, pC);
|
|
jointype = JT_INNER;
|
|
}
|
|
return jointype;
|
|
@@ -128159,17 +138590,36 @@ SQLITE_PRIVATE int sqlite3JoinType(Parse *pParse, Token *pA, Token *pB, Token *p
|
|
** Return the index of a column in a table. Return -1 if the column
|
|
** is not contained in the table.
|
|
*/
|
|
-static int columnIndex(Table *pTab, const char *zCol){
|
|
+SQLITE_PRIVATE int sqlite3ColumnIndex(Table *pTab, const char *zCol){
|
|
int i;
|
|
- for(i=0; i<pTab->nCol; i++){
|
|
- if( sqlite3StrICmp(pTab->aCol[i].zName, zCol)==0 ) return i;
|
|
+ u8 h = sqlite3StrIHash(zCol);
|
|
+ Column *pCol;
|
|
+ for(pCol=pTab->aCol, i=0; i<pTab->nCol; pCol++, i++){
|
|
+ if( pCol->hName==h && sqlite3StrICmp(pCol->zCnName, zCol)==0 ) return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
-** Search the first N tables in pSrc, from left to right, looking for a
|
|
-** table that has a column named zCol.
|
|
+** Mark a subquery result column as having been used.
|
|
+*/
|
|
+SQLITE_PRIVATE void sqlite3SrcItemColumnUsed(SrcItem *pItem, int iCol){
|
|
+ assert( pItem!=0 );
|
|
+ assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem->pSelect) );
|
|
+ if( pItem->fg.isNestedFrom ){
|
|
+ ExprList *pResults;
|
|
+ assert( pItem->pSelect!=0 );
|
|
+ pResults = pItem->pSelect->pEList;
|
|
+ assert( pResults!=0 );
|
|
+ assert( iCol>=0 && iCol<pResults->nExpr );
|
|
+ pResults->a[iCol].fg.bUsed = 1;
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+** Search the tables iStart..iEnd (inclusive) in pSrc, looking for a
|
|
+** table that has a column named zCol. The search is left-to-right.
|
|
+** The first match found is returned.
|
|
**
|
|
** When found, set *piTab and *piCol to the table index and column index
|
|
** of the matching column and return TRUE.
|
|
@@ -128178,22 +138628,27 @@ static int columnIndex(Table *pTab, const char *zCol){
|
|
*/
|
|
static int tableAndColumnIndex(
|
|
SrcList *pSrc, /* Array of tables to search */
|
|
- int N, /* Number of tables in pSrc->a[] to search */
|
|
+ int iStart, /* First member of pSrc->a[] to check */
|
|
+ int iEnd, /* Last member of pSrc->a[] to check */
|
|
const char *zCol, /* Name of the column we are looking for */
|
|
int *piTab, /* Write index of pSrc->a[] here */
|
|
int *piCol, /* Write index of pSrc->a[*piTab].pTab->aCol[] here */
|
|
- int bIgnoreHidden /* True to ignore hidden columns */
|
|
+ int bIgnoreHidden /* Ignore hidden columns */
|
|
){
|
|
int i; /* For looping over tables in pSrc */
|
|
int iCol; /* Index of column matching zCol */
|
|
|
|
+ assert( iEnd<pSrc->nSrc );
|
|
+ assert( iStart>=0 );
|
|
assert( (piTab==0)==(piCol==0) ); /* Both or neither are NULL */
|
|
- for(i=0; i<N; i++){
|
|
- iCol = columnIndex(pSrc->a[i].pTab, zCol);
|
|
- if( iCol>=0
|
|
+
|
|
+ for(i=iStart; i<=iEnd; i++){
|
|
+ iCol = sqlite3ColumnIndex(pSrc->a[i].pTab, zCol);
|
|
+ if( iCol>=0
|
|
&& (bIgnoreHidden==0 || IsHiddenColumn(&pSrc->a[i].pTab->aCol[iCol])==0)
|
|
){
|
|
if( piTab ){
|
|
+ sqlite3SrcItemColumnUsed(&pSrc->a[i], iCol);
|
|
*piTab = i;
|
|
*piCol = iCol;
|
|
}
|
|
@@ -128204,63 +138659,19 @@ static int tableAndColumnIndex(
|
|
}
|
|
|
|
/*
|
|
-** This function is used to add terms implied by JOIN syntax to the
|
|
-** WHERE clause expression of a SELECT statement. The new term, which
|
|
-** is ANDed with the existing WHERE clause, is of the form:
|
|
-**
|
|
-** (tab1.col1 = tab2.col2)
|
|
-**
|
|
-** where tab1 is the iSrc'th table in SrcList pSrc and tab2 is the
|
|
-** (iSrc+1)'th. Column col1 is column iColLeft of tab1, and col2 is
|
|
-** column iColRight of tab2.
|
|
-*/
|
|
-static void addWhereTerm(
|
|
- Parse *pParse, /* Parsing context */
|
|
- SrcList *pSrc, /* List of tables in FROM clause */
|
|
- int iLeft, /* Index of first table to join in pSrc */
|
|
- int iColLeft, /* Index of column in first table */
|
|
- int iRight, /* Index of second table in pSrc */
|
|
- int iColRight, /* Index of column in second table */
|
|
- int isOuterJoin, /* True if this is an OUTER join */
|
|
- Expr **ppWhere /* IN/OUT: The WHERE clause to add to */
|
|
-){
|
|
- sqlite3 *db = pParse->db;
|
|
- Expr *pE1;
|
|
- Expr *pE2;
|
|
- Expr *pEq;
|
|
-
|
|
- assert( iLeft<iRight );
|
|
- assert( pSrc->nSrc>iRight );
|
|
- assert( pSrc->a[iLeft].pTab );
|
|
- assert( pSrc->a[iRight].pTab );
|
|
-
|
|
- pE1 = sqlite3CreateColumnExpr(db, pSrc, iLeft, iColLeft);
|
|
- pE2 = sqlite3CreateColumnExpr(db, pSrc, iRight, iColRight);
|
|
-
|
|
- pEq = sqlite3PExpr(pParse, TK_EQ, pE1, pE2);
|
|
- if( pEq && isOuterJoin ){
|
|
- ExprSetProperty(pEq, EP_FromJoin);
|
|
- assert( !ExprHasProperty(pEq, EP_TokenOnly|EP_Reduced) );
|
|
- ExprSetVVAProperty(pEq, EP_NoReduce);
|
|
- pEq->iRightJoinTable = (i16)pE2->iTable;
|
|
- }
|
|
- *ppWhere = sqlite3ExprAnd(pParse, *ppWhere, pEq);
|
|
-}
|
|
-
|
|
-/*
|
|
-** Set the EP_FromJoin property on all terms of the given expression.
|
|
-** And set the Expr.iRightJoinTable to iTable for every term in the
|
|
+** Set the EP_OuterON property on all terms of the given expression.
|
|
+** And set the Expr.w.iJoin to iTable for every term in the
|
|
** expression.
|
|
**
|
|
-** The EP_FromJoin property is used on terms of an expression to tell
|
|
-** the LEFT OUTER JOIN processing logic that this term is part of the
|
|
+** The EP_OuterON property is used on terms of an expression to tell
|
|
+** the OUTER JOIN processing logic that this term is part of the
|
|
** join restriction specified in the ON or USING clause and not a part
|
|
** of the more general WHERE clause. These terms are moved over to the
|
|
** WHERE clause during join processing but we need to remember that they
|
|
** originated in the ON or USING clause.
|
|
**
|
|
-** The Expr.iRightJoinTable tells the WHERE clause processing that the
|
|
-** expression depends on table iRightJoinTable even if that table is not
|
|
+** The Expr.w.iJoin tells the WHERE clause processing that the
|
|
+** expression depends on table w.iJoin even if that table is not
|
|
** explicitly mentioned in the expression. That information is needed
|
|
** for cases like this:
|
|
**
|
|
@@ -128273,144 +138684,222 @@ static void addWhereTerm(
|
|
** after the t1 loop and rows with t1.x!=5 will never appear in
|
|
** the output, which is incorrect.
|
|
*/
|
|
-SQLITE_PRIVATE void sqlite3SetJoinExpr(Expr *p, int iTable){
|
|
+SQLITE_PRIVATE void sqlite3SetJoinExpr(Expr *p, int iTable, u32 joinFlag){
|
|
+ assert( joinFlag==EP_OuterON || joinFlag==EP_InnerON );
|
|
while( p ){
|
|
- ExprSetProperty(p, EP_FromJoin);
|
|
+ ExprSetProperty(p, joinFlag);
|
|
assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) );
|
|
ExprSetVVAProperty(p, EP_NoReduce);
|
|
- p->iRightJoinTable = (i16)iTable;
|
|
- if( p->op==TK_FUNCTION && p->x.pList ){
|
|
- int i;
|
|
- for(i=0; i<p->x.pList->nExpr; i++){
|
|
- sqlite3SetJoinExpr(p->x.pList->a[i].pExpr, iTable);
|
|
+ p->w.iJoin = iTable;
|
|
+ if( p->op==TK_FUNCTION ){
|
|
+ assert( ExprUseXList(p) );
|
|
+ if( p->x.pList ){
|
|
+ int i;
|
|
+ for(i=0; i<p->x.pList->nExpr; i++){
|
|
+ sqlite3SetJoinExpr(p->x.pList->a[i].pExpr, iTable, joinFlag);
|
|
+ }
|
|
}
|
|
}
|
|
- sqlite3SetJoinExpr(p->pLeft, iTable);
|
|
+ sqlite3SetJoinExpr(p->pLeft, iTable, joinFlag);
|
|
p = p->pRight;
|
|
- }
|
|
+ }
|
|
}
|
|
|
|
-/* Undo the work of sqlite3SetJoinExpr(). In the expression p, convert every
|
|
-** term that is marked with EP_FromJoin and iRightJoinTable==iTable into
|
|
-** an ordinary term that omits the EP_FromJoin mark.
|
|
+/* Undo the work of sqlite3SetJoinExpr(). This is used when a LEFT JOIN
|
|
+** is simplified into an ordinary JOIN, and when an ON expression is
|
|
+** "pushed down" into the WHERE clause of a subquery.
|
|
+**
|
|
+** Convert every term that is marked with EP_OuterON and w.iJoin==iTable into
|
|
+** an ordinary term that omits the EP_OuterON mark. Or if iTable<0, then
|
|
+** just clear every EP_OuterON and EP_InnerON mark from the expression tree.
|
|
**
|
|
-** This happens when a LEFT JOIN is simplified into an ordinary JOIN.
|
|
+** If nullable is true, that means that Expr p might evaluate to NULL even
|
|
+** if it is a reference to a NOT NULL column. This can happen, for example,
|
|
+** if the table that p references is on the left side of a RIGHT JOIN.
|
|
+** If nullable is true, then take care to not remove the EP_CanBeNull bit.
|
|
+** See forum thread https://sqlite.org/forum/forumpost/b40696f50145d21c
|
|
*/
|
|
-static void unsetJoinExpr(Expr *p, int iTable){
|
|
+static void unsetJoinExpr(Expr *p, int iTable, int nullable){
|
|
while( p ){
|
|
- if( ExprHasProperty(p, EP_FromJoin)
|
|
- && (iTable<0 || p->iRightJoinTable==iTable) ){
|
|
- ExprClearProperty(p, EP_FromJoin);
|
|
+ if( iTable<0 || (ExprHasProperty(p, EP_OuterON) && p->w.iJoin==iTable) ){
|
|
+ ExprClearProperty(p, EP_OuterON|EP_InnerON);
|
|
+ if( iTable>=0 ) ExprSetProperty(p, EP_InnerON);
|
|
}
|
|
- if( p->op==TK_FUNCTION && p->x.pList ){
|
|
- int i;
|
|
- for(i=0; i<p->x.pList->nExpr; i++){
|
|
- unsetJoinExpr(p->x.pList->a[i].pExpr, iTable);
|
|
+ if( p->op==TK_COLUMN && p->iTable==iTable && !nullable ){
|
|
+ ExprClearProperty(p, EP_CanBeNull);
|
|
+ }
|
|
+ if( p->op==TK_FUNCTION ){
|
|
+ assert( ExprUseXList(p) );
|
|
+ if( p->x.pList ){
|
|
+ int i;
|
|
+ for(i=0; i<p->x.pList->nExpr; i++){
|
|
+ unsetJoinExpr(p->x.pList->a[i].pExpr, iTable, nullable);
|
|
+ }
|
|
}
|
|
}
|
|
- unsetJoinExpr(p->pLeft, iTable);
|
|
+ unsetJoinExpr(p->pLeft, iTable, nullable);
|
|
p = p->pRight;
|
|
- }
|
|
+ }
|
|
}
|
|
|
|
/*
|
|
** This routine processes the join information for a SELECT statement.
|
|
-** ON and USING clauses are converted into extra terms of the WHERE clause.
|
|
-** NATURAL joins also create extra WHERE clause terms.
|
|
+**
|
|
+** * A NATURAL join is converted into a USING join. After that, we
|
|
+** do not need to be concerned with NATURAL joins and we only have
|
|
+** think about USING joins.
|
|
+**
|
|
+** * ON and USING clauses result in extra terms being added to the
|
|
+** WHERE clause to enforce the specified constraints. The extra
|
|
+** WHERE clause terms will be tagged with EP_OuterON or
|
|
+** EP_InnerON so that we know that they originated in ON/USING.
|
|
**
|
|
** The terms of a FROM clause are contained in the Select.pSrc structure.
|
|
** The left most table is the first entry in Select.pSrc. The right-most
|
|
** table is the last entry. The join operator is held in the entry to
|
|
-** the left. Thus entry 0 contains the join operator for the join between
|
|
+** the right. Thus entry 1 contains the join operator for the join between
|
|
** entries 0 and 1. Any ON or USING clauses associated with the join are
|
|
-** also attached to the left entry.
|
|
+** also attached to the right entry.
|
|
**
|
|
** This routine returns the number of errors encountered.
|
|
*/
|
|
-static int sqliteProcessJoin(Parse *pParse, Select *p){
|
|
+static int sqlite3ProcessJoin(Parse *pParse, Select *p){
|
|
SrcList *pSrc; /* All tables in the FROM clause */
|
|
int i, j; /* Loop counters */
|
|
- struct SrcList_item *pLeft; /* Left table being joined */
|
|
- struct SrcList_item *pRight; /* Right table being joined */
|
|
+ SrcItem *pLeft; /* Left table being joined */
|
|
+ SrcItem *pRight; /* Right table being joined */
|
|
|
|
pSrc = p->pSrc;
|
|
pLeft = &pSrc->a[0];
|
|
pRight = &pLeft[1];
|
|
for(i=0; i<pSrc->nSrc-1; i++, pRight++, pLeft++){
|
|
Table *pRightTab = pRight->pTab;
|
|
- int isOuter;
|
|
+ u32 joinType;
|
|
|
|
if( NEVER(pLeft->pTab==0 || pRightTab==0) ) continue;
|
|
- isOuter = (pRight->fg.jointype & JT_OUTER)!=0;
|
|
+ joinType = (pRight->fg.jointype & JT_OUTER)!=0 ? EP_OuterON : EP_InnerON;
|
|
|
|
- /* When the NATURAL keyword is present, add WHERE clause terms for
|
|
- ** every column that the two tables have in common.
|
|
+ /* If this is a NATURAL join, synthesize an approprate USING clause
|
|
+ ** to specify which columns should be joined.
|
|
*/
|
|
if( pRight->fg.jointype & JT_NATURAL ){
|
|
- if( pRight->pOn || pRight->pUsing ){
|
|
+ IdList *pUsing = 0;
|
|
+ if( pRight->fg.isUsing || pRight->u3.pOn ){
|
|
sqlite3ErrorMsg(pParse, "a NATURAL join may not have "
|
|
"an ON or USING clause", 0);
|
|
return 1;
|
|
}
|
|
for(j=0; j<pRightTab->nCol; j++){
|
|
char *zName; /* Name of column in the right table */
|
|
- int iLeft; /* Matching left table */
|
|
- int iLeftCol; /* Matching column in the left table */
|
|
|
|
if( IsHiddenColumn(&pRightTab->aCol[j]) ) continue;
|
|
- zName = pRightTab->aCol[j].zName;
|
|
- if( tableAndColumnIndex(pSrc, i+1, zName, &iLeft, &iLeftCol, 1) ){
|
|
- addWhereTerm(pParse, pSrc, iLeft, iLeftCol, i+1, j,
|
|
- isOuter, &p->pWhere);
|
|
+ zName = pRightTab->aCol[j].zCnName;
|
|
+ if( tableAndColumnIndex(pSrc, 0, i, zName, 0, 0, 1) ){
|
|
+ pUsing = sqlite3IdListAppend(pParse, pUsing, 0);
|
|
+ if( pUsing ){
|
|
+ assert( pUsing->nId>0 );
|
|
+ assert( pUsing->a[pUsing->nId-1].zName==0 );
|
|
+ pUsing->a[pUsing->nId-1].zName = sqlite3DbStrDup(pParse->db, zName);
|
|
+ }
|
|
}
|
|
}
|
|
- }
|
|
-
|
|
- /* Disallow both ON and USING clauses in the same join
|
|
- */
|
|
- if( pRight->pOn && pRight->pUsing ){
|
|
- sqlite3ErrorMsg(pParse, "cannot have both ON and USING "
|
|
- "clauses in the same join");
|
|
- return 1;
|
|
- }
|
|
-
|
|
- /* Add the ON clause to the end of the WHERE clause, connected by
|
|
- ** an AND operator.
|
|
- */
|
|
- if( pRight->pOn ){
|
|
- if( isOuter ) sqlite3SetJoinExpr(pRight->pOn, pRight->iCursor);
|
|
- p->pWhere = sqlite3ExprAnd(pParse, p->pWhere, pRight->pOn);
|
|
- pRight->pOn = 0;
|
|
+ if( pUsing ){
|
|
+ pRight->fg.isUsing = 1;
|
|
+ pRight->fg.isSynthUsing = 1;
|
|
+ pRight->u3.pUsing = pUsing;
|
|
+ }
|
|
+ if( pParse->nErr ) return 1;
|
|
}
|
|
|
|
/* Create extra terms on the WHERE clause for each column named
|
|
- ** in the USING clause. Example: If the two tables to be joined are
|
|
+ ** in the USING clause. Example: If the two tables to be joined are
|
|
** A and B and the USING clause names X, Y, and Z, then add this
|
|
** to the WHERE clause: A.X=B.X AND A.Y=B.Y AND A.Z=B.Z
|
|
** Report an error if any column mentioned in the USING clause is
|
|
** not contained in both tables to be joined.
|
|
*/
|
|
- if( pRight->pUsing ){
|
|
- IdList *pList = pRight->pUsing;
|
|
+ if( pRight->fg.isUsing ){
|
|
+ IdList *pList = pRight->u3.pUsing;
|
|
+ sqlite3 *db = pParse->db;
|
|
+ assert( pList!=0 );
|
|
for(j=0; j<pList->nId; j++){
|
|
char *zName; /* Name of the term in the USING clause */
|
|
int iLeft; /* Table on the left with matching column name */
|
|
int iLeftCol; /* Column number of matching column on the left */
|
|
int iRightCol; /* Column number of matching column on the right */
|
|
+ Expr *pE1; /* Reference to the column on the LEFT of the join */
|
|
+ Expr *pE2; /* Reference to the column on the RIGHT of the join */
|
|
+ Expr *pEq; /* Equality constraint. pE1 == pE2 */
|
|
|
|
zName = pList->a[j].zName;
|
|
- iRightCol = columnIndex(pRightTab, zName);
|
|
+ iRightCol = sqlite3ColumnIndex(pRightTab, zName);
|
|
if( iRightCol<0
|
|
- || !tableAndColumnIndex(pSrc, i+1, zName, &iLeft, &iLeftCol, 0)
|
|
+ || tableAndColumnIndex(pSrc, 0, i, zName, &iLeft, &iLeftCol,
|
|
+ pRight->fg.isSynthUsing)==0
|
|
){
|
|
sqlite3ErrorMsg(pParse, "cannot join using column %s - column "
|
|
"not present in both tables", zName);
|
|
return 1;
|
|
}
|
|
- addWhereTerm(pParse, pSrc, iLeft, iLeftCol, i+1, iRightCol,
|
|
- isOuter, &p->pWhere);
|
|
+ pE1 = sqlite3CreateColumnExpr(db, pSrc, iLeft, iLeftCol);
|
|
+ sqlite3SrcItemColumnUsed(&pSrc->a[iLeft], iLeftCol);
|
|
+ if( (pSrc->a[0].fg.jointype & JT_LTORJ)!=0 ){
|
|
+ /* This branch runs if the query contains one or more RIGHT or FULL
|
|
+ ** JOINs. If only a single table on the left side of this join
|
|
+ ** contains the zName column, then this branch is a no-op.
|
|
+ ** But if there are two or more tables on the left side
|
|
+ ** of the join, construct a coalesce() function that gathers all
|
|
+ ** such tables. Raise an error if more than one of those references
|
|
+ ** to zName is not also within a prior USING clause.
|
|
+ **
|
|
+ ** We really ought to raise an error if there are two or more
|
|
+ ** non-USING references to zName on the left of an INNER or LEFT
|
|
+ ** JOIN. But older versions of SQLite do not do that, so we avoid
|
|
+ ** adding a new error so as to not break legacy applications.
|
|
+ */
|
|
+ ExprList *pFuncArgs = 0; /* Arguments to the coalesce() */
|
|
+ static const Token tkCoalesce = { "coalesce", 8 };
|
|
+ while( tableAndColumnIndex(pSrc, iLeft+1, i, zName, &iLeft, &iLeftCol,
|
|
+ pRight->fg.isSynthUsing)!=0 ){
|
|
+ if( pSrc->a[iLeft].fg.isUsing==0
|
|
+ || sqlite3IdListIndex(pSrc->a[iLeft].u3.pUsing, zName)<0
|
|
+ ){
|
|
+ sqlite3ErrorMsg(pParse, "ambiguous reference to %s in USING()",
|
|
+ zName);
|
|
+ break;
|
|
+ }
|
|
+ pFuncArgs = sqlite3ExprListAppend(pParse, pFuncArgs, pE1);
|
|
+ pE1 = sqlite3CreateColumnExpr(db, pSrc, iLeft, iLeftCol);
|
|
+ sqlite3SrcItemColumnUsed(&pSrc->a[iLeft], iLeftCol);
|
|
+ }
|
|
+ if( pFuncArgs ){
|
|
+ pFuncArgs = sqlite3ExprListAppend(pParse, pFuncArgs, pE1);
|
|
+ pE1 = sqlite3ExprFunction(pParse, pFuncArgs, &tkCoalesce, 0);
|
|
+ }
|
|
+ }
|
|
+ pE2 = sqlite3CreateColumnExpr(db, pSrc, i+1, iRightCol);
|
|
+ sqlite3SrcItemColumnUsed(pRight, iRightCol);
|
|
+ pEq = sqlite3PExpr(pParse, TK_EQ, pE1, pE2);
|
|
+ assert( pE2!=0 || pEq==0 );
|
|
+ if( pEq ){
|
|
+ ExprSetProperty(pEq, joinType);
|
|
+ assert( !ExprHasProperty(pEq, EP_TokenOnly|EP_Reduced) );
|
|
+ ExprSetVVAProperty(pEq, EP_NoReduce);
|
|
+ pEq->w.iJoin = pE2->iTable;
|
|
+ }
|
|
+ p->pWhere = sqlite3ExprAnd(pParse, p->pWhere, pEq);
|
|
}
|
|
}
|
|
+
|
|
+ /* Add the ON clause to the end of the WHERE clause, connected by
|
|
+ ** an AND operator.
|
|
+ */
|
|
+ else if( pRight->u3.pOn ){
|
|
+ sqlite3SetJoinExpr(pRight->u3.pOn, pRight->iCursor, joinType);
|
|
+ p->pWhere = sqlite3ExprAnd(pParse, p->pWhere, pRight->u3.pOn);
|
|
+ pRight->u3.pOn = 0;
|
|
+ pRight->fg.isOn = 1;
|
|
+ }
|
|
}
|
|
return 0;
|
|
}
|
|
@@ -128505,13 +138994,17 @@ static void pushOntoSorter(
|
|
** 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
|
|
- ** SQLITE_ECEL_OMITREF optimization, or due to the
|
|
+ ** SQLITE_ECEL_OMITREF optimization, or due to the
|
|
** SortCtx.pDeferredRowLoad optimiation. In any of these cases
|
|
** regOrigData is 0 to prevent this routine from trying to copy
|
|
** values that might not yet exist.
|
|
*/
|
|
assert( nData==1 || regData==regOrigData || regOrigData==0 );
|
|
|
|
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
|
|
+ pSort->addrPush = sqlite3VdbeCurrentAddr(v);
|
|
+#endif
|
|
+
|
|
if( nPrefixReg ){
|
|
assert( nPrefixReg==nExpr+bSeq );
|
|
regBase = regData - nPrefixReg;
|
|
@@ -128543,7 +139036,7 @@ static void pushOntoSorter(
|
|
pParse->nMem += pSort->nOBSat;
|
|
nKey = nExpr - pSort->nOBSat + bSeq;
|
|
if( bSeq ){
|
|
- addrFirst = sqlite3VdbeAddOp1(v, OP_IfNot, regBase+nExpr);
|
|
+ addrFirst = sqlite3VdbeAddOp1(v, OP_IfNot, regBase+nExpr);
|
|
}else{
|
|
addrFirst = sqlite3VdbeAddOp1(v, OP_SequenceTest, pSort->iECursor);
|
|
}
|
|
@@ -128577,10 +139070,10 @@ static void pushOntoSorter(
|
|
/* At this point the values for the new sorter entry are stored
|
|
** in an array of registers. They need to be composed into a record
|
|
** and inserted into the sorter if either (a) there are currently
|
|
- ** less than LIMIT+OFFSET items or (b) the new record is smaller than
|
|
+ ** less than LIMIT+OFFSET items or (b) the new record is smaller than
|
|
** the largest record currently in the sorter. If (b) is true and there
|
|
** are already LIMIT+OFFSET items in the sorter, delete the largest
|
|
- ** entry before inserting the new one. This way there are never more
|
|
+ ** entry before inserting the new one. This way there are never more
|
|
** than LIMIT+OFFSET items in the sorter.
|
|
**
|
|
** If the new record does not need to be inserted into the sorter,
|
|
@@ -128612,6 +139105,9 @@ static void pushOntoSorter(
|
|
sqlite3VdbeChangeP2(v, iSkip,
|
|
pSort->labelOBLopt ? pSort->labelOBLopt : sqlite3VdbeCurrentAddr(v));
|
|
}
|
|
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
|
|
+ pSort->addrPushEnd = sqlite3VdbeCurrentAddr(v)-1;
|
|
+#endif
|
|
}
|
|
|
|
/*
|
|
@@ -128629,38 +139125,164 @@ static void codeOffset(
|
|
}
|
|
|
|
/*
|
|
-** Add code that will check to make sure the N registers starting at iMem
|
|
-** form a distinct entry. iTab is a sorting index that holds previously
|
|
-** seen combinations of the N values. A new entry is made in iTab
|
|
-** if the current N values are new.
|
|
+** Add code that will check to make sure the array of registers starting at
|
|
+** iMem form a distinct entry. This is used by both "SELECT DISTINCT ..." and
|
|
+** distinct aggregates ("SELECT count(DISTINCT <expr>) ..."). Three strategies
|
|
+** are available. Which is used depends on the value of parameter eTnctType,
|
|
+** as follows:
|
|
**
|
|
-** A jump to addrRepeat is made and the N+1 values are popped from the
|
|
-** stack if the top N elements are not distinct.
|
|
-*/
|
|
-static void codeDistinct(
|
|
+** WHERE_DISTINCT_UNORDERED/WHERE_DISTINCT_NOOP:
|
|
+** Build an ephemeral table that contains all entries seen before and
|
|
+** skip entries which have been seen before.
|
|
+**
|
|
+** Parameter iTab is the cursor number of an ephemeral table that must
|
|
+** be opened before the VM code generated by this routine is executed.
|
|
+** The ephemeral cursor table is queried for a record identical to the
|
|
+** record formed by the current array of registers. If one is found,
|
|
+** jump to VM address addrRepeat. Otherwise, insert a new record into
|
|
+** the ephemeral cursor and proceed.
|
|
+**
|
|
+** 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
|
|
+** 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,
|
|
+** the VM program proceeds with processing the new row.
|
|
+**
|
|
+** The returned value in this case is the register number of the first
|
|
+** in an array of registers used to store the previous result row so that
|
|
+** it can be compared to the next. The caller must ensure that this
|
|
+** register is initialized to NULL. (The fixDistinctOpenEph() routine
|
|
+** will take care of this initialization.)
|
|
+**
|
|
+** WHERE_DISTINCT_UNIQUE:
|
|
+** In this case it has already been determined that the rows are distinct.
|
|
+** No special action is required. The return value is zero.
|
|
+**
|
|
+** Parameter pEList is the list of expressions used to generated the
|
|
+** contents of each row. It is used by this routine to determine (a)
|
|
+** how many elements there are in the array of registers and (b) the
|
|
+** collation sequences that should be used for the comparisons if
|
|
+** eTnctType is WHERE_DISTINCT_ORDERED.
|
|
+*/
|
|
+static int codeDistinct(
|
|
Parse *pParse, /* Parsing and code generating context */
|
|
+ int eTnctType, /* WHERE_DISTINCT_* value */
|
|
int iTab, /* A sorting index used to test for distinctness */
|
|
int addrRepeat, /* Jump to here if not distinct */
|
|
- int N, /* Number of elements */
|
|
- int iMem /* First element */
|
|
+ ExprList *pEList, /* Expression for each element */
|
|
+ int regElem /* First element */
|
|
){
|
|
- Vdbe *v;
|
|
- int r1;
|
|
+ int iRet = 0;
|
|
+ int nResultCol = pEList->nExpr;
|
|
+ Vdbe *v = pParse->pVdbe;
|
|
|
|
- v = pParse->pVdbe;
|
|
- r1 = sqlite3GetTempReg(pParse);
|
|
- sqlite3VdbeAddOp4Int(v, OP_Found, iTab, addrRepeat, iMem, N); VdbeCoverage(v);
|
|
- sqlite3VdbeAddOp3(v, OP_MakeRecord, iMem, N, r1);
|
|
- sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iTab, r1, iMem, N);
|
|
- sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
|
|
- sqlite3ReleaseTempReg(pParse, r1);
|
|
+ switch( eTnctType ){
|
|
+ case WHERE_DISTINCT_ORDERED: {
|
|
+ int i;
|
|
+ int iJump; /* Jump destination */
|
|
+ int regPrev; /* Previous row content */
|
|
+
|
|
+ /* Allocate space for the previous row */
|
|
+ iRet = regPrev = pParse->nMem+1;
|
|
+ pParse->nMem += nResultCol;
|
|
+
|
|
+ iJump = sqlite3VdbeCurrentAddr(v) + nResultCol;
|
|
+ for(i=0; i<nResultCol; i++){
|
|
+ CollSeq *pColl = sqlite3ExprCollSeq(pParse, pEList->a[i].pExpr);
|
|
+ if( i<nResultCol-1 ){
|
|
+ sqlite3VdbeAddOp3(v, OP_Ne, regElem+i, iJump, regPrev+i);
|
|
+ VdbeCoverage(v);
|
|
+ }else{
|
|
+ sqlite3VdbeAddOp3(v, OP_Eq, regElem+i, addrRepeat, regPrev+i);
|
|
+ VdbeCoverage(v);
|
|
+ }
|
|
+ sqlite3VdbeChangeP4(v, -1, (const char *)pColl, P4_COLLSEQ);
|
|
+ sqlite3VdbeChangeP5(v, SQLITE_NULLEQ);
|
|
+ }
|
|
+ assert( sqlite3VdbeCurrentAddr(v)==iJump || pParse->db->mallocFailed );
|
|
+ sqlite3VdbeAddOp3(v, OP_Copy, regElem, regPrev, nResultCol-1);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ case WHERE_DISTINCT_UNIQUE: {
|
|
+ /* nothing to do */
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ default: {
|
|
+ int r1 = sqlite3GetTempReg(pParse);
|
|
+ sqlite3VdbeAddOp4Int(v, OP_Found, iTab, addrRepeat, regElem, nResultCol);
|
|
+ VdbeCoverage(v);
|
|
+ sqlite3VdbeAddOp3(v, OP_MakeRecord, regElem, nResultCol, r1);
|
|
+ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iTab, r1, regElem, nResultCol);
|
|
+ sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
|
|
+ sqlite3ReleaseTempReg(pParse, r1);
|
|
+ iRet = iTab;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return iRet;
|
|
+}
|
|
+
|
|
+/*
|
|
+** This routine runs after codeDistinct(). It makes necessary
|
|
+** adjustments to the OP_OpenEphemeral opcode that the codeDistinct()
|
|
+** routine made use of. This processing must be done separately since
|
|
+** sometimes codeDistinct is called before the OP_OpenEphemeral is actually
|
|
+** laid down.
|
|
+**
|
|
+** WHERE_DISTINCT_NOOP:
|
|
+** WHERE_DISTINCT_UNORDERED:
|
|
+**
|
|
+** No adjustments necessary. This function is a no-op.
|
|
+**
|
|
+** WHERE_DISTINCT_UNIQUE:
|
|
+**
|
|
+** The ephemeral table is not needed. So change the
|
|
+** OP_OpenEphemeral opcode into an OP_Noop.
|
|
+**
|
|
+** WHERE_DISTINCT_ORDERED:
|
|
+**
|
|
+** The ephemeral table is not needed. But we do need register
|
|
+** iVal to be initialized to NULL. So change the OP_OpenEphemeral
|
|
+** into an OP_Null on the iVal register.
|
|
+*/
|
|
+static void fixDistinctOpenEph(
|
|
+ Parse *pParse, /* Parsing and code generating context */
|
|
+ int eTnctType, /* WHERE_DISTINCT_* value */
|
|
+ int iVal, /* Value returned by codeDistinct() */
|
|
+ int iOpenEphAddr /* Address of OP_OpenEphemeral instruction for iTab */
|
|
+){
|
|
+ if( pParse->nErr==0
|
|
+ && (eTnctType==WHERE_DISTINCT_UNIQUE || eTnctType==WHERE_DISTINCT_ORDERED)
|
|
+ ){
|
|
+ Vdbe *v = pParse->pVdbe;
|
|
+ sqlite3VdbeChangeToNoop(v, iOpenEphAddr);
|
|
+ if( sqlite3VdbeGetOp(v, iOpenEphAddr+1)->opcode==OP_Explain ){
|
|
+ sqlite3VdbeChangeToNoop(v, iOpenEphAddr+1);
|
|
+ }
|
|
+ if( eTnctType==WHERE_DISTINCT_ORDERED ){
|
|
+ /* Change the OP_OpenEphemeral to an OP_Null that sets the MEM_Cleared
|
|
+ ** bit on the first register of the previous value. This will cause the
|
|
+ ** OP_Ne added in codeDistinct() to always fail on the first iteration of
|
|
+ ** the loop even if the first row is all NULLs. */
|
|
+ VdbeOp *pOp = sqlite3VdbeGetOp(v, iOpenEphAddr);
|
|
+ pOp->opcode = OP_Null;
|
|
+ pOp->p1 = 1;
|
|
+ pOp->p2 = iVal;
|
|
+ }
|
|
+ }
|
|
}
|
|
|
|
#ifdef SQLITE_ENABLE_SORTER_REFERENCES
|
|
/*
|
|
** This function is called as part of inner-loop generation for a SELECT
|
|
-** statement with an ORDER BY that is not optimized by an index. It
|
|
-** determines the expressions, if any, that the sorter-reference
|
|
+** statement with an ORDER BY that is not optimized by an index. It
|
|
+** determines the expressions, if any, that the sorter-reference
|
|
** optimization should be used for. The sorter-reference optimization
|
|
** is used for SELECT queries like:
|
|
**
|
|
@@ -128670,11 +139292,11 @@ static void codeDistinct(
|
|
** storing values read from that column in the sorter records, the PK of
|
|
** the row from table t1 is stored instead. Then, as records are extracted from
|
|
** the sorter to return to the user, the required value of bigblob is
|
|
-** retrieved directly from table t1. If the values are very large, this
|
|
+** retrieved directly from table t1. If the values are very large, this
|
|
** can be more efficient than storing them directly in the sorter records.
|
|
**
|
|
-** The ExprList_item.bSorterRef flag is set for each expression in pEList
|
|
-** for which the sorter-reference optimization should be enabled.
|
|
+** The ExprList_item.fg.bSorterRef flag is set for each expression in pEList
|
|
+** for which the sorter-reference optimization should be enabled.
|
|
** Additionally, the pSort->aDefer[] array is populated with entries
|
|
** for all cursors required to evaluate all selected expressions. Finally.
|
|
** output variable (*ppExtra) is set to an expression list containing
|
|
@@ -128694,9 +139316,13 @@ static void selectExprDefer(
|
|
struct ExprList_item *pItem = &pEList->a[i];
|
|
if( pItem->u.x.iOrderByCol==0 ){
|
|
Expr *pExpr = pItem->pExpr;
|
|
- Table *pTab = pExpr->y.pTab;
|
|
- if( pExpr->op==TK_COLUMN && pExpr->iColumn>=0 && pTab && !IsVirtual(pTab)
|
|
- && (pTab->aCol[pExpr->iColumn].colFlags & COLFLAG_SORTERREF)
|
|
+ Table *pTab;
|
|
+ if( pExpr->op==TK_COLUMN
|
|
+ && pExpr->iColumn>=0
|
|
+ && ALWAYS( ExprUseYTab(pExpr) )
|
|
+ && (pTab = pExpr->y.pTab)!=0
|
|
+ && IsOrdinaryTable(pTab)
|
|
+ && (pTab->aCol[pExpr->iColumn].colFlags & COLFLAG_SORTERREF)!=0
|
|
){
|
|
int j;
|
|
for(j=0; j<nDefer; j++){
|
|
@@ -128717,6 +139343,7 @@ static void selectExprDefer(
|
|
Expr *pNew = sqlite3PExpr(pParse, TK_COLUMN, 0, 0);
|
|
if( pNew ){
|
|
pNew->iTable = pExpr->iTable;
|
|
+ assert( ExprUseYTab(pNew) );
|
|
pNew->y.pTab = pExpr->y.pTab;
|
|
pNew->iColumn = pPk ? pPk->aiColumn[k] : -1;
|
|
pExtra = sqlite3ExprListAppend(pParse, pExtra, pNew);
|
|
@@ -128728,7 +139355,7 @@ static void selectExprDefer(
|
|
nDefer++;
|
|
}
|
|
}
|
|
- pItem->bSorterRef = 1;
|
|
+ pItem->fg.bSorterRef = 1;
|
|
}
|
|
}
|
|
}
|
|
@@ -128743,7 +139370,7 @@ static void selectExprDefer(
|
|
**
|
|
** If srcTab is negative, then the p->pEList expressions
|
|
** are evaluated in order to get the data for this row. If srcTab is
|
|
-** zero or more, then data is pulled from srcTab and p->pEList is used only
|
|
+** zero or more, then data is pulled from srcTab and p->pEList is used only
|
|
** to get the number of columns and the collation sequence for each column.
|
|
*/
|
|
static void selectInnerLoop(
|
|
@@ -128825,8 +139452,8 @@ static void selectInnerLoop(
|
|
}
|
|
if( pSort && hasDistinct==0 && eDest!=SRT_EphemTab && eDest!=SRT_Table ){
|
|
/* For each expression in p->pEList that is a copy of an expression in
|
|
- ** the ORDER BY clause (pSort->pOrderBy), set the associated
|
|
- ** iOrderByCol value to one more than the index of the ORDER BY
|
|
+ ** the ORDER BY clause (pSort->pOrderBy), set the associated
|
|
+ ** iOrderByCol value to one more than the index of the ORDER BY
|
|
** expression within the sort-key that pushOntoSorter() will generate.
|
|
** This allows the p->pEList field to be omitted from the sorted record,
|
|
** saving space and CPU cycles. */
|
|
@@ -128842,7 +139469,7 @@ static void selectInnerLoop(
|
|
selectExprDefer(pParse, pSort, p->pEList, &pExtra);
|
|
if( pExtra && pParse->db->mallocFailed==0 ){
|
|
/* If there are any extra PK columns to add to the sorter records,
|
|
- ** allocate extra memory cells and adjust the OpenEphemeral
|
|
+ ** allocate extra memory cells and adjust the OpenEphemeral
|
|
** instruction to account for the larger records. This is only
|
|
** required if there are one or more WITHOUT ROWID tables with
|
|
** composite primary keys in the SortCtx.aDefer[] array. */
|
|
@@ -128859,7 +139486,7 @@ static void selectInnerLoop(
|
|
for(i=0; i<pEList->nExpr; i++){
|
|
if( pEList->a[i].u.x.iOrderByCol>0
|
|
#ifdef SQLITE_ENABLE_SORTER_REFERENCES
|
|
- || pEList->a[i].bSorterRef
|
|
+ || pEList->a[i].fg.bSorterRef
|
|
#endif
|
|
){
|
|
nResultCol--;
|
|
@@ -128872,8 +139499,9 @@ static void selectInnerLoop(
|
|
testcase( eDest==SRT_Mem );
|
|
testcase( eDest==SRT_Coroutine );
|
|
testcase( eDest==SRT_Output );
|
|
- assert( eDest==SRT_Set || eDest==SRT_Mem
|
|
- || eDest==SRT_Coroutine || eDest==SRT_Output );
|
|
+ assert( eDest==SRT_Set || eDest==SRT_Mem
|
|
+ || eDest==SRT_Coroutine || eDest==SRT_Output
|
|
+ || eDest==SRT_Upfrom );
|
|
}
|
|
sRowLoadInfo.regResult = regResult;
|
|
sRowLoadInfo.ecelFlags = ecelFlags;
|
|
@@ -128883,7 +139511,7 @@ static void selectInnerLoop(
|
|
if( pExtra ) nResultCol += pExtra->nExpr;
|
|
#endif
|
|
if( p->iLimit
|
|
- && (ecelFlags & SQLITE_ECEL_OMITREF)!=0
|
|
+ && (ecelFlags & SQLITE_ECEL_OMITREF)!=0
|
|
&& nPrefixReg>0
|
|
){
|
|
assert( pSort!=0 );
|
|
@@ -128900,59 +139528,11 @@ static void selectInnerLoop(
|
|
** part of the result.
|
|
*/
|
|
if( hasDistinct ){
|
|
- switch( pDistinct->eTnctType ){
|
|
- case WHERE_DISTINCT_ORDERED: {
|
|
- VdbeOp *pOp; /* No longer required OpenEphemeral instr. */
|
|
- int iJump; /* Jump destination */
|
|
- int regPrev; /* Previous row content */
|
|
-
|
|
- /* Allocate space for the previous row */
|
|
- regPrev = pParse->nMem+1;
|
|
- pParse->nMem += nResultCol;
|
|
-
|
|
- /* Change the OP_OpenEphemeral coded earlier to an OP_Null
|
|
- ** sets the MEM_Cleared bit on the first register of the
|
|
- ** previous value. This will cause the OP_Ne below to always
|
|
- ** fail on the first iteration of the loop even if the first
|
|
- ** row is all NULLs.
|
|
- */
|
|
- sqlite3VdbeChangeToNoop(v, pDistinct->addrTnct);
|
|
- pOp = sqlite3VdbeGetOp(v, pDistinct->addrTnct);
|
|
- pOp->opcode = OP_Null;
|
|
- pOp->p1 = 1;
|
|
- pOp->p2 = regPrev;
|
|
- pOp = 0; /* Ensure pOp is not used after sqlite3VdbeAddOp() */
|
|
-
|
|
- iJump = sqlite3VdbeCurrentAddr(v) + nResultCol;
|
|
- for(i=0; i<nResultCol; i++){
|
|
- CollSeq *pColl = sqlite3ExprCollSeq(pParse, p->pEList->a[i].pExpr);
|
|
- if( i<nResultCol-1 ){
|
|
- sqlite3VdbeAddOp3(v, OP_Ne, regResult+i, iJump, regPrev+i);
|
|
- VdbeCoverage(v);
|
|
- }else{
|
|
- sqlite3VdbeAddOp3(v, OP_Eq, regResult+i, iContinue, regPrev+i);
|
|
- VdbeCoverage(v);
|
|
- }
|
|
- sqlite3VdbeChangeP4(v, -1, (const char *)pColl, P4_COLLSEQ);
|
|
- sqlite3VdbeChangeP5(v, SQLITE_NULLEQ);
|
|
- }
|
|
- assert( sqlite3VdbeCurrentAddr(v)==iJump || pParse->db->mallocFailed );
|
|
- sqlite3VdbeAddOp3(v, OP_Copy, regResult, regPrev, nResultCol-1);
|
|
- break;
|
|
- }
|
|
-
|
|
- case WHERE_DISTINCT_UNIQUE: {
|
|
- sqlite3VdbeChangeToNoop(v, pDistinct->addrTnct);
|
|
- break;
|
|
- }
|
|
-
|
|
- default: {
|
|
- assert( pDistinct->eTnctType==WHERE_DISTINCT_UNORDERED );
|
|
- codeDistinct(pParse, pDistinct->tabTnct, iContinue, nResultCol,
|
|
- regResult);
|
|
- break;
|
|
- }
|
|
- }
|
|
+ int eType = pDistinct->eTnctType;
|
|
+ int iTab = pDistinct->tabTnct;
|
|
+ assert( nResultCol==p->pEList->nExpr );
|
|
+ iTab = codeDistinct(pParse, eType, iTab, iContinue, p->pEList, regResult);
|
|
+ fixDistinctOpenEph(pParse, eType, iTab, pDistinct->addrTnct);
|
|
if( pSort==0 ){
|
|
codeOffset(v, p->iOffset, iContinue);
|
|
}
|
|
@@ -129022,6 +139602,30 @@ static void selectInnerLoop(
|
|
break;
|
|
}
|
|
|
|
+ case SRT_Upfrom: {
|
|
+ if( pSort ){
|
|
+ pushOntoSorter(
|
|
+ pParse, pSort, p, regResult, regOrig, nResultCol, nPrefixReg);
|
|
+ }else{
|
|
+ int i2 = pDest->iSDParm2;
|
|
+ int r1 = sqlite3GetTempReg(pParse);
|
|
+
|
|
+ /* If the UPDATE FROM join is an aggregate that matches no rows, it
|
|
+ ** might still be trying to return one row, because that is what
|
|
+ ** aggregates do. Don't record that empty row in the output table. */
|
|
+ sqlite3VdbeAddOp2(v, OP_IsNull, regResult, iBreak); VdbeCoverage(v);
|
|
+
|
|
+ sqlite3VdbeAddOp3(v, OP_MakeRecord,
|
|
+ regResult+(i2<0), nResultCol-(i2<0), r1);
|
|
+ if( i2<0 ){
|
|
+ sqlite3VdbeAddOp3(v, OP_Insert, iParm, r1, regResult);
|
|
+ }else{
|
|
+ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regResult, i2);
|
|
+ }
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+
|
|
#ifndef SQLITE_OMIT_SUBQUERY
|
|
/* If we are creating a set for an "expr IN (SELECT ...)" construct,
|
|
** then there should be a single item on the stack. Write this
|
|
@@ -129038,7 +139642,7 @@ static void selectInnerLoop(
|
|
}else{
|
|
int r1 = sqlite3GetTempReg(pParse);
|
|
assert( sqlite3Strlen30(pDest->zAffSdst)==nResultCol );
|
|
- sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult, nResultCol,
|
|
+ sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult, nResultCol,
|
|
r1, pDest->zAffSdst, nResultCol);
|
|
sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regResult, nResultCol);
|
|
sqlite3ReleaseTempReg(pParse, r1);
|
|
@@ -129046,6 +139650,7 @@ static void selectInnerLoop(
|
|
break;
|
|
}
|
|
|
|
+
|
|
/* If any row exist in the result set, record that fact and abort.
|
|
*/
|
|
case SRT_Exists: {
|
|
@@ -129055,7 +139660,7 @@ static void selectInnerLoop(
|
|
}
|
|
|
|
/* If this is a scalar select that is part of an expression, then
|
|
- ** store the results in the appropriate memory cell or array of
|
|
+ ** store the results in the appropriate memory cell or array of
|
|
** memory cells and break out of the scan loop.
|
|
*/
|
|
case SRT_Mem: {
|
|
@@ -129110,7 +139715,7 @@ static void selectInnerLoop(
|
|
/* If the destination is DistQueue, then cursor (iParm+1) is open
|
|
** on a second ephemeral index that holds all values every previously
|
|
** added to the queue. */
|
|
- addrTest = sqlite3VdbeAddOp4Int(v, OP_Found, iParm+1, 0,
|
|
+ addrTest = sqlite3VdbeAddOp4Int(v, OP_Found, iParm+1, 0,
|
|
regResult, nResultCol);
|
|
VdbeCoverage(v);
|
|
}
|
|
@@ -129174,7 +139779,7 @@ SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){
|
|
p->nRef = 1;
|
|
memset(&p[1], 0, nExtra);
|
|
}else{
|
|
- sqlite3OomFault(db);
|
|
+ return (KeyInfo*)sqlite3OomFault(db);
|
|
}
|
|
return p;
|
|
}
|
|
@@ -129184,9 +139789,10 @@ SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3KeyInfoUnref(KeyInfo *p){
|
|
if( p ){
|
|
+ assert( p->db!=0 );
|
|
assert( p->nRef>0 );
|
|
p->nRef--;
|
|
- if( p->nRef==0 ) sqlite3DbFreeNN(p->db, p);
|
|
+ if( p->nRef==0 ) sqlite3DbNNFreeNN(p->db, p);
|
|
}
|
|
}
|
|
|
|
@@ -129243,7 +139849,7 @@ SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoFromExprList(
|
|
assert( sqlite3KeyInfoIsWriteable(pInfo) );
|
|
for(i=iStart, pItem=pList->a+iStart; i<nExpr; i++, pItem++){
|
|
pInfo->aColl[i-iStart] = sqlite3ExprNNCollSeq(pParse, pItem->pExpr);
|
|
- pInfo->aSortFlags[i-iStart] = pItem->sortFlags;
|
|
+ pInfo->aSortFlags[i-iStart] = pItem->fg.sortFlags;
|
|
}
|
|
}
|
|
return pInfo;
|
|
@@ -129252,7 +139858,7 @@ SQLITE_PRIVATE KeyInfo *sqlite3KeyInfoFromExprList(
|
|
/*
|
|
** Name of the connection operator, used for error messages.
|
|
*/
|
|
-static const char *selectOpName(int id){
|
|
+SQLITE_PRIVATE const char *sqlite3SelectOpName(int id){
|
|
char *z;
|
|
switch( id ){
|
|
case TK_ALL: z = "UNION ALL"; break;
|
|
@@ -129325,6 +139931,16 @@ static void generateSortTail(
|
|
int bSeq; /* True if sorter record includes seq. no. */
|
|
int nRefKey = 0;
|
|
struct ExprList_item *aOutEx = p->pEList->a;
|
|
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
|
|
+ int addrExplain; /* Address of OP_Explain instruction */
|
|
+#endif
|
|
+
|
|
+ ExplainQueryPlan2(addrExplain, (pParse, 0,
|
|
+ "USE TEMP B-TREE FOR %sORDER BY", pSort->nOBSat>0?"RIGHT PART OF ":"")
|
|
+ );
|
|
+ sqlite3VdbeScanStatusRange(v, addrExplain,pSort->addrPush,pSort->addrPushEnd);
|
|
+ sqlite3VdbeScanStatusCounters(v, addrExplain, addrExplain, pSort->addrPush);
|
|
+
|
|
|
|
assert( addrBreak<0 );
|
|
if( pSort->labelBkOut ){
|
|
@@ -129345,6 +139961,9 @@ static void generateSortTail(
|
|
|
|
iTab = pSort->iECursor;
|
|
if( eDest==SRT_Output || eDest==SRT_Coroutine || eDest==SRT_Mem ){
|
|
+ if( eDest==SRT_Mem && p->iOffset ){
|
|
+ sqlite3VdbeAddOp2(v, OP_Null, 0, pDest->iSdst);
|
|
+ }
|
|
regRowid = 0;
|
|
regRow = pDest->iSdst;
|
|
}else{
|
|
@@ -129363,12 +139982,12 @@ static void generateSortTail(
|
|
if( pSort->labelBkOut ){
|
|
addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
|
|
}
|
|
- sqlite3VdbeAddOp3(v, OP_OpenPseudo, iSortTab, regSortOut,
|
|
+ sqlite3VdbeAddOp3(v, OP_OpenPseudo, iSortTab, regSortOut,
|
|
nKey+1+nColumn+nRefKey);
|
|
if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce);
|
|
addr = 1 + sqlite3VdbeAddOp2(v, OP_SorterSort, iTab, addrBreak);
|
|
VdbeCoverage(v);
|
|
- codeOffset(v, p->iOffset, addrContinue);
|
|
+ assert( p->iLimit==0 && p->iOffset==0 );
|
|
sqlite3VdbeAddOp3(v, OP_SorterData, iTab, regSortOut, iSortTab);
|
|
bSeq = 0;
|
|
}else{
|
|
@@ -129376,10 +139995,13 @@ static void generateSortTail(
|
|
codeOffset(v, p->iOffset, addrContinue);
|
|
iSortTab = iTab;
|
|
bSeq = 1;
|
|
+ if( p->iOffset>0 ){
|
|
+ sqlite3VdbeAddOp2(v, OP_AddImm, p->iLimit, -1);
|
|
+ }
|
|
}
|
|
for(i=0, iCol=nKey+bSeq-1; i<nColumn; i++){
|
|
#ifdef SQLITE_ENABLE_SORTER_REFERENCES
|
|
- if( aOutEx[i].bSorterRef ) continue;
|
|
+ if( aOutEx[i].fg.bSorterRef ) continue;
|
|
#endif
|
|
if( aOutEx[i].u.x.iOrderByCol==0 ) iCol++;
|
|
}
|
|
@@ -129396,7 +140018,7 @@ static void generateSortTail(
|
|
sqlite3VdbeAddOp1(v, OP_NullRow, iCsr);
|
|
if( HasRowid(pTab) ){
|
|
sqlite3VdbeAddOp3(v, OP_Column, iSortTab, iKey++, regKey);
|
|
- sqlite3VdbeAddOp3(v, OP_SeekRowid, iCsr,
|
|
+ sqlite3VdbeAddOp3(v, OP_SeekRowid, iCsr,
|
|
sqlite3VdbeCurrentAddr(v)+1, regKey);
|
|
}else{
|
|
int k;
|
|
@@ -129416,7 +140038,7 @@ static void generateSortTail(
|
|
#endif
|
|
for(i=nColumn-1; i>=0; i--){
|
|
#ifdef SQLITE_ENABLE_SORTER_REFERENCES
|
|
- if( aOutEx[i].bSorterRef ){
|
|
+ if( aOutEx[i].fg.bSorterRef ){
|
|
sqlite3ExprCode(pParse, aOutEx[i].pExpr, regRow+i);
|
|
}else
|
|
#endif
|
|
@@ -129431,6 +140053,7 @@ static void generateSortTail(
|
|
VdbeComment((v, "%s", aOutEx[i].zEName));
|
|
}
|
|
}
|
|
+ sqlite3VdbeScanStatusRange(v, addrExplain, addrExplain, -1);
|
|
switch( eDest ){
|
|
case SRT_Table:
|
|
case SRT_EphemTab: {
|
|
@@ -129453,8 +140076,19 @@ static void generateSortTail(
|
|
break;
|
|
}
|
|
#endif
|
|
+ case SRT_Upfrom: {
|
|
+ int i2 = pDest->iSDParm2;
|
|
+ int r1 = sqlite3GetTempReg(pParse);
|
|
+ sqlite3VdbeAddOp3(v, OP_MakeRecord,regRow+(i2<0),nColumn-(i2<0),r1);
|
|
+ if( i2<0 ){
|
|
+ sqlite3VdbeAddOp3(v, OP_Insert, iParm, r1, regRow);
|
|
+ }else{
|
|
+ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iParm, r1, regRow, i2);
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
default: {
|
|
- assert( eDest==SRT_Output || eDest==SRT_Coroutine );
|
|
+ assert( eDest==SRT_Output || eDest==SRT_Coroutine );
|
|
testcase( eDest==SRT_Output );
|
|
testcase( eDest==SRT_Coroutine );
|
|
if( eDest==SRT_Output ){
|
|
@@ -129481,6 +140115,7 @@ static void generateSortTail(
|
|
}else{
|
|
sqlite3VdbeAddOp2(v, OP_Next, iTab, addr); VdbeCoverage(v);
|
|
}
|
|
+ sqlite3VdbeScanStatusRange(v, addrExplain, sqlite3VdbeCurrentAddr(v)-1, -1);
|
|
if( pSort->regReturn ) sqlite3VdbeAddOp1(v, OP_Return, pSort->regReturn);
|
|
sqlite3VdbeResolveLabel(v, addrBreak);
|
|
}
|
|
@@ -129489,21 +140124,18 @@ static void generateSortTail(
|
|
** Return a pointer to a string containing the 'declaration type' of the
|
|
** expression pExpr. The string may be treated as static by the caller.
|
|
**
|
|
-** Also try to estimate the size of the returned value and return that
|
|
-** result in *pEstWidth.
|
|
-**
|
|
** The declaration type is the exact datatype definition extracted from the
|
|
** original CREATE TABLE statement if the expression is a column. The
|
|
** declaration type for a ROWID field is INTEGER. Exactly when an expression
|
|
** is considered a column can be complex in the presence of subqueries. The
|
|
-** result-set expression in all of the following SELECT statements is
|
|
+** result-set expression in all of the following SELECT statements is
|
|
** considered a column by this function.
|
|
**
|
|
** SELECT col FROM tbl;
|
|
** SELECT (SELECT col FROM tbl;
|
|
** SELECT (SELECT col FROM tbl);
|
|
** SELECT abc FROM (SELECT col AS abc FROM tbl);
|
|
-**
|
|
+**
|
|
** The declaration type for any expression other than a column is NULL.
|
|
**
|
|
** This routine has either 3 or 6 parameters depending on whether or not
|
|
@@ -129515,7 +140147,7 @@ static void generateSortTail(
|
|
# define columnType(A,B,C,D,E) columnTypeImpl(A,B)
|
|
#endif
|
|
static const char *columnTypeImpl(
|
|
- NameContext *pNC,
|
|
+ NameContext *pNC,
|
|
#ifndef SQLITE_ENABLE_COLUMN_METADATA
|
|
Expr *pExpr
|
|
#else
|
|
@@ -129558,33 +140190,39 @@ static const char *columnTypeImpl(
|
|
if( pTab==0 ){
|
|
/* At one time, code such as "SELECT new.x" within a trigger would
|
|
** cause this condition to run. Since then, we have restructured how
|
|
- ** trigger code is generated and so this condition is no longer
|
|
+ ** trigger code is generated and so this condition is no longer
|
|
** possible. However, it can still be true for statements like
|
|
** the following:
|
|
**
|
|
** CREATE TABLE t1(col INTEGER);
|
|
** SELECT (SELECT t1.col) FROM FROM t1;
|
|
**
|
|
- ** when columnType() is called on the expression "t1.col" in the
|
|
+ ** when columnType() is called on the expression "t1.col" in the
|
|
** sub-select. In this case, set the column type to NULL, even
|
|
** though it should really be "INTEGER".
|
|
**
|
|
** This is not a problem, as the column type of "t1.col" is never
|
|
- ** used. When columnType() is called on the expression
|
|
+ ** used. When columnType() is called on the expression
|
|
** "(SELECT t1.col)", the correct type is returned (see the TK_SELECT
|
|
** branch below. */
|
|
break;
|
|
}
|
|
|
|
- assert( pTab && pExpr->y.pTab==pTab );
|
|
+ assert( pTab && ExprUseYTab(pExpr) && pExpr->y.pTab==pTab );
|
|
if( pS ){
|
|
/* The "table" is actually a sub-select or a view in the FROM clause
|
|
** of the SELECT statement. Return the declaration type and origin
|
|
** data for the result-set column of the sub-select.
|
|
*/
|
|
- if( iCol>=0 && iCol<pS->pEList->nExpr ){
|
|
+ if( iCol<pS->pEList->nExpr
|
|
+#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
|
|
+ && iCol>=0
|
|
+#else
|
|
+ && ALWAYS(iCol>=0)
|
|
+#endif
|
|
+ ){
|
|
/* If iCol is less than zero, then the expression requests the
|
|
- ** rowid of the sub-select or view. This expression is legal (see
|
|
+ ** rowid of the sub-select or view. This expression is legal (see
|
|
** test case misc2.2.2) - it always evaluates to NULL.
|
|
*/
|
|
NameContext sNC;
|
|
@@ -129592,7 +140230,7 @@ static const char *columnTypeImpl(
|
|
sNC.pSrcList = pS->pSrc;
|
|
sNC.pNext = pNC;
|
|
sNC.pParse = pNC->pParse;
|
|
- zType = columnType(&sNC, p,&zOrigDb,&zOrigTab,&zOrigCol);
|
|
+ zType = columnType(&sNC, p,&zOrigDb,&zOrigTab,&zOrigCol);
|
|
}
|
|
}else{
|
|
/* A real table or a CTE table */
|
|
@@ -129604,7 +140242,7 @@ static const char *columnTypeImpl(
|
|
zType = "INTEGER";
|
|
zOrigCol = "rowid";
|
|
}else{
|
|
- zOrigCol = pTab->aCol[iCol].zName;
|
|
+ zOrigCol = pTab->aCol[iCol].zCnName;
|
|
zType = sqlite3ColumnType(&pTab->aCol[iCol],0);
|
|
}
|
|
zOrigTab = pTab->zName;
|
|
@@ -129630,19 +140268,21 @@ static const char *columnTypeImpl(
|
|
** statement.
|
|
*/
|
|
NameContext sNC;
|
|
- Select *pS = pExpr->x.pSelect;
|
|
- Expr *p = pS->pEList->a[0].pExpr;
|
|
- assert( ExprHasProperty(pExpr, EP_xIsSelect) );
|
|
+ Select *pS;
|
|
+ Expr *p;
|
|
+ assert( ExprUseXSelect(pExpr) );
|
|
+ pS = pExpr->x.pSelect;
|
|
+ p = pS->pEList->a[0].pExpr;
|
|
sNC.pSrcList = pS->pSrc;
|
|
sNC.pNext = pNC;
|
|
sNC.pParse = pNC->pParse;
|
|
- zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol);
|
|
+ zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol);
|
|
break;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
-#ifdef SQLITE_ENABLE_COLUMN_METADATA
|
|
+#ifdef SQLITE_ENABLE_COLUMN_METADATA
|
|
if( pzOrigDb ){
|
|
assert( pzOrigTab && pzOrigCol );
|
|
*pzOrigDb = zOrigDb;
|
|
@@ -129678,7 +140318,7 @@ static void generateColumnTypes(
|
|
const char *zOrigCol = 0;
|
|
zType = columnType(&sNC, p, &zOrigDb, &zOrigTab, &zOrigCol);
|
|
|
|
- /* The vdbe must make its own copy of the column-type and other
|
|
+ /* The vdbe must make its own copy of the column-type and other
|
|
** column specific strings, in case the schema is reset before this
|
|
** virtual machine is deleted.
|
|
*/
|
|
@@ -129724,7 +140364,7 @@ static void generateColumnTypes(
|
|
** then the result column name with the table name
|
|
** prefix, ex: TABLE.COLUMN. Otherwise use zSpan.
|
|
*/
|
|
-static void generateColumnNames(
|
|
+SQLITE_PRIVATE void sqlite3GenerateColumnNames(
|
|
Parse *pParse, /* Parser context */
|
|
Select *pSelect /* Generate column names for this SELECT statement */
|
|
){
|
|
@@ -129747,7 +140387,7 @@ static void generateColumnNames(
|
|
if( pParse->colNamesSet ) return;
|
|
/* Column names are determined by the left-most term of a compound select */
|
|
while( pSelect->pPrior ) pSelect = pSelect->pPrior;
|
|
- SELECTTRACE(1,pParse,pSelect,("generating column names\n"));
|
|
+ TREETRACE(0x80,pParse,pSelect,("generating column names\n"));
|
|
pTabList = pSelect->pSrc;
|
|
pEList = pSelect->pEList;
|
|
assert( v!=0 );
|
|
@@ -129761,8 +140401,9 @@ static void generateColumnNames(
|
|
|
|
assert( p!=0 );
|
|
assert( p->op!=TK_AGG_COLUMN ); /* Agg processing has not run yet */
|
|
- assert( p->op!=TK_COLUMN || p->y.pTab!=0 ); /* Covering idx not yet coded */
|
|
- if( pEList->a[i].zEName && pEList->a[i].eEName==ENAME_NAME ){
|
|
+ assert( p->op!=TK_COLUMN
|
|
+ || (ExprUseYTab(p) && p->y.pTab!=0) ); /* Covering idx not yet coded */
|
|
+ if( pEList->a[i].zEName && pEList->a[i].fg.eEName==ENAME_NAME ){
|
|
/* An AS clause always takes first priority */
|
|
char *zName = pEList->a[i].zEName;
|
|
sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, SQLITE_TRANSIENT);
|
|
@@ -129776,7 +140417,7 @@ static void generateColumnNames(
|
|
if( iCol<0 ){
|
|
zCol = "rowid";
|
|
}else{
|
|
- zCol = pTab->aCol[iCol].zName;
|
|
+ zCol = pTab->aCol[iCol].zCnName;
|
|
}
|
|
if( fullName ){
|
|
char *zName = 0;
|
|
@@ -129814,7 +140455,7 @@ static void generateColumnNames(
|
|
** and will break if those assumptions changes. Hence, use extreme caution
|
|
** when modifying this routine to avoid breaking legacy.
|
|
**
|
|
-** See Also: generateColumnNames()
|
|
+** See Also: sqlite3GenerateColumnNames()
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3ColumnsFromExprList(
|
|
Parse *pParse, /* Parsing context */
|
|
@@ -129830,13 +140471,14 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList(
|
|
char *zName; /* Column name */
|
|
int nName; /* Size of name in zName[] */
|
|
Hash ht; /* Hash table of column names */
|
|
+ Table *pTab;
|
|
|
|
sqlite3HashInit(&ht);
|
|
if( pEList ){
|
|
nCol = pEList->nExpr;
|
|
aCol = sqlite3DbMallocZero(db, sizeof(aCol[0])*nCol);
|
|
testcase( aCol==0 );
|
|
- if( nCol>32767 ) nCol = 32767;
|
|
+ if( NEVER(nCol>32767) ) nCol = 32767;
|
|
}else{
|
|
nCol = 0;
|
|
aCol = 0;
|
|
@@ -129845,30 +140487,34 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList(
|
|
*pnCol = nCol;
|
|
*paCol = aCol;
|
|
|
|
- for(i=0, pCol=aCol; i<nCol && !db->mallocFailed; i++, pCol++){
|
|
+ for(i=0, pCol=aCol; i<nCol && !pParse->nErr; i++, pCol++){
|
|
+ struct ExprList_item *pX = &pEList->a[i];
|
|
+ struct ExprList_item *pCollide;
|
|
/* Get an appropriate name for the column
|
|
*/
|
|
- if( (zName = pEList->a[i].zEName)!=0 && pEList->a[i].eEName==ENAME_NAME ){
|
|
+ if( (zName = pX->zEName)!=0 && pX->fg.eEName==ENAME_NAME ){
|
|
/* If the column contains an "AS <name>" phrase, use <name> as the name */
|
|
}else{
|
|
- Expr *pColExpr = sqlite3ExprSkipCollateAndLikely(pEList->a[i].pExpr);
|
|
- while( pColExpr->op==TK_DOT ){
|
|
+ Expr *pColExpr = sqlite3ExprSkipCollateAndLikely(pX->pExpr);
|
|
+ while( ALWAYS(pColExpr!=0) && pColExpr->op==TK_DOT ){
|
|
pColExpr = pColExpr->pRight;
|
|
assert( pColExpr!=0 );
|
|
}
|
|
- if( pColExpr->op==TK_COLUMN ){
|
|
+ if( pColExpr->op==TK_COLUMN
|
|
+ && ALWAYS( ExprUseYTab(pColExpr) )
|
|
+ && ALWAYS( pColExpr->y.pTab!=0 )
|
|
+ ){
|
|
/* For columns use the column name name */
|
|
int iCol = pColExpr->iColumn;
|
|
- Table *pTab = pColExpr->y.pTab;
|
|
- assert( pTab!=0 );
|
|
+ pTab = pColExpr->y.pTab;
|
|
if( iCol<0 ) iCol = pTab->iPKey;
|
|
- zName = iCol>=0 ? pTab->aCol[iCol].zName : "rowid";
|
|
+ zName = iCol>=0 ? pTab->aCol[iCol].zCnName : "rowid";
|
|
}else if( pColExpr->op==TK_ID ){
|
|
assert( !ExprHasProperty(pColExpr, EP_IntValue) );
|
|
zName = pColExpr->u.zToken;
|
|
}else{
|
|
/* Use the original text of the column expression as its name */
|
|
- zName = pEList->a[i].zEName;
|
|
+ assert( zName==pX->zEName ); /* pointer comparison intended */
|
|
}
|
|
}
|
|
if( zName && !sqlite3IsTrueOrFalse(zName) ){
|
|
@@ -129881,86 +140527,136 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList(
|
|
** append an integer to the name so that it becomes unique.
|
|
*/
|
|
cnt = 0;
|
|
- while( zName && sqlite3HashFind(&ht, zName)!=0 ){
|
|
+ while( zName && (pCollide = sqlite3HashFind(&ht, zName))!=0 ){
|
|
+ if( pCollide->fg.bUsingTerm ){
|
|
+ pCol->colFlags |= COLFLAG_NOEXPAND;
|
|
+ }
|
|
nName = sqlite3Strlen30(zName);
|
|
if( nName>0 ){
|
|
for(j=nName-1; j>0 && sqlite3Isdigit(zName[j]); j--){}
|
|
if( zName[j]==':' ) nName = j;
|
|
}
|
|
zName = sqlite3MPrintf(db, "%.*z:%u", nName, zName, ++cnt);
|
|
- if( cnt>3 ) sqlite3_randomness(sizeof(cnt), &cnt);
|
|
+ sqlite3ProgressCheck(pParse);
|
|
+ if( cnt>3 ){
|
|
+ sqlite3_randomness(sizeof(cnt), &cnt);
|
|
+ }
|
|
+ }
|
|
+ pCol->zCnName = zName;
|
|
+ pCol->hName = sqlite3StrIHash(zName);
|
|
+ if( pX->fg.bNoExpand ){
|
|
+ pCol->colFlags |= COLFLAG_NOEXPAND;
|
|
}
|
|
- pCol->zName = zName;
|
|
sqlite3ColumnPropertiesFromName(0, pCol);
|
|
- if( zName && sqlite3HashInsert(&ht, zName, pCol)==pCol ){
|
|
+ if( zName && sqlite3HashInsert(&ht, zName, pX)==pX ){
|
|
sqlite3OomFault(db);
|
|
}
|
|
}
|
|
sqlite3HashClear(&ht);
|
|
- if( db->mallocFailed ){
|
|
+ if( pParse->nErr ){
|
|
for(j=0; j<i; j++){
|
|
- sqlite3DbFree(db, aCol[j].zName);
|
|
+ sqlite3DbFree(db, aCol[j].zCnName);
|
|
}
|
|
sqlite3DbFree(db, aCol);
|
|
*paCol = 0;
|
|
*pnCol = 0;
|
|
- return SQLITE_NOMEM_BKPT;
|
|
+ return pParse->rc;
|
|
}
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
/*
|
|
-** Add type and collation information to a column list based on
|
|
-** a SELECT statement.
|
|
-**
|
|
-** The column list presumably came from selectColumnNamesFromExprList().
|
|
-** The column list has only names, not types or collations. This
|
|
-** routine goes through and adds the types and collations.
|
|
+** pTab is a transient Table object that represents a subquery of some
|
|
+** kind (maybe a parenthesized subquery in the FROM clause of a larger
|
|
+** query, or a VIEW, or a CTE). This routine computes type information
|
|
+** for that Table object based on the Select object that implements the
|
|
+** subquery. For the purposes of this routine, "type infomation" means:
|
|
**
|
|
-** This routine requires that all identifiers in the SELECT
|
|
-** statement be resolved.
|
|
+** * The datatype name, as it might appear in a CREATE TABLE statement
|
|
+** * Which collating sequence to use for the column
|
|
+** * The affinity of the column
|
|
*/
|
|
-SQLITE_PRIVATE void sqlite3SelectAddColumnTypeAndCollation(
|
|
- Parse *pParse, /* Parsing contexts */
|
|
- Table *pTab, /* Add column type information to this table */
|
|
- Select *pSelect, /* SELECT used to determine types and collations */
|
|
- char aff /* Default affinity for columns */
|
|
+SQLITE_PRIVATE void sqlite3SubqueryColumnTypes(
|
|
+ Parse *pParse, /* Parsing contexts */
|
|
+ Table *pTab, /* Add column type information to this table */
|
|
+ Select *pSelect, /* SELECT used to determine types and collations */
|
|
+ char aff /* Default affinity. */
|
|
){
|
|
sqlite3 *db = pParse->db;
|
|
- NameContext sNC;
|
|
Column *pCol;
|
|
CollSeq *pColl;
|
|
- int i;
|
|
+ int i,j;
|
|
Expr *p;
|
|
struct ExprList_item *a;
|
|
+ NameContext sNC;
|
|
|
|
assert( pSelect!=0 );
|
|
assert( (pSelect->selFlags & SF_Resolved)!=0 );
|
|
- assert( pTab->nCol==pSelect->pEList->nExpr || db->mallocFailed );
|
|
+ assert( pTab->nCol==pSelect->pEList->nExpr || pParse->nErr>0 );
|
|
+ assert( aff==SQLITE_AFF_NONE || aff==SQLITE_AFF_BLOB );
|
|
if( db->mallocFailed ) return;
|
|
+ while( pSelect->pPrior ) pSelect = pSelect->pPrior;
|
|
+ a = pSelect->pEList->a;
|
|
memset(&sNC, 0, sizeof(sNC));
|
|
sNC.pSrcList = pSelect->pSrc;
|
|
- a = pSelect->pEList->a;
|
|
for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
|
|
const char *zType;
|
|
- int n, m;
|
|
+ i64 n;
|
|
+ pTab->tabFlags |= (pCol->colFlags & COLFLAG_NOINSERT);
|
|
p = a[i].pExpr;
|
|
- zType = columnType(&sNC, p, 0, 0, 0);
|
|
/* pCol->szEst = ... // Column size est for SELECT tables never used */
|
|
pCol->affinity = sqlite3ExprAffinity(p);
|
|
- if( zType ){
|
|
- m = sqlite3Strlen30(zType);
|
|
- n = sqlite3Strlen30(pCol->zName);
|
|
- pCol->zName = sqlite3DbReallocOrFree(db, pCol->zName, n+m+2);
|
|
- if( pCol->zName ){
|
|
- memcpy(&pCol->zName[n+1], zType, m+1);
|
|
- pCol->colFlags |= COLFLAG_HASTYPE;
|
|
+ if( pCol->affinity<=SQLITE_AFF_NONE ){
|
|
+ pCol->affinity = aff;
|
|
+ }
|
|
+ if( pCol->affinity>=SQLITE_AFF_TEXT && pSelect->pNext ){
|
|
+ int m = 0;
|
|
+ Select *pS2;
|
|
+ for(m=0, pS2=pSelect->pNext; pS2; pS2=pS2->pNext){
|
|
+ m |= sqlite3ExprDataType(pS2->pEList->a[i].pExpr);
|
|
+ }
|
|
+ if( pCol->affinity==SQLITE_AFF_TEXT && (m&0x01)!=0 ){
|
|
+ pCol->affinity = SQLITE_AFF_BLOB;
|
|
+ }else
|
|
+ if( pCol->affinity>=SQLITE_AFF_NUMERIC && (m&0x02)!=0 ){
|
|
+ pCol->affinity = SQLITE_AFF_BLOB;
|
|
+ }
|
|
+ if( pCol->affinity>=SQLITE_AFF_NUMERIC && p->op==TK_CAST ){
|
|
+ pCol->affinity = SQLITE_AFF_FLEXNUM;
|
|
+ }
|
|
+ }
|
|
+ zType = columnType(&sNC, p, 0, 0, 0);
|
|
+ if( zType==0 || pCol->affinity!=sqlite3AffinityType(zType, 0) ){
|
|
+ if( pCol->affinity==SQLITE_AFF_NUMERIC
|
|
+ || pCol->affinity==SQLITE_AFF_FLEXNUM
|
|
+ ){
|
|
+ zType = "NUM";
|
|
+ }else{
|
|
+ zType = 0;
|
|
+ for(j=1; j<SQLITE_N_STDTYPE; j++){
|
|
+ if( sqlite3StdTypeAffinity[j]==pCol->affinity ){
|
|
+ zType = sqlite3StdType[j];
|
|
+ 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( pCol->affinity<=SQLITE_AFF_NONE ) pCol->affinity = aff;
|
|
pColl = sqlite3ExprCollSeq(pParse, p);
|
|
- if( pColl && pCol->zColl==0 ){
|
|
- pCol->zColl = sqlite3DbStrDup(db, pColl->zName);
|
|
+ if( pColl ){
|
|
+ assert( pTab->pIndex==0 );
|
|
+ sqlite3ColumnSetColl(db, pCol, pColl->zName);
|
|
}
|
|
}
|
|
pTab->szTabRow = 1; /* Any non-zero value works */
|
|
@@ -129990,7 +140686,7 @@ SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect, c
|
|
pTab->zName = 0;
|
|
pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
|
|
sqlite3ColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol, &pTab->aCol);
|
|
- sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSelect, aff);
|
|
+ sqlite3SubqueryColumnTypes(pParse, pTab, pSelect, aff);
|
|
pTab->iPKey = -1;
|
|
if( db->mallocFailed ){
|
|
sqlite3DeleteTable(db, pTab);
|
|
@@ -130020,9 +140716,9 @@ SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse *pParse){
|
|
** Compute the iLimit and iOffset fields of the SELECT based on the
|
|
** pLimit expressions. pLimit->pLeft and pLimit->pRight hold the expressions
|
|
** that appear in the original SQL statement after the LIMIT and OFFSET
|
|
-** keywords. Or NULL if those keywords are omitted. iLimit and iOffset
|
|
-** are the integer memory register numbers for counters used to compute
|
|
-** the limit and offset. If there is no limit and/or offset, then
|
|
+** keywords. Or NULL if those keywords are omitted. iLimit and iOffset
|
|
+** are the integer memory register numbers for counters used to compute
|
|
+** the limit and offset. If there is no limit and/or offset, then
|
|
** iLimit and iOffset are negative.
|
|
**
|
|
** This routine changes the values of iLimit and iOffset only if
|
|
@@ -130048,7 +140744,7 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){
|
|
|
|
if( p->iLimit ) return;
|
|
|
|
- /*
|
|
+ /*
|
|
** "LIMIT -1" always shows all rows. There is some
|
|
** controversy about what the correct behavior should be.
|
|
** The current implementation interprets "LIMIT 0" to mean
|
|
@@ -130124,7 +140820,7 @@ static CollSeq *multiSelectCollSeq(Parse *pParse, Select *p, int iCol){
|
|
*/
|
|
static KeyInfo *multiSelectOrderByKeyInfo(Parse *pParse, Select *p, int nExtra){
|
|
ExprList *pOrderBy = p->pOrderBy;
|
|
- int nOrderBy = p->pOrderBy->nExpr;
|
|
+ int nOrderBy = ALWAYS(pOrderBy!=0) ? pOrderBy->nExpr : 0;
|
|
sqlite3 *db = pParse->db;
|
|
KeyInfo *pRet = sqlite3KeyInfoAlloc(db, nOrderBy+nExtra, 1);
|
|
if( pRet ){
|
|
@@ -130144,7 +140840,7 @@ static KeyInfo *multiSelectOrderByKeyInfo(Parse *pParse, Select *p, int nExtra){
|
|
}
|
|
assert( sqlite3KeyInfoIsWriteable(pRet) );
|
|
pRet->aColl[i] = pColl;
|
|
- pRet->aSortFlags[i] = pOrderBy->a[i].sortFlags;
|
|
+ pRet->aSortFlags[i] = pOrderBy->a[i].fg.sortFlags;
|
|
}
|
|
}
|
|
|
|
@@ -130176,7 +140872,7 @@ static KeyInfo *multiSelectOrderByKeyInfo(Parse *pParse, Select *p, int nExtra){
|
|
** inserted into the Queue table. The iDistinct table keeps a copy of all rows
|
|
** that have ever been inserted into Queue and causes duplicates to be
|
|
** discarded. If the operator is UNION ALL, then duplicates are allowed.
|
|
-**
|
|
+**
|
|
** If the query has an ORDER BY, then entries in the Queue table are kept in
|
|
** ORDER BY order and the first entry is extracted for each cycle. Without
|
|
** an ORDER BY, the Queue table is just a FIFO.
|
|
@@ -130196,7 +140892,8 @@ static void generateWithRecursiveQuery(
|
|
SrcList *pSrc = p->pSrc; /* The FROM clause of the recursive query */
|
|
int nCol = p->pEList->nExpr; /* Number of columns in the recursive table */
|
|
Vdbe *v = pParse->pVdbe; /* The prepared statement under construction */
|
|
- Select *pSetup = p->pPrior; /* The setup query */
|
|
+ Select *pSetup; /* The setup query */
|
|
+ Select *pFirstRec; /* Left-most recursive term */
|
|
int addrTop; /* Top of the loop */
|
|
int addrCont, addrBreak; /* CONTINUE and BREAK addresses */
|
|
int iCurrent = 0; /* The Current table */
|
|
@@ -130272,7 +140969,24 @@ static void generateWithRecursiveQuery(
|
|
/* Detach the ORDER BY clause from the compound SELECT */
|
|
p->pOrderBy = 0;
|
|
|
|
+ /* Figure out how many elements of the compound SELECT are part of the
|
|
+ ** recursive query. Make sure no recursive elements use aggregate
|
|
+ ** functions. Mark the recursive elements as UNION ALL even if they
|
|
+ ** are really UNION because the distinctness will be enforced by the
|
|
+ ** iDistinct table. pFirstRec is left pointing to the left-most
|
|
+ ** recursive term of the CTE.
|
|
+ */
|
|
+ for(pFirstRec=p; ALWAYS(pFirstRec!=0); pFirstRec=pFirstRec->pPrior){
|
|
+ if( pFirstRec->selFlags & SF_Aggregate ){
|
|
+ sqlite3ErrorMsg(pParse, "recursive aggregate queries not supported");
|
|
+ goto end_of_recursive_query;
|
|
+ }
|
|
+ pFirstRec->op = TK_ALL;
|
|
+ if( (pFirstRec->pPrior->selFlags & SF_Recursive)==0 ) break;
|
|
+ }
|
|
+
|
|
/* Store the results of the setup-query in Queue. */
|
|
+ pSetup = pFirstRec->pPrior;
|
|
pSetup->pNext = 0;
|
|
ExplainQueryPlan((pParse, 1, "SETUP"));
|
|
rc = sqlite3Select(pParse, pSetup, &destQueue);
|
|
@@ -130305,15 +141019,11 @@ static void generateWithRecursiveQuery(
|
|
/* Execute the recursive SELECT taking the single row in Current as
|
|
** the value for the recursive-table. Store the results in the Queue.
|
|
*/
|
|
- if( p->selFlags & SF_Aggregate ){
|
|
- sqlite3ErrorMsg(pParse, "recursive aggregate queries not supported");
|
|
- }else{
|
|
- p->pPrior = 0;
|
|
- ExplainQueryPlan((pParse, 1, "RECURSIVE STEP"));
|
|
- sqlite3Select(pParse, p, &destQueue);
|
|
- assert( p->pPrior==0 );
|
|
- p->pPrior = pSetup;
|
|
- }
|
|
+ pFirstRec->pPrior = 0;
|
|
+ ExplainQueryPlan((pParse, 1, "RECURSIVE STEP"));
|
|
+ sqlite3Select(pParse, p, &destQueue);
|
|
+ assert( pFirstRec->pPrior==0 );
|
|
+ pFirstRec->pPrior = pSetup;
|
|
|
|
/* Keep running the loop until the Queue is empty */
|
|
sqlite3VdbeGoto(v, addrTop);
|
|
@@ -130348,7 +141058,7 @@ static int multiSelectOrderBy(
|
|
** The "LIMIT of exactly 1" case of condition (1) comes about when a VALUES
|
|
** clause occurs within scalar expression (ex: "SELECT (VALUES(1),(2),(3))").
|
|
** The sqlite3CodeSubselect will have added the LIMIT 1 clause in tht case.
|
|
-** Since the limit is exactly 1, we only need to evalutes the left-most VALUES.
|
|
+** Since the limit is exactly 1, we only need to evaluate the left-most VALUES.
|
|
*/
|
|
static int multiSelectValues(
|
|
Parse *pParse, /* Parsing context */
|
|
@@ -130382,6 +141092,16 @@ static int multiSelectValues(
|
|
return rc;
|
|
}
|
|
|
|
+/*
|
|
+** Return true if the SELECT statement which is known to be the recursive
|
|
+** part of a recursive CTE still has its anchor terms attached. If the
|
|
+** anchor terms have already been removed, then return false.
|
|
+*/
|
|
+static int hasAnchor(Select *p){
|
|
+ while( p && (p->selFlags & SF_Recursive)!=0 ){ p = p->pPrior; }
|
|
+ return p!=0;
|
|
+}
|
|
+
|
|
/*
|
|
** This routine is called to process a compound query form from
|
|
** two or more separate queries using UNION, UNION ALL, EXCEPT, or
|
|
@@ -130389,7 +141109,7 @@ static int multiSelectValues(
|
|
**
|
|
** "p" points to the right-most of the two queries. the query on the
|
|
** left is p->pPrior. The left query could also be a compound query
|
|
-** in which case this routine will be called recursively.
|
|
+** in which case this routine will be called recursively.
|
|
**
|
|
** The results of the total query are to be written into a destination
|
|
** of type eDest with parameter iParm.
|
|
@@ -130434,12 +141154,8 @@ static int multiSelect(
|
|
db = pParse->db;
|
|
pPrior = p->pPrior;
|
|
dest = *pDest;
|
|
- if( pPrior->pOrderBy || pPrior->pLimit ){
|
|
- sqlite3ErrorMsg(pParse,"%s clause should come after %s not before",
|
|
- pPrior->pOrderBy!=0 ? "ORDER BY" : "LIMIT", selectOpName(p->op));
|
|
- rc = 1;
|
|
- goto multi_select_end;
|
|
- }
|
|
+ assert( pPrior->pOrderBy==0 );
|
|
+ assert( pPrior->pLimit==0 );
|
|
|
|
v = sqlite3GetVdbe(pParse);
|
|
assert( v!=0 ); /* The VDBE already created by calling function */
|
|
@@ -130467,7 +141183,7 @@ static int multiSelect(
|
|
assert( p->pEList->nExpr==pPrior->pEList->nExpr );
|
|
|
|
#ifndef SQLITE_OMIT_CTE
|
|
- if( p->selFlags & SF_Recursive ){
|
|
+ if( (p->selFlags & SF_Recursive)!=0 && hasAnchor(p) ){
|
|
generateWithRecursiveQuery(pParse, p, &dest);
|
|
}else
|
|
#endif
|
|
@@ -130490,13 +141206,14 @@ static int multiSelect(
|
|
switch( p->op ){
|
|
case TK_ALL: {
|
|
int addr = 0;
|
|
- int nLimit;
|
|
+ int nLimit = 0; /* Initialize to suppress harmless compiler warning */
|
|
assert( !pPrior->pLimit );
|
|
pPrior->iLimit = p->iLimit;
|
|
pPrior->iOffset = p->iOffset;
|
|
pPrior->pLimit = p->pLimit;
|
|
+ TREETRACE(0x200, pParse, p, ("multiSelect UNION ALL left...\n"));
|
|
rc = sqlite3Select(pParse, pPrior, &dest);
|
|
- p->pLimit = 0;
|
|
+ pPrior->pLimit = 0;
|
|
if( rc ){
|
|
goto multi_select_end;
|
|
}
|
|
@@ -130512,14 +141229,15 @@ static int multiSelect(
|
|
}
|
|
}
|
|
ExplainQueryPlan((pParse, 1, "UNION ALL"));
|
|
+ TREETRACE(0x200, pParse, p, ("multiSelect UNION ALL right...\n"));
|
|
rc = sqlite3Select(pParse, p, &dest);
|
|
testcase( rc!=SQLITE_OK );
|
|
pDelete = p->pPrior;
|
|
p->pPrior = pPrior;
|
|
p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow);
|
|
- if( pPrior->pLimit
|
|
- && sqlite3ExprIsInteger(pPrior->pLimit->pLeft, &nLimit)
|
|
- && nLimit>0 && p->nSelectRow > sqlite3LogEst((u64)nLimit)
|
|
+ if( p->pLimit
|
|
+ && sqlite3ExprIsInteger(p->pLimit->pLeft, &nLimit)
|
|
+ && nLimit>0 && p->nSelectRow > sqlite3LogEst((u64)nLimit)
|
|
){
|
|
p->nSelectRow = sqlite3LogEst((u64)nLimit);
|
|
}
|
|
@@ -130536,7 +141254,7 @@ static int multiSelect(
|
|
Expr *pLimit; /* Saved values of p->nLimit */
|
|
int addr;
|
|
SelectDest uniondest;
|
|
-
|
|
+
|
|
testcase( p->op==TK_EXCEPT );
|
|
testcase( p->op==TK_UNION );
|
|
priorOp = SRT_Union;
|
|
@@ -130558,16 +141276,18 @@ static int multiSelect(
|
|
findRightmost(p)->selFlags |= SF_UsesEphemeral;
|
|
assert( p->pEList );
|
|
}
|
|
-
|
|
+
|
|
+
|
|
/* Code the SELECT statements to our left
|
|
*/
|
|
assert( !pPrior->pOrderBy );
|
|
sqlite3SelectDestInit(&uniondest, priorOp, unionTab);
|
|
+ TREETRACE(0x200, pParse, p, ("multiSelect EXCEPT/UNION left...\n"));
|
|
rc = sqlite3Select(pParse, pPrior, &uniondest);
|
|
if( rc ){
|
|
goto multi_select_end;
|
|
}
|
|
-
|
|
+
|
|
/* Code the current SELECT statement
|
|
*/
|
|
if( p->op==TK_EXCEPT ){
|
|
@@ -130581,12 +141301,11 @@ static int multiSelect(
|
|
p->pLimit = 0;
|
|
uniondest.eDest = op;
|
|
ExplainQueryPlan((pParse, 1, "%s USING TEMP B-TREE",
|
|
- selectOpName(p->op)));
|
|
+ sqlite3SelectOpName(p->op)));
|
|
+ TREETRACE(0x200, pParse, p, ("multiSelect EXCEPT/UNION right...\n"));
|
|
rc = sqlite3Select(pParse, p, &uniondest);
|
|
testcase( rc!=SQLITE_OK );
|
|
- /* Query flattening in sqlite3Select() might refill p->pOrderBy.
|
|
- ** Be sure to delete p->pOrderBy, therefore, to avoid a memory leak. */
|
|
- sqlite3ExprListDelete(db, p->pOrderBy);
|
|
+ assert( p->pOrderBy==0 );
|
|
pDelete = p->pPrior;
|
|
p->pPrior = pPrior;
|
|
p->pOrderBy = 0;
|
|
@@ -130597,7 +141316,7 @@ static int multiSelect(
|
|
p->pLimit = pLimit;
|
|
p->iLimit = 0;
|
|
p->iOffset = 0;
|
|
-
|
|
+
|
|
/* Convert the data in the temporary table into whatever form
|
|
** it is that we currently need.
|
|
*/
|
|
@@ -130626,7 +141345,7 @@ static int multiSelect(
|
|
int addr;
|
|
SelectDest intersectdest;
|
|
int r1;
|
|
-
|
|
+
|
|
/* INTERSECT is different from the others since it requires
|
|
** two temporary tables. Hence it has its own case. Begin
|
|
** by allocating the tables we will need.
|
|
@@ -130634,21 +141353,22 @@ static int multiSelect(
|
|
tab1 = pParse->nTab++;
|
|
tab2 = pParse->nTab++;
|
|
assert( p->pOrderBy==0 );
|
|
-
|
|
+
|
|
addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, tab1, 0);
|
|
assert( p->addrOpenEphm[0] == -1 );
|
|
p->addrOpenEphm[0] = addr;
|
|
findRightmost(p)->selFlags |= SF_UsesEphemeral;
|
|
assert( p->pEList );
|
|
-
|
|
+
|
|
/* Code the SELECTs to our left into temporary table "tab1".
|
|
*/
|
|
sqlite3SelectDestInit(&intersectdest, SRT_Union, tab1);
|
|
+ TREETRACE(0x400, pParse, p, ("multiSelect INTERSECT left...\n"));
|
|
rc = sqlite3Select(pParse, pPrior, &intersectdest);
|
|
if( rc ){
|
|
goto multi_select_end;
|
|
}
|
|
-
|
|
+
|
|
/* Code the current SELECT into temporary table "tab2"
|
|
*/
|
|
addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, tab2, 0);
|
|
@@ -130659,7 +141379,8 @@ static int multiSelect(
|
|
p->pLimit = 0;
|
|
intersectdest.iSDParm = tab2;
|
|
ExplainQueryPlan((pParse, 1, "%s USING TEMP B-TREE",
|
|
- selectOpName(p->op)));
|
|
+ sqlite3SelectOpName(p->op)));
|
|
+ TREETRACE(0x400, pParse, p, ("multiSelect INTERSECT right...\n"));
|
|
rc = sqlite3Select(pParse, p, &intersectdest);
|
|
testcase( rc!=SQLITE_OK );
|
|
pDelete = p->pPrior;
|
|
@@ -130669,10 +141390,11 @@ static int multiSelect(
|
|
}
|
|
sqlite3ExprDelete(db, p->pLimit);
|
|
p->pLimit = pLimit;
|
|
-
|
|
+
|
|
/* Generate code to take the intersection of the two temporary
|
|
** tables.
|
|
*/
|
|
+ if( rc ) break;
|
|
assert( p->pEList );
|
|
iBreak = sqlite3VdbeMakeLabel(pParse);
|
|
iCont = sqlite3VdbeMakeLabel(pParse);
|
|
@@ -130693,7 +141415,7 @@ static int multiSelect(
|
|
break;
|
|
}
|
|
}
|
|
-
|
|
+
|
|
#ifndef SQLITE_OMIT_EXPLAIN
|
|
if( p->pNext==0 ){
|
|
ExplainQueryPlanPop(pParse);
|
|
@@ -130701,8 +141423,8 @@ static int multiSelect(
|
|
#endif
|
|
}
|
|
if( pParse->nErr ) goto multi_select_end;
|
|
-
|
|
- /* Compute collating sequences used by
|
|
+
|
|
+ /* Compute collating sequences used by
|
|
** temporary tables needed to implement the compound select.
|
|
** Attach the KeyInfo structure to all temporary tables.
|
|
**
|
|
@@ -130719,6 +141441,7 @@ static int multiSelect(
|
|
int nCol; /* Number of columns in result set */
|
|
|
|
assert( p->pNext==0 );
|
|
+ assert( p->pEList!=0 );
|
|
nCol = p->pEList->nExpr;
|
|
pKeyInfo = sqlite3KeyInfoAlloc(db, nCol, 1);
|
|
if( !pKeyInfo ){
|
|
@@ -130753,7 +141476,11 @@ static int multiSelect(
|
|
multi_select_end:
|
|
pDest->iSdst = dest.iSdst;
|
|
pDest->nSdst = dest.nSdst;
|
|
- sqlite3SelectDelete(db, pDelete);
|
|
+ if( pDelete ){
|
|
+ sqlite3ParserAddCleanup(pParse,
|
|
+ (void(*)(sqlite3*,void*))sqlite3SelectDelete,
|
|
+ pDelete);
|
|
+ }
|
|
return rc;
|
|
}
|
|
#endif /* SQLITE_OMIT_COMPOUND_SELECT */
|
|
@@ -130767,7 +141494,8 @@ SQLITE_PRIVATE void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p){
|
|
sqlite3ErrorMsg(pParse, "all VALUES must have the same number of terms");
|
|
}else{
|
|
sqlite3ErrorMsg(pParse, "SELECTs to the left and right of %s"
|
|
- " do not have the same number of result columns", selectOpName(p->op));
|
|
+ " do not have the same number of result columns",
|
|
+ sqlite3SelectOpName(p->op));
|
|
}
|
|
}
|
|
|
|
@@ -130808,7 +141536,7 @@ static int generateOutputSubroutine(
|
|
addr = sqlite3VdbeCurrentAddr(v);
|
|
iContinue = sqlite3VdbeMakeLabel(pParse);
|
|
|
|
- /* Suppress duplicates for UNION, EXCEPT, and INTERSECT
|
|
+ /* Suppress duplicates for UNION, EXCEPT, and INTERSECT
|
|
*/
|
|
if( regPrev ){
|
|
int addr1, addr2;
|
|
@@ -130850,7 +141578,7 @@ static int generateOutputSubroutine(
|
|
int r1;
|
|
testcase( pIn->nSdst>1 );
|
|
r1 = sqlite3GetTempReg(pParse);
|
|
- sqlite3VdbeAddOp4(v, OP_MakeRecord, pIn->iSdst, pIn->nSdst,
|
|
+ sqlite3VdbeAddOp4(v, OP_MakeRecord, pIn->iSdst, pIn->nSdst,
|
|
r1, pDest->zAffSdst, pIn->nSdst);
|
|
sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pDest->iSDParm, r1,
|
|
pIn->iSdst, pIn->nSdst);
|
|
@@ -130864,10 +141592,8 @@ static int generateOutputSubroutine(
|
|
** if it is the RHS of a row-value IN operator.
|
|
*/
|
|
case SRT_Mem: {
|
|
- if( pParse->nErr==0 ){
|
|
- testcase( pIn->nSdst>1 );
|
|
- sqlite3ExprCodeMove(pParse, pIn->iSdst, pDest->iSDParm, pIn->nSdst);
|
|
- }
|
|
+ testcase( pIn->nSdst>1 );
|
|
+ sqlite3ExprCodeMove(pParse, pIn->iSdst, pDest->iSDParm, pIn->nSdst);
|
|
/* The LIMIT clause will jump out of the loop for us */
|
|
break;
|
|
}
|
|
@@ -130890,7 +141616,7 @@ static int generateOutputSubroutine(
|
|
** SRT_Output. This routine is never called with any other
|
|
** destination other than the ones handled above or SRT_Output.
|
|
**
|
|
- ** For SRT_Output, results are stored in a sequence of registers.
|
|
+ ** For SRT_Output, results are stored in a sequence of registers.
|
|
** Then the OP_ResultRow opcode is used to cause sqlite3_step() to
|
|
** return the next row of result.
|
|
*/
|
|
@@ -130947,7 +141673,7 @@ static int generateOutputSubroutine(
|
|
**
|
|
** EofB: Called when data is exhausted from selectB.
|
|
**
|
|
-** The implementation of the latter five subroutines depend on which
|
|
+** The implementation of the latter five subroutines depend on which
|
|
** <operator> is used:
|
|
**
|
|
**
|
|
@@ -131008,6 +141734,8 @@ static int multiSelectOrderBy(
|
|
){
|
|
int i, j; /* Loop counters */
|
|
Select *pPrior; /* Another SELECT immediately to our left */
|
|
+ Select *pSplit; /* Left-most SELECT in the right-hand group */
|
|
+ int nSelect; /* Number of SELECT statements in the compound */
|
|
Vdbe *v; /* Generate code to this VDBE */
|
|
SelectDest destA; /* Destination for coroutine A */
|
|
SelectDest destB; /* Destination for coroutine B */
|
|
@@ -131039,7 +141767,7 @@ static int multiSelectOrderBy(
|
|
sqlite3 *db; /* Database connection */
|
|
ExprList *pOrderBy; /* The ORDER BY clause */
|
|
int nOrderBy; /* Number of terms in the ORDER BY clause */
|
|
- int *aPermute; /* Mapping from ORDER BY terms to result set columns */
|
|
+ u32 *aPermute; /* Mapping from ORDER BY terms to result set columns */
|
|
|
|
assert( p->pOrderBy!=0 );
|
|
assert( pKeyDup==0 ); /* "Managed" code needs this. Ticket #3382. */
|
|
@@ -131052,9 +141780,8 @@ static int multiSelectOrderBy(
|
|
|
|
/* Patch up the ORDER BY clause
|
|
*/
|
|
- op = p->op;
|
|
- pPrior = p->pPrior;
|
|
- assert( pPrior->pOrderBy==0 );
|
|
+ op = p->op;
|
|
+ assert( p->pPrior->pOrderBy==0 );
|
|
pOrderBy = p->pOrderBy;
|
|
assert( pOrderBy );
|
|
nOrderBy = pOrderBy->nExpr;
|
|
@@ -131067,6 +141794,7 @@ static int multiSelectOrderBy(
|
|
for(i=1; db->mallocFailed==0 && i<=p->pEList->nExpr; i++){
|
|
struct ExprList_item *pItem;
|
|
for(j=0, pItem=pOrderBy->a; j<nOrderBy; j++, pItem++){
|
|
+ assert( pItem!=0 );
|
|
assert( pItem->u.x.iOrderByCol>0 );
|
|
if( pItem->u.x.iOrderByCol==i ) break;
|
|
}
|
|
@@ -131088,11 +141816,12 @@ static int multiSelectOrderBy(
|
|
** to the right and the left are evaluated, they use the correct
|
|
** collation.
|
|
*/
|
|
- aPermute = sqlite3DbMallocRawNN(db, sizeof(int)*(nOrderBy + 1));
|
|
+ aPermute = sqlite3DbMallocRawNN(db, sizeof(u32)*(nOrderBy + 1));
|
|
if( aPermute ){
|
|
struct ExprList_item *pItem;
|
|
aPermute[0] = nOrderBy;
|
|
for(i=1, pItem=pOrderBy->a; i<=nOrderBy; i++, pItem++){
|
|
+ assert( pItem!=0 );
|
|
assert( pItem->u.x.iOrderByCol>0 );
|
|
assert( pItem->u.x.iOrderByCol<=p->pEList->nExpr );
|
|
aPermute[i] = pItem->u.x.iOrderByCol - 1;
|
|
@@ -131102,11 +141831,6 @@ static int multiSelectOrderBy(
|
|
pKeyMerge = 0;
|
|
}
|
|
|
|
- /* Reattach the ORDER BY clause to the query.
|
|
- */
|
|
- p->pOrderBy = pOrderBy;
|
|
- pPrior->pOrderBy = sqlite3ExprListDup(pParse->db, pOrderBy, 0);
|
|
-
|
|
/* Allocate a range of temporary registers and the KeyInfo needed
|
|
** for the logic that removes duplicate result rows when the
|
|
** operator is UNION, EXCEPT, or INTERSECT (but not UNION ALL).
|
|
@@ -131128,15 +141852,33 @@ static int multiSelectOrderBy(
|
|
}
|
|
}
|
|
}
|
|
-
|
|
+
|
|
/* Separate the left and the right query from one another
|
|
*/
|
|
- p->pPrior = 0;
|
|
+ nSelect = 1;
|
|
+ if( (op==TK_ALL || op==TK_UNION)
|
|
+ && OptimizationEnabled(db, SQLITE_BalancedMerge)
|
|
+ ){
|
|
+ for(pSplit=p; pSplit->pPrior!=0 && pSplit->op==op; pSplit=pSplit->pPrior){
|
|
+ nSelect++;
|
|
+ assert( pSplit->pPrior->pNext==pSplit );
|
|
+ }
|
|
+ }
|
|
+ if( nSelect<=3 ){
|
|
+ pSplit = p;
|
|
+ }else{
|
|
+ pSplit = p;
|
|
+ for(i=2; i<nSelect; i+=2){ pSplit = pSplit->pPrior; }
|
|
+ }
|
|
+ pPrior = pSplit->pPrior;
|
|
+ assert( pPrior!=0 );
|
|
+ pSplit->pPrior = 0;
|
|
pPrior->pNext = 0;
|
|
+ assert( p->pOrderBy == pOrderBy );
|
|
+ assert( pOrderBy!=0 || db->mallocFailed );
|
|
+ pPrior->pOrderBy = sqlite3ExprListDup(pParse->db, pOrderBy, 0);
|
|
sqlite3ResolveOrderGroupBy(pParse, p, p->pOrderBy, "ORDER");
|
|
- if( pPrior->pPrior==0 ){
|
|
- sqlite3ResolveOrderGroupBy(pParse, pPrior, pPrior->pOrderBy, "ORDER");
|
|
- }
|
|
+ sqlite3ResolveOrderGroupBy(pParse, pPrior, pPrior->pOrderBy, "ORDER");
|
|
|
|
/* Compute the limit registers */
|
|
computeLimitRegisters(pParse, p, labelEnd);
|
|
@@ -131159,7 +141901,7 @@ static int multiSelectOrderBy(
|
|
sqlite3SelectDestInit(&destA, SRT_Coroutine, regAddrA);
|
|
sqlite3SelectDestInit(&destB, SRT_Coroutine, regAddrB);
|
|
|
|
- ExplainQueryPlan((pParse, 1, "MERGE (%s)", selectOpName(p->op)));
|
|
+ ExplainQueryPlan((pParse, 1, "MERGE (%s)", sqlite3SelectOpName(p->op)));
|
|
|
|
/* Generate a coroutine to evaluate the SELECT statement to the
|
|
** left of the compound operator - the "A" select.
|
|
@@ -131173,7 +141915,7 @@ static int multiSelectOrderBy(
|
|
sqlite3VdbeEndCoroutine(v, regAddrA);
|
|
sqlite3VdbeJumpHere(v, addr1);
|
|
|
|
- /* Generate a coroutine to evaluate the SELECT statement on
|
|
+ /* Generate a coroutine to evaluate the SELECT statement on
|
|
** the right - the "B" select
|
|
*/
|
|
addrSelectB = sqlite3VdbeCurrentAddr(v) + 1;
|
|
@@ -131182,7 +141924,7 @@ static int multiSelectOrderBy(
|
|
savedLimit = p->iLimit;
|
|
savedOffset = p->iOffset;
|
|
p->iLimit = regLimitB;
|
|
- p->iOffset = 0;
|
|
+ p->iOffset = 0;
|
|
ExplainQueryPlan((pParse, 1, "RIGHT"));
|
|
sqlite3Select(pParse, p, &destB);
|
|
p->iLimit = savedLimit;
|
|
@@ -131196,7 +141938,7 @@ static int multiSelectOrderBy(
|
|
addrOutA = generateOutputSubroutine(pParse,
|
|
p, &destA, pDest, regOutA,
|
|
regPrev, pKeyDup, labelEnd);
|
|
-
|
|
+
|
|
/* Generate a subroutine that outputs the current row of the B
|
|
** select as the next output row of the compound select.
|
|
*/
|
|
@@ -131213,7 +141955,7 @@ static int multiSelectOrderBy(
|
|
*/
|
|
if( op==TK_EXCEPT || op==TK_INTERSECT ){
|
|
addrEofA_noB = addrEofA = labelEnd;
|
|
- }else{
|
|
+ }else{
|
|
VdbeNoopComment((v, "eof-A subroutine"));
|
|
addrEofA = sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB);
|
|
addrEofA_noB = sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, labelEnd);
|
|
@@ -131228,7 +141970,7 @@ static int multiSelectOrderBy(
|
|
if( op==TK_INTERSECT ){
|
|
addrEofB = addrEofA;
|
|
if( p->nSelectRow > pPrior->nSelectRow ) p->nSelectRow = pPrior->nSelectRow;
|
|
- }else{
|
|
+ }else{
|
|
VdbeNoopComment((v, "eof-B subroutine"));
|
|
addrEofB = sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA);
|
|
sqlite3VdbeAddOp2(v, OP_Yield, regAddrA, labelEnd); VdbeCoverage(v);
|
|
@@ -131285,13 +142027,16 @@ static int multiSelectOrderBy(
|
|
*/
|
|
sqlite3VdbeResolveLabel(v, labelEnd);
|
|
|
|
- /* Reassembly the compound query so that it will be freed correctly
|
|
- ** by the calling function */
|
|
- if( p->pPrior ){
|
|
- sqlite3SelectDelete(db, p->pPrior);
|
|
+ /* Make arrangements to free the 2nd and subsequent arms of the compound
|
|
+ ** after the parse has finished */
|
|
+ if( pSplit->pPrior ){
|
|
+ sqlite3ParserAddCleanup(pParse,
|
|
+ (void(*)(sqlite3*,void*))sqlite3SelectDelete, pSplit->pPrior);
|
|
}
|
|
- p->pPrior = pPrior;
|
|
- pPrior->pNext = p;
|
|
+ pSplit->pPrior = pPrior;
|
|
+ pPrior->pNext = pSplit;
|
|
+ sqlite3ExprListDelete(db, pPrior->pOrderBy);
|
|
+ pPrior->pOrderBy = 0;
|
|
|
|
/*** TBD: Insert subroutine calls to close cursors on incomplete
|
|
**** subqueries ****/
|
|
@@ -131307,13 +142052,42 @@ static int multiSelectOrderBy(
|
|
**
|
|
** All references to columns in table iTable are to be replaced by corresponding
|
|
** expressions in pEList.
|
|
+**
|
|
+** ## About "isOuterJoin":
|
|
+**
|
|
+** The isOuterJoin column indicates that the replacement will occur into a
|
|
+** position in the parent that NULL-able due to an OUTER JOIN. Either the
|
|
+** target slot in the parent is the right operand of a LEFT JOIN, or one of
|
|
+** the left operands of a RIGHT JOIN. In either case, we need to potentially
|
|
+** bypass the substituted expression with OP_IfNullRow.
|
|
+**
|
|
+** Suppose the original expression is an integer constant. Even though the table
|
|
+** has the nullRow flag set, because the expression is an integer constant,
|
|
+** it will not be NULLed out. So instead, we insert an OP_IfNullRow opcode
|
|
+** that checks to see if the nullRow flag is set on the table. If the nullRow
|
|
+** flag is set, then the value in the register is set to NULL and the original
|
|
+** expression is bypassed. If the nullRow flag is not set, then the original
|
|
+** expression runs to populate the register.
|
|
+**
|
|
+** Example where this is needed:
|
|
+**
|
|
+** CREATE TABLE t1(a INTEGER PRIMARY KEY, b INT);
|
|
+** CREATE TABLE t2(x INT UNIQUE);
|
|
+**
|
|
+** SELECT a,b,m,x FROM t1 LEFT JOIN (SELECT 59 AS m,x FROM t2) ON b=x;
|
|
+**
|
|
+** When the subquery on the right side of the LEFT JOIN is flattened, we
|
|
+** have to add OP_IfNullRow in front of the OP_Integer that implements the
|
|
+** "m" value of the subquery so that a NULL will be loaded instead of 59
|
|
+** when processing a non-matched row of the left.
|
|
*/
|
|
typedef struct SubstContext {
|
|
Parse *pParse; /* The parsing context */
|
|
int iTable; /* Replace references to this table */
|
|
int iNewTable; /* New table number */
|
|
- int isLeftJoin; /* Add TK_IF_NULL_ROW opcodes on each replacement */
|
|
+ int isOuterJoin; /* Add TK_IF_NULL_ROW opcodes on each replacement */
|
|
ExprList *pEList; /* Replacement expressions */
|
|
+ ExprList *pCList; /* Collation sequences for replacement expr */
|
|
} SubstContext;
|
|
|
|
/* Forward Declarations */
|
|
@@ -131323,13 +142097,13 @@ static void substSelect(SubstContext*, Select*, int);
|
|
/*
|
|
** Scan through the expression pExpr. Replace every reference to
|
|
** a column in table number iTable with a copy of the iColumn-th
|
|
-** entry in pEList. (But leave references to the ROWID column
|
|
+** entry in pEList. (But leave references to the ROWID column
|
|
** unchanged.)
|
|
**
|
|
** This routine is part of the flattening procedure. A subquery
|
|
** whose result set is defined by pEList appears as entry in the
|
|
** FROM clause of a SELECT such that the VDBE cursor assigned to that
|
|
-** FORM clause entry is iTable. This routine makes the necessary
|
|
+** FORM clause entry is iTable. This routine makes the necessary
|
|
** changes to pExpr so that it refers directly to the source table
|
|
** of the subquery rather the result set of the subquery.
|
|
*/
|
|
@@ -131338,54 +142112,78 @@ static Expr *substExpr(
|
|
Expr *pExpr /* Expr in which substitution occurs */
|
|
){
|
|
if( pExpr==0 ) return 0;
|
|
- if( ExprHasProperty(pExpr, EP_FromJoin)
|
|
- && pExpr->iRightJoinTable==pSubst->iTable
|
|
+ if( ExprHasProperty(pExpr, EP_OuterON|EP_InnerON)
|
|
+ && pExpr->w.iJoin==pSubst->iTable
|
|
){
|
|
- pExpr->iRightJoinTable = pSubst->iNewTable;
|
|
+ testcase( ExprHasProperty(pExpr, EP_InnerON) );
|
|
+ pExpr->w.iJoin = pSubst->iNewTable;
|
|
}
|
|
- if( pExpr->op==TK_COLUMN && pExpr->iTable==pSubst->iTable ){
|
|
+ if( pExpr->op==TK_COLUMN
|
|
+ && pExpr->iTable==pSubst->iTable
|
|
+ && !ExprHasProperty(pExpr, EP_FixedCol)
|
|
+ ){
|
|
+#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
|
|
if( pExpr->iColumn<0 ){
|
|
pExpr->op = TK_NULL;
|
|
- }else{
|
|
+ }else
|
|
+#endif
|
|
+ {
|
|
Expr *pNew;
|
|
- Expr *pCopy = pSubst->pEList->a[pExpr->iColumn].pExpr;
|
|
+ int iColumn = pExpr->iColumn;
|
|
+ Expr *pCopy = pSubst->pEList->a[iColumn].pExpr;
|
|
Expr ifNullRow;
|
|
- assert( pSubst->pEList!=0 && pExpr->iColumn<pSubst->pEList->nExpr );
|
|
+ assert( pSubst->pEList!=0 && iColumn<pSubst->pEList->nExpr );
|
|
assert( pExpr->pRight==0 );
|
|
if( sqlite3ExprIsVector(pCopy) ){
|
|
sqlite3VectorErrorMsg(pSubst->pParse, pCopy);
|
|
}else{
|
|
sqlite3 *db = pSubst->pParse->db;
|
|
- if( pSubst->isLeftJoin && pCopy->op!=TK_COLUMN ){
|
|
+ if( pSubst->isOuterJoin
|
|
+ && (pCopy->op!=TK_COLUMN || pCopy->iTable!=pSubst->iNewTable)
|
|
+ ){
|
|
memset(&ifNullRow, 0, sizeof(ifNullRow));
|
|
ifNullRow.op = TK_IF_NULL_ROW;
|
|
ifNullRow.pLeft = pCopy;
|
|
ifNullRow.iTable = pSubst->iNewTable;
|
|
+ ifNullRow.iColumn = -99;
|
|
+ ifNullRow.flags = EP_IfNullRow;
|
|
pCopy = &ifNullRow;
|
|
}
|
|
testcase( ExprHasProperty(pCopy, EP_Subquery) );
|
|
pNew = sqlite3ExprDup(db, pCopy, 0);
|
|
- if( pNew && pSubst->isLeftJoin ){
|
|
+ if( db->mallocFailed ){
|
|
+ sqlite3ExprDelete(db, pNew);
|
|
+ return pExpr;
|
|
+ }
|
|
+ if( pSubst->isOuterJoin ){
|
|
ExprSetProperty(pNew, EP_CanBeNull);
|
|
}
|
|
- if( pNew && ExprHasProperty(pExpr,EP_FromJoin) ){
|
|
- pNew->iRightJoinTable = pExpr->iRightJoinTable;
|
|
- ExprSetProperty(pNew, EP_FromJoin);
|
|
+ if( ExprHasProperty(pExpr,EP_OuterON|EP_InnerON) ){
|
|
+ sqlite3SetJoinExpr(pNew, pExpr->w.iJoin,
|
|
+ pExpr->flags & (EP_OuterON|EP_InnerON));
|
|
}
|
|
sqlite3ExprDelete(db, pExpr);
|
|
pExpr = pNew;
|
|
+ if( pExpr->op==TK_TRUEFALSE ){
|
|
+ pExpr->u.iValue = sqlite3ExprTruthValue(pExpr);
|
|
+ pExpr->op = TK_INTEGER;
|
|
+ ExprSetProperty(pExpr, EP_IntValue);
|
|
+ }
|
|
|
|
/* Ensure that the expression now has an implicit collation sequence,
|
|
** just as it did when it was a column of a view or sub-query. */
|
|
- if( pExpr ){
|
|
- if( pExpr->op!=TK_COLUMN && pExpr->op!=TK_COLLATE ){
|
|
- CollSeq *pColl = sqlite3ExprCollSeq(pSubst->pParse, pExpr);
|
|
- pExpr = sqlite3ExprAddCollateString(pSubst->pParse, pExpr,
|
|
+ {
|
|
+ CollSeq *pNat = sqlite3ExprCollSeq(pSubst->pParse, pExpr);
|
|
+ CollSeq *pColl = sqlite3ExprCollSeq(pSubst->pParse,
|
|
+ pSubst->pCList->a[iColumn].pExpr
|
|
+ );
|
|
+ if( pNat!=pColl || (pExpr->op!=TK_COLUMN && pExpr->op!=TK_COLLATE) ){
|
|
+ pExpr = sqlite3ExprAddCollateString(pSubst->pParse, pExpr,
|
|
(pColl ? pColl->zName : "BINARY")
|
|
);
|
|
}
|
|
- ExprClearProperty(pExpr, EP_Collate);
|
|
}
|
|
+ ExprClearProperty(pExpr, EP_Collate);
|
|
}
|
|
}
|
|
}else{
|
|
@@ -131394,7 +142192,7 @@ static Expr *substExpr(
|
|
}
|
|
pExpr->pLeft = substExpr(pSubst, pExpr->pLeft);
|
|
pExpr->pRight = substExpr(pSubst, pExpr->pRight);
|
|
- if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
|
+ if( ExprUseXSelect(pExpr) ){
|
|
substSelect(pSubst, pExpr->x.pSelect, 1);
|
|
}else{
|
|
substExprList(pSubst, pExpr->x.pList);
|
|
@@ -131426,7 +142224,7 @@ static void substSelect(
|
|
int doPrior /* Do substitutes on p->pPrior too */
|
|
){
|
|
SrcList *pSrc;
|
|
- struct SrcList_item *pItem;
|
|
+ SrcItem *pItem;
|
|
int i;
|
|
if( !p ) return;
|
|
do{
|
|
@@ -131447,6 +142245,175 @@ static void substSelect(
|
|
}
|
|
#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
|
|
|
|
+#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
|
|
+/*
|
|
+** pSelect is a SELECT statement and pSrcItem is one item in the FROM
|
|
+** clause of that SELECT.
|
|
+**
|
|
+** This routine scans the entire SELECT statement and recomputes the
|
|
+** pSrcItem->colUsed mask.
|
|
+*/
|
|
+static int recomputeColumnsUsedExpr(Walker *pWalker, Expr *pExpr){
|
|
+ SrcItem *pItem;
|
|
+ if( pExpr->op!=TK_COLUMN ) return WRC_Continue;
|
|
+ pItem = pWalker->u.pSrcItem;
|
|
+ if( pItem->iCursor!=pExpr->iTable ) return WRC_Continue;
|
|
+ if( pExpr->iColumn<0 ) return WRC_Continue;
|
|
+ pItem->colUsed |= sqlite3ExprColUsed(pExpr);
|
|
+ return WRC_Continue;
|
|
+}
|
|
+static void recomputeColumnsUsed(
|
|
+ Select *pSelect, /* The complete SELECT statement */
|
|
+ SrcItem *pSrcItem /* Which FROM clause item to recompute */
|
|
+){
|
|
+ Walker w;
|
|
+ if( NEVER(pSrcItem->pTab==0) ) return;
|
|
+ memset(&w, 0, sizeof(w));
|
|
+ w.xExprCallback = recomputeColumnsUsedExpr;
|
|
+ w.xSelectCallback = sqlite3SelectWalkNoop;
|
|
+ w.u.pSrcItem = pSrcItem;
|
|
+ pSrcItem->colUsed = 0;
|
|
+ sqlite3WalkSelect(&w, pSelect);
|
|
+}
|
|
+#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
|
|
+
|
|
+#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
|
|
+/*
|
|
+** Assign new cursor numbers to each of the items in pSrc. For each
|
|
+** new cursor number assigned, set an entry in the aCsrMap[] array
|
|
+** to map the old cursor number to the new:
|
|
+**
|
|
+** aCsrMap[iOld+1] = iNew;
|
|
+**
|
|
+** The array is guaranteed by the caller to be large enough for all
|
|
+** existing cursor numbers in pSrc. aCsrMap[0] is the array size.
|
|
+**
|
|
+** If pSrc contains any sub-selects, call this routine recursively
|
|
+** on the FROM clause of each such sub-select, with iExcept set to -1.
|
|
+*/
|
|
+static void srclistRenumberCursors(
|
|
+ Parse *pParse, /* Parse context */
|
|
+ int *aCsrMap, /* Array to store cursor mappings in */
|
|
+ SrcList *pSrc, /* FROM clause to renumber */
|
|
+ int iExcept /* FROM clause item to skip */
|
|
+){
|
|
+ int i;
|
|
+ SrcItem *pItem;
|
|
+ for(i=0, pItem=pSrc->a; i<pSrc->nSrc; i++, pItem++){
|
|
+ if( i!=iExcept ){
|
|
+ Select *p;
|
|
+ assert( pItem->iCursor < aCsrMap[0] );
|
|
+ if( !pItem->fg.isRecursive || aCsrMap[pItem->iCursor+1]==0 ){
|
|
+ aCsrMap[pItem->iCursor+1] = pParse->nTab++;
|
|
+ }
|
|
+ pItem->iCursor = aCsrMap[pItem->iCursor+1];
|
|
+ for(p=pItem->pSelect; p; p=p->pPrior){
|
|
+ srclistRenumberCursors(pParse, aCsrMap, p->pSrc, -1);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+** *piCursor is a cursor number. Change it if it needs to be mapped.
|
|
+*/
|
|
+static void renumberCursorDoMapping(Walker *pWalker, int *piCursor){
|
|
+ int *aCsrMap = pWalker->u.aiCol;
|
|
+ int iCsr = *piCursor;
|
|
+ if( iCsr < aCsrMap[0] && aCsrMap[iCsr+1]>0 ){
|
|
+ *piCursor = aCsrMap[iCsr+1];
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+** Expression walker callback used by renumberCursors() to update
|
|
+** Expr objects to match newly assigned cursor numbers.
|
|
+*/
|
|
+static int renumberCursorsCb(Walker *pWalker, Expr *pExpr){
|
|
+ int op = pExpr->op;
|
|
+ if( op==TK_COLUMN || op==TK_IF_NULL_ROW ){
|
|
+ renumberCursorDoMapping(pWalker, &pExpr->iTable);
|
|
+ }
|
|
+ if( ExprHasProperty(pExpr, EP_OuterON) ){
|
|
+ renumberCursorDoMapping(pWalker, &pExpr->w.iJoin);
|
|
+ }
|
|
+ return WRC_Continue;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Assign a new cursor number to each cursor in the FROM clause (Select.pSrc)
|
|
+** of the SELECT statement passed as the second argument, and to each
|
|
+** cursor in the FROM clause of any FROM clause sub-selects, recursively.
|
|
+** Except, do not assign a new cursor number to the iExcept'th element in
|
|
+** the FROM clause of (*p). Update all expressions and other references
|
|
+** to refer to the new cursor numbers.
|
|
+**
|
|
+** Argument aCsrMap is an array that may be used for temporary working
|
|
+** space. Two guarantees are made by the caller:
|
|
+**
|
|
+** * the array is larger than the largest cursor number used within the
|
|
+** select statement passed as an argument, and
|
|
+**
|
|
+** * the array entries for all cursor numbers that do *not* appear in
|
|
+** FROM clauses of the select statement as described above are
|
|
+** initialized to zero.
|
|
+*/
|
|
+static void renumberCursors(
|
|
+ Parse *pParse, /* Parse context */
|
|
+ Select *p, /* Select to renumber cursors within */
|
|
+ int iExcept, /* FROM clause item to skip */
|
|
+ int *aCsrMap /* Working space */
|
|
+){
|
|
+ Walker w;
|
|
+ srclistRenumberCursors(pParse, aCsrMap, p->pSrc, iExcept);
|
|
+ memset(&w, 0, sizeof(w));
|
|
+ w.u.aiCol = aCsrMap;
|
|
+ w.xExprCallback = renumberCursorsCb;
|
|
+ w.xSelectCallback = sqlite3SelectWalkNoop;
|
|
+ sqlite3WalkSelect(&w, p);
|
|
+}
|
|
+#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
|
|
+
|
|
+/*
|
|
+** If pSel is not part of a compound SELECT, return a pointer to its
|
|
+** expression list. Otherwise, return a pointer to the expression list
|
|
+** of the leftmost SELECT in the compound.
|
|
+*/
|
|
+static ExprList *findLeftmostExprlist(Select *pSel){
|
|
+ while( pSel->pPrior ){
|
|
+ pSel = pSel->pPrior;
|
|
+ }
|
|
+ return pSel->pEList;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Return true if any of the result-set columns in the compound query
|
|
+** have incompatible affinities on one or more arms of the compound.
|
|
+*/
|
|
+static int compoundHasDifferentAffinities(Select *p){
|
|
+ int ii;
|
|
+ ExprList *pList;
|
|
+ assert( p!=0 );
|
|
+ assert( p->pEList!=0 );
|
|
+ assert( p->pPrior!=0 );
|
|
+ pList = p->pEList;
|
|
+ for(ii=0; ii<pList->nExpr; ii++){
|
|
+ char aff;
|
|
+ Select *pSub1;
|
|
+ assert( pList->a[ii].pExpr!=0 );
|
|
+ aff = sqlite3ExprAffinity(pList->a[ii].pExpr);
|
|
+ for(pSub1=p->pPrior; pSub1; pSub1=pSub1->pPrior){
|
|
+ assert( pSub1->pEList!=0 );
|
|
+ assert( pSub1->pEList->nExpr>ii );
|
|
+ assert( pSub1->pEList->a[ii].pExpr!=0 );
|
|
+ if( sqlite3ExprAffinity(pSub1->pEList->a[ii].pExpr)!=aff ){
|
|
+ return 1;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
|
|
/*
|
|
** This routine attempts to flatten subqueries as a performance optimization.
|
|
@@ -131470,7 +142437,7 @@ static void substSelect(
|
|
** SELECT x+y AS a FROM t1 WHERE z<100 AND a>5
|
|
**
|
|
** The code generated for this simplification gives the same result
|
|
-** but only has to scan the data once. And because indices might
|
|
+** but only has to scan the data once. And because indices might
|
|
** exist on the table t1, a complete scan of the data might be
|
|
** avoided.
|
|
**
|
|
@@ -131491,13 +142458,15 @@ static void substSelect(
|
|
** (3a) the subquery may not be a join and
|
|
** (3b) the FROM clause of the subquery may not contain a virtual
|
|
** table and
|
|
-** (3c) the outer query may not be an aggregate.
|
|
+** (**) Was: "The outer query may not have a GROUP BY." This case
|
|
+** is now managed correctly
|
|
** (3d) the outer query may not be DISTINCT.
|
|
+** See also (26) for restrictions on RIGHT JOIN.
|
|
**
|
|
** (4) The subquery can not be DISTINCT.
|
|
**
|
|
** (**) At one point restrictions (4) and (5) defined a subset of DISTINCT
|
|
-** sub-queries that were excluded from this optimization. Restriction
|
|
+** sub-queries that were excluded from this optimization. Restriction
|
|
** (4) has since been expanded to exclude all DISTINCT subqueries.
|
|
**
|
|
** (**) We no longer attempt to flatten aggregate subqueries. Was:
|
|
@@ -131514,7 +142483,7 @@ static void substSelect(
|
|
**
|
|
** (**) Restriction (10) was removed from the code on 2005-02-05 but we
|
|
** accidently carried the comment forward until 2014-09-15. Original
|
|
-** constraint: "If the subquery is aggregate then the outer query
|
|
+** constraint: "If the subquery is aggregate then the outer query
|
|
** may not use LIMIT."
|
|
**
|
|
** (11) The subquery and the outer query may not both have ORDER BY clauses.
|
|
@@ -131532,7 +142501,7 @@ static void substSelect(
|
|
**
|
|
** (16) If the outer query is aggregate, then the subquery may not
|
|
** use ORDER BY. (Ticket #2942) This used to not matter
|
|
-** until we introduced the group_concat() function.
|
|
+** until we introduced the group_concat() function.
|
|
**
|
|
** (17) If the subquery is a compound select, then
|
|
** (17a) all compound operators must be a UNION ALL, and
|
|
@@ -131541,9 +142510,15 @@ static void substSelect(
|
|
** (17c) every term within the subquery compound must have a FROM clause
|
|
** (17d) the outer query may not be
|
|
** (17d1) aggregate, or
|
|
-** (17d2) DISTINCT, or
|
|
-** (17d3) a join.
|
|
-** (17e) the subquery may not contain window functions
|
|
+** (17d2) DISTINCT
|
|
+** (17e) the subquery may not contain window functions, and
|
|
+** (17f) the subquery must not be the RHS of a LEFT JOIN.
|
|
+** (17g) either the subquery is the first element of the outer
|
|
+** query or there are no RIGHT or FULL JOINs in any arm
|
|
+** of the subquery. (This is a duplicate of condition (27b).)
|
|
+** (17h) The corresponding result set expressions in all arms of the
|
|
+** compound must have the same affinity. (See restriction (9)
|
|
+** on the push-down optimization.)
|
|
**
|
|
** The parent and sub-query may contain WHERE clauses. Subject to
|
|
** rules (11), (13) and (14), they may also contain ORDER BY,
|
|
@@ -131559,8 +142534,8 @@ static void substSelect(
|
|
** syntax error and return a detailed message.
|
|
**
|
|
** (18) If the sub-query is a compound select, then all terms of the
|
|
-** ORDER BY clause of the parent must be simple references to
|
|
-** columns of the sub-query.
|
|
+** ORDER BY clause of the parent must be copies of a term returned
|
|
+** by the parent query.
|
|
**
|
|
** (19) If the subquery uses LIMIT then the outer query may not
|
|
** have a WHERE clause.
|
|
@@ -131576,14 +142551,13 @@ static void substSelect(
|
|
**
|
|
** (22) The subquery may not be a recursive CTE.
|
|
**
|
|
-** (**) Subsumed into restriction (17d3). Was: If the outer query is
|
|
-** a recursive CTE, then the sub-query may not be a compound query.
|
|
-** This restriction is because transforming the
|
|
+** (23) If the outer query is a recursive CTE, then the sub-query may not be
|
|
+** a compound query. This restriction is because transforming the
|
|
** parent to a compound query confuses the code that handles
|
|
** recursive queries in multiSelect().
|
|
**
|
|
** (**) We no longer attempt to flatten aggregate subqueries. Was:
|
|
-** The subquery may not be an aggregate that uses the built-in min() or
|
|
+** The subquery may not be an aggregate that uses the built-in min() or
|
|
** or max() functions. (Without this restriction, a query like:
|
|
** "SELECT x FROM (SELECT max(y), x FROM t1)" would not necessarily
|
|
** return the value X for which Y was maximal.)
|
|
@@ -131592,6 +142566,17 @@ static void substSelect(
|
|
** function in the select list or ORDER BY clause, flattening
|
|
** is not attempted.
|
|
**
|
|
+** (26) The subquery may not be the right operand of a RIGHT JOIN.
|
|
+** See also (3) for restrictions on LEFT JOIN.
|
|
+**
|
|
+** (27) The subquery may not contain a FULL or RIGHT JOIN unless it
|
|
+** is the first element of the parent query. Two subcases:
|
|
+** (27a) the subquery is not a compound query.
|
|
+** (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.
|
|
+**
|
|
**
|
|
** In this routine, the "p" parameter is a pointer to the outer query.
|
|
** The subquery is p->pSrc->a[iFrom]. isAgg is true if the outer query
|
|
@@ -131617,11 +142602,13 @@ static int flattenSubquery(
|
|
SrcList *pSubSrc; /* The FROM clause of the subquery */
|
|
int iParent; /* VDBE cursor number of the pSub result set temp table */
|
|
int iNewParent = -1;/* Replacement table for iParent */
|
|
- int isLeftJoin = 0; /* True if pSub is the right side of a LEFT JOIN */
|
|
+ int isOuterJoin = 0; /* True if pSub is the right side of a LEFT JOIN */
|
|
int i; /* Loop counter */
|
|
Expr *pWhere; /* The WHERE clause */
|
|
- struct SrcList_item *pSubitem; /* The subquery */
|
|
+ SrcItem *pSubitem; /* The subquery */
|
|
sqlite3 *db = pParse->db;
|
|
+ Walker w; /* Walker to persist agginfo data */
|
|
+ int *aCsrMap = 0;
|
|
|
|
/* Check to see if flattening is permitted. Return 0 if not.
|
|
*/
|
|
@@ -131681,32 +142668,26 @@ static int flattenSubquery(
|
|
**
|
|
** which is not at all the same thing.
|
|
**
|
|
- ** If the subquery is the right operand of a LEFT JOIN, then the outer
|
|
- ** query cannot be an aggregate. (3c) This is an artifact of the way
|
|
- ** aggregates are processed - there is no mechanism to determine if
|
|
- ** the LEFT JOIN table should be all-NULL.
|
|
- **
|
|
** See also tickets #306, #350, and #3300.
|
|
*/
|
|
- if( (pSubitem->fg.jointype & JT_OUTER)!=0 ){
|
|
- isLeftJoin = 1;
|
|
- if( pSubSrc->nSrc>1 /* (3a) */
|
|
- || isAgg /* (3b) */
|
|
- || IsVirtual(pSubSrc->a[0].pTab) /* (3c) */
|
|
- || (p->selFlags & SF_Distinct)!=0 /* (3d) */
|
|
+ if( (pSubitem->fg.jointype & (JT_OUTER|JT_LTORJ))!=0 ){
|
|
+ if( pSubSrc->nSrc>1 /* (3a) */
|
|
+ || IsVirtual(pSubSrc->a[0].pTab) /* (3b) */
|
|
+ || (p->selFlags & SF_Distinct)!=0 /* (3d) */
|
|
+ || (pSubitem->fg.jointype & JT_RIGHT)!=0 /* (26) */
|
|
){
|
|
return 0;
|
|
}
|
|
+ isOuterJoin = 1;
|
|
}
|
|
-#ifdef SQLITE_EXTRA_IFNULLROW
|
|
- else if( iFrom>0 && !isAgg ){
|
|
- /* Setting isLeftJoin to -1 causes OP_IfNullRow opcodes to be generated for
|
|
- ** every reference to any result column from subquery in a join, even
|
|
- ** though they are not necessary. This will stress-test the OP_IfNullRow
|
|
- ** opcode. */
|
|
- isLeftJoin = -1;
|
|
+
|
|
+ assert( pSubSrc->nSrc>0 ); /* True by restriction (7) */
|
|
+ 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) */
|
|
}
|
|
-#endif
|
|
|
|
/* 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
|
|
@@ -131714,16 +142695,18 @@ static int flattenSubquery(
|
|
** queries.
|
|
*/
|
|
if( pSub->pPrior ){
|
|
+ int ii;
|
|
if( pSub->pOrderBy ){
|
|
return 0; /* Restriction (20) */
|
|
}
|
|
- if( isAgg || (p->selFlags & SF_Distinct)!=0 || pSrc->nSrc!=1 ){
|
|
- return 0; /* (17d1), (17d2), or (17d3) */
|
|
+ if( isAgg || (p->selFlags & SF_Distinct)!=0 || isOuterJoin>0 ){
|
|
+ return 0; /* (17d1), (17d2), or (17f) */
|
|
}
|
|
for(pSub1=pSub; pSub1; pSub1=pSub1->pPrior){
|
|
testcase( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct );
|
|
testcase( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))==SF_Aggregate );
|
|
assert( pSub->pSrc!=0 );
|
|
+ assert( (pSub->selFlags & SF_Recursive)==0 );
|
|
assert( pSub->pEList->nExpr==pSub1->pEList->nExpr );
|
|
if( (pSub1->selFlags & (SF_Distinct|SF_Aggregate))!=0 /* (17b) */
|
|
|| (pSub1->pPrior && pSub1->op!=TK_ALL) /* (17a) */
|
|
@@ -131734,28 +142717,38 @@ static int flattenSubquery(
|
|
){
|
|
return 0;
|
|
}
|
|
+ if( iFrom>0 && (pSub1->pSrc->a[0].fg.jointype & JT_LTORJ)!=0 ){
|
|
+ /* Without this restriction, the JT_LTORJ flag would end up being
|
|
+ ** omitted on left-hand tables of the right join that is being
|
|
+ ** flattened. */
|
|
+ return 0; /* Restrictions (17g), (27b) */
|
|
+ }
|
|
testcase( pSub1->pSrc->nSrc>1 );
|
|
}
|
|
|
|
/* Restriction (18). */
|
|
if( p->pOrderBy ){
|
|
- int ii;
|
|
for(ii=0; ii<p->pOrderBy->nExpr; ii++){
|
|
if( p->pOrderBy->a[ii].u.x.iOrderByCol==0 ) return 0;
|
|
}
|
|
}
|
|
- }
|
|
|
|
- /* Ex-restriction (23):
|
|
- ** The only way that the recursive part of a CTE can contain a compound
|
|
- ** subquery is for the subquery to be one term of a join. But if the
|
|
- ** subquery is a join, then the flattening has already been stopped by
|
|
- ** restriction (17d3)
|
|
- */
|
|
- assert( (p->selFlags & SF_Recursive)==0 || pSub->pPrior==0 );
|
|
+ /* Restriction (23) */
|
|
+ if( (p->selFlags & SF_Recursive) ) return 0;
|
|
+
|
|
+ /* Restriction (17h) */
|
|
+ if( compoundHasDifferentAffinities(pSub) ) return 0;
|
|
+
|
|
+ if( pSrc->nSrc>1 ){
|
|
+ if( pParse->nSelect>500 ) return 0;
|
|
+ if( OptimizationDisabled(db, SQLITE_FlttnUnionAll) ) return 0;
|
|
+ aCsrMap = sqlite3DbMallocZero(db, ((i64)pParse->nTab+1)*sizeof(int));
|
|
+ if( aCsrMap ) aCsrMap[0] = pParse->nTab;
|
|
+ }
|
|
+ }
|
|
|
|
/***** If we reach this point, flattening is permitted. *****/
|
|
- SELECTTRACE(1,pParse,p,("flatten %u.%p from term %d\n",
|
|
+ TREETRACE(0x4,pParse,p,("flatten %u.%p from term %d\n",
|
|
pSub->selId, pSub, iFrom));
|
|
|
|
/* Authorize the subquery */
|
|
@@ -131764,14 +142757,25 @@ static int flattenSubquery(
|
|
testcase( i==SQLITE_DENY );
|
|
pParse->zAuthContext = zSavedAuthContext;
|
|
|
|
+ /* Delete the transient structures associated with thesubquery */
|
|
+ pSub1 = pSubitem->pSelect;
|
|
+ sqlite3DbFree(db, pSubitem->zDatabase);
|
|
+ sqlite3DbFree(db, pSubitem->zName);
|
|
+ sqlite3DbFree(db, pSubitem->zAlias);
|
|
+ pSubitem->zDatabase = 0;
|
|
+ pSubitem->zName = 0;
|
|
+ pSubitem->zAlias = 0;
|
|
+ pSubitem->pSelect = 0;
|
|
+ assert( pSubitem->fg.isUsing!=0 || pSubitem->u3.pOn==0 );
|
|
+
|
|
/* If the sub-query is a compound SELECT statement, then (by restrictions
|
|
- ** 17 and 18 above) it must be a UNION ALL and the parent query must
|
|
+ ** 17 and 18 above) it must be a UNION ALL and the parent query must
|
|
** be of the form:
|
|
**
|
|
- ** SELECT <expr-list> FROM (<sub-query>) <where-clause>
|
|
+ ** SELECT <expr-list> FROM (<sub-query>) <where-clause>
|
|
**
|
|
** followed by any ORDER BY, LIMIT and/or OFFSET clauses. This block
|
|
- ** creates N-1 copies of the parent query without any ORDER BY, LIMIT or
|
|
+ ** creates N-1 copies of the parent query without any ORDER BY, LIMIT or
|
|
** OFFSET clauses and joins them to the left-hand-side of the original
|
|
** using UNION ALL operators. In this case N is the number of simple
|
|
** select statements in the compound sub-query.
|
|
@@ -131802,43 +142806,37 @@ static int flattenSubquery(
|
|
ExprList *pOrderBy = p->pOrderBy;
|
|
Expr *pLimit = p->pLimit;
|
|
Select *pPrior = p->pPrior;
|
|
+ Table *pItemTab = pSubitem->pTab;
|
|
+ pSubitem->pTab = 0;
|
|
p->pOrderBy = 0;
|
|
- p->pSrc = 0;
|
|
p->pPrior = 0;
|
|
p->pLimit = 0;
|
|
pNew = sqlite3SelectDup(db, p, 0);
|
|
p->pLimit = pLimit;
|
|
p->pOrderBy = pOrderBy;
|
|
- p->pSrc = pSrc;
|
|
p->op = TK_ALL;
|
|
+ pSubitem->pTab = pItemTab;
|
|
if( pNew==0 ){
|
|
p->pPrior = pPrior;
|
|
}else{
|
|
+ pNew->selId = ++pParse->nSelect;
|
|
+ if( aCsrMap && ALWAYS(db->mallocFailed==0) ){
|
|
+ renumberCursors(pParse, pNew, iFrom, aCsrMap);
|
|
+ }
|
|
pNew->pPrior = pPrior;
|
|
if( pPrior ) pPrior->pNext = pNew;
|
|
pNew->pNext = p;
|
|
p->pPrior = pNew;
|
|
- SELECTTRACE(2,pParse,p,("compound-subquery flattener"
|
|
+ TREETRACE(0x4,pParse,p,("compound-subquery flattener"
|
|
" creates %u as peer\n",pNew->selId));
|
|
}
|
|
- if( db->mallocFailed ) return 1;
|
|
+ assert( pSubitem->pSelect==0 );
|
|
+ }
|
|
+ sqlite3DbFree(db, aCsrMap);
|
|
+ if( db->mallocFailed ){
|
|
+ pSubitem->pSelect = pSub1;
|
|
+ return 1;
|
|
}
|
|
-
|
|
- /* Begin flattening the iFrom-th entry of the FROM clause
|
|
- ** in the outer query.
|
|
- */
|
|
- pSub = pSub1 = pSubitem->pSelect;
|
|
-
|
|
- /* Delete the transient table structure associated with the
|
|
- ** subquery
|
|
- */
|
|
- sqlite3DbFree(db, pSubitem->zDatabase);
|
|
- sqlite3DbFree(db, pSubitem->zName);
|
|
- sqlite3DbFree(db, pSubitem->zAlias);
|
|
- pSubitem->zDatabase = 0;
|
|
- pSubitem->zName = 0;
|
|
- pSubitem->zAlias = 0;
|
|
- pSubitem->pSelect = 0;
|
|
|
|
/* Defer deleting the Table object associated with the
|
|
** subquery until code generation is
|
|
@@ -131851,8 +142849,10 @@ static int flattenSubquery(
|
|
Table *pTabToDel = pSubitem->pTab;
|
|
if( pTabToDel->nTabRef==1 ){
|
|
Parse *pToplevel = sqlite3ParseToplevel(pParse);
|
|
- pTabToDel->pNextZombie = pToplevel->pZombieTab;
|
|
- pToplevel->pZombieTab = pTabToDel;
|
|
+ sqlite3ParserAddCleanup(pToplevel,
|
|
+ (void(*)(sqlite3*,void*))sqlite3DeleteTable,
|
|
+ pTabToDel);
|
|
+ testcase( pToplevel->earlyCleanup );
|
|
}else{
|
|
pTabToDel->nTabRef--;
|
|
}
|
|
@@ -131872,22 +142872,18 @@ static int flattenSubquery(
|
|
** those references with expressions that resolve to the subquery FROM
|
|
** elements we are now copying in.
|
|
*/
|
|
+ pSub = pSub1;
|
|
for(pParent=p; pParent; pParent=pParent->pPrior, pSub=pSub->pPrior){
|
|
int nSubSrc;
|
|
u8 jointype = 0;
|
|
+ u8 ltorj = pSrc->a[iFrom].fg.jointype & JT_LTORJ;
|
|
assert( pSub!=0 );
|
|
pSubSrc = pSub->pSrc; /* FROM clause of subquery */
|
|
nSubSrc = pSubSrc->nSrc; /* Number of terms in subquery FROM clause */
|
|
pSrc = pParent->pSrc; /* FROM clause of the outer query */
|
|
|
|
- if( pSrc ){
|
|
- assert( pParent==p ); /* First time through the loop */
|
|
- jointype = pSubitem->fg.jointype;
|
|
- }else{
|
|
- assert( pParent!=p ); /* 2nd and subsequent times through the loop */
|
|
- pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
|
|
- if( pSrc==0 ) break;
|
|
- pParent->pSrc = pSrc;
|
|
+ if( pParent==p ){
|
|
+ jointype = pSubitem->fg.jointype; /* First time through the loop */
|
|
}
|
|
|
|
/* The subquery uses a single slot of the FROM clause of the outer
|
|
@@ -131915,17 +142911,20 @@ static int flattenSubquery(
|
|
** outer query.
|
|
*/
|
|
for(i=0; i<nSubSrc; i++){
|
|
- sqlite3IdListDelete(db, pSrc->a[i+iFrom].pUsing);
|
|
- assert( pSrc->a[i+iFrom].fg.isTabFunc==0 );
|
|
- pSrc->a[i+iFrom] = pSubSrc->a[i];
|
|
+ SrcItem *pItem = &pSrc->a[i+iFrom];
|
|
+ if( pItem->fg.isUsing ) sqlite3IdListDelete(db, pItem->u3.pUsing);
|
|
+ assert( pItem->fg.isTabFunc==0 );
|
|
+ *pItem = pSubSrc->a[i];
|
|
+ pItem->fg.jointype |= ltorj;
|
|
iNewParent = pSubSrc->a[i].iCursor;
|
|
memset(&pSubSrc->a[i], 0, sizeof(pSubSrc->a[i]));
|
|
}
|
|
- pSrc->a[iFrom].fg.jointype = jointype;
|
|
-
|
|
- /* Now begin substituting subquery result set expressions for
|
|
+ pSrc->a[iFrom].fg.jointype &= JT_LTORJ;
|
|
+ pSrc->a[iFrom].fg.jointype |= jointype | ltorj;
|
|
+
|
|
+ /* Now begin substituting subquery result set expressions for
|
|
** references to the iParent in the outer query.
|
|
- **
|
|
+ **
|
|
** Example:
|
|
**
|
|
** SELECT a+5, b*10 FROM (SELECT x*3 AS a, y+10 AS b FROM t1) WHERE a>b;
|
|
@@ -131935,7 +142934,7 @@ static int flattenSubquery(
|
|
** We look at every expression in the outer query and every place we see
|
|
** "a" we substitute "x*3" and every place we see "b" we substitute "y+10".
|
|
*/
|
|
- if( pSub->pOrderBy ){
|
|
+ if( pSub->pOrderBy && (pParent->selFlags & SF_NoopOrderBy)==0 ){
|
|
/* At this point, any non-zero iOrderByCol values indicate that the
|
|
** ORDER BY column expression is identical to the iOrderByCol'th
|
|
** expression returned by SELECT statement pSub. Since these values
|
|
@@ -131956,25 +142955,32 @@ static int flattenSubquery(
|
|
}
|
|
pWhere = pSub->pWhere;
|
|
pSub->pWhere = 0;
|
|
- if( isLeftJoin>0 ){
|
|
- sqlite3SetJoinExpr(pWhere, iNewParent);
|
|
+ if( isOuterJoin>0 ){
|
|
+ sqlite3SetJoinExpr(pWhere, iNewParent, EP_OuterON);
|
|
+ }
|
|
+ if( pWhere ){
|
|
+ if( pParent->pWhere ){
|
|
+ pParent->pWhere = sqlite3PExpr(pParse, TK_AND, pWhere, pParent->pWhere);
|
|
+ }else{
|
|
+ pParent->pWhere = pWhere;
|
|
+ }
|
|
}
|
|
- pParent->pWhere = sqlite3ExprAnd(pParse, pWhere, pParent->pWhere);
|
|
if( db->mallocFailed==0 ){
|
|
SubstContext x;
|
|
x.pParse = pParse;
|
|
x.iTable = iParent;
|
|
x.iNewTable = iNewParent;
|
|
- x.isLeftJoin = isLeftJoin;
|
|
+ x.isOuterJoin = isOuterJoin;
|
|
x.pEList = pSub->pEList;
|
|
+ x.pCList = findLeftmostExprlist(pSub);
|
|
substSelect(&x, pParent, 0);
|
|
}
|
|
-
|
|
+
|
|
/* The flattened query is a compound if either the inner or the
|
|
** outer query is a compound. */
|
|
pParent->selFlags |= pSub->selFlags & SF_Compound;
|
|
assert( (pSub->selFlags & SF_Distinct)==0 ); /* restriction (17b) */
|
|
-
|
|
+
|
|
/*
|
|
** SELECT ... FROM (SELECT ... LIMIT a OFFSET b) LIMIT x OFFSET y;
|
|
**
|
|
@@ -131985,16 +142991,24 @@ static int flattenSubquery(
|
|
pParent->pLimit = pSub->pLimit;
|
|
pSub->pLimit = 0;
|
|
}
|
|
+
|
|
+ /* Recompute the SrcItem.colUsed masks for the flattened
|
|
+ ** tables. */
|
|
+ for(i=0; i<nSubSrc; i++){
|
|
+ recomputeColumnsUsed(pParent, &pSrc->a[i+iFrom]);
|
|
+ }
|
|
}
|
|
|
|
/* Finially, delete what is left of the subquery and return
|
|
** success.
|
|
*/
|
|
+ sqlite3AggInfoPersistWalkerInit(&w, pParse);
|
|
+ sqlite3WalkSelect(&w,pSub1);
|
|
sqlite3SelectDelete(db, pSub1);
|
|
|
|
-#if SELECTTRACE_ENABLED
|
|
- if( sqlite3SelectTrace & 0x100 ){
|
|
- SELECTTRACE(0x100,pParse,p,("After flattening:\n"));
|
|
+#if TREETRACE_ENABLED
|
|
+ if( sqlite3TreeTrace & 0x4 ){
|
|
+ TREETRACE(0x4,pParse,p,("After flattening:\n"));
|
|
sqlite3TreeViewSelect(0, p, 0);
|
|
}
|
|
#endif
|
|
@@ -132010,8 +143024,12 @@ static int flattenSubquery(
|
|
typedef struct WhereConst WhereConst;
|
|
struct WhereConst {
|
|
Parse *pParse; /* Parsing context */
|
|
+ u8 *pOomFault; /* Pointer to pParse->db->mallocFailed */
|
|
int nConst; /* Number for COLUMN=CONSTANT terms */
|
|
int nChng; /* Number of times a constant is propagated */
|
|
+ int bHasAffBlob; /* At least one column in apExpr[] as affinity BLOB */
|
|
+ u32 mExcludeOn; /* Which ON expressions to exclude from considertion.
|
|
+ ** Either EP_OuterON or EP_InnerON|EP_OuterON */
|
|
Expr **apExpr; /* [i*2] is COLUMN and [i*2+1] is VALUE */
|
|
};
|
|
|
|
@@ -132033,9 +143051,8 @@ static void constInsert(
|
|
assert( pColumn->op==TK_COLUMN );
|
|
assert( sqlite3ExprIsConstant(pValue) );
|
|
|
|
- if( !ExprHasProperty(pValue, EP_FixedCol) && sqlite3ExprAffinity(pValue)!=0 ){
|
|
- return;
|
|
- }
|
|
+ if( ExprHasProperty(pColumn, EP_FixedCol) ) return;
|
|
+ if( sqlite3ExprAffinity(pValue)!=0 ) return;
|
|
if( !sqlite3IsBinary(sqlite3ExprCompareCollSeq(pConst->pParse,pExpr)) ){
|
|
return;
|
|
}
|
|
@@ -132051,6 +143068,9 @@ static void constInsert(
|
|
return; /* Already present. Return without doing anything. */
|
|
}
|
|
}
|
|
+ if( sqlite3ExprAffinity(pColumn)==SQLITE_AFF_BLOB ){
|
|
+ pConst->bHasAffBlob = 1;
|
|
+ }
|
|
|
|
pConst->nConst++;
|
|
pConst->apExpr = sqlite3DbReallocOrFree(pConst->pParse->db, pConst->apExpr,
|
|
@@ -132058,9 +143078,6 @@ static void constInsert(
|
|
if( pConst->apExpr==0 ){
|
|
pConst->nConst = 0;
|
|
}else{
|
|
- if( ExprHasProperty(pValue, EP_FixedCol) ){
|
|
- pValue = pValue->pLeft;
|
|
- }
|
|
pConst->apExpr[pConst->nConst*2-2] = pColumn;
|
|
pConst->apExpr[pConst->nConst*2-1] = pValue;
|
|
}
|
|
@@ -132074,8 +143091,12 @@ static void constInsert(
|
|
*/
|
|
static void findConstInWhere(WhereConst *pConst, Expr *pExpr){
|
|
Expr *pRight, *pLeft;
|
|
- if( pExpr==0 ) return;
|
|
- if( ExprHasProperty(pExpr, EP_FromJoin) ) return;
|
|
+ if( NEVER(pExpr==0) ) return;
|
|
+ if( ExprHasProperty(pExpr, pConst->mExcludeOn) ){
|
|
+ testcase( ExprHasProperty(pExpr, EP_OuterON) );
|
|
+ testcase( ExprHasProperty(pExpr, EP_InnerON) );
|
|
+ return;
|
|
+ }
|
|
if( pExpr->op==TK_AND ){
|
|
findConstInWhere(pConst, pExpr->pRight);
|
|
findConstInWhere(pConst, pExpr->pLeft);
|
|
@@ -132095,37 +143116,84 @@ static void findConstInWhere(WhereConst *pConst, Expr *pExpr){
|
|
}
|
|
|
|
/*
|
|
-** This is a Walker expression callback. pExpr is a candidate expression
|
|
-** to be replaced by a value. If pExpr is equivalent to one of the
|
|
-** columns named in pWalker->u.pConst, then overwrite it with its
|
|
-** corresponding value.
|
|
+** This is a helper function for Walker callback propagateConstantExprRewrite().
|
|
+**
|
|
+** Argument pExpr is a candidate expression to be replaced by a value. If
|
|
+** pExpr is equivalent to one of the columns named in pWalker->u.pConst,
|
|
+** then overwrite it with the corresponding value. Except, do not do so
|
|
+** if argument bIgnoreAffBlob is non-zero and the affinity of pExpr
|
|
+** is SQLITE_AFF_BLOB.
|
|
*/
|
|
-static int propagateConstantExprRewrite(Walker *pWalker, Expr *pExpr){
|
|
+static int propagateConstantExprRewriteOne(
|
|
+ WhereConst *pConst,
|
|
+ Expr *pExpr,
|
|
+ int bIgnoreAffBlob
|
|
+){
|
|
int i;
|
|
- WhereConst *pConst;
|
|
+ if( pConst->pOomFault[0] ) return WRC_Prune;
|
|
if( pExpr->op!=TK_COLUMN ) return WRC_Continue;
|
|
- if( ExprHasProperty(pExpr, EP_FixedCol|EP_FromJoin) ){
|
|
+ if( ExprHasProperty(pExpr, EP_FixedCol|pConst->mExcludeOn) ){
|
|
testcase( ExprHasProperty(pExpr, EP_FixedCol) );
|
|
- testcase( ExprHasProperty(pExpr, EP_FromJoin) );
|
|
+ testcase( ExprHasProperty(pExpr, EP_OuterON) );
|
|
+ testcase( ExprHasProperty(pExpr, EP_InnerON) );
|
|
return WRC_Continue;
|
|
}
|
|
- pConst = pWalker->u.pConst;
|
|
for(i=0; i<pConst->nConst; i++){
|
|
Expr *pColumn = pConst->apExpr[i*2];
|
|
if( pColumn==pExpr ) continue;
|
|
if( pColumn->iTable!=pExpr->iTable ) continue;
|
|
if( pColumn->iColumn!=pExpr->iColumn ) continue;
|
|
+ if( bIgnoreAffBlob && sqlite3ExprAffinity(pColumn)==SQLITE_AFF_BLOB ){
|
|
+ break;
|
|
+ }
|
|
/* A match is found. Add the EP_FixedCol property */
|
|
pConst->nChng++;
|
|
ExprClearProperty(pExpr, EP_Leaf);
|
|
ExprSetProperty(pExpr, EP_FixedCol);
|
|
assert( pExpr->pLeft==0 );
|
|
pExpr->pLeft = sqlite3ExprDup(pConst->pParse->db, pConst->apExpr[i*2+1], 0);
|
|
+ if( pConst->pParse->db->mallocFailed ) return WRC_Prune;
|
|
break;
|
|
}
|
|
return WRC_Prune;
|
|
}
|
|
|
|
+/*
|
|
+** This is a Walker expression callback. pExpr is a node from the WHERE
|
|
+** clause of a SELECT statement. This function examines pExpr to see if
|
|
+** any substitutions based on the contents of pWalker->u.pConst should
|
|
+** be made to pExpr or its immediate children.
|
|
+**
|
|
+** A substitution is made if:
|
|
+**
|
|
+** + pExpr is a column with an affinity other than BLOB that matches
|
|
+** one of the columns in pWalker->u.pConst, or
|
|
+**
|
|
+** + pExpr is a binary comparison operator (=, <=, >=, <, >) that
|
|
+** uses an affinity other than TEXT and one of its immediate
|
|
+** children is a column that matches one of the columns in
|
|
+** pWalker->u.pConst.
|
|
+*/
|
|
+static int propagateConstantExprRewrite(Walker *pWalker, Expr *pExpr){
|
|
+ WhereConst *pConst = pWalker->u.pConst;
|
|
+ assert( TK_GT==TK_EQ+1 );
|
|
+ assert( TK_LE==TK_EQ+2 );
|
|
+ assert( TK_LT==TK_EQ+3 );
|
|
+ assert( TK_GE==TK_EQ+4 );
|
|
+ if( pConst->bHasAffBlob ){
|
|
+ if( (pExpr->op>=TK_EQ && pExpr->op<=TK_GE)
|
|
+ || pExpr->op==TK_IS
|
|
+ ){
|
|
+ propagateConstantExprRewriteOne(pConst, pExpr->pLeft, 0);
|
|
+ if( pConst->pOomFault[0] ) return WRC_Prune;
|
|
+ if( sqlite3ExprAffinity(pExpr->pLeft)!=SQLITE_AFF_TEXT ){
|
|
+ propagateConstantExprRewriteOne(pConst, pExpr->pRight, 0);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ return propagateConstantExprRewriteOne(pConst, pExpr, pConst->bHasAffBlob);
|
|
+}
|
|
+
|
|
/*
|
|
** The WHERE-clause constant propagation optimization.
|
|
**
|
|
@@ -132161,6 +143229,21 @@ static int propagateConstantExprRewrite(Walker *pWalker, Expr *pExpr){
|
|
** routines know to generate the constant "123" instead of looking up the
|
|
** column value. Also, to avoid collation problems, this optimization is
|
|
** only attempted if the "a=123" term uses the default BINARY collation.
|
|
+**
|
|
+** 2021-05-25 forum post 6a06202608: Another troublesome case is...
|
|
+**
|
|
+** CREATE TABLE t1(x);
|
|
+** INSERT INTO t1 VALUES(10.0);
|
|
+** SELECT 1 FROM t1 WHERE x=10 AND x LIKE 10;
|
|
+**
|
|
+** The query should return no rows, because the t1.x value is '10.0' not '10'
|
|
+** and '10.0' is not LIKE '10'. But if we are not careful, the first WHERE
|
|
+** term "x=10" will cause the second WHERE term to become "10 LIKE 10",
|
|
+** resulting in a false positive. To avoid this, constant propagation for
|
|
+** columns with BLOB affinity is only allowed if the constant is used with
|
|
+** operators ==, <=, <, >=, >, or IS in a way that will cause the correct
|
|
+** type conversions to occur. See logic associated with the bHasAffBlob flag
|
|
+** for details.
|
|
*/
|
|
static int propagateConstants(
|
|
Parse *pParse, /* The parsing context */
|
|
@@ -132170,10 +143253,23 @@ static int propagateConstants(
|
|
Walker w;
|
|
int nChng = 0;
|
|
x.pParse = pParse;
|
|
+ x.pOomFault = &pParse->db->mallocFailed;
|
|
do{
|
|
x.nConst = 0;
|
|
x.nChng = 0;
|
|
x.apExpr = 0;
|
|
+ x.bHasAffBlob = 0;
|
|
+ if( ALWAYS(p->pSrc!=0)
|
|
+ && p->pSrc->nSrc>0
|
|
+ && (p->pSrc->a[0].fg.jointype & JT_LTORJ)!=0
|
|
+ ){
|
|
+ /* Do not propagate constants on any ON clause if there is a
|
|
+ ** RIGHT JOIN anywhere in the query */
|
|
+ x.mExcludeOn = EP_InnerON | EP_OuterON;
|
|
+ }else{
|
|
+ /* Do not propagate constants through the ON clause of a LEFT JOIN */
|
|
+ x.mExcludeOn = EP_OuterON;
|
|
+ }
|
|
findConstInWhere(&x, p->pWhere);
|
|
if( x.nConst ){
|
|
memset(&w, 0, sizeof(w));
|
|
@@ -132187,10 +143283,39 @@ static int propagateConstants(
|
|
sqlite3DbFree(x.pParse->db, x.apExpr);
|
|
nChng += x.nChng;
|
|
}
|
|
- }while( x.nChng );
|
|
+ }while( x.nChng );
|
|
return nChng;
|
|
}
|
|
|
|
+#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
|
|
+# if !defined(SQLITE_OMIT_WINDOWFUNC)
|
|
+/*
|
|
+** This function is called to determine whether or not it is safe to
|
|
+** push WHERE clause expression pExpr down to FROM clause sub-query
|
|
+** pSubq, which contains at least one window function. Return 1
|
|
+** if it is safe and the expression should be pushed down, or 0
|
|
+** otherwise.
|
|
+**
|
|
+** It is only safe to push the expression down if it consists only
|
|
+** of constants and copies of expressions that appear in the PARTITION
|
|
+** BY clause of all window function used by the sub-query. It is safe
|
|
+** to filter out entire partitions, but not rows within partitions, as
|
|
+** this may change the results of the window functions.
|
|
+**
|
|
+** 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.
|
|
+*/
|
|
+static int pushDownWindowCheck(Parse *pParse, Select *pSubq, Expr *pExpr){
|
|
+ assert( pSubq->pWin->pPartition );
|
|
+ assert( (pSubq->selFlags & SF_MultiPart)==0 );
|
|
+ assert( pSubq->pPrior==0 );
|
|
+ return sqlite3ExprIsConstantOrGroupBy(pParse, pExpr, pSubq->pWin->pPartition);
|
|
+}
|
|
+# endif /* SQLITE_OMIT_WINDOWFUNC */
|
|
+#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
|
|
+
|
|
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
|
|
/*
|
|
** Make copies of relevant WHERE clause terms of the outer query into
|
|
@@ -132238,9 +143363,33 @@ static int propagateConstants(
|
|
** But if the (b2=2) term were to be pushed down into the bb subquery,
|
|
** then the (1,1,NULL) row would be suppressed.
|
|
**
|
|
-** (6) The inner query features one or more window-functions (since
|
|
-** changes to the WHERE clause of the inner query could change the
|
|
-** window over which window functions are calculated).
|
|
+** (6) Window functions make things tricky as changes to the WHERE clause
|
|
+** of the inner query could change the window over which window
|
|
+** functions are calculated. Therefore, do not attempt the optimization
|
|
+** if:
|
|
+**
|
|
+** (6a) The inner query uses multiple incompatible window partitions.
|
|
+**
|
|
+** (6b) The inner query is a compound and uses window-functions.
|
|
+**
|
|
+** (6c) The WHERE clause does not consist entirely of constants and
|
|
+** copies of expressions found in the PARTITION BY clause of
|
|
+** all window-functions used by the sub-query. It is safe to
|
|
+** filter out entire partitions, as this does not change the
|
|
+** window over which any window-function is calculated.
|
|
+**
|
|
+** (7) The inner query is a Common Table Expression (CTE) that should
|
|
+** be materialized. (This restriction is implemented in the calling
|
|
+** routine.)
|
|
+**
|
|
+** (8) If the subquery is a compound that uses UNION, INTERSECT,
|
|
+** or EXCEPT, then all of the result set columns for all arms of
|
|
+** the compound must use the BINARY collating sequence.
|
|
+**
|
|
+** (9) If the subquery is a compound, then all arms of the compound must
|
|
+** have the same affinity. (This is the same as restriction (17h)
|
|
+** for query flattening.)
|
|
+**
|
|
**
|
|
** Return 0 if no changes are made and non-zero if one or more WHERE clause
|
|
** terms are duplicated into the subquery.
|
|
@@ -132249,17 +143398,52 @@ 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 */
|
|
- int iCursor, /* Cursor number of the subquery */
|
|
- int isLeftJoin /* True if pSubq is the right term of a LEFT JOIN */
|
|
+ SrcItem *pSrc /* The subquery term of the outer FROM clause */
|
|
){
|
|
Expr *pNew;
|
|
int nChng = 0;
|
|
if( pWhere==0 ) return 0;
|
|
- if( pSubq->selFlags & SF_Recursive ) return 0; /* restriction (2) */
|
|
+ if( pSubq->selFlags & (SF_Recursive|SF_MultiPart) ) return 0;
|
|
+ if( pSrc->fg.jointype & (JT_LTORJ|JT_RIGHT) ) return 0;
|
|
|
|
+ if( pSubq->pPrior ){
|
|
+ Select *pSel;
|
|
+ int notUnionAll = 0;
|
|
+ for(pSel=pSubq; pSel; pSel=pSel->pPrior){
|
|
+ u8 op = pSel->op;
|
|
+ assert( op==TK_ALL || op==TK_SELECT
|
|
+ || op==TK_UNION || op==TK_INTERSECT || op==TK_EXCEPT );
|
|
+ if( op!=TK_ALL && op!=TK_SELECT ){
|
|
+ notUnionAll = 1;
|
|
+ }
|
|
+#ifndef SQLITE_OMIT_WINDOWFUNC
|
|
+ if( pSel->pWin ) return 0; /* restriction (6b) */
|
|
+#endif
|
|
+ }
|
|
+ if( compoundHasDifferentAffinities(pSubq) ){
|
|
+ return 0; /* restriction (9) */
|
|
+ }
|
|
+ if( notUnionAll ){
|
|
+ /* If any of the compound arms are connected using UNION, INTERSECT,
|
|
+ ** or EXCEPT, then we must ensure that none of the columns use a
|
|
+ ** non-BINARY collating sequence. */
|
|
+ for(pSel=pSubq; pSel; pSel=pSel->pPrior){
|
|
+ int ii;
|
|
+ const ExprList *pList = pSel->pEList;
|
|
+ assert( pList!=0 );
|
|
+ for(ii=0; ii<pList->nExpr; ii++){
|
|
+ CollSeq *pColl = sqlite3ExprCollSeq(pParse, pList->a[ii].pExpr);
|
|
+ if( !sqlite3IsBinary(pColl) ){
|
|
+ return 0; /* Restriction (8) */
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }else{
|
|
#ifndef SQLITE_OMIT_WINDOWFUNC
|
|
- if( pSubq->pWin ) return 0; /* restriction (6) */
|
|
+ if( pSubq->pWin && pSubq->pWin->pPartition==0 ) return 0;
|
|
#endif
|
|
+ }
|
|
|
|
#ifdef SQLITE_DEBUG
|
|
/* Only the first term of a compound can have a WITH clause. But make
|
|
@@ -132267,7 +143451,7 @@ static int pushDownWhereTerms(
|
|
** in the future.
|
|
*/
|
|
{
|
|
- Select *pX;
|
|
+ Select *pX;
|
|
for(pX=pSubq; pX; pX=pX->pPrior){
|
|
assert( (pX->selFlags & (SF_Recursive))==0 );
|
|
}
|
|
@@ -132278,31 +143462,46 @@ static int pushDownWhereTerms(
|
|
return 0; /* restriction (3) */
|
|
}
|
|
while( pWhere->op==TK_AND ){
|
|
- nChng += pushDownWhereTerms(pParse, pSubq, pWhere->pRight,
|
|
- iCursor, isLeftJoin);
|
|
+ nChng += pushDownWhereTerms(pParse, pSubq, pWhere->pRight, pSrc);
|
|
pWhere = pWhere->pLeft;
|
|
}
|
|
+
|
|
+#if 0 /* Legacy code. Checks now done by sqlite3ExprIsTableConstraint() */
|
|
if( isLeftJoin
|
|
- && (ExprHasProperty(pWhere,EP_FromJoin)==0
|
|
- || pWhere->iRightJoinTable!=iCursor)
|
|
+ && (ExprHasProperty(pWhere,EP_OuterON)==0
|
|
+ || pWhere->w.iJoin!=iCursor)
|
|
){
|
|
return 0; /* restriction (4) */
|
|
}
|
|
- if( ExprHasProperty(pWhere,EP_FromJoin) && pWhere->iRightJoinTable!=iCursor ){
|
|
+ if( ExprHasProperty(pWhere,EP_OuterON)
|
|
+ && pWhere->w.iJoin!=iCursor
|
|
+ ){
|
|
return 0; /* restriction (5) */
|
|
}
|
|
- if( sqlite3ExprIsTableConstant(pWhere, iCursor) ){
|
|
+#endif
|
|
+
|
|
+ if( sqlite3ExprIsTableConstraint(pWhere, pSrc) ){
|
|
nChng++;
|
|
+ pSubq->selFlags |= SF_PushDown;
|
|
while( pSubq ){
|
|
SubstContext x;
|
|
pNew = sqlite3ExprDup(pParse->db, pWhere, 0);
|
|
- unsetJoinExpr(pNew, -1);
|
|
+ unsetJoinExpr(pNew, -1, 1);
|
|
x.pParse = pParse;
|
|
- x.iTable = iCursor;
|
|
- x.iNewTable = iCursor;
|
|
- x.isLeftJoin = 0;
|
|
+ x.iTable = pSrc->iCursor;
|
|
+ x.iNewTable = pSrc->iCursor;
|
|
+ x.isOuterJoin = 0;
|
|
x.pEList = pSubq->pEList;
|
|
+ x.pCList = findLeftmostExprlist(pSubq);
|
|
pNew = substExpr(&x, pNew);
|
|
+#ifndef SQLITE_OMIT_WINDOWFUNC
|
|
+ if( pSubq->pWin && 0==pushDownWindowCheck(pParse, pSubq, pNew) ){
|
|
+ /* Restriction 6c has prevented push-down in this case */
|
|
+ sqlite3ExprDelete(pParse->db, pNew);
|
|
+ nChng--;
|
|
+ break;
|
|
+ }
|
|
+#endif
|
|
if( pSubq->selFlags & SF_Aggregate ){
|
|
pSubq->pHaving = sqlite3ExprAnd(pParse, pSubq->pHaving, pNew);
|
|
}else{
|
|
@@ -132317,7 +143516,7 @@ static int pushDownWhereTerms(
|
|
|
|
/*
|
|
** The pFunc is the only aggregate function in the query. Check to see
|
|
-** if the query is a candidate for the min/max optimization.
|
|
+** if the query is a candidate for the min/max optimization.
|
|
**
|
|
** If the query is a candidate for the min/max optimization, then set
|
|
** *ppMinMax to be an ORDER BY clause to be used for the optimization
|
|
@@ -132333,21 +143532,30 @@ static int pushDownWhereTerms(
|
|
*/
|
|
static u8 minMaxQuery(sqlite3 *db, Expr *pFunc, ExprList **ppMinMax){
|
|
int eRet = WHERE_ORDERBY_NORMAL; /* Return value */
|
|
- ExprList *pEList = pFunc->x.pList; /* Arguments to agg function */
|
|
+ ExprList *pEList; /* Arguments to agg function */
|
|
const char *zFunc; /* Name of aggregate function pFunc */
|
|
ExprList *pOrderBy;
|
|
- u8 sortFlags;
|
|
+ u8 sortFlags = 0;
|
|
|
|
assert( *ppMinMax==0 );
|
|
assert( pFunc->op==TK_AGG_FUNCTION );
|
|
assert( !IsWindowFunc(pFunc) );
|
|
- if( pEList==0 || pEList->nExpr!=1 || ExprHasProperty(pFunc, EP_WinFunc) ){
|
|
+ assert( ExprUseXList(pFunc) );
|
|
+ pEList = pFunc->x.pList;
|
|
+ if( pEList==0
|
|
+ || pEList->nExpr!=1
|
|
+ || ExprHasProperty(pFunc, EP_WinFunc)
|
|
+ || OptimizationDisabled(db, SQLITE_MinMaxOpt)
|
|
+ ){
|
|
return eRet;
|
|
}
|
|
+ assert( !ExprHasProperty(pFunc, EP_IntValue) );
|
|
zFunc = pFunc->u.zToken;
|
|
if( sqlite3StrICmp(zFunc, "min")==0 ){
|
|
eRet = WHERE_ORDERBY_MIN;
|
|
- sortFlags = KEYINFO_ORDER_BIGNULL;
|
|
+ if( sqlite3ExprCanBeNull(pEList->a[0].pExpr) ){
|
|
+ sortFlags = KEYINFO_ORDER_BIGNULL;
|
|
+ }
|
|
}else if( sqlite3StrICmp(zFunc, "max")==0 ){
|
|
eRet = WHERE_ORDERBY_MAX;
|
|
sortFlags = KEYINFO_ORDER_DESC;
|
|
@@ -132356,20 +143564,26 @@ static u8 minMaxQuery(sqlite3 *db, Expr *pFunc, ExprList **ppMinMax){
|
|
}
|
|
*ppMinMax = pOrderBy = sqlite3ExprListDup(db, pEList, 0);
|
|
assert( pOrderBy!=0 || db->mallocFailed );
|
|
- if( pOrderBy ) pOrderBy->a[0].sortFlags = sortFlags;
|
|
+ if( pOrderBy ) pOrderBy->a[0].fg.sortFlags = sortFlags;
|
|
return eRet;
|
|
}
|
|
|
|
/*
|
|
** The select statement passed as the first argument is an aggregate query.
|
|
-** The second argument is the associated aggregate-info object. This
|
|
+** The second argument is the associated aggregate-info object. This
|
|
** function tests if the SELECT is of the form:
|
|
**
|
|
** SELECT count(*) FROM <tbl>
|
|
**
|
|
** where table is a database table, not a sub-select or view. If the query
|
|
** does match this pattern, then a pointer to the Table object representing
|
|
-** <tbl> is returned. Otherwise, 0 is returned.
|
|
+** <tbl> is returned. Otherwise, NULL is returned.
|
|
+**
|
|
+** This routine checks to see if it is safe to use the count optimization.
|
|
+** A correct answer is still obtained (though perhaps more slowly) if
|
|
+** this routine returns NULL when it could have returned a table pointer.
|
|
+** But returning the pointer when NULL should have been returned can
|
|
+** result in incorrect answers and/or crashes. So, when in doubt, return NULL.
|
|
*/
|
|
static Table *isSimpleCount(Select *p, AggInfo *pAggInfo){
|
|
Table *pTab;
|
|
@@ -132377,19 +143591,27 @@ static Table *isSimpleCount(Select *p, AggInfo *pAggInfo){
|
|
|
|
assert( !p->pGroupBy );
|
|
|
|
- if( p->pWhere || p->pEList->nExpr!=1
|
|
- || p->pSrc->nSrc!=1 || p->pSrc->a[0].pSelect
|
|
+ if( p->pWhere
|
|
+ || p->pEList->nExpr!=1
|
|
+ || p->pSrc->nSrc!=1
|
|
+ || p->pSrc->a[0].pSelect
|
|
+ || pAggInfo->nFunc!=1
|
|
+ || p->pHaving
|
|
){
|
|
return 0;
|
|
}
|
|
pTab = p->pSrc->a[0].pTab;
|
|
+ assert( pTab!=0 );
|
|
+ assert( !IsView(pTab) );
|
|
+ if( !IsOrdinaryTable(pTab) ) return 0;
|
|
pExpr = p->pEList->a[0].pExpr;
|
|
- assert( pTab && !pTab->pSelect && pExpr );
|
|
-
|
|
- if( IsVirtual(pTab) ) return 0;
|
|
+ assert( pExpr!=0 );
|
|
if( pExpr->op!=TK_AGG_FUNCTION ) return 0;
|
|
- if( NEVER(pAggInfo->nFunc==0) ) return 0;
|
|
+ if( pExpr->pAggInfo!=pAggInfo ) return 0;
|
|
if( (pAggInfo->aFunc[0].pFunc->funcFlags&SQLITE_FUNC_COUNT)==0 ) return 0;
|
|
+ assert( pAggInfo->aFunc[0].pFExpr==pExpr );
|
|
+ testcase( ExprHasProperty(pExpr, EP_Distinct) );
|
|
+ testcase( ExprHasProperty(pExpr, EP_WinFunc) );
|
|
if( ExprHasProperty(pExpr, EP_Distinct|EP_WinFunc) ) return 0;
|
|
|
|
return pTab;
|
|
@@ -132398,30 +143620,33 @@ static Table *isSimpleCount(Select *p, AggInfo *pAggInfo){
|
|
/*
|
|
** If the source-list item passed as an argument was augmented with an
|
|
** INDEXED BY clause, then try to locate the specified index. If there
|
|
-** was such a clause and the named index cannot be found, return
|
|
-** SQLITE_ERROR and leave an error in pParse. Otherwise, populate
|
|
+** was such a clause and the named index cannot be found, return
|
|
+** SQLITE_ERROR and leave an error in pParse. Otherwise, populate
|
|
** pFrom->pIndex and return SQLITE_OK.
|
|
*/
|
|
-SQLITE_PRIVATE int sqlite3IndexedByLookup(Parse *pParse, struct SrcList_item *pFrom){
|
|
- if( pFrom->pTab && pFrom->fg.isIndexedBy ){
|
|
- Table *pTab = pFrom->pTab;
|
|
- char *zIndexedBy = pFrom->u1.zIndexedBy;
|
|
- Index *pIdx;
|
|
- for(pIdx=pTab->pIndex;
|
|
- pIdx && sqlite3StrICmp(pIdx->zName, zIndexedBy);
|
|
- pIdx=pIdx->pNext
|
|
- );
|
|
- if( !pIdx ){
|
|
- sqlite3ErrorMsg(pParse, "no such index: %s", zIndexedBy, 0);
|
|
- pParse->checkSchema = 1;
|
|
- return SQLITE_ERROR;
|
|
- }
|
|
- pFrom->pIBIndex = pIdx;
|
|
+SQLITE_PRIVATE int sqlite3IndexedByLookup(Parse *pParse, SrcItem *pFrom){
|
|
+ Table *pTab = pFrom->pTab;
|
|
+ char *zIndexedBy = pFrom->u1.zIndexedBy;
|
|
+ Index *pIdx;
|
|
+ assert( pTab!=0 );
|
|
+ assert( pFrom->fg.isIndexedBy!=0 );
|
|
+
|
|
+ for(pIdx=pTab->pIndex;
|
|
+ pIdx && sqlite3StrICmp(pIdx->zName, zIndexedBy);
|
|
+ pIdx=pIdx->pNext
|
|
+ );
|
|
+ if( !pIdx ){
|
|
+ sqlite3ErrorMsg(pParse, "no such index: %s", zIndexedBy, 0);
|
|
+ pParse->checkSchema = 1;
|
|
+ return SQLITE_ERROR;
|
|
}
|
|
+ assert( pFrom->fg.isCte==0 );
|
|
+ pFrom->u2.pIBIndex = pIdx;
|
|
return SQLITE_OK;
|
|
}
|
|
+
|
|
/*
|
|
-** Detect compound SELECT statements that use an ORDER BY clause with
|
|
+** Detect compound SELECT statements that use an ORDER BY clause with
|
|
** an alternative collating sequence.
|
|
**
|
|
** SELECT ... FROM t1 EXCEPT SELECT ... FROM t2 ORDER BY .. COLLATE ...
|
|
@@ -132456,6 +143681,14 @@ static int convertCompoundSelectToSubquery(Walker *pWalker, Select *p){
|
|
for(pX=p; pX && (pX->op==TK_ALL || pX->op==TK_SELECT); pX=pX->pPrior){}
|
|
if( pX==0 ) return WRC_Continue;
|
|
a = p->pOrderBy->a;
|
|
+#ifndef SQLITE_OMIT_WINDOWFUNC
|
|
+ /* If iOrderByCol is already non-zero, then it has already been matched
|
|
+ ** to a result column of the SELECT statement. This occurs when the
|
|
+ ** SELECT is rewritten for window-functions processing and then passed
|
|
+ ** to sqlite3SelectPrep() and similar a second time. The rewriting done
|
|
+ ** by this function is not required in this case. */
|
|
+ if( a[0].u.x.iOrderByCol ) return WRC_Continue;
|
|
+#endif
|
|
for(i=p->pOrderBy->nExpr-1; i>=0; i--){
|
|
if( a[i].pExpr->flags & EP_Collate ) break;
|
|
}
|
|
@@ -132468,7 +143701,7 @@ static int convertCompoundSelectToSubquery(Walker *pWalker, Select *p){
|
|
pNew = sqlite3DbMallocZero(db, sizeof(*pNew) );
|
|
if( pNew==0 ) return WRC_Abort;
|
|
memset(&dummy, 0, sizeof(dummy));
|
|
- pNewSrc = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&dummy,pNew,0,0);
|
|
+ pNewSrc = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&dummy,pNew,0);
|
|
if( pNewSrc==0 ) return WRC_Abort;
|
|
*pNew = *p;
|
|
p->pSrc = pNewSrc;
|
|
@@ -132498,7 +143731,7 @@ static int convertCompoundSelectToSubquery(Walker *pWalker, Select *p){
|
|
** arguments. If it does, leave an error message in pParse and return
|
|
** non-zero, since pFrom is not allowed to be a table-valued function.
|
|
*/
|
|
-static int cannotBeFunction(Parse *pParse, struct SrcList_item *pFrom){
|
|
+static int cannotBeFunction(Parse *pParse, SrcItem *pFrom){
|
|
if( pFrom->fg.isTabFunc ){
|
|
sqlite3ErrorMsg(pParse, "'%s' is not a function", pFrom->zName);
|
|
return 1;
|
|
@@ -132508,9 +143741,9 @@ static int cannotBeFunction(Parse *pParse, struct SrcList_item *pFrom){
|
|
|
|
#ifndef SQLITE_OMIT_CTE
|
|
/*
|
|
-** Argument pWith (which may be NULL) points to a linked list of nested
|
|
-** WITH contexts, from inner to outermost. If the table identified by
|
|
-** FROM clause element pItem is really a common-table-expression (CTE)
|
|
+** Argument pWith (which may be NULL) points to a linked list of nested
|
|
+** WITH contexts, from inner to outermost. If the table identified by
|
|
+** FROM clause element pItem is really a common-table-expression (CTE)
|
|
** then return a pointer to the CTE definition for that table. Otherwise
|
|
** return NULL.
|
|
**
|
|
@@ -132519,21 +143752,22 @@ static int cannotBeFunction(Parse *pParse, struct SrcList_item *pFrom){
|
|
*/
|
|
static struct Cte *searchWith(
|
|
With *pWith, /* Current innermost WITH clause */
|
|
- struct SrcList_item *pItem, /* FROM clause element to resolve */
|
|
+ SrcItem *pItem, /* FROM clause element to resolve */
|
|
With **ppContext /* OUT: WITH clause return value belongs to */
|
|
){
|
|
- const char *zName;
|
|
- if( pItem->zDatabase==0 && (zName = pItem->zName)!=0 ){
|
|
- With *p;
|
|
- for(p=pWith; p; p=p->pOuter){
|
|
- int i;
|
|
- for(i=0; i<p->nCte; i++){
|
|
- if( sqlite3StrICmp(zName, p->a[i].zName)==0 ){
|
|
- *ppContext = p;
|
|
- return &p->a[i];
|
|
- }
|
|
+ const char *zName = pItem->zName;
|
|
+ With *p;
|
|
+ assert( pItem->zDatabase==0 );
|
|
+ assert( zName!=0 );
|
|
+ for(p=pWith; p; p=p->pOuter){
|
|
+ int i;
|
|
+ for(i=0; i<p->nCte; i++){
|
|
+ if( sqlite3StrICmp(zName, p->a[i].zName)==0 ){
|
|
+ *ppContext = p;
|
|
+ return &p->a[i];
|
|
}
|
|
}
|
|
+ if( p->bView ) break;
|
|
}
|
|
return 0;
|
|
}
|
|
@@ -132543,58 +143777,92 @@ static struct Cte *searchWith(
|
|
**
|
|
** This routine pushes the WITH clause passed as the second argument
|
|
** onto the top of the stack. If argument bFree is true, then this
|
|
-** WITH clause will never be popped from the stack. In this case it
|
|
-** should be freed along with the Parse object. In other cases, when
|
|
-** bFree==0, the With object will be freed along with the SELECT
|
|
+** WITH clause will never be popped from the stack but should instead
|
|
+** be freed along with the Parse object. In other cases, when
|
|
+** bFree==0, the With object will be freed along with the SELECT
|
|
** statement with which it is associated.
|
|
+**
|
|
+** This routine returns a copy of pWith. Or, if bFree is true and
|
|
+** the pWith object is destroyed immediately due to an OOM condition,
|
|
+** then this routine return NULL.
|
|
+**
|
|
+** If bFree is true, do not continue to use the pWith pointer after
|
|
+** calling this routine, Instead, use only the return value.
|
|
*/
|
|
-SQLITE_PRIVATE void sqlite3WithPush(Parse *pParse, With *pWith, u8 bFree){
|
|
- assert( bFree==0 || (pParse->pWith==0 && pParse->pWithToFree==0) );
|
|
+SQLITE_PRIVATE With *sqlite3WithPush(Parse *pParse, With *pWith, u8 bFree){
|
|
if( pWith ){
|
|
- assert( pParse->pWith!=pWith );
|
|
- pWith->pOuter = pParse->pWith;
|
|
- pParse->pWith = pWith;
|
|
- if( bFree ) pParse->pWithToFree = pWith;
|
|
+ if( bFree ){
|
|
+ pWith = (With*)sqlite3ParserAddCleanup(pParse,
|
|
+ (void(*)(sqlite3*,void*))sqlite3WithDelete,
|
|
+ pWith);
|
|
+ if( pWith==0 ) return 0;
|
|
+ }
|
|
+ if( pParse->nErr==0 ){
|
|
+ assert( pParse->pWith!=pWith );
|
|
+ pWith->pOuter = pParse->pWith;
|
|
+ pParse->pWith = pWith;
|
|
+ }
|
|
}
|
|
+ return pWith;
|
|
}
|
|
|
|
/*
|
|
-** This function checks if argument pFrom refers to a CTE declared by
|
|
-** a WITH clause on the stack currently maintained by the parser. And,
|
|
-** if currently processing a CTE expression, if it is a recursive
|
|
-** reference to the current CTE.
|
|
+** This function checks if argument pFrom refers to a CTE declared by
|
|
+** a WITH clause on the stack currently maintained by the parser (on the
|
|
+** pParse->pWith linked list). And if currently processing a CTE
|
|
+** CTE expression, through routine checks to see if the reference is
|
|
+** a recursive reference to the CTE.
|
|
**
|
|
-** If pFrom falls into either of the two categories above, pFrom->pTab
|
|
-** and other fields are populated accordingly. The caller should check
|
|
-** (pFrom->pTab!=0) to determine whether or not a successful match
|
|
-** was found.
|
|
+** If pFrom matches a CTE according to either of these two above, pFrom->pTab
|
|
+** and other fields are populated accordingly.
|
|
**
|
|
-** Whether or not a match is found, SQLITE_OK is returned if no error
|
|
-** occurs. If an error does occur, an error message is stored in the
|
|
-** parser and some error code other than SQLITE_OK returned.
|
|
+** Return 0 if no match is found.
|
|
+** Return 1 if a match is found.
|
|
+** Return 2 if an error condition is detected.
|
|
*/
|
|
-static int withExpand(
|
|
- Walker *pWalker,
|
|
- struct SrcList_item *pFrom
|
|
+static int resolveFromTermToCte(
|
|
+ Parse *pParse, /* The parsing context */
|
|
+ Walker *pWalker, /* Current tree walker */
|
|
+ SrcItem *pFrom /* The FROM clause term to check */
|
|
){
|
|
- Parse *pParse = pWalker->pParse;
|
|
- sqlite3 *db = pParse->db;
|
|
- struct Cte *pCte; /* Matched CTE (or NULL if no match) */
|
|
- With *pWith; /* WITH clause that pCte belongs to */
|
|
+ Cte *pCte; /* Matched CTE (or NULL if no match) */
|
|
+ With *pWith; /* The matching WITH */
|
|
|
|
assert( pFrom->pTab==0 );
|
|
+ if( pParse->pWith==0 ){
|
|
+ /* There are no WITH clauses in the stack. No match is possible */
|
|
+ return 0;
|
|
+ }
|
|
if( pParse->nErr ){
|
|
- return SQLITE_ERROR;
|
|
+ /* Prior errors might have left pParse->pWith in a goofy state, so
|
|
+ ** go no further. */
|
|
+ return 0;
|
|
+ }
|
|
+ if( pFrom->zDatabase!=0 ){
|
|
+ /* The FROM term contains a schema qualifier (ex: main.t1) and so
|
|
+ ** it cannot possibly be a CTE reference. */
|
|
+ return 0;
|
|
+ }
|
|
+ if( pFrom->fg.notCte ){
|
|
+ /* The FROM term is specifically excluded from matching a CTE.
|
|
+ ** (1) It is part of a trigger that used to have zDatabase but had
|
|
+ ** zDatabase removed by sqlite3FixTriggerStep().
|
|
+ ** (2) This is the first term in the FROM clause of an UPDATE.
|
|
+ */
|
|
+ return 0;
|
|
}
|
|
-
|
|
pCte = searchWith(pParse->pWith, pFrom, &pWith);
|
|
if( pCte ){
|
|
+ sqlite3 *db = pParse->db;
|
|
Table *pTab;
|
|
ExprList *pEList;
|
|
Select *pSel;
|
|
Select *pLeft; /* Left-most SELECT statement */
|
|
+ Select *pRecTerm; /* Left-most recursive term */
|
|
int bMayRecursive; /* True if compound joined by UNION [ALL] */
|
|
With *pSavedWith; /* Initial value of pParse->pWith */
|
|
+ int iRecTab = -1; /* Cursor for recursive table */
|
|
+ CteUse *pCteUse;
|
|
|
|
/* If pCte->zCteErr is non-NULL at this point, then this is an illegal
|
|
** recursive reference to CTE pCte. Leave an error in pParse and return
|
|
@@ -132602,63 +143870,95 @@ static int withExpand(
|
|
** In this case, proceed. */
|
|
if( pCte->zCteErr ){
|
|
sqlite3ErrorMsg(pParse, pCte->zCteErr, pCte->zName);
|
|
- return SQLITE_ERROR;
|
|
+ return 2;
|
|
}
|
|
- if( cannotBeFunction(pParse, pFrom) ) return SQLITE_ERROR;
|
|
+ if( cannotBeFunction(pParse, pFrom) ) return 2;
|
|
|
|
assert( pFrom->pTab==0 );
|
|
- pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table));
|
|
- if( pTab==0 ) return WRC_Abort;
|
|
+ pTab = sqlite3DbMallocZero(db, sizeof(Table));
|
|
+ if( pTab==0 ) return 2;
|
|
+ pCteUse = pCte->pUse;
|
|
+ if( pCteUse==0 ){
|
|
+ pCte->pUse = pCteUse = sqlite3DbMallocZero(db, sizeof(pCteUse[0]));
|
|
+ if( pCteUse==0
|
|
+ || sqlite3ParserAddCleanup(pParse,sqlite3DbFree,pCteUse)==0
|
|
+ ){
|
|
+ sqlite3DbFree(db, pTab);
|
|
+ return 2;
|
|
+ }
|
|
+ pCteUse->eM10d = pCte->eM10d;
|
|
+ }
|
|
+ pFrom->pTab = pTab;
|
|
pTab->nTabRef = 1;
|
|
pTab->zName = sqlite3DbStrDup(db, pCte->zName);
|
|
pTab->iPKey = -1;
|
|
pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
|
|
pTab->tabFlags |= TF_Ephemeral | TF_NoVisibleRowid;
|
|
pFrom->pSelect = sqlite3SelectDup(db, pCte->pSelect, 0);
|
|
- if( db->mallocFailed ) return SQLITE_NOMEM_BKPT;
|
|
+ if( db->mallocFailed ) return 2;
|
|
+ pFrom->pSelect->selFlags |= SF_CopyCte;
|
|
assert( pFrom->pSelect );
|
|
+ if( pFrom->fg.isIndexedBy ){
|
|
+ sqlite3ErrorMsg(pParse, "no such index: \"%s\"", pFrom->u1.zIndexedBy);
|
|
+ return 2;
|
|
+ }
|
|
+ pFrom->fg.isCte = 1;
|
|
+ pFrom->u2.pCteUse = pCteUse;
|
|
+ pCteUse->nUse++;
|
|
|
|
/* Check if this is a recursive CTE. */
|
|
- pSel = pFrom->pSelect;
|
|
+ pRecTerm = pSel = pFrom->pSelect;
|
|
bMayRecursive = ( pSel->op==TK_ALL || pSel->op==TK_UNION );
|
|
- if( bMayRecursive ){
|
|
+ while( bMayRecursive && pRecTerm->op==pSel->op ){
|
|
int i;
|
|
- SrcList *pSrc = pFrom->pSelect->pSrc;
|
|
+ SrcList *pSrc = pRecTerm->pSrc;
|
|
+ assert( pRecTerm->pPrior!=0 );
|
|
for(i=0; i<pSrc->nSrc; i++){
|
|
- struct SrcList_item *pItem = &pSrc->a[i];
|
|
- if( pItem->zDatabase==0
|
|
- && pItem->zName!=0
|
|
+ SrcItem *pItem = &pSrc->a[i];
|
|
+ if( pItem->zDatabase==0
|
|
+ && pItem->zName!=0
|
|
&& 0==sqlite3StrICmp(pItem->zName, pCte->zName)
|
|
- ){
|
|
+ ){
|
|
pItem->pTab = pTab;
|
|
- pItem->fg.isRecursive = 1;
|
|
pTab->nTabRef++;
|
|
- pSel->selFlags |= SF_Recursive;
|
|
+ pItem->fg.isRecursive = 1;
|
|
+ if( pRecTerm->selFlags & SF_Recursive ){
|
|
+ sqlite3ErrorMsg(pParse,
|
|
+ "multiple references to recursive table: %s", pCte->zName
|
|
+ );
|
|
+ return 2;
|
|
+ }
|
|
+ pRecTerm->selFlags |= SF_Recursive;
|
|
+ if( iRecTab<0 ) iRecTab = pParse->nTab++;
|
|
+ pItem->iCursor = iRecTab;
|
|
}
|
|
}
|
|
+ if( (pRecTerm->selFlags & SF_Recursive)==0 ) break;
|
|
+ pRecTerm = pRecTerm->pPrior;
|
|
}
|
|
|
|
- /* Only one recursive reference is permitted. */
|
|
- if( pTab->nTabRef>2 ){
|
|
- sqlite3ErrorMsg(
|
|
- pParse, "multiple references to recursive table: %s", pCte->zName
|
|
- );
|
|
- return SQLITE_ERROR;
|
|
- }
|
|
- assert( pTab->nTabRef==1 ||
|
|
- ((pSel->selFlags&SF_Recursive) && pTab->nTabRef==2 ));
|
|
-
|
|
pCte->zCteErr = "circular reference: %s";
|
|
pSavedWith = pParse->pWith;
|
|
pParse->pWith = pWith;
|
|
- if( bMayRecursive ){
|
|
- Select *pPrior = pSel->pPrior;
|
|
- assert( pPrior->pWith==0 );
|
|
- pPrior->pWith = pSel->pWith;
|
|
- sqlite3WalkSelect(pWalker, pPrior);
|
|
- pPrior->pWith = 0;
|
|
+ if( pSel->selFlags & SF_Recursive ){
|
|
+ int rc;
|
|
+ assert( pRecTerm!=0 );
|
|
+ assert( (pRecTerm->selFlags & SF_Recursive)==0 );
|
|
+ assert( pRecTerm->pNext!=0 );
|
|
+ assert( (pRecTerm->pNext->selFlags & SF_Recursive)!=0 );
|
|
+ assert( pRecTerm->pWith==0 );
|
|
+ pRecTerm->pWith = pSel->pWith;
|
|
+ rc = sqlite3WalkSelect(pWalker, pRecTerm);
|
|
+ pRecTerm->pWith = 0;
|
|
+ if( rc ){
|
|
+ pParse->pWith = pSavedWith;
|
|
+ return 2;
|
|
+ }
|
|
}else{
|
|
- sqlite3WalkSelect(pWalker, pSel);
|
|
+ if( sqlite3WalkSelect(pWalker, pSel) ){
|
|
+ pParse->pWith = pSavedWith;
|
|
+ return 2;
|
|
+ }
|
|
}
|
|
pParse->pWith = pWith;
|
|
|
|
@@ -132670,7 +143970,7 @@ static int withExpand(
|
|
pCte->zName, pEList->nExpr, pCte->pCols->nExpr
|
|
);
|
|
pParse->pWith = pSavedWith;
|
|
- return SQLITE_ERROR;
|
|
+ return 2;
|
|
}
|
|
pEList = pCte->pCols;
|
|
}
|
|
@@ -132686,22 +143986,22 @@ static int withExpand(
|
|
}
|
|
pCte->zCteErr = 0;
|
|
pParse->pWith = pSavedWith;
|
|
+ return 1; /* Success */
|
|
}
|
|
-
|
|
- return SQLITE_OK;
|
|
+ return 0; /* No match */
|
|
}
|
|
#endif
|
|
|
|
#ifndef SQLITE_OMIT_CTE
|
|
/*
|
|
-** If the SELECT passed as the second argument has an associated WITH
|
|
+** If the SELECT passed as the second argument has an associated WITH
|
|
** clause, pop it from the stack stored as part of the Parse object.
|
|
**
|
|
** This function is used as the xSelectCallback2() callback by
|
|
** sqlite3SelectExpand() when walking a SELECT tree to resolve table
|
|
-** names and other FROM clause elements.
|
|
+** names and other FROM clause elements.
|
|
*/
|
|
-static void selectPopWith(Walker *pWalker, Select *p){
|
|
+SQLITE_PRIVATE void sqlite3SelectPopWith(Walker *pWalker, Select *p){
|
|
Parse *pParse = pWalker->pParse;
|
|
if( OK_IF_ALWAYS_TRUE(pParse->pWith) && p->pPrior==0 ){
|
|
With *pWith = findRightmost(p)->pWith;
|
|
@@ -132711,18 +144011,16 @@ static void selectPopWith(Walker *pWalker, Select *p){
|
|
}
|
|
}
|
|
}
|
|
-#else
|
|
-#define selectPopWith 0
|
|
#endif
|
|
|
|
/*
|
|
-** The SrcList_item structure passed as the second argument represents a
|
|
+** The SrcItem structure passed as the second argument represents a
|
|
** sub-query in the FROM clause of a SELECT statement. This function
|
|
-** allocates and populates the SrcList_item.pTab object. If successful,
|
|
+** allocates and populates the SrcItem.pTab object. If successful,
|
|
** SQLITE_OK is returned. Otherwise, if an OOM error is encountered,
|
|
** SQLITE_NOMEM.
|
|
*/
|
|
-SQLITE_PRIVATE int sqlite3ExpandSubquery(Parse *pParse, struct SrcList_item *pFrom){
|
|
+SQLITE_PRIVATE int sqlite3ExpandSubquery(Parse *pParse, SrcItem *pFrom){
|
|
Select *pSel = pFrom->pSelect;
|
|
Table *pTab;
|
|
|
|
@@ -132733,17 +144031,47 @@ SQLITE_PRIVATE int sqlite3ExpandSubquery(Parse *pParse, struct SrcList_item *pFr
|
|
if( pFrom->zAlias ){
|
|
pTab->zName = sqlite3DbStrDup(pParse->db, pFrom->zAlias);
|
|
}else{
|
|
- pTab->zName = sqlite3MPrintf(pParse->db, "subquery_%u", pSel->selId);
|
|
+ pTab->zName = sqlite3MPrintf(pParse->db, "%!S", pFrom);
|
|
}
|
|
while( pSel->pPrior ){ pSel = pSel->pPrior; }
|
|
sqlite3ColumnsFromExprList(pParse, pSel->pEList,&pTab->nCol,&pTab->aCol);
|
|
pTab->iPKey = -1;
|
|
pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
|
|
- pTab->tabFlags |= TF_Ephemeral;
|
|
-
|
|
+#ifndef SQLITE_ALLOW_ROWID_IN_VIEW
|
|
+ /* The usual case - do not allow ROWID on a subquery */
|
|
+ pTab->tabFlags |= TF_Ephemeral | TF_NoVisibleRowid;
|
|
+#else
|
|
+ pTab->tabFlags |= TF_Ephemeral; /* Legacy compatibility mode */
|
|
+#endif
|
|
return pParse->nErr ? SQLITE_ERROR : SQLITE_OK;
|
|
}
|
|
|
|
+
|
|
+/*
|
|
+** Check the N SrcItem objects to the right of pBase. (N might be zero!)
|
|
+** If any of those SrcItem objects have a USING clause containing zName
|
|
+** then return true.
|
|
+**
|
|
+** If N is zero, or none of the N SrcItem objects to the right of pBase
|
|
+** contains a USING clause, or if none of the USING clauses contain zName,
|
|
+** then return false.
|
|
+*/
|
|
+static int inAnyUsingClause(
|
|
+ const char *zName, /* Name we are looking for */
|
|
+ SrcItem *pBase, /* The base SrcItem. Looking at pBase[1] and following */
|
|
+ int N /* How many SrcItems to check */
|
|
+){
|
|
+ while( N>0 ){
|
|
+ N--;
|
|
+ pBase++;
|
|
+ if( pBase->fg.isUsing==0 ) continue;
|
|
+ if( NEVER(pBase->u3.pUsing==0) ) continue;
|
|
+ if( sqlite3IdListIndex(pBase->u3.pUsing, zName)>=0 ) return 1;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+
|
|
/*
|
|
** This routine is a Walker callback for "expanding" a SELECT statement.
|
|
** "Expanding" means to do the following:
|
|
@@ -132751,7 +144079,7 @@ SQLITE_PRIVATE int sqlite3ExpandSubquery(Parse *pParse, struct SrcList_item *pFr
|
|
** (1) Make sure VDBE cursor numbers have been assigned to every
|
|
** element of the FROM clause.
|
|
**
|
|
-** (2) Fill in the pTabList->a[].pTab fields in the SrcList that
|
|
+** (2) Fill in the pTabList->a[].pTab fields in the SrcList that
|
|
** defines FROM clause. When views appear in the FROM clause,
|
|
** fill pTabList->a[].pSelect with a copy of the SELECT statement
|
|
** that implements the view. A copy is made of the view's SELECT
|
|
@@ -132770,10 +144098,10 @@ SQLITE_PRIVATE int sqlite3ExpandSubquery(Parse *pParse, struct SrcList_item *pFr
|
|
*/
|
|
static int selectExpander(Walker *pWalker, Select *p){
|
|
Parse *pParse = pWalker->pParse;
|
|
- int i, j, k;
|
|
+ int i, j, k, rc;
|
|
SrcList *pTabList;
|
|
ExprList *pEList;
|
|
- struct SrcList_item *pFrom;
|
|
+ SrcItem *pFrom;
|
|
sqlite3 *db = pParse->db;
|
|
Expr *pE, *pRight, *pExpr;
|
|
u16 selFlags = p->selFlags;
|
|
@@ -132793,6 +144121,15 @@ static int selectExpander(Walker *pWalker, Select *p){
|
|
}
|
|
pTabList = p->pSrc;
|
|
pEList = p->pEList;
|
|
+ if( pParse->pWith && (p->selFlags & SF_View) ){
|
|
+ if( p->pWith==0 ){
|
|
+ p->pWith = (With*)sqlite3DbMallocZero(db, sizeof(With));
|
|
+ if( p->pWith==0 ){
|
|
+ return WRC_Abort;
|
|
+ }
|
|
+ }
|
|
+ p->pWith->bView = 1;
|
|
+ }
|
|
sqlite3WithPush(pParse, p->pWith, 0);
|
|
|
|
/* Make sure cursor numbers have been assigned to all entries in
|
|
@@ -132807,12 +144144,8 @@ static int selectExpander(Walker *pWalker, Select *p){
|
|
for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
|
|
Table *pTab;
|
|
assert( pFrom->fg.isRecursive==0 || pFrom->pTab!=0 );
|
|
- if( pFrom->fg.isRecursive ) continue;
|
|
- assert( pFrom->pTab==0 );
|
|
-#ifndef SQLITE_OMIT_CTE
|
|
- if( withExpand(pWalker, pFrom) ) return WRC_Abort;
|
|
- if( pFrom->pTab ) {} else
|
|
-#endif
|
|
+ if( pFrom->pTab ) continue;
|
|
+ assert( pFrom->fg.isRecursive==0 );
|
|
if( pFrom->zName==0 ){
|
|
#ifndef SQLITE_OMIT_SUBQUERY
|
|
Select *pSel = pFrom->pSelect;
|
|
@@ -132821,6 +144154,12 @@ static int selectExpander(Walker *pWalker, Select *p){
|
|
assert( pFrom->pTab==0 );
|
|
if( sqlite3WalkSelect(pWalker, pSel) ) return WRC_Abort;
|
|
if( sqlite3ExpandSubquery(pParse, pFrom) ) return WRC_Abort;
|
|
+#endif
|
|
+#ifndef SQLITE_OMIT_CTE
|
|
+ }else if( (rc = resolveFromTermToCte(pParse, pWalker, pFrom))!=0 ){
|
|
+ if( rc>1 ) return WRC_Abort;
|
|
+ pTab = pFrom->pTab;
|
|
+ assert( pTab!=0 );
|
|
#endif
|
|
}else{
|
|
/* An ordinary table or view name in the FROM clause */
|
|
@@ -132838,26 +144177,31 @@ static int selectExpander(Walker *pWalker, Select *p){
|
|
return WRC_Abort;
|
|
}
|
|
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
|
|
- if( IsVirtual(pTab) || pTab->pSelect ){
|
|
+ if( !IsOrdinaryTable(pTab) ){
|
|
i16 nCol;
|
|
u8 eCodeOrig = pWalker->eCode;
|
|
if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort;
|
|
assert( pFrom->pSelect==0 );
|
|
- if( pTab->pSelect && (db->flags & SQLITE_EnableView)==0 ){
|
|
- sqlite3ErrorMsg(pParse, "access to view \"%s\" prohibited",
|
|
- pTab->zName);
|
|
+ if( IsView(pTab) ){
|
|
+ if( (db->flags & SQLITE_EnableView)==0
|
|
+ && pTab->pSchema!=db->aDb[1].pSchema
|
|
+ ){
|
|
+ sqlite3ErrorMsg(pParse, "access to view \"%s\" prohibited",
|
|
+ pTab->zName);
|
|
+ }
|
|
+ pFrom->pSelect = sqlite3SelectDup(db, pTab->u.view.pSelect, 0);
|
|
}
|
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
|
- if( IsVirtual(pTab)
|
|
+ else if( ALWAYS(IsVirtual(pTab))
|
|
&& pFrom->fg.fromDDL
|
|
- && ALWAYS(pTab->pVTable!=0)
|
|
- && pTab->pVTable->eVtabRisk > ((db->flags & SQLITE_TrustedSchema)!=0)
|
|
+ && ALWAYS(pTab->u.vtab.p!=0)
|
|
+ && pTab->u.vtab.p->eVtabRisk > ((db->flags & SQLITE_TrustedSchema)!=0)
|
|
){
|
|
sqlite3ErrorMsg(pParse, "unsafe use of virtual table \"%s\"",
|
|
pTab->zName);
|
|
}
|
|
+ assert( SQLITE_VTABRISK_Normal==1 && SQLITE_VTABRISK_High==2 );
|
|
#endif
|
|
- pFrom->pSelect = sqlite3SelectDup(db, pTab->pSelect, 0);
|
|
nCol = pTab->nCol;
|
|
pTab->nCol = -1;
|
|
pWalker->eCode = 1; /* Turn on Select.selId renumbering */
|
|
@@ -132869,14 +144213,15 @@ static int selectExpander(Walker *pWalker, Select *p){
|
|
}
|
|
|
|
/* Locate the index named by the INDEXED BY clause, if any. */
|
|
- if( sqlite3IndexedByLookup(pParse, pFrom) ){
|
|
+ if( pFrom->fg.isIndexedBy && sqlite3IndexedByLookup(pParse, pFrom) ){
|
|
return WRC_Abort;
|
|
}
|
|
}
|
|
|
|
/* Process NATURAL keywords, and ON and USING clauses of joins.
|
|
*/
|
|
- if( pParse->nErr || db->mallocFailed || sqliteProcessJoin(pParse, p) ){
|
|
+ assert( db->mallocFailed==0 || pParse->nErr!=0 );
|
|
+ if( pParse->nErr || sqlite3ProcessJoin(pParse, p) ){
|
|
return WRC_Abort;
|
|
}
|
|
|
|
@@ -132924,7 +144269,7 @@ static int selectExpander(Walker *pWalker, Select *p){
|
|
pNew = sqlite3ExprListAppend(pParse, pNew, a[k].pExpr);
|
|
if( pNew ){
|
|
pNew->a[pNew->nExpr-1].zEName = a[k].zEName;
|
|
- pNew->a[pNew->nExpr-1].eEName = a[k].eEName;
|
|
+ pNew->a[pNew->nExpr-1].fg.eEName = a[k].fg.eEName;
|
|
a[k].zEName = 0;
|
|
}
|
|
a[k].pExpr = 0;
|
|
@@ -132939,32 +144284,60 @@ static int selectExpander(Walker *pWalker, Select *p){
|
|
zTName = pE->pLeft->u.zToken;
|
|
}
|
|
for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
|
|
- Table *pTab = pFrom->pTab;
|
|
- Select *pSub = pFrom->pSelect;
|
|
- char *zTabName = pFrom->zAlias;
|
|
- const char *zSchemaName = 0;
|
|
- int iDb;
|
|
- if( zTabName==0 ){
|
|
+ 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 */
|
|
+ const char *zSchemaName = 0; /* Schema name for this data source */
|
|
+ int iDb; /* Schema index for this data src */
|
|
+ IdList *pUsing; /* USING clause for pFrom[1] */
|
|
+
|
|
+ if( (zTabName = pFrom->zAlias)==0 ){
|
|
zTabName = pTab->zName;
|
|
}
|
|
if( db->mallocFailed ) break;
|
|
- if( pSub==0 || (pSub->selFlags & SF_NestedFrom)==0 ){
|
|
- pSub = 0;
|
|
+ assert( (int)pFrom->fg.isNestedFrom == IsNestedFrom(pFrom->pSelect) );
|
|
+ if( pFrom->fg.isNestedFrom ){
|
|
+ assert( pFrom->pSelect!=0 );
|
|
+ pNestedFrom = pFrom->pSelect->pEList;
|
|
+ assert( pNestedFrom!=0 );
|
|
+ assert( pNestedFrom->nExpr==pTab->nCol );
|
|
+ }else{
|
|
if( zTName && sqlite3StrICmp(zTName, zTabName)!=0 ){
|
|
continue;
|
|
}
|
|
+ pNestedFrom = 0;
|
|
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
|
zSchemaName = iDb>=0 ? db->aDb[iDb].zDbSName : "*";
|
|
}
|
|
+ if( i+1<pTabList->nSrc
|
|
+ && pFrom[1].fg.isUsing
|
|
+ && (selFlags & SF_NestedFrom)!=0
|
|
+ ){
|
|
+ int ii;
|
|
+ pUsing = pFrom[1].u3.pUsing;
|
|
+ for(ii=0; ii<pUsing->nId; ii++){
|
|
+ const char *zUName = pUsing->a[ii].zName;
|
|
+ pRight = sqlite3Expr(db, TK_ID, zUName);
|
|
+ pNew = sqlite3ExprListAppend(pParse, pNew, pRight);
|
|
+ if( pNew ){
|
|
+ struct ExprList_item *pX = &pNew->a[pNew->nExpr-1];
|
|
+ assert( pX->zEName==0 );
|
|
+ pX->zEName = sqlite3MPrintf(db,"..%s", zUName);
|
|
+ pX->fg.eEName = ENAME_TAB;
|
|
+ pX->fg.bUsingTerm = 1;
|
|
+ }
|
|
+ }
|
|
+ }else{
|
|
+ pUsing = 0;
|
|
+ }
|
|
for(j=0; j<pTab->nCol; j++){
|
|
- char *zName = pTab->aCol[j].zName;
|
|
- char *zColname; /* The computed column name */
|
|
- char *zToFree; /* Malloced string that needs to be freed */
|
|
- Token sColname; /* Computed column name as a token */
|
|
+ char *zName = pTab->aCol[j].zCnName;
|
|
+ struct ExprList_item *pX; /* Newly added ExprList term */
|
|
|
|
assert( zName );
|
|
- if( zTName && pSub
|
|
- && sqlite3MatchEName(&pSub->pEList->a[j], 0, zTName, 0)==0
|
|
+ if( zTName
|
|
+ && pNestedFrom
|
|
+ && sqlite3MatchEName(&pNestedFrom->a[j], 0, zTName, 0)==0
|
|
){
|
|
continue;
|
|
}
|
|
@@ -132974,61 +144347,79 @@ static int selectExpander(Walker *pWalker, Select *p){
|
|
** bit set.
|
|
*/
|
|
if( (p->selFlags & SF_IncludeHidden)==0
|
|
- && IsHiddenColumn(&pTab->aCol[j])
|
|
+ && IsHiddenColumn(&pTab->aCol[j])
|
|
+ ){
|
|
+ continue;
|
|
+ }
|
|
+ if( (pTab->aCol[j].colFlags & COLFLAG_NOEXPAND)!=0
|
|
+ && zTName==0
|
|
+ && (selFlags & (SF_NestedFrom))==0
|
|
){
|
|
continue;
|
|
}
|
|
tableSeen = 1;
|
|
|
|
- if( i>0 && zTName==0 ){
|
|
- if( (pFrom->fg.jointype & JT_NATURAL)!=0
|
|
- && tableAndColumnIndex(pTabList, i, zName, 0, 0, 1)
|
|
+ if( i>0 && zTName==0 && (selFlags & SF_NestedFrom)==0 ){
|
|
+ if( pFrom->fg.isUsing
|
|
+ && sqlite3IdListIndex(pFrom->u3.pUsing, zName)>=0
|
|
){
|
|
- /* In a NATURAL join, omit the join columns from the
|
|
- ** table to the right of the join */
|
|
- continue;
|
|
- }
|
|
- if( sqlite3IdListIndex(pFrom->pUsing, zName)>=0 ){
|
|
/* In a join with a USING clause, omit columns in the
|
|
** using clause from the table on the right. */
|
|
continue;
|
|
}
|
|
}
|
|
pRight = sqlite3Expr(db, TK_ID, zName);
|
|
- zColname = zName;
|
|
- zToFree = 0;
|
|
- if( longNames || pTabList->nSrc>1 ){
|
|
+ if( (pTabList->nSrc>1
|
|
+ && ( (pFrom->fg.jointype & JT_LTORJ)==0
|
|
+ || (selFlags & SF_NestedFrom)!=0
|
|
+ || !inAnyUsingClause(zName,pFrom,pTabList->nSrc-i-1)
|
|
+ )
|
|
+ )
|
|
+ || IN_RENAME_OBJECT
|
|
+ ){
|
|
Expr *pLeft;
|
|
pLeft = sqlite3Expr(db, TK_ID, zTabName);
|
|
pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight);
|
|
+ if( IN_RENAME_OBJECT && pE->pLeft ){
|
|
+ sqlite3RenameTokenRemap(pParse, pLeft, pE->pLeft);
|
|
+ }
|
|
if( zSchemaName ){
|
|
pLeft = sqlite3Expr(db, TK_ID, zSchemaName);
|
|
pExpr = sqlite3PExpr(pParse, TK_DOT, pLeft, pExpr);
|
|
}
|
|
- if( longNames ){
|
|
- zColname = sqlite3MPrintf(db, "%s.%s", zTabName, zName);
|
|
- zToFree = zColname;
|
|
- }
|
|
}else{
|
|
pExpr = pRight;
|
|
}
|
|
pNew = sqlite3ExprListAppend(pParse, pNew, pExpr);
|
|
- sqlite3TokenInit(&sColname, zColname);
|
|
- sqlite3ExprListSetName(pParse, pNew, &sColname, 0);
|
|
- if( pNew && (p->selFlags & SF_NestedFrom)!=0 ){
|
|
- struct ExprList_item *pX = &pNew->a[pNew->nExpr-1];
|
|
- sqlite3DbFree(db, pX->zEName);
|
|
- if( pSub ){
|
|
- pX->zEName = sqlite3DbStrDup(db, pSub->pEList->a[j].zEName);
|
|
+ if( pNew==0 ){
|
|
+ break; /* OOM */
|
|
+ }
|
|
+ pX = &pNew->a[pNew->nExpr-1];
|
|
+ assert( pX->zEName==0 );
|
|
+ if( (selFlags & SF_NestedFrom)!=0 && !IN_RENAME_OBJECT ){
|
|
+ if( pNestedFrom ){
|
|
+ pX->zEName = sqlite3DbStrDup(db, pNestedFrom->a[j].zEName);
|
|
testcase( pX->zEName==0 );
|
|
}else{
|
|
pX->zEName = sqlite3MPrintf(db, "%s.%s.%s",
|
|
- zSchemaName, zTabName, zColname);
|
|
+ zSchemaName, zTabName, zName);
|
|
testcase( pX->zEName==0 );
|
|
}
|
|
- pX->eEName = ENAME_TAB;
|
|
+ pX->fg.eEName = ENAME_TAB;
|
|
+ if( (pFrom->fg.isUsing
|
|
+ && sqlite3IdListIndex(pFrom->u3.pUsing, zName)>=0)
|
|
+ || (pUsing && sqlite3IdListIndex(pUsing, zName)>=0)
|
|
+ || (pTab->aCol[j].colFlags & COLFLAG_NOEXPAND)!=0
|
|
+ ){
|
|
+ pX->fg.bNoExpand = 1;
|
|
+ }
|
|
+ }else if( longNames ){
|
|
+ pX->zEName = sqlite3MPrintf(db, "%s.%s", zTabName, zName);
|
|
+ pX->fg.eEName = ENAME_NAME;
|
|
+ }else{
|
|
+ pX->zEName = sqlite3DbStrDup(db, zName);
|
|
+ pX->fg.eEName = ENAME_NAME;
|
|
}
|
|
- sqlite3DbFree(db, zToFree);
|
|
}
|
|
}
|
|
if( !tableSeen ){
|
|
@@ -133052,29 +144443,12 @@ static int selectExpander(Walker *pWalker, Select *p){
|
|
p->selFlags |= SF_ComplexResult;
|
|
}
|
|
}
|
|
- return WRC_Continue;
|
|
-}
|
|
-
|
|
-/*
|
|
-** No-op routine for the parse-tree walker.
|
|
-**
|
|
-** When this routine is the Walker.xExprCallback then expression trees
|
|
-** are walked without any actions being taken at each node. Presumably,
|
|
-** when this routine is used for Walker.xExprCallback then
|
|
-** Walker.xSelectCallback is set to do something useful for every
|
|
-** subquery in the parser tree.
|
|
-*/
|
|
-SQLITE_PRIVATE int sqlite3ExprWalkNoop(Walker *NotUsed, Expr *NotUsed2){
|
|
- UNUSED_PARAMETER2(NotUsed, NotUsed2);
|
|
- return WRC_Continue;
|
|
-}
|
|
-
|
|
-/*
|
|
-** No-op routine for the parse-tree walker for SELECT statements.
|
|
-** subquery in the parser tree.
|
|
-*/
|
|
-SQLITE_PRIVATE int sqlite3SelectWalkNoop(Walker *NotUsed, Select *NotUsed2){
|
|
- UNUSED_PARAMETER2(NotUsed, NotUsed2);
|
|
+#if TREETRACE_ENABLED
|
|
+ if( sqlite3TreeTrace & 0x8 ){
|
|
+ TREETRACE(0x8,pParse,p,("After result-set wildcard expansion:\n"));
|
|
+ sqlite3TreeViewSelect(0, p, 0);
|
|
+ }
|
|
+#endif
|
|
return WRC_Continue;
|
|
}
|
|
|
|
@@ -133111,7 +144485,7 @@ static void sqlite3SelectExpand(Parse *pParse, Select *pSelect){
|
|
sqlite3WalkSelect(&w, pSelect);
|
|
}
|
|
w.xSelectCallback = selectExpander;
|
|
- w.xSelectCallback2 = selectPopWith;
|
|
+ w.xSelectCallback2 = sqlite3SelectPopWith;
|
|
w.eCode = 0;
|
|
sqlite3WalkSelect(&w, pSelect);
|
|
}
|
|
@@ -133122,20 +144496,20 @@ static void sqlite3SelectExpand(Parse *pParse, Select *pSelect){
|
|
** This is a Walker.xSelectCallback callback for the sqlite3SelectTypeInfo()
|
|
** interface.
|
|
**
|
|
-** For each FROM-clause subquery, add Column.zType and Column.zColl
|
|
-** information to the Table structure that represents the result set
|
|
-** of that subquery.
|
|
+** For each FROM-clause subquery, add Column.zType, Column.zColl, and
|
|
+** Column.affinity information to the Table structure that represents
|
|
+** the result set of that subquery.
|
|
**
|
|
** The Table structure that represents the result set was constructed
|
|
-** by selectExpander() but the type and collation information was omitted
|
|
-** at that point because identifiers had not yet been resolved. This
|
|
-** routine is called after identifier resolution.
|
|
+** by selectExpander() but the type and collation and affinity information
|
|
+** was omitted at that point because identifiers had not yet been resolved.
|
|
+** This routine is called after identifier resolution.
|
|
*/
|
|
static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){
|
|
Parse *pParse;
|
|
int i;
|
|
SrcList *pTabList;
|
|
- struct SrcList_item *pFrom;
|
|
+ SrcItem *pFrom;
|
|
|
|
assert( p->selFlags & SF_Resolved );
|
|
if( p->selFlags & SF_HasTypeInfo ) return;
|
|
@@ -133149,9 +144523,7 @@ static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){
|
|
/* A sub-query in the FROM clause of a SELECT */
|
|
Select *pSel = pFrom->pSelect;
|
|
if( pSel ){
|
|
- while( pSel->pPrior ) pSel = pSel->pPrior;
|
|
- sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSel,
|
|
- SQLITE_AFF_NONE);
|
|
+ sqlite3SubqueryColumnTypes(pParse, pTab, pSel, SQLITE_AFF_NONE);
|
|
}
|
|
}
|
|
}
|
|
@@ -133196,15 +144568,185 @@ SQLITE_PRIVATE void sqlite3SelectPrep(
|
|
NameContext *pOuterNC /* Name context for container */
|
|
){
|
|
assert( p!=0 || pParse->db->mallocFailed );
|
|
+ assert( pParse->db->pParse==pParse );
|
|
if( pParse->db->mallocFailed ) return;
|
|
if( p->selFlags & SF_HasTypeInfo ) return;
|
|
sqlite3SelectExpand(pParse, p);
|
|
- if( pParse->nErr || pParse->db->mallocFailed ) return;
|
|
+ if( pParse->nErr ) return;
|
|
sqlite3ResolveSelectNames(pParse, p, pOuterNC);
|
|
- if( pParse->nErr || pParse->db->mallocFailed ) return;
|
|
+ if( pParse->nErr ) return;
|
|
sqlite3SelectAddTypeInfo(pParse, p);
|
|
}
|
|
|
|
+#if TREETRACE_ENABLED
|
|
+/*
|
|
+** Display all information about an AggInfo object
|
|
+*/
|
|
+static void printAggInfo(AggInfo *pAggInfo){
|
|
+ int ii;
|
|
+ for(ii=0; ii<pAggInfo->nColumn; ii++){
|
|
+ struct AggInfo_col *pCol = &pAggInfo->aCol[ii];
|
|
+ sqlite3DebugPrintf(
|
|
+ "agg-column[%d] pTab=%s iTable=%d iColumn=%d iMem=%d"
|
|
+ " iSorterColumn=%d %s\n",
|
|
+ ii, pCol->pTab ? pCol->pTab->zName : "NULL",
|
|
+ pCol->iTable, pCol->iColumn, pAggInfo->iFirstReg+ii,
|
|
+ pCol->iSorterColumn,
|
|
+ ii>=pAggInfo->nAccumulator ? "" : " Accumulator");
|
|
+ sqlite3TreeViewExpr(0, pAggInfo->aCol[ii].pCExpr, 0);
|
|
+ }
|
|
+ for(ii=0; ii<pAggInfo->nFunc; ii++){
|
|
+ sqlite3DebugPrintf("agg-func[%d]: iMem=%d\n",
|
|
+ ii, pAggInfo->iFirstReg+pAggInfo->nColumn+ii);
|
|
+ sqlite3TreeViewExpr(0, pAggInfo->aFunc[ii].pFExpr, 0);
|
|
+ }
|
|
+}
|
|
+#endif /* TREETRACE_ENABLED */
|
|
+
|
|
+/*
|
|
+** Analyze the arguments to aggregate functions. Create new pAggInfo->aCol[]
|
|
+** entries for columns that are arguments to aggregate functions but which
|
|
+** are not otherwise used.
|
|
+**
|
|
+** The aCol[] entries in AggInfo prior to nAccumulator are columns that
|
|
+** are referenced outside of aggregate functions. These might be columns
|
|
+** that are part of the GROUP by clause, for example. Other database engines
|
|
+** would throw an error if there is a column reference that is not in the
|
|
+** GROUP BY clause and that is not part of an aggregate function argument.
|
|
+** But SQLite allows this.
|
|
+**
|
|
+** The aCol[] entries beginning with the aCol[nAccumulator] and following
|
|
+** are column references that are used exclusively as arguments to
|
|
+** aggregate functions. This routine is responsible for computing
|
|
+** (or recomputing) those aCol[] entries.
|
|
+*/
|
|
+static void analyzeAggFuncArgs(
|
|
+ AggInfo *pAggInfo,
|
|
+ NameContext *pNC
|
|
+){
|
|
+ int i;
|
|
+ assert( pAggInfo!=0 );
|
|
+ assert( pAggInfo->iFirstReg==0 );
|
|
+ pNC->ncFlags |= NC_InAggFunc;
|
|
+ for(i=0; i<pAggInfo->nFunc; i++){
|
|
+ Expr *pExpr = pAggInfo->aFunc[i].pFExpr;
|
|
+ assert( ExprUseXList(pExpr) );
|
|
+ sqlite3ExprAnalyzeAggList(pNC, pExpr->x.pList);
|
|
+#ifndef SQLITE_OMIT_WINDOWFUNC
|
|
+ assert( !IsWindowFunc(pExpr) );
|
|
+ if( ExprHasProperty(pExpr, EP_WinFunc) ){
|
|
+ sqlite3ExprAnalyzeAggregates(pNC, pExpr->y.pWin->pFilter);
|
|
+ }
|
|
+#endif
|
|
+ }
|
|
+ pNC->ncFlags &= ~NC_InAggFunc;
|
|
+}
|
|
+
|
|
+/*
|
|
+** An index on expressions is being used in the inner loop of an
|
|
+** aggregate query with a GROUP BY clause. This routine attempts
|
|
+** to adjust the AggInfo object to take advantage of index and to
|
|
+** perhaps use the index as a covering index.
|
|
+**
|
|
+*/
|
|
+static void optimizeAggregateUseOfIndexedExpr(
|
|
+ Parse *pParse, /* Parsing context */
|
|
+ Select *pSelect, /* The SELECT statement being processed */
|
|
+ AggInfo *pAggInfo, /* The aggregate info */
|
|
+ NameContext *pNC /* Name context used to resolve agg-func args */
|
|
+){
|
|
+ assert( pAggInfo->iFirstReg==0 );
|
|
+ assert( pSelect!=0 );
|
|
+ assert( pSelect->pGroupBy!=0 );
|
|
+ pAggInfo->nColumn = pAggInfo->nAccumulator;
|
|
+ if( ALWAYS(pAggInfo->nSortingColumn>0) ){
|
|
+ if( pAggInfo->nColumn==0 ){
|
|
+ pAggInfo->nSortingColumn = pSelect->pGroupBy->nExpr;
|
|
+ }else{
|
|
+ pAggInfo->nSortingColumn =
|
|
+ pAggInfo->aCol[pAggInfo->nColumn-1].iSorterColumn+1;
|
|
+ }
|
|
+ }
|
|
+ analyzeAggFuncArgs(pAggInfo, pNC);
|
|
+#if TREETRACE_ENABLED
|
|
+ if( sqlite3TreeTrace & 0x20 ){
|
|
+ IndexedExpr *pIEpr;
|
|
+ TREETRACE(0x20, pParse, pSelect,
|
|
+ ("AggInfo (possibly) adjusted for Indexed Exprs\n"));
|
|
+ sqlite3TreeViewSelect(0, pSelect, 0);
|
|
+ for(pIEpr=pParse->pIdxEpr; pIEpr; pIEpr=pIEpr->pIENext){
|
|
+ printf("data-cursor=%d index={%d,%d}\n",
|
|
+ pIEpr->iDataCur, pIEpr->iIdxCur, pIEpr->iIdxCol);
|
|
+ sqlite3TreeViewExpr(0, pIEpr->pExpr, 0);
|
|
+ }
|
|
+ printAggInfo(pAggInfo);
|
|
+ }
|
|
+#else
|
|
+ UNUSED_PARAMETER(pSelect);
|
|
+ UNUSED_PARAMETER(pParse);
|
|
+#endif
|
|
+}
|
|
+
|
|
+/*
|
|
+** Walker callback for aggregateConvertIndexedExprRefToColumn().
|
|
+*/
|
|
+static int aggregateIdxEprRefToColCallback(Walker *pWalker, Expr *pExpr){
|
|
+ AggInfo *pAggInfo;
|
|
+ struct AggInfo_col *pCol;
|
|
+ UNUSED_PARAMETER(pWalker);
|
|
+ if( pExpr->pAggInfo==0 ) return WRC_Continue;
|
|
+ if( pExpr->op==TK_AGG_COLUMN ) return WRC_Continue;
|
|
+ if( pExpr->op==TK_AGG_FUNCTION ) return WRC_Continue;
|
|
+ if( pExpr->op==TK_IF_NULL_ROW ) return WRC_Continue;
|
|
+ pAggInfo = pExpr->pAggInfo;
|
|
+ assert( pExpr->iAgg>=0 && pExpr->iAgg<pAggInfo->nColumn );
|
|
+ pCol = &pAggInfo->aCol[pExpr->iAgg];
|
|
+ pExpr->op = TK_AGG_COLUMN;
|
|
+ pExpr->iTable = pCol->iTable;
|
|
+ pExpr->iColumn = pCol->iColumn;
|
|
+ return WRC_Prune;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Convert every pAggInfo->aFunc[].pExpr such that any node within
|
|
+** those expressions that has pAppInfo set is changed into a TK_AGG_COLUMN
|
|
+** opcode.
|
|
+*/
|
|
+static void aggregateConvertIndexedExprRefToColumn(AggInfo *pAggInfo){
|
|
+ int i;
|
|
+ Walker w;
|
|
+ memset(&w, 0, sizeof(w));
|
|
+ w.xExprCallback = aggregateIdxEprRefToColCallback;
|
|
+ for(i=0; i<pAggInfo->nFunc; i++){
|
|
+ sqlite3WalkExpr(&w, pAggInfo->aFunc[i].pFExpr);
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
+/*
|
|
+** Allocate a block of registers so that there is one register for each
|
|
+** pAggInfo->aCol[] and pAggInfo->aFunc[] entry in pAggInfo. The first
|
|
+** register in this block is stored in pAggInfo->iFirstReg.
|
|
+**
|
|
+** This routine may only be called once for each AggInfo object. Prior
|
|
+** to calling this routine:
|
|
+**
|
|
+** * The aCol[] and aFunc[] arrays may be modified
|
|
+** * The AggInfoColumnReg() and AggInfoFuncReg() macros may not be used
|
|
+**
|
|
+** After clling this routine:
|
|
+**
|
|
+** * The aCol[] and aFunc[] arrays are fixed
|
|
+** * The AggInfoColumnReg() and AggInfoFuncReg() macros may be used
|
|
+**
|
|
+*/
|
|
+static void assignAggregateRegisters(Parse *pParse, AggInfo *pAggInfo){
|
|
+ assert( pAggInfo!=0 );
|
|
+ assert( pAggInfo->iFirstReg==0 );
|
|
+ pAggInfo->iFirstReg = pParse->nMem + 1;
|
|
+ pParse->nMem += pAggInfo->nColumn + pAggInfo->nFunc;
|
|
+}
|
|
+
|
|
/*
|
|
** Reset the aggregate accumulator.
|
|
**
|
|
@@ -133218,33 +144760,27 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
|
|
int i;
|
|
struct AggInfo_func *pFunc;
|
|
int nReg = pAggInfo->nFunc + pAggInfo->nColumn;
|
|
+ assert( pAggInfo->iFirstReg>0 );
|
|
+ assert( pParse->db->pParse==pParse );
|
|
+ assert( pParse->db->mallocFailed==0 || pParse->nErr!=0 );
|
|
if( nReg==0 ) return;
|
|
-#ifdef SQLITE_DEBUG
|
|
- /* Verify that all AggInfo registers are within the range specified by
|
|
- ** AggInfo.mnReg..AggInfo.mxReg */
|
|
- assert( nReg==pAggInfo->mxReg-pAggInfo->mnReg+1 );
|
|
- for(i=0; i<pAggInfo->nColumn; i++){
|
|
- assert( pAggInfo->aCol[i].iMem>=pAggInfo->mnReg
|
|
- && pAggInfo->aCol[i].iMem<=pAggInfo->mxReg );
|
|
- }
|
|
- for(i=0; i<pAggInfo->nFunc; i++){
|
|
- assert( pAggInfo->aFunc[i].iMem>=pAggInfo->mnReg
|
|
- && pAggInfo->aFunc[i].iMem<=pAggInfo->mxReg );
|
|
- }
|
|
-#endif
|
|
- sqlite3VdbeAddOp3(v, OP_Null, 0, pAggInfo->mnReg, pAggInfo->mxReg);
|
|
+ if( pParse->nErr ) return;
|
|
+ sqlite3VdbeAddOp3(v, OP_Null, 0, pAggInfo->iFirstReg,
|
|
+ pAggInfo->iFirstReg+nReg-1);
|
|
for(pFunc=pAggInfo->aFunc, i=0; i<pAggInfo->nFunc; i++, pFunc++){
|
|
if( pFunc->iDistinct>=0 ){
|
|
- Expr *pE = pFunc->pExpr;
|
|
- assert( !ExprHasProperty(pE, EP_xIsSelect) );
|
|
+ Expr *pE = pFunc->pFExpr;
|
|
+ assert( ExprUseXList(pE) );
|
|
if( pE->x.pList==0 || pE->x.pList->nExpr!=1 ){
|
|
sqlite3ErrorMsg(pParse, "DISTINCT aggregates must have exactly one "
|
|
"argument");
|
|
pFunc->iDistinct = -1;
|
|
}else{
|
|
KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pE->x.pList,0,0);
|
|
- sqlite3VdbeAddOp4(v, OP_OpenEphemeral, pFunc->iDistinct, 0, 0,
|
|
- (char*)pKeyInfo, P4_KEYINFO);
|
|
+ pFunc->iDistAddr = sqlite3VdbeAddOp4(v, OP_OpenEphemeral,
|
|
+ pFunc->iDistinct, 0, 0, (char*)pKeyInfo, P4_KEYINFO);
|
|
+ ExplainQueryPlan((pParse, 0, "USE TEMP B-TREE FOR %s(DISTINCT)",
|
|
+ pFunc->pFunc->zName));
|
|
}
|
|
}
|
|
}
|
|
@@ -133259,24 +144795,31 @@ static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){
|
|
int i;
|
|
struct AggInfo_func *pF;
|
|
for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){
|
|
- ExprList *pList = pF->pExpr->x.pList;
|
|
- assert( !ExprHasProperty(pF->pExpr, EP_xIsSelect) );
|
|
- sqlite3VdbeAddOp2(v, OP_AggFinal, pF->iMem, pList ? pList->nExpr : 0);
|
|
+ ExprList *pList;
|
|
+ assert( ExprUseXList(pF->pFExpr) );
|
|
+ pList = pF->pFExpr->x.pList;
|
|
+ sqlite3VdbeAddOp2(v, OP_AggFinal, AggInfoFuncReg(pAggInfo,i),
|
|
+ pList ? pList->nExpr : 0);
|
|
sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
-** Update the accumulator memory cells for an aggregate based on
|
|
-** the current cursor position.
|
|
+** Generate code that will update the accumulator memory cells for an
|
|
+** aggregate based on the current cursor position.
|
|
**
|
|
** If regAcc is non-zero and there are no min() or max() aggregates
|
|
** in pAggInfo, then only populate the pAggInfo->nAccumulator accumulator
|
|
** registers if register regAcc contains 0. The caller will take care
|
|
** of setting and clearing regAcc.
|
|
*/
|
|
-static void updateAccumulator(Parse *pParse, int regAcc, AggInfo *pAggInfo){
|
|
+static void updateAccumulator(
|
|
+ Parse *pParse,
|
|
+ int regAcc,
|
|
+ AggInfo *pAggInfo,
|
|
+ int eDistinctType
|
|
+){
|
|
Vdbe *v = pParse->pVdbe;
|
|
int i;
|
|
int regHit = 0;
|
|
@@ -133284,27 +144827,34 @@ static void updateAccumulator(Parse *pParse, int regAcc, AggInfo *pAggInfo){
|
|
struct AggInfo_func *pF;
|
|
struct AggInfo_col *pC;
|
|
|
|
+ assert( pAggInfo->iFirstReg>0 );
|
|
+ if( pParse->nErr ) return;
|
|
pAggInfo->directMode = 1;
|
|
for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){
|
|
int nArg;
|
|
int addrNext = 0;
|
|
int regAgg;
|
|
- ExprList *pList = pF->pExpr->x.pList;
|
|
- assert( !ExprHasProperty(pF->pExpr, EP_xIsSelect) );
|
|
- assert( !IsWindowFunc(pF->pExpr) );
|
|
- if( ExprHasProperty(pF->pExpr, EP_WinFunc) ){
|
|
- Expr *pFilter = pF->pExpr->y.pWin->pFilter;
|
|
- if( pAggInfo->nAccumulator
|
|
- && (pF->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL)
|
|
+ ExprList *pList;
|
|
+ assert( ExprUseXList(pF->pFExpr) );
|
|
+ assert( !IsWindowFunc(pF->pFExpr) );
|
|
+ pList = pF->pFExpr->x.pList;
|
|
+ if( ExprHasProperty(pF->pFExpr, EP_WinFunc) ){
|
|
+ Expr *pFilter = pF->pFExpr->y.pWin->pFilter;
|
|
+ if( pAggInfo->nAccumulator
|
|
+ && (pF->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL)
|
|
+ && regAcc
|
|
){
|
|
+ /* If regAcc==0, there there exists some min() or max() function
|
|
+ ** without a FILTER clause that will ensure the magnet registers
|
|
+ ** are populated. */
|
|
if( regHit==0 ) regHit = ++pParse->nMem;
|
|
- /* If this is the first row of the group (regAcc==0), clear the
|
|
+ /* If this is the first row of the group (regAcc contains 0), clear the
|
|
** "magnet" register regHit so that the accumulator registers
|
|
- ** are populated if the FILTER clause jumps over the the
|
|
+ ** are populated if the FILTER clause jumps over the the
|
|
** invocation of min() or max() altogether. Or, if this is not
|
|
- ** the first row (regAcc==1), set the magnet register so that the
|
|
- ** accumulators are not populated unless the min()/max() is invoked and
|
|
- ** indicates that they should be. */
|
|
+ ** the first row (regAcc contains 1), set the magnet register so that
|
|
+ ** the accumulators are not populated unless the min()/max() is invoked
|
|
+ ** and indicates that they should be. */
|
|
sqlite3VdbeAddOp2(v, OP_Copy, regAcc, regHit);
|
|
}
|
|
addrNext = sqlite3VdbeMakeLabel(pParse);
|
|
@@ -133318,13 +144868,12 @@ static void updateAccumulator(Parse *pParse, int regAcc, AggInfo *pAggInfo){
|
|
nArg = 0;
|
|
regAgg = 0;
|
|
}
|
|
- if( pF->iDistinct>=0 ){
|
|
- if( addrNext==0 ){
|
|
+ if( pF->iDistinct>=0 && pList ){
|
|
+ if( addrNext==0 ){
|
|
addrNext = sqlite3VdbeMakeLabel(pParse);
|
|
}
|
|
- testcase( nArg==0 ); /* Error condition */
|
|
- testcase( nArg>1 ); /* Also an error */
|
|
- codeDistinct(pParse, pF->iDistinct, addrNext, 1, regAgg);
|
|
+ pF->iDistinct = codeDistinct(pParse, eDistinctType,
|
|
+ pF->iDistinct, addrNext, pList, regAgg);
|
|
}
|
|
if( pF->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){
|
|
CollSeq *pColl = 0;
|
|
@@ -133340,7 +144889,7 @@ static void updateAccumulator(Parse *pParse, int regAcc, AggInfo *pAggInfo){
|
|
if( regHit==0 && pAggInfo->nAccumulator ) regHit = ++pParse->nMem;
|
|
sqlite3VdbeAddOp4(v, OP_CollSeq, regHit, 0, 0, (char *)pColl, P4_COLLSEQ);
|
|
}
|
|
- sqlite3VdbeAddOp3(v, OP_AggStep, 0, regAgg, pF->iMem);
|
|
+ sqlite3VdbeAddOp3(v, OP_AggStep, 0, regAgg, AggInfoFuncReg(pAggInfo,i));
|
|
sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF);
|
|
sqlite3VdbeChangeP5(v, (u8)nArg);
|
|
sqlite3ReleaseTempRange(pParse, regAgg, nArg);
|
|
@@ -133355,12 +144904,12 @@ static void updateAccumulator(Parse *pParse, int regAcc, AggInfo *pAggInfo){
|
|
addrHitTest = sqlite3VdbeAddOp1(v, OP_If, regHit); VdbeCoverage(v);
|
|
}
|
|
for(i=0, pC=pAggInfo->aCol; i<pAggInfo->nAccumulator; i++, pC++){
|
|
- sqlite3ExprCode(pParse, pC->pExpr, pC->iMem);
|
|
+ sqlite3ExprCode(pParse, pC->pCExpr, AggInfoColumnReg(pAggInfo,i));
|
|
}
|
|
|
|
pAggInfo->directMode = 0;
|
|
if( addrHitTest ){
|
|
- sqlite3VdbeJumpHere(v, addrHitTest);
|
|
+ sqlite3VdbeJumpHereOrPopInst(v, addrHitTest);
|
|
}
|
|
}
|
|
|
|
@@ -133376,7 +144925,7 @@ static void explainSimpleCount(
|
|
){
|
|
if( pParse->explain==2 ){
|
|
int bCover = (pIdx!=0 && (HasRowid(pTab) || !IsPrimaryKeyIndex(pIdx)));
|
|
- sqlite3VdbeExplain(pParse, 0, "SCAN TABLE %s%s%s",
|
|
+ sqlite3VdbeExplain(pParse, 0, "SCAN %s%s%s",
|
|
pTab->zName,
|
|
bCover ? " USING COVERING INDEX " : "",
|
|
bCover ? pIdx->zName : ""
|
|
@@ -133390,10 +144939,10 @@ static void explainSimpleCount(
|
|
/*
|
|
** sqlite3WalkExpr() callback used by havingToWhere().
|
|
**
|
|
-** If the node passed to the callback is a TK_AND node, return
|
|
+** If the node passed to the callback is a TK_AND node, return
|
|
** WRC_Continue to tell sqlite3WalkExpr() to iterate through child nodes.
|
|
**
|
|
-** Otherwise, return WRC_Prune. In this case, also check if the
|
|
+** Otherwise, return WRC_Prune. In this case, also check if the
|
|
** sub-expression matches the criteria for being moved to the WHERE
|
|
** clause. If so, add it to the WHERE clause and replace the sub-expression
|
|
** within the HAVING expression with a constant "1".
|
|
@@ -133401,7 +144950,17 @@ static void explainSimpleCount(
|
|
static int havingToWhereExprCb(Walker *pWalker, Expr *pExpr){
|
|
if( pExpr->op!=TK_AND ){
|
|
Select *pS = pWalker->u.pSelect;
|
|
- if( sqlite3ExprIsConstantOrGroupBy(pWalker->pParse, pExpr, pS->pGroupBy) ){
|
|
+ /* This routine is called before the HAVING clause of the current
|
|
+ ** SELECT is analyzed for aggregates. So if pExpr->pAggInfo is set
|
|
+ ** here, it indicates that the expression is a correlated reference to a
|
|
+ ** column from an outer aggregate query, or an aggregate function that
|
|
+ ** belongs to an outer query. Do not move the expression to the WHERE
|
|
+ ** clause in this obscure case, as doing so may corrupt the outer Select
|
|
+ ** statements AggInfo structure. */
|
|
+ if( sqlite3ExprIsConstantOrGroupBy(pWalker->pParse, pExpr, pS->pGroupBy)
|
|
+ && ExprAlwaysFalse(pExpr)==0
|
|
+ && pExpr->pAggInfo==0
|
|
+ ){
|
|
sqlite3 *db = pWalker->pParse->db;
|
|
Expr *pNew = sqlite3Expr(db, TK_INTEGER, "1");
|
|
if( pNew ){
|
|
@@ -133439,26 +144998,33 @@ static void havingToWhere(Parse *pParse, Select *p){
|
|
sWalker.xExprCallback = havingToWhereExprCb;
|
|
sWalker.u.pSelect = p;
|
|
sqlite3WalkExpr(&sWalker, p->pHaving);
|
|
-#if SELECTTRACE_ENABLED
|
|
- if( sWalker.eCode && (sqlite3SelectTrace & 0x100)!=0 ){
|
|
- SELECTTRACE(0x100,pParse,p,("Move HAVING terms into WHERE:\n"));
|
|
+#if TREETRACE_ENABLED
|
|
+ if( sWalker.eCode && (sqlite3TreeTrace & 0x100)!=0 ){
|
|
+ TREETRACE(0x100,pParse,p,("Move HAVING terms into WHERE:\n"));
|
|
sqlite3TreeViewSelect(0, p, 0);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
-** Check to see if the pThis entry of pTabList is a self-join of a prior view.
|
|
-** If it is, then return the SrcList_item for the prior view. If it is not,
|
|
-** then return 0.
|
|
+** Check to see if the pThis entry of pTabList is a self-join of another view.
|
|
+** Search FROM-clause entries in the range of iFirst..iEnd, including iFirst
|
|
+** but stopping before iEnd.
|
|
+**
|
|
+** If pThis is a self-join, then return the SrcItem for the first other
|
|
+** instance of that view found. If pThis is not a self-join then return 0.
|
|
*/
|
|
-static struct SrcList_item *isSelfJoinView(
|
|
+static SrcItem *isSelfJoinView(
|
|
SrcList *pTabList, /* Search for self-joins in this FROM clause */
|
|
- struct SrcList_item *pThis /* Search for prior reference to this subquery */
|
|
+ SrcItem *pThis, /* Search for prior reference to this subquery */
|
|
+ int iFirst, int iEnd /* Range of FROM-clause entries to search. */
|
|
){
|
|
- struct SrcList_item *pItem;
|
|
- for(pItem = pTabList->a; pItem<pThis; pItem++){
|
|
+ SrcItem *pItem;
|
|
+ assert( pThis->pSelect!=0 );
|
|
+ if( pThis->pSelect->selFlags & SF_PushDown ) return 0;
|
|
+ while( iFirst<iEnd ){
|
|
Select *pS1;
|
|
+ pItem = &pTabList->a[iFirst++];
|
|
if( pItem->pSelect==0 ) continue;
|
|
if( pItem->fg.viaCoroutine ) continue;
|
|
if( pItem->zName==0 ) continue;
|
|
@@ -133472,9 +145038,7 @@ static struct SrcList_item *isSelfJoinView(
|
|
** names in the same FROM clause. */
|
|
continue;
|
|
}
|
|
- if( sqlite3ExprCompare(0, pThis->pSelect->pWhere, pS1->pWhere, -1)
|
|
- || sqlite3ExprCompare(0, pThis->pSelect->pHaving, pS1->pHaving, -1)
|
|
- ){
|
|
+ if( pItem->pSelect->selFlags & SF_PushDown ){
|
|
/* The view was modified by some other optimization such as
|
|
** pushDownWhereTerms() */
|
|
continue;
|
|
@@ -133484,6 +145048,15 @@ static struct SrcList_item *isSelfJoinView(
|
|
return 0;
|
|
}
|
|
|
|
+/*
|
|
+** Deallocate a single AggInfo object
|
|
+*/
|
|
+static void agginfoFree(sqlite3 *db, AggInfo *p){
|
|
+ sqlite3DbFree(db, p->aCol);
|
|
+ sqlite3DbFree(db, p->aFunc);
|
|
+ sqlite3DbFreeNN(db, p);
|
|
+}
|
|
+
|
|
#ifdef SQLITE_COUNTOFVIEW_OPTIMIZATION
|
|
/*
|
|
** Attempt to transform a query of the form
|
|
@@ -133513,14 +145086,19 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
|
|
if( p->pEList->nExpr!=1 ) return 0; /* Single result column */
|
|
if( p->pWhere ) return 0;
|
|
if( p->pGroupBy ) return 0;
|
|
+ if( p->pOrderBy ) return 0;
|
|
pExpr = p->pEList->a[0].pExpr;
|
|
if( pExpr->op!=TK_AGG_FUNCTION ) return 0; /* Result is an aggregate */
|
|
+ assert( ExprUseUToken(pExpr) );
|
|
if( sqlite3_stricmp(pExpr->u.zToken,"count") ) return 0; /* Is count() */
|
|
+ assert( ExprUseXList(pExpr) );
|
|
if( pExpr->x.pList!=0 ) return 0; /* Must be count(*) */
|
|
if( p->pSrc->nSrc!=1 ) return 0; /* One table in FROM */
|
|
+ if( ExprHasProperty(pExpr, EP_WinFunc) ) return 0;/* Not a window function */
|
|
pSub = p->pSrc->a[0].pSelect;
|
|
if( pSub==0 ) return 0; /* The FROM is a subquery */
|
|
- if( pSub->pPrior==0 ) return 0; /* Must be a compound ry */
|
|
+ if( pSub->pPrior==0 ) return 0; /* Must be a compound */
|
|
+ if( pSub->selFlags & SF_CopyCte ) return 0; /* Not a CTE */
|
|
do{
|
|
if( pSub->op!=TK_ALL && pSub->pPrior ) return 0; /* Must be UNION ALL */
|
|
if( pSub->pWhere ) return 0; /* No WHERE clause */
|
|
@@ -133561,9 +145139,9 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
|
|
p->pEList->a[0].pExpr = pExpr;
|
|
p->selFlags &= ~SF_Aggregate;
|
|
|
|
-#if SELECTTRACE_ENABLED
|
|
- if( sqlite3SelectTrace & 0x400 ){
|
|
- SELECTTRACE(0x400,pParse,p,("After count-of-view optimization:\n"));
|
|
+#if TREETRACE_ENABLED
|
|
+ if( sqlite3TreeTrace & 0x200 ){
|
|
+ TREETRACE(0x200,pParse,p,("After count-of-view optimization:\n"));
|
|
sqlite3TreeViewSelect(0, p, 0);
|
|
}
|
|
#endif
|
|
@@ -133572,7 +145150,92 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
|
|
#endif /* SQLITE_COUNTOFVIEW_OPTIMIZATION */
|
|
|
|
/*
|
|
-** Generate code for the SELECT statement given in the p argument.
|
|
+** If any term of pSrc, or any SF_NestedFrom sub-query, is not the same
|
|
+** as pSrcItem but has the same alias as p0, then return true.
|
|
+** Otherwise return false.
|
|
+*/
|
|
+static int sameSrcAlias(SrcItem *p0, SrcList *pSrc){
|
|
+ int i;
|
|
+ for(i=0; i<pSrc->nSrc; i++){
|
|
+ SrcItem *p1 = &pSrc->a[i];
|
|
+ if( p1==p0 ) continue;
|
|
+ if( p0->pTab==p1->pTab && 0==sqlite3_stricmp(p0->zAlias, p1->zAlias) ){
|
|
+ return 1;
|
|
+ }
|
|
+ if( p1->pSelect
|
|
+ && (p1->pSelect->selFlags & SF_NestedFrom)!=0
|
|
+ && sameSrcAlias(p0, p1->pSelect->pSrc)
|
|
+ ){
|
|
+ return 1;
|
|
+ }
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Return TRUE (non-zero) if the i-th entry in the pTabList SrcList can
|
|
+** be implemented as a co-routine. The i-th entry is guaranteed to be
|
|
+** a subquery.
|
|
+**
|
|
+** The subquery is implemented as a co-routine if all of the following are
|
|
+** true:
|
|
+**
|
|
+** (1) The subquery will likely be implemented in the outer loop of
|
|
+** the query. This will be the case if any one of the following
|
|
+** conditions hold:
|
|
+** (a) The subquery is the only term in the FROM clause
|
|
+** (b) The subquery is the left-most term and a CROSS JOIN or similar
|
|
+** requires it to be the outer loop
|
|
+** (c) All of the following are true:
|
|
+** (i) The subquery is the left-most subquery in the FROM clause
|
|
+** (ii) There is nothing that would prevent the subquery from
|
|
+** being used as the outer loop if the sqlite3WhereBegin()
|
|
+** routine nominates it to that position.
|
|
+** (iii) The query is not a UPDATE ... FROM
|
|
+** (2) The subquery is not a CTE that should be materialized because
|
|
+** (a) the AS MATERIALIZED keyword is used, or
|
|
+** (b) the CTE is used multiple times and does not have the
|
|
+** NOT MATERIALIZED keyword
|
|
+** (3) The subquery is not part of a left operand for a RIGHT JOIN
|
|
+** (4) The SQLITE_Coroutine optimization disable flag is not set
|
|
+** (5) The subquery is not self-joined
|
|
+*/
|
|
+static int fromClauseTermCanBeCoroutine(
|
|
+ Parse *pParse, /* Parsing context */
|
|
+ SrcList *pTabList, /* FROM clause */
|
|
+ int i, /* Which term of the FROM clause holds the subquery */
|
|
+ int selFlags /* Flags on the SELECT statement */
|
|
+){
|
|
+ SrcItem *pItem = &pTabList->a[i];
|
|
+ if( pItem->fg.isCte ){
|
|
+ const CteUse *pCteUse = pItem->u2.pCteUse;
|
|
+ if( pCteUse->eM10d==M10d_Yes ) return 0; /* (2a) */
|
|
+ if( pCteUse->nUse>=2 && pCteUse->eM10d!=M10d_No ) return 0; /* (2b) */
|
|
+ }
|
|
+ if( pTabList->a[0].fg.jointype & JT_LTORJ ) return 0; /* (3) */
|
|
+ if( OptimizationDisabled(pParse->db, SQLITE_Coroutines) ) return 0; /* (4) */
|
|
+ if( isSelfJoinView(pTabList, pItem, i+1, pTabList->nSrc)!=0 ){
|
|
+ return 0; /* (5) */
|
|
+ }
|
|
+ if( i==0 ){
|
|
+ if( pTabList->nSrc==1 ) return 1; /* (1a) */
|
|
+ if( pTabList->a[1].fg.jointype & JT_CROSS ) return 1; /* (1b) */
|
|
+ if( selFlags & SF_UpdateFrom ) return 0; /* (1c-iii) */
|
|
+ return 1;
|
|
+ }
|
|
+ if( selFlags & SF_UpdateFrom ) return 0; /* (1c-iii) */
|
|
+ while( 1 /*exit-by-break*/ ){
|
|
+ if( pItem->fg.jointype & (JT_OUTER|JT_CROSS) ) return 0; /* (1c-ii) */
|
|
+ if( i==0 ) break;
|
|
+ i--;
|
|
+ pItem--;
|
|
+ if( pItem->pSelect!=0 ) return 0; /* (1c-i) */
|
|
+ }
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Generate code for the SELECT statement given in the p argument.
|
|
**
|
|
** The results are returned according to the SelectDest structure.
|
|
** See comments in sqliteInt.h for further information.
|
|
@@ -133598,26 +145261,31 @@ SQLITE_PRIVATE int sqlite3Select(
|
|
Expr *pWhere; /* The WHERE clause. May be NULL */
|
|
ExprList *pGroupBy; /* The GROUP BY clause. May be NULL */
|
|
Expr *pHaving; /* The HAVING clause. May be NULL */
|
|
+ AggInfo *pAggInfo = 0; /* Aggregate information */
|
|
int rc = 1; /* Value to return from this function */
|
|
DistinctCtx sDistinct; /* Info on how to code the DISTINCT keyword */
|
|
SortCtx sSort; /* Info on how to code the ORDER BY clause */
|
|
- AggInfo sAggInfo; /* Information used by aggregate queries */
|
|
int iEnd; /* Address of the end of the query */
|
|
sqlite3 *db; /* The database connection */
|
|
ExprList *pMinMaxOrderBy = 0; /* Added ORDER BY for min/max queries */
|
|
u8 minMaxFlag; /* Flag for min/max queries */
|
|
|
|
db = pParse->db;
|
|
+ assert( pParse==db->pParse );
|
|
v = sqlite3GetVdbe(pParse);
|
|
- if( p==0 || db->mallocFailed || pParse->nErr ){
|
|
+ if( p==0 || pParse->nErr ){
|
|
return 1;
|
|
}
|
|
+ assert( db->mallocFailed==0 );
|
|
if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1;
|
|
- memset(&sAggInfo, 0, sizeof(sAggInfo));
|
|
-#if SELECTTRACE_ENABLED
|
|
- SELECTTRACE(1,pParse,p, ("begin processing:\n", pParse->addrExplain));
|
|
- if( sqlite3SelectTrace & 0x100 ){
|
|
- sqlite3TreeViewSelect(0, p, 0);
|
|
+#if TREETRACE_ENABLED
|
|
+ TREETRACE(0x1,pParse,p, ("begin processing:\n", pParse->addrExplain));
|
|
+ if( sqlite3TreeTrace & 0x10000 ){
|
|
+ if( (sqlite3TreeTrace & 0x10001)==0x10000 ){
|
|
+ sqlite3TreeViewLine(0, "In sqlite3Select() at %s:%d",
|
|
+ __FILE__, __LINE__);
|
|
+ }
|
|
+ sqlite3ShowSelect(p);
|
|
}
|
|
#endif
|
|
|
|
@@ -133625,42 +145293,78 @@ SQLITE_PRIVATE int sqlite3Select(
|
|
assert( p->pOrderBy==0 || pDest->eDest!=SRT_Fifo );
|
|
assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistQueue );
|
|
assert( p->pOrderBy==0 || pDest->eDest!=SRT_Queue );
|
|
- if( IgnorableOrderby(pDest) ){
|
|
- assert(pDest->eDest==SRT_Exists || pDest->eDest==SRT_Union ||
|
|
- pDest->eDest==SRT_Except || pDest->eDest==SRT_Discard ||
|
|
- pDest->eDest==SRT_Queue || pDest->eDest==SRT_DistFifo ||
|
|
- pDest->eDest==SRT_DistQueue || pDest->eDest==SRT_Fifo);
|
|
- /* If ORDER BY makes no difference in the output then neither does
|
|
- ** DISTINCT so it can be removed too. */
|
|
- sqlite3ExprListDelete(db, p->pOrderBy);
|
|
- p->pOrderBy = 0;
|
|
+ if( IgnorableDistinct(pDest) ){
|
|
+ assert(pDest->eDest==SRT_Exists || pDest->eDest==SRT_Union ||
|
|
+ pDest->eDest==SRT_Except || pDest->eDest==SRT_Discard ||
|
|
+ pDest->eDest==SRT_DistQueue || pDest->eDest==SRT_DistFifo );
|
|
+ /* All of these destinations are also able to ignore the ORDER BY clause */
|
|
+ if( p->pOrderBy ){
|
|
+#if TREETRACE_ENABLED
|
|
+ TREETRACE(0x800,pParse,p, ("dropping superfluous ORDER BY:\n"));
|
|
+ if( sqlite3TreeTrace & 0x800 ){
|
|
+ sqlite3TreeViewExprList(0, p->pOrderBy, 0, "ORDERBY");
|
|
+ }
|
|
+#endif
|
|
+ sqlite3ParserAddCleanup(pParse,
|
|
+ (void(*)(sqlite3*,void*))sqlite3ExprListDelete,
|
|
+ p->pOrderBy);
|
|
+ testcase( pParse->earlyCleanup );
|
|
+ p->pOrderBy = 0;
|
|
+ }
|
|
p->selFlags &= ~SF_Distinct;
|
|
+ p->selFlags |= SF_NoopOrderBy;
|
|
}
|
|
sqlite3SelectPrep(pParse, p, 0);
|
|
- if( pParse->nErr || db->mallocFailed ){
|
|
+ if( pParse->nErr ){
|
|
goto select_end;
|
|
}
|
|
+ assert( db->mallocFailed==0 );
|
|
assert( p->pEList!=0 );
|
|
-#if SELECTTRACE_ENABLED
|
|
- if( sqlite3SelectTrace & 0x104 ){
|
|
- SELECTTRACE(0x104,pParse,p, ("after name resolution:\n"));
|
|
+#if TREETRACE_ENABLED
|
|
+ if( sqlite3TreeTrace & 0x10 ){
|
|
+ TREETRACE(0x10,pParse,p, ("after name resolution:\n"));
|
|
sqlite3TreeViewSelect(0, p, 0);
|
|
}
|
|
#endif
|
|
|
|
+ /* If the SF_UFSrcCheck flag is set, then this function is being called
|
|
+ ** as part of populating the temp table for an UPDATE...FROM statement.
|
|
+ ** In this case, it is an error if the target object (pSrc->a[0]) name
|
|
+ ** or alias is duplicated within FROM clause (pSrc->a[1..n]).
|
|
+ **
|
|
+ ** Postgres disallows this case too. The reason is that some other
|
|
+ ** systems handle this case differently, and not all the same way,
|
|
+ ** which is just confusing. To avoid this, we follow PG's lead and
|
|
+ ** disallow it altogether. */
|
|
+ if( p->selFlags & SF_UFSrcCheck ){
|
|
+ SrcItem *p0 = &p->pSrc->a[0];
|
|
+ if( sameSrcAlias(p0, p->pSrc) ){
|
|
+ sqlite3ErrorMsg(pParse,
|
|
+ "target object/alias may not appear in FROM clause: %s",
|
|
+ p0->zAlias ? p0->zAlias : p0->pTab->zName
|
|
+ );
|
|
+ goto select_end;
|
|
+ }
|
|
+
|
|
+ /* Clear the SF_UFSrcCheck flag. The check has already been performed,
|
|
+ ** and leaving this flag set can cause errors if a compound sub-query
|
|
+ ** in p->pSrc is flattened into this query and this function called
|
|
+ ** again as part of compound SELECT processing. */
|
|
+ p->selFlags &= ~SF_UFSrcCheck;
|
|
+ }
|
|
+
|
|
if( pDest->eDest==SRT_Output ){
|
|
- generateColumnNames(pParse, p);
|
|
+ sqlite3GenerateColumnNames(pParse, p);
|
|
}
|
|
|
|
#ifndef SQLITE_OMIT_WINDOWFUNC
|
|
- rc = sqlite3WindowRewrite(pParse, p);
|
|
- if( rc ){
|
|
- assert( db->mallocFailed || pParse->nErr>0 );
|
|
+ if( sqlite3WindowRewrite(pParse, p) ){
|
|
+ assert( pParse->nErr );
|
|
goto select_end;
|
|
}
|
|
-#if SELECTTRACE_ENABLED
|
|
- if( p->pWin && (sqlite3SelectTrace & 0x108)!=0 ){
|
|
- SELECTTRACE(0x104,pParse,p, ("after window rewrite:\n"));
|
|
+#if TREETRACE_ENABLED
|
|
+ if( p->pWin && (sqlite3TreeTrace & 0x40)!=0 ){
|
|
+ TREETRACE(0x40,pParse,p, ("after window rewrite:\n"));
|
|
sqlite3TreeViewSelect(0, p, 0);
|
|
}
|
|
#endif
|
|
@@ -133670,26 +145374,33 @@ SQLITE_PRIVATE int sqlite3Select(
|
|
memset(&sSort, 0, sizeof(sSort));
|
|
sSort.pOrderBy = p->pOrderBy;
|
|
|
|
- /* Try to various optimizations (flattening subqueries, and strength
|
|
+ /* Try to do various optimizations (flattening subqueries, and strength
|
|
** reduction of join operators) in the FROM clause up into the main query
|
|
*/
|
|
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
|
|
for(i=0; !p->pPrior && i<pTabList->nSrc; i++){
|
|
- struct SrcList_item *pItem = &pTabList->a[i];
|
|
+ SrcItem *pItem = &pTabList->a[i];
|
|
Select *pSub = pItem->pSelect;
|
|
Table *pTab = pItem->pTab;
|
|
|
|
+ /* The expander should have already created transient Table objects
|
|
+ ** even for FROM clause elements such as subqueries that do not correspond
|
|
+ ** 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.
|
|
*/
|
|
- if( (pItem->fg.jointype & JT_LEFT)!=0
|
|
+ if( (pItem->fg.jointype & (JT_LEFT|JT_RIGHT))==JT_LEFT
|
|
&& sqlite3ExprImpliesNonNullRow(p->pWhere, pItem->iCursor)
|
|
&& OptimizationEnabled(db, SQLITE_SimplifyJoin)
|
|
){
|
|
- SELECTTRACE(0x100,pParse,p,
|
|
+ TREETRACE(0x1000,pParse,p,
|
|
("LEFT-JOIN simplifies to JOIN on term %d\n",i));
|
|
pItem->fg.jointype &= ~(JT_LEFT|JT_OUTER);
|
|
- unsetJoinExpr(p->pWhere, pItem->iCursor);
|
|
+ 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 */
|
|
@@ -133713,6 +145424,41 @@ SQLITE_PRIVATE int sqlite3Select(
|
|
if( (pSub->selFlags & SF_Aggregate)!=0 ) continue;
|
|
assert( pSub->pGroupBy==0 );
|
|
|
|
+ /* If a FROM-clause subquery has an ORDER BY clause that is not
|
|
+ ** really doing anything, then delete it now so that it does not
|
|
+ ** interfere with query flattening. See the discussion at
|
|
+ ** https://sqlite.org/forum/forumpost/2d76f2bcf65d256a
|
|
+ **
|
|
+ ** Beware of these cases where the ORDER BY clause may not be safely
|
|
+ ** omitted:
|
|
+ **
|
|
+ ** (1) There is also a LIMIT clause
|
|
+ ** (2) The subquery was added to help with window-function
|
|
+ ** processing
|
|
+ ** (3) The subquery is in the FROM clause of an UPDATE
|
|
+ ** (4) The outer query uses an aggregate function other than
|
|
+ ** the built-in count(), min(), or max().
|
|
+ ** (5) The ORDER BY isn't going to accomplish anything because
|
|
+ ** one of:
|
|
+ ** (a) The outer query has a different ORDER BY clause
|
|
+ ** (b) The subquery is part of a join
|
|
+ ** See forum post 062d576715d277c8
|
|
+ */
|
|
+ if( pSub->pOrderBy!=0
|
|
+ && (p->pOrderBy!=0 || pTabList->nSrc>1) /* Condition (5) */
|
|
+ && pSub->pLimit==0 /* Condition (1) */
|
|
+ && (pSub->selFlags & SF_OrderByReqd)==0 /* Condition (2) */
|
|
+ && (p->selFlags & SF_OrderByReqd)==0 /* Condition (3) and (4) */
|
|
+ && OptimizationEnabled(db, SQLITE_OmitOrderBy)
|
|
+ ){
|
|
+ TREETRACE(0x800,pParse,p,
|
|
+ ("omit superfluous ORDER BY on %r FROM-clause subquery\n",i+1));
|
|
+ sqlite3ParserAddCleanup(pParse,
|
|
+ (void(*)(sqlite3*,void*))sqlite3ExprListDelete,
|
|
+ pSub->pOrderBy);
|
|
+ pSub->pOrderBy = 0;
|
|
+ }
|
|
+
|
|
/* If the outer query contains a "complex" result set (that is,
|
|
** if the result set of the outer query uses functions or subqueries)
|
|
** and if the subquery contains an ORDER BY clause and if
|
|
@@ -133735,7 +145481,7 @@ SQLITE_PRIVATE int sqlite3Select(
|
|
&& i==0
|
|
&& (p->selFlags & SF_ComplexResult)!=0
|
|
&& (pTabList->nSrc==1
|
|
- || (pTabList->a[1].fg.jointype&(JT_LEFT|JT_CROSS))!=0)
|
|
+ || (pTabList->a[1].fg.jointype&(JT_OUTER|JT_CROSS))!=0)
|
|
){
|
|
continue;
|
|
}
|
|
@@ -133759,9 +145505,9 @@ SQLITE_PRIVATE int sqlite3Select(
|
|
*/
|
|
if( p->pPrior ){
|
|
rc = multiSelect(pParse, p, pDest);
|
|
-#if SELECTTRACE_ENABLED
|
|
- SELECTTRACE(0x1,pParse,p,("end compound-select processing\n"));
|
|
- if( (sqlite3SelectTrace & 0x2000)!=0 && ExplainQueryPlanParent(pParse)==0 ){
|
|
+#if TREETRACE_ENABLED
|
|
+ TREETRACE(0x400,pParse,p,("end compound-select processing\n"));
|
|
+ if( (sqlite3TreeTrace & 0x400)!=0 && ExplainQueryPlanParent(pParse)==0 ){
|
|
sqlite3TreeViewSelect(0, p, 0);
|
|
}
|
|
#endif
|
|
@@ -133775,18 +145521,19 @@ SQLITE_PRIVATE int sqlite3Select(
|
|
** as the equivalent optimization will be handled by query planner in
|
|
** sqlite3WhereBegin().
|
|
*/
|
|
- if( pTabList->nSrc>1
|
|
+ if( p->pWhere!=0
|
|
+ && p->pWhere->op==TK_AND
|
|
&& OptimizationEnabled(db, SQLITE_PropagateConst)
|
|
&& propagateConstants(pParse, p)
|
|
){
|
|
-#if SELECTTRACE_ENABLED
|
|
- if( sqlite3SelectTrace & 0x100 ){
|
|
- SELECTTRACE(0x100,pParse,p,("After constant propagation:\n"));
|
|
+#if TREETRACE_ENABLED
|
|
+ if( sqlite3TreeTrace & 0x2000 ){
|
|
+ TREETRACE(0x2000,pParse,p,("After constant propagation:\n"));
|
|
sqlite3TreeViewSelect(0, p, 0);
|
|
}
|
|
#endif
|
|
}else{
|
|
- SELECTTRACE(0x100,pParse,p,("Constant propagation not helpful\n"));
|
|
+ TREETRACE(0x2000,pParse,p,("Constant propagation not helpful\n"));
|
|
}
|
|
|
|
#ifdef SQLITE_COUNTOFVIEW_OPTIMIZATION
|
|
@@ -133794,7 +145541,6 @@ SQLITE_PRIVATE int sqlite3Select(
|
|
&& countOfViewOptimization(pParse, p)
|
|
){
|
|
if( db->mallocFailed ) goto select_end;
|
|
- pEList = p->pEList;
|
|
pTabList = p->pSrc;
|
|
}
|
|
#endif
|
|
@@ -133804,7 +145550,8 @@ SQLITE_PRIVATE int sqlite3Select(
|
|
** (2) Generate code for all sub-queries
|
|
*/
|
|
for(i=0; i<pTabList->nSrc; i++){
|
|
- struct SrcList_item *pItem = &pTabList->a[i];
|
|
+ SrcItem *pItem = &pTabList->a[i];
|
|
+ SrcItem *pPrior;
|
|
SelectDest dest;
|
|
Select *pSub;
|
|
#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
|
|
@@ -133837,19 +145584,8 @@ SQLITE_PRIVATE int sqlite3Select(
|
|
pSub = pItem->pSelect;
|
|
if( pSub==0 ) continue;
|
|
|
|
- /* The code for a subquery should only be generated once, though it is
|
|
- ** technically harmless for it to be generated multiple times. The
|
|
- ** following assert() will detect if something changes to cause
|
|
- ** the same subquery to be coded multiple times, as a signal to the
|
|
- ** developers to try to optimize the situation.
|
|
- **
|
|
- ** Update 2019-07-24:
|
|
- ** See ticket https://sqlite.org/src/tktview/c52b09c7f38903b1311cec40.
|
|
- ** The dbsqlfuzz fuzzer found a case where the same subquery gets
|
|
- ** coded twice. So this assert() now becomes a testcase(). It should
|
|
- ** be very rare, though.
|
|
- */
|
|
- testcase( pItem->addrFillSub!=0 );
|
|
+ /* The code for a subquery should only be generated once. */
|
|
+ assert( pItem->addrFillSub==0 );
|
|
|
|
/* Increment Parse.nHeight by the height of the largest expression
|
|
** tree referred to by this, the parent select. The child select
|
|
@@ -133864,47 +145600,39 @@ SQLITE_PRIVATE int sqlite3Select(
|
|
** inside the subquery. This can help the subquery to run more efficiently.
|
|
*/
|
|
if( OptimizationEnabled(db, SQLITE_PushDown)
|
|
- && pushDownWhereTerms(pParse, pSub, p->pWhere, pItem->iCursor,
|
|
- (pItem->fg.jointype & JT_OUTER)!=0)
|
|
+ && (pItem->fg.isCte==0
|
|
+ || (pItem->u2.pCteUse->eM10d!=M10d_Yes && pItem->u2.pCteUse->nUse<2))
|
|
+ && pushDownWhereTerms(pParse, pSub, p->pWhere, pItem)
|
|
){
|
|
-#if SELECTTRACE_ENABLED
|
|
- if( sqlite3SelectTrace & 0x100 ){
|
|
- SELECTTRACE(0x100,pParse,p,
|
|
+#if TREETRACE_ENABLED
|
|
+ if( sqlite3TreeTrace & 0x4000 ){
|
|
+ TREETRACE(0x4000,pParse,p,
|
|
("After WHERE-clause push-down into subquery %d:\n", pSub->selId));
|
|
sqlite3TreeViewSelect(0, p, 0);
|
|
}
|
|
#endif
|
|
+ assert( pItem->pSelect && (pItem->pSelect->selFlags & SF_PushDown)!=0 );
|
|
}else{
|
|
- SELECTTRACE(0x100,pParse,p,("Push-down not possible\n"));
|
|
+ TREETRACE(0x4000,pParse,p,("Push-down not possible\n"));
|
|
}
|
|
|
|
zSavedAuthContext = pParse->zAuthContext;
|
|
pParse->zAuthContext = pItem->zName;
|
|
|
|
/* Generate code to implement the subquery
|
|
- **
|
|
- ** The subquery is implemented as a co-routine if the subquery is
|
|
- ** guaranteed to be the outer loop (so that it does not need to be
|
|
- ** computed more than once)
|
|
- **
|
|
- ** TODO: Are there other reasons beside (1) to use a co-routine
|
|
- ** implementation?
|
|
*/
|
|
- if( i==0
|
|
- && (pTabList->nSrc==1
|
|
- || (pTabList->a[1].fg.jointype&(JT_LEFT|JT_CROSS))!=0) /* (1) */
|
|
- ){
|
|
+ if( fromClauseTermCanBeCoroutine(pParse, pTabList, i, p->selFlags) ){
|
|
/* Implement a co-routine that will return a single row of the result
|
|
** set on each invocation.
|
|
*/
|
|
int addrTop = sqlite3VdbeCurrentAddr(v)+1;
|
|
-
|
|
+
|
|
pItem->regReturn = ++pParse->nMem;
|
|
sqlite3VdbeAddOp3(v, OP_InitCoroutine, pItem->regReturn, 0, addrTop);
|
|
- VdbeComment((v, "%s", pItem->pTab->zName));
|
|
+ VdbeComment((v, "%!S", pItem));
|
|
pItem->addrFillSub = addrTop;
|
|
sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn);
|
|
- ExplainQueryPlan((pParse, 1, "CO-ROUTINE %u", pSub->selId));
|
|
+ ExplainQueryPlan((pParse, 1, "CO-ROUTINE %!S", pItem));
|
|
sqlite3Select(pParse, pSub, &dest);
|
|
pItem->pTab->nRowLogEst = pSub->nSelectRow;
|
|
pItem->fg.viaCoroutine = 1;
|
|
@@ -133912,46 +145640,67 @@ SQLITE_PRIVATE int sqlite3Select(
|
|
sqlite3VdbeEndCoroutine(v, pItem->regReturn);
|
|
sqlite3VdbeJumpHere(v, addrTop-1);
|
|
sqlite3ClearTempRegCache(pParse);
|
|
- }else{
|
|
- /* Generate a subroutine that will fill an ephemeral table with
|
|
- ** the content of this subquery. pItem->addrFillSub will point
|
|
- ** to the address of the generated subroutine. pItem->regReturn
|
|
- ** is a register allocated to hold the subroutine return address
|
|
- */
|
|
+ }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
|
|
+ ** holds the result of the materialization. */
|
|
+ CteUse *pCteUse = pItem->u2.pCteUse;
|
|
+ sqlite3VdbeAddOp2(v, OP_Gosub, pCteUse->regRtn, pCteUse->addrM9e);
|
|
+ if( pItem->iCursor!=pCteUse->iCur ){
|
|
+ sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pCteUse->iCur);
|
|
+ VdbeComment((v, "%!S", pItem));
|
|
+ }
|
|
+ pSub->nSelectRow = pCteUse->nRowEst;
|
|
+ }else if( (pPrior = isSelfJoinView(pTabList, pItem, 0, i))!=0 ){
|
|
+ /* This view has already been materialized by a prior entry in
|
|
+ ** this same FROM clause. Reuse it. */
|
|
+ if( pPrior->addrFillSub ){
|
|
+ sqlite3VdbeAddOp2(v, OP_Gosub, pPrior->regReturn, pPrior->addrFillSub);
|
|
+ }
|
|
+ sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pPrior->iCursor);
|
|
+ pSub->nSelectRow = pPrior->pSelect->nSelectRow;
|
|
+ }else{
|
|
+ /* Materialize the view. If the view is not correlated, generate a
|
|
+ ** subroutine to do the materialization so that subsequent uses of
|
|
+ ** the same view can reuse the materialization. */
|
|
int topAddr;
|
|
int onceAddr = 0;
|
|
- int retAddr;
|
|
- struct SrcList_item *pPrior;
|
|
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
|
|
+ int addrExplain;
|
|
+#endif
|
|
|
|
- testcase( pItem->addrFillSub==0 ); /* Ticket c52b09c7f38903b1311 */
|
|
pItem->regReturn = ++pParse->nMem;
|
|
- topAddr = sqlite3VdbeAddOp2(v, OP_Integer, 0, pItem->regReturn);
|
|
+ topAddr = sqlite3VdbeAddOp0(v, OP_Goto);
|
|
pItem->addrFillSub = topAddr+1;
|
|
+ pItem->fg.isMaterialized = 1;
|
|
if( pItem->fg.isCorrelated==0 ){
|
|
/* If the subquery is not correlated and if we are not inside of
|
|
** a trigger, then we only need to compute the value of the subquery
|
|
** once. */
|
|
onceAddr = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
|
|
- VdbeComment((v, "materialize \"%s\"", pItem->pTab->zName));
|
|
+ VdbeComment((v, "materialize %!S", pItem));
|
|
}else{
|
|
- VdbeNoopComment((v, "materialize \"%s\"", pItem->pTab->zName));
|
|
- }
|
|
- pPrior = isSelfJoinView(pTabList, pItem);
|
|
- if( pPrior ){
|
|
- sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pPrior->iCursor);
|
|
- assert( pPrior->pSelect!=0 );
|
|
- pSub->nSelectRow = pPrior->pSelect->nSelectRow;
|
|
- }else{
|
|
- sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
|
|
- ExplainQueryPlan((pParse, 1, "MATERIALIZE %u", pSub->selId));
|
|
- sqlite3Select(pParse, pSub, &dest);
|
|
+ VdbeNoopComment((v, "materialize %!S", pItem));
|
|
}
|
|
+ sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
|
|
+
|
|
+ ExplainQueryPlan2(addrExplain, (pParse, 1, "MATERIALIZE %!S", pItem));
|
|
+ sqlite3Select(pParse, pSub, &dest);
|
|
pItem->pTab->nRowLogEst = pSub->nSelectRow;
|
|
if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr);
|
|
- retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn);
|
|
- VdbeComment((v, "end %s", pItem->pTab->zName));
|
|
- sqlite3VdbeChangeP1(v, topAddr, retAddr);
|
|
+ sqlite3VdbeAddOp2(v, OP_Return, pItem->regReturn, topAddr+1);
|
|
+ VdbeComment((v, "end %!S", pItem));
|
|
+ sqlite3VdbeScanStatusRange(v, addrExplain, addrExplain, -1);
|
|
+ sqlite3VdbeJumpHere(v, topAddr);
|
|
sqlite3ClearTempRegCache(pParse);
|
|
+ if( pItem->fg.isCte && pItem->fg.isCorrelated==0 ){
|
|
+ CteUse *pCteUse = pItem->u2.pCteUse;
|
|
+ pCteUse->addrM9e = pItem->addrFillSub;
|
|
+ pCteUse->regRtn = pItem->regReturn;
|
|
+ pCteUse->iCur = pItem->iCursor;
|
|
+ pCteUse->nRowEst = pSub->nSelectRow;
|
|
+ }
|
|
}
|
|
if( db->mallocFailed ) goto select_end;
|
|
pParse->nHeight -= sqlite3SelectExprHeight(p);
|
|
@@ -133967,14 +145716,14 @@ SQLITE_PRIVATE int sqlite3Select(
|
|
pHaving = p->pHaving;
|
|
sDistinct.isTnct = (p->selFlags & SF_Distinct)!=0;
|
|
|
|
-#if SELECTTRACE_ENABLED
|
|
- if( sqlite3SelectTrace & 0x400 ){
|
|
- SELECTTRACE(0x400,pParse,p,("After all FROM-clause analysis:\n"));
|
|
+#if TREETRACE_ENABLED
|
|
+ if( sqlite3TreeTrace & 0x8000 ){
|
|
+ TREETRACE(0x8000,pParse,p,("After all FROM-clause analysis:\n"));
|
|
sqlite3TreeViewSelect(0, p, 0);
|
|
}
|
|
#endif
|
|
|
|
- /* If the query is DISTINCT with an ORDER BY but is not an aggregate, and
|
|
+ /* If the query is DISTINCT with an ORDER BY but is not an aggregate, and
|
|
** if the select-list is the same as the ORDER BY list, then this query
|
|
** can be rewritten as a GROUP BY. In other words, this:
|
|
**
|
|
@@ -133984,12 +145733,12 @@ SQLITE_PRIVATE int sqlite3Select(
|
|
**
|
|
** SELECT xyz FROM ... GROUP BY xyz ORDER BY xyz
|
|
**
|
|
- ** The second form is preferred as a single index (or temp-table) may be
|
|
- ** used for both the ORDER BY and DISTINCT processing. As originally
|
|
- ** written the query must use a temp-table for at least one of the ORDER
|
|
+ ** The second form is preferred as a single index (or temp-table) may be
|
|
+ ** used for both the ORDER BY and DISTINCT processing. As originally
|
|
+ ** written the query must use a temp-table for at least one of the ORDER
|
|
** BY and DISTINCT, and an index or separate temp-table for the other.
|
|
*/
|
|
- if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct
|
|
+ if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct
|
|
&& sqlite3ExprListCompare(sSort.pOrderBy, pEList, -1)==0
|
|
#ifndef SQLITE_OMIT_WINDOWFUNC
|
|
&& p->pWin==0
|
|
@@ -134002,10 +145751,11 @@ SQLITE_PRIVATE int sqlite3Select(
|
|
** the sDistinct.isTnct is still set. Hence, isTnct represents the
|
|
** original setting of the SF_Distinct flag, not the current setting */
|
|
assert( sDistinct.isTnct );
|
|
+ sDistinct.isTnct = 2;
|
|
|
|
-#if SELECTTRACE_ENABLED
|
|
- if( sqlite3SelectTrace & 0x400 ){
|
|
- SELECTTRACE(0x400,pParse,p,("Transform DISTINCT into GROUP BY:\n"));
|
|
+#if TREETRACE_ENABLED
|
|
+ if( sqlite3TreeTrace & 0x20000 ){
|
|
+ TREETRACE(0x20000,pParse,p,("Transform DISTINCT into GROUP BY:\n"));
|
|
sqlite3TreeViewSelect(0, p, 0);
|
|
}
|
|
#endif
|
|
@@ -134037,6 +145787,18 @@ SQLITE_PRIVATE int sqlite3Select(
|
|
*/
|
|
if( pDest->eDest==SRT_EphemTab ){
|
|
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pDest->iSDParm, pEList->nExpr);
|
|
+ if( p->selFlags & SF_NestedFrom ){
|
|
+ /* Delete or NULL-out result columns that will never be used */
|
|
+ int ii;
|
|
+ for(ii=pEList->nExpr-1; ii>0 && pEList->a[ii].fg.bUsed==0; ii--){
|
|
+ sqlite3ExprDelete(db, pEList->a[ii].pExpr);
|
|
+ sqlite3DbFree(db, pEList->a[ii].zEName);
|
|
+ pEList->nExpr--;
|
|
+ }
|
|
+ for(ii=0; ii<pEList->nExpr; ii++){
|
|
+ if( pEList->a[ii].fg.bUsed==0 ) pEList->a[ii].pExpr->op = TK_NULL;
|
|
+ }
|
|
+ }
|
|
}
|
|
|
|
/* Set the limiter.
|
|
@@ -134045,7 +145807,7 @@ SQLITE_PRIVATE int sqlite3Select(
|
|
if( (p->selFlags & SF_FixedLimit)==0 ){
|
|
p->nSelectRow = 320; /* 4 billion rows */
|
|
}
|
|
- computeLimitRegisters(pParse, p, iEnd);
|
|
+ if( p->pLimit ) computeLimitRegisters(pParse, p, iEnd);
|
|
if( p->iLimit==0 && sSort.addrSortIndex>=0 ){
|
|
sqlite3VdbeChangeOpcode(v, sSort.addrSortIndex, OP_SorterOpen);
|
|
sSort.sortFlags |= SORTFLAG_UseSorter;
|
|
@@ -134070,7 +145832,7 @@ SQLITE_PRIVATE int sqlite3Select(
|
|
u16 wctrlFlags = (sDistinct.isTnct ? WHERE_WANT_DISTINCT : 0)
|
|
| (p->selFlags & SF_FixedLimit);
|
|
#ifndef SQLITE_OMIT_WINDOWFUNC
|
|
- Window *pWin = p->pWin; /* Master window object (or NULL) */
|
|
+ Window *pWin = p->pWin; /* Main window object (or NULL) */
|
|
if( pWin ){
|
|
sqlite3WindowCodeInit(pParse, p);
|
|
}
|
|
@@ -134079,9 +145841,9 @@ SQLITE_PRIVATE int sqlite3Select(
|
|
|
|
|
|
/* Begin the database scan. */
|
|
- SELECTTRACE(1,pParse,p,("WhereBegin\n"));
|
|
+ TREETRACE(0x2,pParse,p,("WhereBegin\n"));
|
|
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, sSort.pOrderBy,
|
|
- p->pEList, wctrlFlags, p->nSelectRow);
|
|
+ p->pEList, p, wctrlFlags, p->nSelectRow);
|
|
if( pWInfo==0 ) goto select_end;
|
|
if( sqlite3WhereOutputRowCount(pWInfo) < p->nSelectRow ){
|
|
p->nSelectRow = sqlite3WhereOutputRowCount(pWInfo);
|
|
@@ -134096,8 +145858,9 @@ SQLITE_PRIVATE int sqlite3Select(
|
|
sSort.pOrderBy = 0;
|
|
}
|
|
}
|
|
+ TREETRACE(0x2,pParse,p,("WhereBegin returns\n"));
|
|
|
|
- /* If sorting index that was created by a prior OP_OpenEphemeral
|
|
+ /* If sorting index that was created by a prior OP_OpenEphemeral
|
|
** instruction ended up not being needed, then change the OP_OpenEphemeral
|
|
** into an OP_Noop.
|
|
*/
|
|
@@ -134134,6 +145897,7 @@ SQLITE_PRIVATE int sqlite3Select(
|
|
|
|
/* End the database scan loop.
|
|
*/
|
|
+ TREETRACE(0x2,pParse,p,("WhereEnd\n"));
|
|
sqlite3WhereEnd(pWInfo);
|
|
}
|
|
}else{
|
|
@@ -134169,8 +145933,8 @@ SQLITE_PRIVATE int sqlite3Select(
|
|
if( p->nSelectRow>66 ) p->nSelectRow = 66;
|
|
|
|
/* If there is both a GROUP BY and an ORDER BY clause and they are
|
|
- ** identical, then it may be possible to disable the ORDER BY clause
|
|
- ** on the grounds that the GROUP BY will cause elements to come out
|
|
+ ** identical, then it may be possible to disable the ORDER BY clause
|
|
+ ** on the grounds that the GROUP BY will cause elements to come out
|
|
** in the correct order. It also may not - the GROUP BY might use a
|
|
** database index that causes rows to be grouped together as required
|
|
** but not actually sorted. Either way, record the fact that the
|
|
@@ -134180,12 +145944,13 @@ SQLITE_PRIVATE int sqlite3Select(
|
|
int ii;
|
|
/* The GROUP BY processing doesn't care whether rows are delivered in
|
|
** ASC or DESC order - only that each group is returned contiguously.
|
|
- ** So set the ASC/DESC flags in the GROUP BY to match those in the
|
|
- ** ORDER BY to maximize the chances of rows being delivered in an
|
|
+ ** So set the ASC/DESC flags in the GROUP BY to match those in the
|
|
+ ** ORDER BY to maximize the chances of rows being delivered in an
|
|
** order that makes the ORDER BY redundant. */
|
|
for(ii=0; ii<pGroupBy->nExpr; ii++){
|
|
- u8 sortFlags = sSort.pOrderBy->a[ii].sortFlags & KEYINFO_ORDER_DESC;
|
|
- pGroupBy->a[ii].sortFlags = sortFlags;
|
|
+ u8 sortFlags;
|
|
+ sortFlags = sSort.pOrderBy->a[ii].fg.sortFlags & KEYINFO_ORDER_DESC;
|
|
+ pGroupBy->a[ii].fg.sortFlags = sortFlags;
|
|
}
|
|
if( sqlite3ExprListCompare(pGroupBy, sSort.pOrderBy, -1)==0 ){
|
|
orderByGrp = 1;
|
|
@@ -134203,14 +145968,26 @@ SQLITE_PRIVATE int sqlite3Select(
|
|
** sAggInfo for all TK_AGG_FUNCTION nodes in expressions of the
|
|
** SELECT statement.
|
|
*/
|
|
+ pAggInfo = sqlite3DbMallocZero(db, sizeof(*pAggInfo) );
|
|
+ if( pAggInfo ){
|
|
+ sqlite3ParserAddCleanup(pParse,
|
|
+ (void(*)(sqlite3*,void*))agginfoFree, pAggInfo);
|
|
+ testcase( pParse->earlyCleanup );
|
|
+ }
|
|
+ if( db->mallocFailed ){
|
|
+ goto select_end;
|
|
+ }
|
|
+ pAggInfo->selId = p->selId;
|
|
+#ifdef SQLITE_DEBUG
|
|
+ pAggInfo->pSelect = p;
|
|
+#endif
|
|
memset(&sNC, 0, sizeof(sNC));
|
|
sNC.pParse = pParse;
|
|
sNC.pSrcList = pTabList;
|
|
- sNC.uNC.pAggInfo = &sAggInfo;
|
|
+ sNC.uNC.pAggInfo = pAggInfo;
|
|
VVA_ONLY( sNC.ncFlags = NC_UAggInfo; )
|
|
- sAggInfo.mnReg = pParse->nMem+1;
|
|
- sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr : 0;
|
|
- sAggInfo.pGroupBy = pGroupBy;
|
|
+ pAggInfo->nSortingColumn = pGroupBy ? pGroupBy->nExpr : 0;
|
|
+ pAggInfo->pGroupBy = pGroupBy;
|
|
sqlite3ExprAnalyzeAggList(&sNC, pEList);
|
|
sqlite3ExprAnalyzeAggList(&sNC, sSort.pOrderBy);
|
|
if( pHaving ){
|
|
@@ -134223,42 +146000,23 @@ SQLITE_PRIVATE int sqlite3Select(
|
|
}
|
|
sqlite3ExprAnalyzeAggregates(&sNC, pHaving);
|
|
}
|
|
- sAggInfo.nAccumulator = sAggInfo.nColumn;
|
|
- if( p->pGroupBy==0 && p->pHaving==0 && sAggInfo.nFunc==1 ){
|
|
- minMaxFlag = minMaxQuery(db, sAggInfo.aFunc[0].pExpr, &pMinMaxOrderBy);
|
|
+ pAggInfo->nAccumulator = pAggInfo->nColumn;
|
|
+ if( p->pGroupBy==0 && p->pHaving==0 && pAggInfo->nFunc==1 ){
|
|
+ minMaxFlag = minMaxQuery(db, pAggInfo->aFunc[0].pFExpr, &pMinMaxOrderBy);
|
|
}else{
|
|
minMaxFlag = WHERE_ORDERBY_NORMAL;
|
|
}
|
|
- for(i=0; i<sAggInfo.nFunc; i++){
|
|
- Expr *pExpr = sAggInfo.aFunc[i].pExpr;
|
|
- assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
|
|
- sNC.ncFlags |= NC_InAggFunc;
|
|
- sqlite3ExprAnalyzeAggList(&sNC, pExpr->x.pList);
|
|
-#ifndef SQLITE_OMIT_WINDOWFUNC
|
|
- assert( !IsWindowFunc(pExpr) );
|
|
- if( ExprHasProperty(pExpr, EP_WinFunc) ){
|
|
- sqlite3ExprAnalyzeAggregates(&sNC, pExpr->y.pWin->pFilter);
|
|
- }
|
|
-#endif
|
|
- sNC.ncFlags &= ~NC_InAggFunc;
|
|
- }
|
|
- sAggInfo.mxReg = pParse->nMem;
|
|
+ analyzeAggFuncArgs(pAggInfo, &sNC);
|
|
if( db->mallocFailed ) goto select_end;
|
|
-#if SELECTTRACE_ENABLED
|
|
- if( sqlite3SelectTrace & 0x400 ){
|
|
- int ii;
|
|
- SELECTTRACE(0x400,pParse,p,("After aggregate analysis:\n"));
|
|
+#if TREETRACE_ENABLED
|
|
+ if( sqlite3TreeTrace & 0x20 ){
|
|
+ TREETRACE(0x20,pParse,p,("After aggregate analysis %p:\n", pAggInfo));
|
|
sqlite3TreeViewSelect(0, p, 0);
|
|
- for(ii=0; ii<sAggInfo.nColumn; ii++){
|
|
- sqlite3DebugPrintf("agg-column[%d] iMem=%d\n",
|
|
- ii, sAggInfo.aCol[ii].iMem);
|
|
- sqlite3TreeViewExpr(0, sAggInfo.aCol[ii].pExpr, 0);
|
|
- }
|
|
- for(ii=0; ii<sAggInfo.nFunc; ii++){
|
|
- sqlite3DebugPrintf("agg-func[%d]: iMem=%d\n",
|
|
- ii, sAggInfo.aFunc[ii].iMem);
|
|
- sqlite3TreeViewExpr(0, sAggInfo.aFunc[ii].pExpr, 0);
|
|
+ if( minMaxFlag ){
|
|
+ sqlite3DebugPrintf("MIN/MAX Optimization (0x%02x) adds:\n", minMaxFlag);
|
|
+ sqlite3TreeViewExprList(0, pMinMaxOrderBy, 0, "ORDERBY");
|
|
}
|
|
+ printAggInfo(pAggInfo);
|
|
}
|
|
#endif
|
|
|
|
@@ -134276,16 +146034,33 @@ SQLITE_PRIVATE int sqlite3Select(
|
|
int addrSortingIdx; /* The OP_OpenEphemeral for the sorting index */
|
|
int addrReset; /* Subroutine for resetting the accumulator */
|
|
int regReset; /* Return address register for reset subroutine */
|
|
+ ExprList *pDistinct = 0;
|
|
+ u16 distFlag = 0;
|
|
+ int eDist = WHERE_DISTINCT_NOOP;
|
|
+
|
|
+ if( pAggInfo->nFunc==1
|
|
+ && pAggInfo->aFunc[0].iDistinct>=0
|
|
+ && ALWAYS(pAggInfo->aFunc[0].pFExpr!=0)
|
|
+ && ALWAYS(ExprUseXList(pAggInfo->aFunc[0].pFExpr))
|
|
+ && pAggInfo->aFunc[0].pFExpr->x.pList!=0
|
|
+ ){
|
|
+ Expr *pExpr = pAggInfo->aFunc[0].pFExpr->x.pList->a[0].pExpr;
|
|
+ pExpr = sqlite3ExprDup(db, pExpr, 0);
|
|
+ pDistinct = sqlite3ExprListDup(db, pGroupBy, 0);
|
|
+ pDistinct = sqlite3ExprListAppend(pParse, pDistinct, pExpr);
|
|
+ distFlag = pDistinct ? (WHERE_WANT_DISTINCT|WHERE_AGG_DISTINCT) : 0;
|
|
+ }
|
|
|
|
/* If there is a GROUP BY clause we might need a sorting index to
|
|
** implement it. Allocate that sorting index now. If it turns out
|
|
** that we do not need it after all, the OP_SorterOpen instruction
|
|
- ** will be converted into a Noop.
|
|
+ ** will be converted into a Noop.
|
|
*/
|
|
- sAggInfo.sortingIdx = pParse->nTab++;
|
|
- pKeyInfo = sqlite3KeyInfoFromExprList(pParse,pGroupBy,0,sAggInfo.nColumn);
|
|
- addrSortingIdx = sqlite3VdbeAddOp4(v, OP_SorterOpen,
|
|
- sAggInfo.sortingIdx, sAggInfo.nSortingColumn,
|
|
+ pAggInfo->sortingIdx = pParse->nTab++;
|
|
+ pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pGroupBy,
|
|
+ 0, pAggInfo->nColumn);
|
|
+ addrSortingIdx = sqlite3VdbeAddOp4(v, OP_SorterOpen,
|
|
+ pAggInfo->sortingIdx, pAggInfo->nSortingColumn,
|
|
0, (char*)pKeyInfo, P4_KEYINFO);
|
|
|
|
/* Initialize memory locations used by GROUP BY aggregate processing
|
|
@@ -134310,11 +146085,21 @@ SQLITE_PRIVATE int sqlite3Select(
|
|
** in the right order to begin with.
|
|
*/
|
|
sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset);
|
|
- SELECTTRACE(1,pParse,p,("WhereBegin\n"));
|
|
- pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy, 0,
|
|
- WHERE_GROUPBY | (orderByGrp ? WHERE_SORTBYGROUP : 0), 0
|
|
+ TREETRACE(0x2,pParse,p,("WhereBegin\n"));
|
|
+ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy, pDistinct,
|
|
+ p, (sDistinct.isTnct==2 ? WHERE_DISTINCTBY : WHERE_GROUPBY)
|
|
+ | (orderByGrp ? WHERE_SORTBYGROUP : 0) | distFlag, 0
|
|
);
|
|
- if( pWInfo==0 ) goto select_end;
|
|
+ if( pWInfo==0 ){
|
|
+ sqlite3ExprListDelete(db, pDistinct);
|
|
+ goto select_end;
|
|
+ }
|
|
+ if( pParse->pIdxEpr ){
|
|
+ optimizeAggregateUseOfIndexedExpr(pParse, p, pAggInfo, &sNC);
|
|
+ }
|
|
+ assignAggregateRegisters(pParse, pAggInfo);
|
|
+ eDist = sqlite3WhereIsDistinct(pWInfo);
|
|
+ TREETRACE(0x2,pParse,p,("WhereBegin returns\n"));
|
|
if( sqlite3WhereIsOrdered(pWInfo)==pGroupBy->nExpr ){
|
|
/* The optimizer is able to deliver rows in group by order so
|
|
** we do not have to sort. The OP_OpenEphemeral table will be
|
|
@@ -134332,7 +146117,7 @@ SQLITE_PRIVATE int sqlite3Select(
|
|
int nCol;
|
|
int nGroupBy;
|
|
|
|
- explainTempTable(pParse,
|
|
+ explainTempTable(pParse,
|
|
(sDistinct.isTnct && (p->selFlags&SF_Distinct)==0) ?
|
|
"DISTINCT" : "GROUP BY");
|
|
|
|
@@ -134340,8 +146125,8 @@ SQLITE_PRIVATE int sqlite3Select(
|
|
nGroupBy = pGroupBy->nExpr;
|
|
nCol = nGroupBy;
|
|
j = nGroupBy;
|
|
- for(i=0; i<sAggInfo.nColumn; i++){
|
|
- if( sAggInfo.aCol[i].iSorterColumn>=j ){
|
|
+ for(i=0; i<pAggInfo->nColumn; i++){
|
|
+ if( pAggInfo->aCol[i].iSorterColumn>=j ){
|
|
nCol++;
|
|
j++;
|
|
}
|
|
@@ -134349,27 +146134,45 @@ SQLITE_PRIVATE int sqlite3Select(
|
|
regBase = sqlite3GetTempRange(pParse, nCol);
|
|
sqlite3ExprCodeExprList(pParse, pGroupBy, regBase, 0, 0);
|
|
j = nGroupBy;
|
|
- for(i=0; i<sAggInfo.nColumn; i++){
|
|
- struct AggInfo_col *pCol = &sAggInfo.aCol[i];
|
|
+ pAggInfo->directMode = 1;
|
|
+ for(i=0; i<pAggInfo->nColumn; i++){
|
|
+ struct AggInfo_col *pCol = &pAggInfo->aCol[i];
|
|
if( pCol->iSorterColumn>=j ){
|
|
- int r1 = j + regBase;
|
|
- sqlite3ExprCodeGetColumnOfTable(v,
|
|
- pCol->pTab, pCol->iTable, pCol->iColumn, r1);
|
|
+ sqlite3ExprCode(pParse, pCol->pCExpr, j + regBase);
|
|
j++;
|
|
}
|
|
}
|
|
+ pAggInfo->directMode = 0;
|
|
regRecord = sqlite3GetTempReg(pParse);
|
|
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regRecord);
|
|
- sqlite3VdbeAddOp2(v, OP_SorterInsert, sAggInfo.sortingIdx, regRecord);
|
|
+ sqlite3VdbeAddOp2(v, OP_SorterInsert, pAggInfo->sortingIdx, regRecord);
|
|
sqlite3ReleaseTempReg(pParse, regRecord);
|
|
sqlite3ReleaseTempRange(pParse, regBase, nCol);
|
|
+ TREETRACE(0x2,pParse,p,("WhereEnd\n"));
|
|
sqlite3WhereEnd(pWInfo);
|
|
- sAggInfo.sortingIdxPTab = sortPTab = pParse->nTab++;
|
|
+ pAggInfo->sortingIdxPTab = sortPTab = pParse->nTab++;
|
|
sortOut = sqlite3GetTempReg(pParse);
|
|
sqlite3VdbeAddOp3(v, OP_OpenPseudo, sortPTab, sortOut, nCol);
|
|
- sqlite3VdbeAddOp2(v, OP_SorterSort, sAggInfo.sortingIdx, addrEnd);
|
|
+ sqlite3VdbeAddOp2(v, OP_SorterSort, pAggInfo->sortingIdx, addrEnd);
|
|
VdbeComment((v, "GROUP BY sort")); VdbeCoverage(v);
|
|
- sAggInfo.useSortingIdx = 1;
|
|
+ pAggInfo->useSortingIdx = 1;
|
|
+ }
|
|
+
|
|
+ /* If there are entries in pAgggInfo->aFunc[] that contain subexpressions
|
|
+ ** that are indexed (and that were previously identified and tagged
|
|
+ ** in optimizeAggregateUseOfIndexedExpr()) then those subexpressions
|
|
+ ** must now be converted into a TK_AGG_COLUMN node so that the value
|
|
+ ** is correctly pulled from the index rather than being recomputed. */
|
|
+ if( pParse->pIdxEpr ){
|
|
+ aggregateConvertIndexedExprRefToColumn(pAggInfo);
|
|
+#if TREETRACE_ENABLED
|
|
+ if( sqlite3TreeTrace & 0x20 ){
|
|
+ TREETRACE(0x20, pParse, p,
|
|
+ ("AggInfo function expressions converted to reference index\n"));
|
|
+ sqlite3TreeViewSelect(0, p, 0);
|
|
+ printAggInfo(pAggInfo);
|
|
+ }
|
|
+#endif
|
|
}
|
|
|
|
/* If the index or temporary table used by the GROUP BY sort
|
|
@@ -134377,9 +146180,9 @@ SQLITE_PRIVATE int sqlite3Select(
|
|
** clause, cancel the ephemeral table open coded earlier.
|
|
**
|
|
** This is an optimization - the correct answer should result regardless.
|
|
- ** Use the SQLITE_GroupByOrder flag with SQLITE_TESTCTRL_OPTIMIZER to
|
|
+ ** Use the SQLITE_GroupByOrder flag with SQLITE_TESTCTRL_OPTIMIZER to
|
|
** disable this optimization for testing purposes. */
|
|
- if( orderByGrp && OptimizationEnabled(db, SQLITE_GroupByOrder)
|
|
+ if( orderByGrp && OptimizationEnabled(db, SQLITE_GroupByOrder)
|
|
&& (groupBySort || sqlite3WhereIsSorted(pWInfo))
|
|
){
|
|
sSort.pOrderBy = 0;
|
|
@@ -134393,14 +146196,14 @@ SQLITE_PRIVATE int sqlite3Select(
|
|
*/
|
|
addrTopOfLoop = sqlite3VdbeCurrentAddr(v);
|
|
if( groupBySort ){
|
|
- sqlite3VdbeAddOp3(v, OP_SorterData, sAggInfo.sortingIdx,
|
|
+ sqlite3VdbeAddOp3(v, OP_SorterData, pAggInfo->sortingIdx,
|
|
sortOut, sortPTab);
|
|
}
|
|
for(j=0; j<pGroupBy->nExpr; j++){
|
|
if( groupBySort ){
|
|
sqlite3VdbeAddOp3(v, OP_Column, sortPTab, j, iBMem+j);
|
|
}else{
|
|
- sAggInfo.directMode = 1;
|
|
+ pAggInfo->directMode = 1;
|
|
sqlite3ExprCode(pParse, pGroupBy->a[j].pExpr, iBMem+j);
|
|
}
|
|
}
|
|
@@ -134430,19 +146233,21 @@ SQLITE_PRIVATE int sqlite3Select(
|
|
** the current row
|
|
*/
|
|
sqlite3VdbeJumpHere(v, addr1);
|
|
- updateAccumulator(pParse, iUseFlag, &sAggInfo);
|
|
+ updateAccumulator(pParse, iUseFlag, pAggInfo, eDist);
|
|
sqlite3VdbeAddOp2(v, OP_Integer, 1, iUseFlag);
|
|
VdbeComment((v, "indicate data in accumulator"));
|
|
|
|
/* End of the loop
|
|
*/
|
|
if( groupBySort ){
|
|
- sqlite3VdbeAddOp2(v, OP_SorterNext, sAggInfo.sortingIdx, addrTopOfLoop);
|
|
+ sqlite3VdbeAddOp2(v, OP_SorterNext, pAggInfo->sortingIdx,addrTopOfLoop);
|
|
VdbeCoverage(v);
|
|
}else{
|
|
+ TREETRACE(0x2,pParse,p,("WhereEnd\n"));
|
|
sqlite3WhereEnd(pWInfo);
|
|
sqlite3VdbeChangeToNoop(v, addrSortingIdx);
|
|
}
|
|
+ sqlite3ExprListDelete(db, pDistinct);
|
|
|
|
/* Output the final row of result
|
|
*/
|
|
@@ -134470,7 +146275,7 @@ SQLITE_PRIVATE int sqlite3Select(
|
|
VdbeCoverage(v);
|
|
VdbeComment((v, "Groupby result generator entry point"));
|
|
sqlite3VdbeAddOp1(v, OP_Return, regOutputRow);
|
|
- finalizeAggFunctions(pParse, &sAggInfo);
|
|
+ finalizeAggFunctions(pParse, pAggInfo);
|
|
sqlite3ExprIfFalse(pParse, pHaving, addrOutputRow+1, SQLITE_JUMPIFNULL);
|
|
selectInnerLoop(pParse, p, -1, &sSort,
|
|
&sDistinct, pDest,
|
|
@@ -134481,16 +146286,19 @@ SQLITE_PRIVATE int sqlite3Select(
|
|
/* Generate a subroutine that will reset the group-by accumulator
|
|
*/
|
|
sqlite3VdbeResolveLabel(v, addrReset);
|
|
- resetAccumulator(pParse, &sAggInfo);
|
|
+ resetAccumulator(pParse, pAggInfo);
|
|
sqlite3VdbeAddOp2(v, OP_Integer, 0, iUseFlag);
|
|
VdbeComment((v, "indicate accumulator empty"));
|
|
sqlite3VdbeAddOp1(v, OP_Return, regReset);
|
|
-
|
|
+
|
|
+ if( distFlag!=0 && eDist!=WHERE_DISTINCT_NOOP ){
|
|
+ struct AggInfo_func *pF = &pAggInfo->aFunc[0];
|
|
+ fixDistinctOpenEph(pParse, eDist, pF->iDistinct, pF->iDistAddr);
|
|
+ }
|
|
} /* endif pGroupBy. Begin aggregate queries without GROUP BY: */
|
|
else {
|
|
-#ifndef SQLITE_OMIT_BTREECOUNT
|
|
Table *pTab;
|
|
- if( (pTab = isSimpleCount(p, &sAggInfo))!=0 ){
|
|
+ if( (pTab = isSimpleCount(p, pAggInfo))!=0 ){
|
|
/* If isSimpleCount() returns a pointer to a Table structure, then
|
|
** the SQL statement is of the form:
|
|
**
|
|
@@ -134509,7 +146317,7 @@ SQLITE_PRIVATE int sqlite3Select(
|
|
Index *pIdx; /* Iterator variable */
|
|
KeyInfo *pKeyInfo = 0; /* Keyinfo for scanned index */
|
|
Index *pBest = 0; /* Best index found so far */
|
|
- int iRoot = pTab->tnum; /* Root page of scanned b-tree */
|
|
+ Pgno iRoot = pTab->tnum; /* Root page of scanned b-tree */
|
|
|
|
sqlite3CodeVerifySchema(pParse, iDb);
|
|
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
|
|
@@ -134520,17 +146328,19 @@ SQLITE_PRIVATE int sqlite3Select(
|
|
**
|
|
** (2013-10-03) Do not count the entries in a partial index.
|
|
**
|
|
- ** In practice the KeyInfo structure will not be used. It is only
|
|
+ ** In practice the KeyInfo structure will not be used. It is only
|
|
** passed to keep OP_OpenRead happy.
|
|
*/
|
|
if( !HasRowid(pTab) ) pBest = sqlite3PrimaryKeyIndex(pTab);
|
|
- for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
|
- if( pIdx->bUnordered==0
|
|
- && pIdx->szIdxRow<pTab->szTabRow
|
|
- && pIdx->pPartIdxWhere==0
|
|
- && (!pBest || pIdx->szIdxRow<pBest->szIdxRow)
|
|
- ){
|
|
- pBest = pIdx;
|
|
+ if( !p->pSrc->a[0].fg.notIndexed ){
|
|
+ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
|
+ if( pIdx->bUnordered==0
|
|
+ && pIdx->szIdxRow<pTab->szTabRow
|
|
+ && pIdx->pPartIdxWhere==0
|
|
+ && (!pBest || pIdx->szIdxRow<pBest->szIdxRow)
|
|
+ ){
|
|
+ pBest = pIdx;
|
|
+ }
|
|
}
|
|
}
|
|
if( pBest ){
|
|
@@ -134539,17 +146349,19 @@ SQLITE_PRIVATE int sqlite3Select(
|
|
}
|
|
|
|
/* Open a read-only cursor, execute the OP_Count, close the cursor. */
|
|
- sqlite3VdbeAddOp4Int(v, OP_OpenRead, iCsr, iRoot, iDb, 1);
|
|
+ sqlite3VdbeAddOp4Int(v, OP_OpenRead, iCsr, (int)iRoot, iDb, 1);
|
|
if( pKeyInfo ){
|
|
sqlite3VdbeChangeP4(v, -1, (char *)pKeyInfo, P4_KEYINFO);
|
|
}
|
|
- sqlite3VdbeAddOp2(v, OP_Count, iCsr, sAggInfo.aFunc[0].iMem);
|
|
+ assignAggregateRegisters(pParse, pAggInfo);
|
|
+ sqlite3VdbeAddOp2(v, OP_Count, iCsr, AggInfoFuncReg(pAggInfo,0));
|
|
sqlite3VdbeAddOp1(v, OP_Close, iCsr);
|
|
explainSimpleCount(pParse, pTab, pBest);
|
|
- }else
|
|
-#endif /* SQLITE_OMIT_BTREECOUNT */
|
|
- {
|
|
+ }else{
|
|
int regAcc = 0; /* "populate accumulators" flag */
|
|
+ ExprList *pDistinct = 0;
|
|
+ u16 distFlag = 0;
|
|
+ int eDist;
|
|
|
|
/* If there are accumulator registers but no min() or max() functions
|
|
** without FILTER clauses, allocate register regAcc. Register regAcc
|
|
@@ -134558,25 +146370,34 @@ SQLITE_PRIVATE int sqlite3Select(
|
|
** that the accumulator registers are (a) updated only once if
|
|
** there are no min() or max functions or (b) always updated for the
|
|
** first row visited by the aggregate, so that they are updated at
|
|
- ** least once even if the FILTER clause means the min() or max()
|
|
+ ** least once even if the FILTER clause means the min() or max()
|
|
** function visits zero rows. */
|
|
- if( sAggInfo.nAccumulator ){
|
|
- for(i=0; i<sAggInfo.nFunc; i++){
|
|
- if( ExprHasProperty(sAggInfo.aFunc[i].pExpr, EP_WinFunc) ) continue;
|
|
- if( sAggInfo.aFunc[i].pFunc->funcFlags&SQLITE_FUNC_NEEDCOLL ) break;
|
|
+ if( pAggInfo->nAccumulator ){
|
|
+ for(i=0; i<pAggInfo->nFunc; i++){
|
|
+ if( ExprHasProperty(pAggInfo->aFunc[i].pFExpr, EP_WinFunc) ){
|
|
+ continue;
|
|
+ }
|
|
+ if( pAggInfo->aFunc[i].pFunc->funcFlags&SQLITE_FUNC_NEEDCOLL ){
|
|
+ break;
|
|
+ }
|
|
}
|
|
- if( i==sAggInfo.nFunc ){
|
|
+ if( i==pAggInfo->nFunc ){
|
|
regAcc = ++pParse->nMem;
|
|
sqlite3VdbeAddOp2(v, OP_Integer, 0, regAcc);
|
|
}
|
|
+ }else if( pAggInfo->nFunc==1 && pAggInfo->aFunc[0].iDistinct>=0 ){
|
|
+ assert( ExprUseXList(pAggInfo->aFunc[0].pFExpr) );
|
|
+ pDistinct = pAggInfo->aFunc[0].pFExpr->x.pList;
|
|
+ distFlag = pDistinct ? (WHERE_WANT_DISTINCT|WHERE_AGG_DISTINCT) : 0;
|
|
}
|
|
+ assignAggregateRegisters(pParse, pAggInfo);
|
|
|
|
/* This case runs if the aggregate has no GROUP BY clause. The
|
|
** processing is much simpler since there is only a single row
|
|
** of output.
|
|
*/
|
|
assert( p->pGroupBy==0 );
|
|
- resetAccumulator(pParse, &sAggInfo);
|
|
+ resetAccumulator(pParse, pAggInfo);
|
|
|
|
/* If this query is a candidate for the min/max optimization, then
|
|
** minMaxFlag will have been previously set to either
|
|
@@ -134586,30 +146407,38 @@ SQLITE_PRIVATE int sqlite3Select(
|
|
assert( minMaxFlag==WHERE_ORDERBY_NORMAL || pMinMaxOrderBy!=0 );
|
|
assert( pMinMaxOrderBy==0 || pMinMaxOrderBy->nExpr==1 );
|
|
|
|
- SELECTTRACE(1,pParse,p,("WhereBegin\n"));
|
|
+ TREETRACE(0x2,pParse,p,("WhereBegin\n"));
|
|
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pMinMaxOrderBy,
|
|
- 0, minMaxFlag, 0);
|
|
+ pDistinct, p, minMaxFlag|distFlag, 0);
|
|
if( pWInfo==0 ){
|
|
goto select_end;
|
|
}
|
|
- updateAccumulator(pParse, regAcc, &sAggInfo);
|
|
+ TREETRACE(0x2,pParse,p,("WhereBegin returns\n"));
|
|
+ eDist = sqlite3WhereIsDistinct(pWInfo);
|
|
+ updateAccumulator(pParse, regAcc, pAggInfo, eDist);
|
|
+ if( eDist!=WHERE_DISTINCT_NOOP ){
|
|
+ struct AggInfo_func *pF = pAggInfo->aFunc;
|
|
+ if( pF ){
|
|
+ fixDistinctOpenEph(pParse, eDist, pF->iDistinct, pF->iDistAddr);
|
|
+ }
|
|
+ }
|
|
+
|
|
if( regAcc ) sqlite3VdbeAddOp2(v, OP_Integer, 1, regAcc);
|
|
- if( sqlite3WhereIsOrdered(pWInfo)>0 ){
|
|
- sqlite3VdbeGoto(v, sqlite3WhereBreakLabel(pWInfo));
|
|
- VdbeComment((v, "%s() by index",
|
|
- (minMaxFlag==WHERE_ORDERBY_MIN?"min":"max")));
|
|
+ if( minMaxFlag ){
|
|
+ sqlite3WhereMinMaxOptEarlyOut(v, pWInfo);
|
|
}
|
|
+ TREETRACE(0x2,pParse,p,("WhereEnd\n"));
|
|
sqlite3WhereEnd(pWInfo);
|
|
- finalizeAggFunctions(pParse, &sAggInfo);
|
|
+ finalizeAggFunctions(pParse, pAggInfo);
|
|
}
|
|
|
|
sSort.pOrderBy = 0;
|
|
sqlite3ExprIfFalse(pParse, pHaving, addrEnd, SQLITE_JUMPIFNULL);
|
|
- selectInnerLoop(pParse, p, -1, 0, 0,
|
|
+ selectInnerLoop(pParse, p, -1, 0, 0,
|
|
pDest, addrEnd, addrEnd);
|
|
}
|
|
sqlite3VdbeResolveLabel(v, addrEnd);
|
|
-
|
|
+
|
|
} /* endif aggregate query */
|
|
|
|
if( sDistinct.eTnctType==WHERE_DISTINCT_UNORDERED ){
|
|
@@ -134620,8 +146449,6 @@ SQLITE_PRIVATE int sqlite3Select(
|
|
** and send them to the callback one by one.
|
|
*/
|
|
if( sSort.pOrderBy ){
|
|
- explainTempTable(pParse,
|
|
- sSort.nOBSat>0 ? "RIGHT PART OF ORDER BY":"ORDER BY");
|
|
assert( p->pEList==pEList );
|
|
generateSortTail(pParse, p, &sSort, pEList->nExpr, pDest);
|
|
}
|
|
@@ -134638,12 +146465,29 @@ SQLITE_PRIVATE int sqlite3Select(
|
|
** successful coding of the SELECT.
|
|
*/
|
|
select_end:
|
|
+ assert( db->mallocFailed==0 || db->mallocFailed==1 );
|
|
+ assert( db->mallocFailed==0 || pParse->nErr!=0 );
|
|
sqlite3ExprListDelete(db, pMinMaxOrderBy);
|
|
- sqlite3DbFree(db, sAggInfo.aCol);
|
|
- sqlite3DbFree(db, sAggInfo.aFunc);
|
|
-#if SELECTTRACE_ENABLED
|
|
- SELECTTRACE(0x1,pParse,p,("end processing\n"));
|
|
- if( (sqlite3SelectTrace & 0x2000)!=0 && ExplainQueryPlanParent(pParse)==0 ){
|
|
+#ifdef SQLITE_DEBUG
|
|
+ if( pAggInfo && !db->mallocFailed ){
|
|
+ for(i=0; i<pAggInfo->nColumn; i++){
|
|
+ Expr *pExpr = pAggInfo->aCol[i].pCExpr;
|
|
+ if( pExpr==0 ) continue;
|
|
+ assert( pExpr->pAggInfo==pAggInfo );
|
|
+ assert( pExpr->iAgg==i );
|
|
+ }
|
|
+ for(i=0; i<pAggInfo->nFunc; i++){
|
|
+ Expr *pExpr = pAggInfo->aFunc[i].pFExpr;
|
|
+ assert( pExpr!=0 );
|
|
+ assert( pExpr->pAggInfo==pAggInfo );
|
|
+ assert( pExpr->iAgg==i );
|
|
+ }
|
|
+ }
|
|
+#endif
|
|
+
|
|
+#if TREETRACE_ENABLED
|
|
+ TREETRACE(0x1,pParse,p,("end processing\n"));
|
|
+ if( (sqlite3TreeTrace & 0x40000)!=0 && ExplainQueryPlanParent(pParse)==0 ){
|
|
sqlite3TreeViewSelect(0, p, 0);
|
|
}
|
|
#endif
|
|
@@ -134711,7 +146555,7 @@ static int sqlite3_get_table_cb(void *pArg, int nCol, char **argv, char **colv){
|
|
if( p->nData + need > p->nAlloc ){
|
|
char **azNew;
|
|
p->nAlloc = p->nAlloc*2 + need;
|
|
- azNew = sqlite3_realloc64( p->azResult, sizeof(char*)*p->nAlloc );
|
|
+ azNew = sqlite3Realloc( p->azResult, sizeof(char*)*p->nAlloc );
|
|
if( azNew==0 ) goto malloc_failed;
|
|
p->azResult = azNew;
|
|
}
|
|
@@ -134764,7 +146608,7 @@ static int sqlite3_get_table_cb(void *pArg, int nCol, char **argv, char **colv){
|
|
** at the conclusion of the call.
|
|
**
|
|
** The result that is written to ***pazResult is held in memory obtained
|
|
-** from malloc(). But the caller cannot free this memory directly.
|
|
+** from malloc(). But the caller cannot free this memory directly.
|
|
** Instead, the entire table should be passed to sqlite3_free_table() when
|
|
** the calling procedure is finished using it.
|
|
*/
|
|
@@ -134820,7 +146664,7 @@ SQLITE_API int sqlite3_get_table(
|
|
}
|
|
if( res.nAlloc>res.nData ){
|
|
char **azNew;
|
|
- azNew = sqlite3_realloc64( res.azResult, sizeof(char*)*res.nData );
|
|
+ azNew = sqlite3Realloc( res.azResult, sizeof(char*)*res.nData );
|
|
if( azNew==0 ){
|
|
sqlite3_free_table(&res.azResult[1]);
|
|
db->errCode = SQLITE_NOMEM;
|
|
@@ -134882,6 +146726,7 @@ SQLITE_PRIVATE void sqlite3DeleteTriggerStep(sqlite3 *db, TriggerStep *pTriggerS
|
|
sqlite3SelectDelete(db, pTmp->pSelect);
|
|
sqlite3IdListDelete(db, pTmp->pIdList);
|
|
sqlite3UpsertDelete(db, pTmp->pUpsert);
|
|
+ sqlite3SrcListDelete(db, pTmp->pFrom);
|
|
sqlite3DbFree(db, pTmp->zSpan);
|
|
|
|
sqlite3DbFree(db, pTmp);
|
|
@@ -134889,7 +146734,7 @@ SQLITE_PRIVATE void sqlite3DeleteTriggerStep(sqlite3 *db, TriggerStep *pTriggerS
|
|
}
|
|
|
|
/*
|
|
-** Given table pTab, return a list of all the triggers attached to
|
|
+** Given table pTab, return a list of all the triggers attached to
|
|
** the table. The list is connected by Trigger.pNext pointers.
|
|
**
|
|
** All of the triggers on pTab that are in the same database as pTab
|
|
@@ -134903,28 +146748,48 @@ SQLITE_PRIVATE void sqlite3DeleteTriggerStep(sqlite3 *db, TriggerStep *pTriggerS
|
|
** pTab as well as the triggers lised in pTab->pTrigger.
|
|
*/
|
|
SQLITE_PRIVATE Trigger *sqlite3TriggerList(Parse *pParse, Table *pTab){
|
|
- Schema * const pTmpSchema = pParse->db->aDb[1].pSchema;
|
|
- Trigger *pList = 0; /* List of triggers to return */
|
|
-
|
|
- if( pParse->disableTriggers ){
|
|
- return 0;
|
|
+ Schema *pTmpSchema; /* Schema of the pTab table */
|
|
+ Trigger *pList; /* List of triggers to return */
|
|
+ HashElem *p; /* Loop variable for TEMP triggers */
|
|
+
|
|
+ assert( pParse->disableTriggers==0 );
|
|
+ pTmpSchema = pParse->db->aDb[1].pSchema;
|
|
+ p = sqliteHashFirst(&pTmpSchema->trigHash);
|
|
+ pList = pTab->pTrigger;
|
|
+ while( p ){
|
|
+ Trigger *pTrig = (Trigger *)sqliteHashData(p);
|
|
+ if( pTrig->pTabSchema==pTab->pSchema
|
|
+ && pTrig->table
|
|
+ && 0==sqlite3StrICmp(pTrig->table, pTab->zName)
|
|
+ && (pTrig->pTabSchema!=pTmpSchema || pTrig->bReturning)
|
|
+ ){
|
|
+ pTrig->pNext = pList;
|
|
+ pList = pTrig;
|
|
+ }else if( pTrig->op==TK_RETURNING ){
|
|
+#ifndef SQLITE_OMIT_VIRTUALTABLE
|
|
+ assert( pParse->db->pVtabCtx==0 );
|
|
+#endif
|
|
+ assert( pParse->bReturning );
|
|
+ assert( &(pParse->u1.pReturning->retTrig) == pTrig );
|
|
+ pTrig->table = pTab->zName;
|
|
+ pTrig->pTabSchema = pTab->pSchema;
|
|
+ pTrig->pNext = pList;
|
|
+ pList = pTrig;
|
|
+ }
|
|
+ p = sqliteHashNext(p);
|
|
}
|
|
-
|
|
- if( pTmpSchema!=pTab->pSchema ){
|
|
- HashElem *p;
|
|
- assert( sqlite3SchemaMutexHeld(pParse->db, 0, pTmpSchema) );
|
|
- for(p=sqliteHashFirst(&pTmpSchema->trigHash); p; p=sqliteHashNext(p)){
|
|
- Trigger *pTrig = (Trigger *)sqliteHashData(p);
|
|
- if( pTrig->pTabSchema==pTab->pSchema
|
|
- && 0==sqlite3StrICmp(pTrig->table, pTab->zName)
|
|
- ){
|
|
- pTrig->pNext = (pList ? pList : pTab->pTrigger);
|
|
- pList = pTrig;
|
|
- }
|
|
+#if 0
|
|
+ if( pList ){
|
|
+ Trigger *pX;
|
|
+ printf("Triggers for %s:", pTab->zName);
|
|
+ for(pX=pList; pX; pX=pX->pNext){
|
|
+ printf(" %s", pX->zName);
|
|
}
|
|
+ printf("\n");
|
|
+ fflush(stdout);
|
|
}
|
|
-
|
|
- return (pList ? pList : pTab->pTrigger);
|
|
+#endif
|
|
+ return pList;
|
|
}
|
|
|
|
/*
|
|
@@ -134984,7 +146849,7 @@ SQLITE_PRIVATE void sqlite3BeginTrigger(
|
|
** ^^^^^^^^
|
|
**
|
|
** To maintain backwards compatibility, ignore the database
|
|
- ** name on pTableName if we are reparsing out of SQLITE_MASTER.
|
|
+ ** name on pTableName if we are reparsing out of the schema table
|
|
*/
|
|
if( db->init.busy && iDb!=1 ){
|
|
sqlite3DbFree(db, pTableName->a[0].zDatabase);
|
|
@@ -135012,22 +146877,11 @@ SQLITE_PRIVATE void sqlite3BeginTrigger(
|
|
pTab = sqlite3SrcListLookup(pParse, pTableName);
|
|
if( !pTab ){
|
|
/* The table does not exist. */
|
|
- if( db->init.iDb==1 ){
|
|
- /* Ticket #3810.
|
|
- ** Normally, whenever a table is dropped, all associated triggers are
|
|
- ** dropped too. But if a TEMP trigger is created on a non-TEMP table
|
|
- ** and the table is dropped by a different database connection, the
|
|
- ** trigger is not visible to the database connection that does the
|
|
- ** drop so the trigger cannot be dropped. This results in an
|
|
- ** "orphaned trigger" - a trigger whose associated table is missing.
|
|
- */
|
|
- db->init.orphanTrigger = 1;
|
|
- }
|
|
- goto trigger_cleanup;
|
|
+ goto trigger_orphan_error;
|
|
}
|
|
if( IsVirtual(pTab) ){
|
|
sqlite3ErrorMsg(pParse, "cannot create triggers on virtual tables");
|
|
- goto trigger_cleanup;
|
|
+ goto trigger_orphan_error;
|
|
}
|
|
|
|
/* Check that the trigger name is not reserved and that no trigger of the
|
|
@@ -135048,6 +146902,7 @@ SQLITE_PRIVATE void sqlite3BeginTrigger(
|
|
}else{
|
|
assert( !db->init.busy );
|
|
sqlite3CodeVerifySchema(pParse, iDb);
|
|
+ VVA_ONLY( pParse->ifNotExists = 1; )
|
|
}
|
|
goto trigger_cleanup;
|
|
}
|
|
@@ -135062,15 +146917,15 @@ SQLITE_PRIVATE void sqlite3BeginTrigger(
|
|
/* INSTEAD of triggers are only for views and views only support INSTEAD
|
|
** of triggers.
|
|
*/
|
|
- if( pTab->pSelect && tr_tm!=TK_INSTEAD ){
|
|
- sqlite3ErrorMsg(pParse, "cannot create %s trigger on view: %S",
|
|
- (tr_tm == TK_BEFORE)?"BEFORE":"AFTER", pTableName, 0);
|
|
- goto trigger_cleanup;
|
|
+ if( IsView(pTab) && tr_tm!=TK_INSTEAD ){
|
|
+ sqlite3ErrorMsg(pParse, "cannot create %s trigger on view: %S",
|
|
+ (tr_tm == TK_BEFORE)?"BEFORE":"AFTER", pTableName->a);
|
|
+ goto trigger_orphan_error;
|
|
}
|
|
- if( !pTab->pSelect && tr_tm==TK_INSTEAD ){
|
|
+ if( !IsView(pTab) && tr_tm==TK_INSTEAD ){
|
|
sqlite3ErrorMsg(pParse, "cannot create INSTEAD OF"
|
|
- " trigger on table: %S", pTableName, 0);
|
|
- goto trigger_cleanup;
|
|
+ " trigger on table: %S", pTableName->a);
|
|
+ goto trigger_orphan_error;
|
|
}
|
|
|
|
#ifndef SQLITE_OMIT_AUTHORIZATION
|
|
@@ -135130,6 +146985,23 @@ SQLITE_PRIVATE void sqlite3BeginTrigger(
|
|
}else{
|
|
assert( pParse->pNewTrigger==pTrigger );
|
|
}
|
|
+ return;
|
|
+
|
|
+trigger_orphan_error:
|
|
+ if( db->init.iDb==1 ){
|
|
+ /* Ticket #3810.
|
|
+ ** Normally, whenever a table is dropped, all associated triggers are
|
|
+ ** dropped too. But if a TEMP trigger is created on a non-TEMP table
|
|
+ ** and the table is dropped by a different database connection, the
|
|
+ ** trigger is not visible to the database connection that does the
|
|
+ ** drop so the trigger cannot be dropped. This results in an
|
|
+ ** "orphaned trigger" - a trigger whose associated table is missing.
|
|
+ **
|
|
+ ** 2020-11-05 see also https://sqlite.org/forum/forumpost/157dc791df
|
|
+ */
|
|
+ db->init.orphanTrigger = 1;
|
|
+ }
|
|
+ goto trigger_cleanup;
|
|
}
|
|
|
|
/*
|
|
@@ -135159,8 +147031,8 @@ SQLITE_PRIVATE void sqlite3FinishTrigger(
|
|
}
|
|
sqlite3TokenInit(&nameToken, pTrig->zName);
|
|
sqlite3FixInit(&sFix, pParse, iDb, "trigger", &nameToken);
|
|
- if( sqlite3FixTriggerStep(&sFix, pTrig->step_list)
|
|
- || sqlite3FixExpr(&sFix, pTrig->pWhen)
|
|
+ if( sqlite3FixTriggerStep(&sFix, pTrig->step_list)
|
|
+ || sqlite3FixExpr(&sFix, pTrig->pWhen)
|
|
){
|
|
goto triggerfinish_cleanup;
|
|
}
|
|
@@ -135174,26 +147046,44 @@ SQLITE_PRIVATE void sqlite3FinishTrigger(
|
|
#endif
|
|
|
|
/* if we are not initializing,
|
|
- ** build the sqlite_master entry
|
|
+ ** build the sqlite_schema entry
|
|
*/
|
|
if( !db->init.busy ){
|
|
Vdbe *v;
|
|
char *z;
|
|
|
|
- /* Make an entry in the sqlite_master table */
|
|
+ /* If this is a new CREATE TABLE statement, and if shadow tables
|
|
+ ** are read-only, and the trigger makes a change to a shadow table,
|
|
+ ** then raise an error - do not allow the trigger to be created. */
|
|
+ if( sqlite3ReadOnlyShadowTables(db) ){
|
|
+ TriggerStep *pStep;
|
|
+ for(pStep=pTrig->step_list; pStep; pStep=pStep->pNext){
|
|
+ if( pStep->zTarget!=0
|
|
+ && sqlite3ShadowTableName(db, pStep->zTarget)
|
|
+ ){
|
|
+ sqlite3ErrorMsg(pParse,
|
|
+ "trigger \"%s\" may not write to shadow table \"%s\"",
|
|
+ pTrig->zName, pStep->zTarget);
|
|
+ goto triggerfinish_cleanup;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Make an entry in the sqlite_schema table */
|
|
v = sqlite3GetVdbe(pParse);
|
|
if( v==0 ) goto triggerfinish_cleanup;
|
|
sqlite3BeginWriteOperation(pParse, 0, iDb);
|
|
z = sqlite3DbStrNDup(db, (char*)pAll->z, pAll->n);
|
|
testcase( z==0 );
|
|
sqlite3NestedParse(pParse,
|
|
- "INSERT INTO %Q.%s VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')",
|
|
- db->aDb[iDb].zDbSName, MASTER_NAME, zName,
|
|
+ "INSERT INTO %Q." LEGACY_SCHEMA_TABLE
|
|
+ " VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')",
|
|
+ db->aDb[iDb].zDbSName, zName,
|
|
pTrig->table, z);
|
|
sqlite3DbFree(db, z);
|
|
sqlite3ChangeCookie(pParse, iDb);
|
|
sqlite3VdbeAddParseSchemaOp(v, iDb,
|
|
- sqlite3MPrintf(db, "type='trigger' AND name='%q'", zName));
|
|
+ sqlite3MPrintf(db, "type='trigger' AND name='%q'", zName), 0);
|
|
}
|
|
|
|
if( db->init.busy ){
|
|
@@ -135228,14 +147118,14 @@ static char *triggerSpanDup(sqlite3 *db, const char *zStart, const char *zEnd){
|
|
int i;
|
|
if( z ) for(i=0; z[i]; i++) if( sqlite3Isspace(z[i]) ) z[i] = ' ';
|
|
return z;
|
|
-}
|
|
+}
|
|
|
|
/*
|
|
** Turn a SELECT statement (that the pSelect parameter points to) into
|
|
** a trigger step. Return a pointer to a TriggerStep structure.
|
|
**
|
|
** The parser calls this routine when it finds a SELECT statement in
|
|
-** body of a TRIGGER.
|
|
+** body of a TRIGGER.
|
|
*/
|
|
SQLITE_PRIVATE TriggerStep *sqlite3TriggerSelectStep(
|
|
sqlite3 *db, /* Database connection */
|
|
@@ -135271,6 +147161,7 @@ static TriggerStep *triggerStepAllocate(
|
|
sqlite3 *db = pParse->db;
|
|
TriggerStep *pTriggerStep;
|
|
|
|
+ if( pParse->nErr ) return 0;
|
|
pTriggerStep = sqlite3DbMallocZero(db, sizeof(TriggerStep) + pName->n + 1);
|
|
if( pTriggerStep ){
|
|
char *z = (char*)&pTriggerStep[1];
|
|
@@ -135341,6 +147232,7 @@ SQLITE_PRIVATE TriggerStep *sqlite3TriggerInsertStep(
|
|
SQLITE_PRIVATE TriggerStep *sqlite3TriggerUpdateStep(
|
|
Parse *pParse, /* Parser */
|
|
Token *pTableName, /* Name of the table to be updated */
|
|
+ SrcList *pFrom, /* FROM clause for an UPDATE-FROM, or NULL */
|
|
ExprList *pEList, /* The SET clause: list of column and new values */
|
|
Expr *pWhere, /* The WHERE clause */
|
|
u8 orconf, /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */
|
|
@@ -135355,16 +147247,20 @@ SQLITE_PRIVATE TriggerStep *sqlite3TriggerUpdateStep(
|
|
if( IN_RENAME_OBJECT ){
|
|
pTriggerStep->pExprList = pEList;
|
|
pTriggerStep->pWhere = pWhere;
|
|
+ pTriggerStep->pFrom = pFrom;
|
|
pEList = 0;
|
|
pWhere = 0;
|
|
+ pFrom = 0;
|
|
}else{
|
|
pTriggerStep->pExprList = sqlite3ExprListDup(db, pEList, EXPRDUP_REDUCE);
|
|
pTriggerStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE);
|
|
+ pTriggerStep->pFrom = sqlite3SrcListDup(db, pFrom, EXPRDUP_REDUCE);
|
|
}
|
|
pTriggerStep->orconf = orconf;
|
|
}
|
|
sqlite3ExprListDelete(db, pEList);
|
|
sqlite3ExprDelete(db, pWhere);
|
|
+ sqlite3SrcListDelete(db, pFrom);
|
|
return pTriggerStep;
|
|
}
|
|
|
|
@@ -135397,11 +147293,11 @@ SQLITE_PRIVATE TriggerStep *sqlite3TriggerDeleteStep(
|
|
return pTriggerStep;
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** Recursively delete a Trigger structure
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3DeleteTrigger(sqlite3 *db, Trigger *pTrigger){
|
|
- if( pTrigger==0 ) return;
|
|
+ if( pTrigger==0 || pTrigger->bReturning ) return;
|
|
sqlite3DeleteTriggerStep(db, pTrigger->step_list);
|
|
sqlite3DbFree(db, pTrigger->zName);
|
|
sqlite3DbFree(db, pTrigger->table);
|
|
@@ -135411,7 +147307,7 @@ SQLITE_PRIVATE void sqlite3DeleteTrigger(sqlite3 *db, Trigger *pTrigger){
|
|
}
|
|
|
|
/*
|
|
-** This function is called to drop a trigger from the database schema.
|
|
+** This function is called to drop a trigger from the database schema.
|
|
**
|
|
** This may be called directly from the parser and therefore identifies
|
|
** the trigger by name. The sqlite3DropTriggerPtr() routine does the
|
|
@@ -135436,14 +147332,14 @@ SQLITE_PRIVATE void sqlite3DropTrigger(Parse *pParse, SrcList *pName, int noErr)
|
|
assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) );
|
|
for(i=OMIT_TEMPDB; i<db->nDb; i++){
|
|
int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
|
|
- if( zDb && sqlite3StrICmp(db->aDb[j].zDbSName, zDb) ) continue;
|
|
+ if( zDb && sqlite3DbIsNamed(db, j, zDb)==0 ) continue;
|
|
assert( sqlite3SchemaMutexHeld(db, j, 0) );
|
|
pTrigger = sqlite3HashFind(&(db->aDb[j].pSchema->trigHash), zName);
|
|
if( pTrigger ) break;
|
|
}
|
|
if( !pTrigger ){
|
|
if( !noErr ){
|
|
- sqlite3ErrorMsg(pParse, "no such trigger: %S", pName, 0);
|
|
+ sqlite3ErrorMsg(pParse, "no such trigger: %S", pName->a);
|
|
}else{
|
|
sqlite3CodeVerifyNamedSchema(pParse, zDb);
|
|
}
|
|
@@ -135466,7 +147362,7 @@ static Table *tableOfTrigger(Trigger *pTrigger){
|
|
|
|
|
|
/*
|
|
-** Drop a trigger given a pointer to that trigger.
|
|
+** Drop a trigger given a pointer to that trigger.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){
|
|
Table *pTable;
|
|
@@ -135495,8 +147391,8 @@ SQLITE_PRIVATE void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){
|
|
*/
|
|
if( (v = sqlite3GetVdbe(pParse))!=0 ){
|
|
sqlite3NestedParse(pParse,
|
|
- "DELETE FROM %Q.%s WHERE name=%Q AND type='trigger'",
|
|
- db->aDb[iDb].zDbSName, MASTER_NAME, pTrigger->zName
|
|
+ "DELETE FROM %Q." LEGACY_SCHEMA_TABLE " WHERE name=%Q AND type='trigger'",
|
|
+ db->aDb[iDb].zDbSName, pTrigger->zName
|
|
);
|
|
sqlite3ChangeCookie(pParse, iDb);
|
|
sqlite3VdbeAddOp4(v, OP_DropTrigger, iDb, 0, 0, pTrigger->zName, 0);
|
|
@@ -135546,16 +147442,25 @@ static int checkColumnOverlap(IdList *pIdList, ExprList *pEList){
|
|
for(e=0; e<pEList->nExpr; e++){
|
|
if( sqlite3IdListIndex(pIdList, pEList->a[e].zEName)>=0 ) return 1;
|
|
}
|
|
- return 0;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Return true if any TEMP triggers exist
|
|
+*/
|
|
+static int tempTriggersExist(sqlite3 *db){
|
|
+ if( NEVER(db->aDb[1].pSchema==0) ) return 0;
|
|
+ if( sqliteHashFirst(&db->aDb[1].pSchema->trigHash)==0 ) return 0;
|
|
+ return 1;
|
|
}
|
|
|
|
/*
|
|
** Return a list of all triggers on table pTab if there exists at least
|
|
-** one trigger that must be fired when an operation of type 'op' is
|
|
+** one trigger that must be fired when an operation of type 'op' is
|
|
** performed on the table, and, if that operation is an UPDATE, if at
|
|
** least one of the columns in pChanges is being modified.
|
|
*/
|
|
-SQLITE_PRIVATE Trigger *sqlite3TriggersExist(
|
|
+static SQLITE_NOINLINE Trigger *triggersReallyExist(
|
|
Parse *pParse, /* Parse context */
|
|
Table *pTab, /* The table the contains the triggers */
|
|
int op, /* one of TK_DELETE, TK_INSERT, TK_UPDATE */
|
|
@@ -135566,20 +147471,74 @@ SQLITE_PRIVATE Trigger *sqlite3TriggersExist(
|
|
Trigger *pList = 0;
|
|
Trigger *p;
|
|
|
|
- if( (pParse->db->flags & SQLITE_EnableTrigger)!=0 ){
|
|
- pList = sqlite3TriggerList(pParse, pTab);
|
|
- }
|
|
- assert( pList==0 || IsVirtual(pTab)==0 );
|
|
- for(p=pList; p; p=p->pNext){
|
|
- if( p->op==op && checkColumnOverlap(p->pColumns, pChanges) ){
|
|
- mask |= p->tr_tm;
|
|
+ pList = sqlite3TriggerList(pParse, pTab);
|
|
+ assert( pList==0 || IsVirtual(pTab)==0
|
|
+ || (pList->bReturning && pList->pNext==0) );
|
|
+ if( pList!=0 ){
|
|
+ p = pList;
|
|
+ if( (pParse->db->flags & SQLITE_EnableTrigger)==0
|
|
+ && pTab->pTrigger!=0
|
|
+ ){
|
|
+ /* The SQLITE_DBCONFIG_ENABLE_TRIGGER setting is off. That means that
|
|
+ ** only TEMP triggers are allowed. Truncate the pList so that it
|
|
+ ** includes only TEMP triggers */
|
|
+ if( pList==pTab->pTrigger ){
|
|
+ pList = 0;
|
|
+ goto exit_triggers_exist;
|
|
+ }
|
|
+ while( ALWAYS(p->pNext) && p->pNext!=pTab->pTrigger ) p = p->pNext;
|
|
+ p->pNext = 0;
|
|
+ p = pList;
|
|
}
|
|
+ do{
|
|
+ if( p->op==op && checkColumnOverlap(p->pColumns, pChanges) ){
|
|
+ mask |= p->tr_tm;
|
|
+ }else if( p->op==TK_RETURNING ){
|
|
+ /* The first time a RETURNING trigger is seen, the "op" value tells
|
|
+ ** us what time of trigger it should be. */
|
|
+ assert( sqlite3IsToplevel(pParse) );
|
|
+ p->op = op;
|
|
+ if( IsVirtual(pTab) ){
|
|
+ if( op!=TK_INSERT ){
|
|
+ sqlite3ErrorMsg(pParse,
|
|
+ "%s RETURNING is not available on virtual tables",
|
|
+ op==TK_DELETE ? "DELETE" : "UPDATE");
|
|
+ }
|
|
+ p->tr_tm = TRIGGER_BEFORE;
|
|
+ }else{
|
|
+ p->tr_tm = TRIGGER_AFTER;
|
|
+ }
|
|
+ mask |= p->tr_tm;
|
|
+ }else if( p->bReturning && p->op==TK_INSERT && op==TK_UPDATE
|
|
+ && sqlite3IsToplevel(pParse) ){
|
|
+ /* Also fire a RETURNING trigger for an UPSERT */
|
|
+ mask |= p->tr_tm;
|
|
+ }
|
|
+ p = p->pNext;
|
|
+ }while( p );
|
|
}
|
|
+exit_triggers_exist:
|
|
if( pMask ){
|
|
*pMask = mask;
|
|
}
|
|
return (mask ? pList : 0);
|
|
}
|
|
+SQLITE_PRIVATE Trigger *sqlite3TriggersExist(
|
|
+ Parse *pParse, /* Parse context */
|
|
+ Table *pTab, /* The table the contains the triggers */
|
|
+ int op, /* one of TK_DELETE, TK_INSERT, TK_UPDATE */
|
|
+ ExprList *pChanges, /* Columns that change in an UPDATE statement */
|
|
+ int *pMask /* OUT: Mask of TRIGGER_BEFORE|TRIGGER_AFTER */
|
|
+){
|
|
+ assert( pTab!=0 );
|
|
+ if( (pTab->pTrigger==0 && !tempTriggersExist(pParse->db))
|
|
+ || pParse->disableTriggers
|
|
+ ){
|
|
+ if( pMask ) *pMask = 0;
|
|
+ return 0;
|
|
+ }
|
|
+ return triggersReallyExist(pParse,pTab,op,pChanges,pMask);
|
|
+}
|
|
|
|
/*
|
|
** Convert the pStep->zTarget string into a SrcList and return a pointer
|
|
@@ -135591,37 +147550,188 @@ SQLITE_PRIVATE Trigger *sqlite3TriggersExist(
|
|
** trigger is in TEMP in which case it can refer to any other database it
|
|
** wants.
|
|
*/
|
|
-static SrcList *targetSrcList(
|
|
+SQLITE_PRIVATE SrcList *sqlite3TriggerStepSrc(
|
|
Parse *pParse, /* The parsing context */
|
|
TriggerStep *pStep /* The trigger containing the target token */
|
|
){
|
|
sqlite3 *db = pParse->db;
|
|
- int iDb; /* Index of the database to use */
|
|
- SrcList *pSrc; /* SrcList to be returned */
|
|
-
|
|
+ SrcList *pSrc; /* SrcList to be returned */
|
|
+ char *zName = sqlite3DbStrDup(db, pStep->zTarget);
|
|
pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
|
|
+ assert( pSrc==0 || pSrc->nSrc==1 );
|
|
+ assert( zName || pSrc==0 );
|
|
if( pSrc ){
|
|
- assert( pSrc->nSrc>0 );
|
|
- pSrc->a[pSrc->nSrc-1].zName = sqlite3DbStrDup(db, pStep->zTarget);
|
|
- iDb = sqlite3SchemaToIndex(db, pStep->pTrig->pSchema);
|
|
- if( iDb==0 || iDb>=2 ){
|
|
- const char *zDb;
|
|
- assert( iDb<db->nDb );
|
|
- zDb = db->aDb[iDb].zDbSName;
|
|
- pSrc->a[pSrc->nSrc-1].zDatabase = sqlite3DbStrDup(db, zDb);
|
|
+ Schema *pSchema = pStep->pTrig->pSchema;
|
|
+ pSrc->a[0].zName = zName;
|
|
+ if( pSchema!=db->aDb[1].pSchema ){
|
|
+ pSrc->a[0].pSchema = pSchema;
|
|
}
|
|
+ if( pStep->pFrom ){
|
|
+ SrcList *pDup = sqlite3SrcListDup(db, pStep->pFrom, 0);
|
|
+ if( pDup && pDup->nSrc>1 && !IN_RENAME_OBJECT ){
|
|
+ Select *pSubquery;
|
|
+ Token as;
|
|
+ pSubquery = sqlite3SelectNew(pParse,0,pDup,0,0,0,0,SF_NestedFrom,0);
|
|
+ as.n = 0;
|
|
+ as.z = 0;
|
|
+ pDup = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&as,pSubquery,0);
|
|
+ }
|
|
+ pSrc = sqlite3SrcListAppendList(pParse, pSrc, pDup);
|
|
+ }
|
|
+ }else{
|
|
+ sqlite3DbFree(db, zName);
|
|
}
|
|
return pSrc;
|
|
}
|
|
|
|
/*
|
|
-** Generate VDBE code for the statements inside the body of a single
|
|
+** Return true if the pExpr term from the RETURNING clause argument
|
|
+** list is of the form "*". Raise an error if the terms if of the
|
|
+** form "table.*".
|
|
+*/
|
|
+static int isAsteriskTerm(
|
|
+ Parse *pParse, /* Parsing context */
|
|
+ Expr *pTerm /* A term in the RETURNING clause */
|
|
+){
|
|
+ assert( pTerm!=0 );
|
|
+ if( pTerm->op==TK_ASTERISK ) return 1;
|
|
+ if( pTerm->op!=TK_DOT ) return 0;
|
|
+ assert( pTerm->pRight!=0 );
|
|
+ assert( pTerm->pLeft!=0 );
|
|
+ if( pTerm->pRight->op!=TK_ASTERISK ) return 0;
|
|
+ sqlite3ErrorMsg(pParse, "RETURNING may not use \"TABLE.*\" wildcards");
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+/* The input list pList is the list of result set terms from a RETURNING
|
|
+** clause. The table that we are returning from is pTab.
|
|
+**
|
|
+** This routine makes a copy of the pList, and at the same time expands
|
|
+** any "*" wildcards to be the complete set of columns from pTab.
|
|
+*/
|
|
+static ExprList *sqlite3ExpandReturning(
|
|
+ Parse *pParse, /* Parsing context */
|
|
+ ExprList *pList, /* The arguments to RETURNING */
|
|
+ Table *pTab /* The table being updated */
|
|
+){
|
|
+ ExprList *pNew = 0;
|
|
+ sqlite3 *db = pParse->db;
|
|
+ int i;
|
|
+
|
|
+ for(i=0; i<pList->nExpr; i++){
|
|
+ Expr *pOldExpr = pList->a[i].pExpr;
|
|
+ if( NEVER(pOldExpr==0) ) continue;
|
|
+ if( isAsteriskTerm(pParse, pOldExpr) ){
|
|
+ int jj;
|
|
+ for(jj=0; jj<pTab->nCol; jj++){
|
|
+ Expr *pNewExpr;
|
|
+ if( IsHiddenColumn(pTab->aCol+jj) ) continue;
|
|
+ pNewExpr = sqlite3Expr(db, TK_ID, pTab->aCol[jj].zCnName);
|
|
+ pNew = sqlite3ExprListAppend(pParse, pNew, pNewExpr);
|
|
+ if( !db->mallocFailed ){
|
|
+ struct ExprList_item *pItem = &pNew->a[pNew->nExpr-1];
|
|
+ pItem->zEName = sqlite3DbStrDup(db, pTab->aCol[jj].zCnName);
|
|
+ pItem->fg.eEName = ENAME_NAME;
|
|
+ }
|
|
+ }
|
|
+ }else{
|
|
+ Expr *pNewExpr = sqlite3ExprDup(db, pOldExpr, 0);
|
|
+ pNew = sqlite3ExprListAppend(pParse, pNew, pNewExpr);
|
|
+ if( !db->mallocFailed && ALWAYS(pList->a[i].zEName!=0) ){
|
|
+ struct ExprList_item *pItem = &pNew->a[pNew->nExpr-1];
|
|
+ pItem->zEName = sqlite3DbStrDup(db, pList->a[i].zEName);
|
|
+ pItem->fg.eEName = pList->a[i].fg.eEName;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ return pNew;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Generate code for the RETURNING trigger. Unlike other triggers
|
|
+** that invoke a subprogram in the bytecode, the code for RETURNING
|
|
+** is generated in-line.
|
|
+*/
|
|
+static void codeReturningTrigger(
|
|
+ Parse *pParse, /* Parse context */
|
|
+ Trigger *pTrigger, /* The trigger step that defines the RETURNING */
|
|
+ Table *pTab, /* The table to code triggers from */
|
|
+ int regIn /* The first in an array of registers */
|
|
+){
|
|
+ Vdbe *v = pParse->pVdbe;
|
|
+ sqlite3 *db = pParse->db;
|
|
+ ExprList *pNew;
|
|
+ Returning *pReturning;
|
|
+ Select sSelect;
|
|
+ SrcList sFrom;
|
|
+
|
|
+ assert( v!=0 );
|
|
+ assert( pParse->bReturning );
|
|
+ assert( db->pParse==pParse );
|
|
+ pReturning = pParse->u1.pReturning;
|
|
+ assert( pTrigger == &(pReturning->retTrig) );
|
|
+ memset(&sSelect, 0, sizeof(sSelect));
|
|
+ memset(&sFrom, 0, sizeof(sFrom));
|
|
+ sSelect.pEList = sqlite3ExprListDup(db, pReturning->pReturnEL, 0);
|
|
+ sSelect.pSrc = &sFrom;
|
|
+ sFrom.nSrc = 1;
|
|
+ sFrom.a[0].pTab = pTab;
|
|
+ sFrom.a[0].iCursor = -1;
|
|
+ sqlite3SelectPrep(pParse, &sSelect, 0);
|
|
+ if( pParse->nErr==0 ){
|
|
+ assert( db->mallocFailed==0 );
|
|
+ sqlite3GenerateColumnNames(pParse, &sSelect);
|
|
+ }
|
|
+ sqlite3ExprListDelete(db, sSelect.pEList);
|
|
+ pNew = sqlite3ExpandReturning(pParse, pReturning->pReturnEL, pTab);
|
|
+ if( pParse->nErr==0 ){
|
|
+ NameContext sNC;
|
|
+ memset(&sNC, 0, sizeof(sNC));
|
|
+ if( pReturning->nRetCol==0 ){
|
|
+ pReturning->nRetCol = pNew->nExpr;
|
|
+ pReturning->iRetCur = pParse->nTab++;
|
|
+ }
|
|
+ sNC.pParse = pParse;
|
|
+ sNC.uNC.iBaseReg = regIn;
|
|
+ sNC.ncFlags = NC_UBaseReg;
|
|
+ pParse->eTriggerOp = pTrigger->op;
|
|
+ pParse->pTriggerTab = pTab;
|
|
+ if( sqlite3ResolveExprListNames(&sNC, pNew)==SQLITE_OK
|
|
+ && ALWAYS(!db->mallocFailed)
|
|
+ ){
|
|
+ int i;
|
|
+ int nCol = pNew->nExpr;
|
|
+ int reg = pParse->nMem+1;
|
|
+ pParse->nMem += nCol+2;
|
|
+ pReturning->iRetReg = reg;
|
|
+ for(i=0; i<nCol; i++){
|
|
+ Expr *pCol = pNew->a[i].pExpr;
|
|
+ assert( pCol!=0 ); /* Due to !db->mallocFailed ~9 lines above */
|
|
+ sqlite3ExprCodeFactorable(pParse, pCol, reg+i);
|
|
+ if( sqlite3ExprAffinity(pCol)==SQLITE_AFF_REAL ){
|
|
+ sqlite3VdbeAddOp1(v, OP_RealAffinity, reg+i);
|
|
+ }
|
|
+ }
|
|
+ sqlite3VdbeAddOp3(v, OP_MakeRecord, reg, i, reg+i);
|
|
+ sqlite3VdbeAddOp2(v, OP_NewRowid, pReturning->iRetCur, reg+i+1);
|
|
+ sqlite3VdbeAddOp3(v, OP_Insert, pReturning->iRetCur, reg+i, reg+i+1);
|
|
+ }
|
|
+ }
|
|
+ sqlite3ExprListDelete(db, pNew);
|
|
+ pParse->eTriggerOp = 0;
|
|
+ pParse->pTriggerTab = 0;
|
|
+}
|
|
+
|
|
+
|
|
+
|
|
+/*
|
|
+** Generate VDBE code for the statements inside the body of a single
|
|
** trigger.
|
|
*/
|
|
static int codeTriggerProgram(
|
|
Parse *pParse, /* The parser context */
|
|
TriggerStep *pStepList, /* List of statements inside the trigger body */
|
|
- int orconf /* Conflict algorithm. (OE_Abort, etc) */
|
|
+ int orconf /* Conflict algorithm. (OE_Abort, etc) */
|
|
){
|
|
TriggerStep *pStep;
|
|
Vdbe *v = pParse->pVdbe;
|
|
@@ -135657,29 +147767,32 @@ static int codeTriggerProgram(
|
|
|
|
switch( pStep->op ){
|
|
case TK_UPDATE: {
|
|
- sqlite3Update(pParse,
|
|
- targetSrcList(pParse, pStep),
|
|
- sqlite3ExprListDup(db, pStep->pExprList, 0),
|
|
- sqlite3ExprDup(db, pStep->pWhere, 0),
|
|
+ sqlite3Update(pParse,
|
|
+ sqlite3TriggerStepSrc(pParse, pStep),
|
|
+ sqlite3ExprListDup(db, pStep->pExprList, 0),
|
|
+ sqlite3ExprDup(db, pStep->pWhere, 0),
|
|
pParse->eOrconf, 0, 0, 0
|
|
);
|
|
+ sqlite3VdbeAddOp0(v, OP_ResetCount);
|
|
break;
|
|
}
|
|
case TK_INSERT: {
|
|
- sqlite3Insert(pParse,
|
|
- targetSrcList(pParse, pStep),
|
|
- sqlite3SelectDup(db, pStep->pSelect, 0),
|
|
- sqlite3IdListDup(db, pStep->pIdList),
|
|
+ sqlite3Insert(pParse,
|
|
+ sqlite3TriggerStepSrc(pParse, pStep),
|
|
+ sqlite3SelectDup(db, pStep->pSelect, 0),
|
|
+ sqlite3IdListDup(db, pStep->pIdList),
|
|
pParse->eOrconf,
|
|
sqlite3UpsertDup(db, pStep->pUpsert)
|
|
);
|
|
+ sqlite3VdbeAddOp0(v, OP_ResetCount);
|
|
break;
|
|
}
|
|
case TK_DELETE: {
|
|
- sqlite3DeleteFrom(pParse,
|
|
- targetSrcList(pParse, pStep),
|
|
+ sqlite3DeleteFrom(pParse,
|
|
+ sqlite3TriggerStepSrc(pParse, pStep),
|
|
sqlite3ExprDup(db, pStep->pWhere, 0), 0, 0
|
|
);
|
|
+ sqlite3VdbeAddOp0(v, OP_ResetCount);
|
|
break;
|
|
}
|
|
default: assert( pStep->op==TK_SELECT ); {
|
|
@@ -135690,9 +147803,6 @@ static int codeTriggerProgram(
|
|
sqlite3SelectDelete(db, pSelect);
|
|
break;
|
|
}
|
|
- }
|
|
- if( pStep->op!=TK_SELECT ){
|
|
- sqlite3VdbeAddOp0(v, OP_ResetCount);
|
|
}
|
|
}
|
|
|
|
@@ -135735,7 +147845,7 @@ static void transferParseError(Parse *pTo, Parse *pFrom){
|
|
}
|
|
|
|
/*
|
|
-** Create and populate a new TriggerPrg object with a sub-program
|
|
+** Create and populate a new TriggerPrg object with a sub-program
|
|
** implementing trigger pTrigger with ON CONFLICT policy orconf.
|
|
*/
|
|
static TriggerPrg *codeRowTrigger(
|
|
@@ -135751,14 +147861,14 @@ static TriggerPrg *codeRowTrigger(
|
|
Vdbe *v; /* Temporary VM */
|
|
NameContext sNC; /* Name context for sub-vdbe */
|
|
SubProgram *pProgram = 0; /* Sub-vdbe for trigger program */
|
|
- Parse *pSubParse; /* Parse context for sub-vdbe */
|
|
int iEndTrigger = 0; /* Label to jump to if WHEN is false */
|
|
+ Parse sSubParse; /* Parse context for sub-vdbe */
|
|
|
|
assert( pTrigger->zName==0 || pTab==tableOfTrigger(pTrigger) );
|
|
assert( pTop->pVdbe );
|
|
|
|
/* Allocate the TriggerPrg and SubProgram objects. To ensure that they
|
|
- ** are freed if an error occurs, link them into the Parse.pTriggerPrg
|
|
+ ** are freed if an error occurs, link them into the Parse.pTriggerPrg
|
|
** list of the top-level Parse object sooner rather than later. */
|
|
pPrg = sqlite3DbMallocZero(db, sizeof(TriggerPrg));
|
|
if( !pPrg ) return 0;
|
|
@@ -135772,23 +147882,21 @@ static TriggerPrg *codeRowTrigger(
|
|
pPrg->aColmask[0] = 0xffffffff;
|
|
pPrg->aColmask[1] = 0xffffffff;
|
|
|
|
- /* Allocate and populate a new Parse context to use for coding the
|
|
+ /* Allocate and populate a new Parse context to use for coding the
|
|
** trigger sub-program. */
|
|
- pSubParse = sqlite3StackAllocZero(db, sizeof(Parse));
|
|
- if( !pSubParse ) return 0;
|
|
+ sqlite3ParseObjectInit(&sSubParse, db);
|
|
memset(&sNC, 0, sizeof(sNC));
|
|
- sNC.pParse = pSubParse;
|
|
- pSubParse->db = db;
|
|
- pSubParse->pTriggerTab = pTab;
|
|
- pSubParse->pToplevel = pTop;
|
|
- pSubParse->zAuthContext = pTrigger->zName;
|
|
- pSubParse->eTriggerOp = pTrigger->op;
|
|
- pSubParse->nQueryLoop = pParse->nQueryLoop;
|
|
- pSubParse->disableVtab = pParse->disableVtab;
|
|
-
|
|
- v = sqlite3GetVdbe(pSubParse);
|
|
+ sNC.pParse = &sSubParse;
|
|
+ sSubParse.pTriggerTab = pTab;
|
|
+ sSubParse.pToplevel = pTop;
|
|
+ sSubParse.zAuthContext = pTrigger->zName;
|
|
+ sSubParse.eTriggerOp = pTrigger->op;
|
|
+ sSubParse.nQueryLoop = pParse->nQueryLoop;
|
|
+ sSubParse.prepFlags = pParse->prepFlags;
|
|
+
|
|
+ v = sqlite3GetVdbe(&sSubParse);
|
|
if( v ){
|
|
- VdbeComment((v, "Start: %s.%s (%s %s%s%s ON %s)",
|
|
+ VdbeComment((v, "Start: %s.%s (%s %s%s%s ON %s)",
|
|
pTrigger->zName, onErrorText(orconf),
|
|
(pTrigger->tr_tm==TRIGGER_BEFORE ? "BEFORE" : "AFTER"),
|
|
(pTrigger->op==TK_UPDATE ? "UPDATE" : ""),
|
|
@@ -135798,28 +147906,28 @@ static TriggerPrg *codeRowTrigger(
|
|
));
|
|
#ifndef SQLITE_OMIT_TRACE
|
|
if( pTrigger->zName ){
|
|
- sqlite3VdbeChangeP4(v, -1,
|
|
+ sqlite3VdbeChangeP4(v, -1,
|
|
sqlite3MPrintf(db, "-- TRIGGER %s", pTrigger->zName), P4_DYNAMIC
|
|
);
|
|
}
|
|
#endif
|
|
|
|
/* If one was specified, code the WHEN clause. If it evaluates to false
|
|
- ** (or NULL) the sub-vdbe is immediately halted by jumping to the
|
|
+ ** (or NULL) the sub-vdbe is immediately halted by jumping to the
|
|
** OP_Halt inserted at the end of the program. */
|
|
if( pTrigger->pWhen ){
|
|
pWhen = sqlite3ExprDup(db, pTrigger->pWhen, 0);
|
|
- if( SQLITE_OK==sqlite3ResolveExprNames(&sNC, pWhen)
|
|
- && db->mallocFailed==0
|
|
+ if( db->mallocFailed==0
|
|
+ && SQLITE_OK==sqlite3ResolveExprNames(&sNC, pWhen)
|
|
){
|
|
- iEndTrigger = sqlite3VdbeMakeLabel(pSubParse);
|
|
- sqlite3ExprIfFalse(pSubParse, pWhen, iEndTrigger, SQLITE_JUMPIFNULL);
|
|
+ iEndTrigger = sqlite3VdbeMakeLabel(&sSubParse);
|
|
+ sqlite3ExprIfFalse(&sSubParse, pWhen, iEndTrigger, SQLITE_JUMPIFNULL);
|
|
}
|
|
sqlite3ExprDelete(db, pWhen);
|
|
}
|
|
|
|
/* Code the trigger program into the sub-vdbe. */
|
|
- codeTriggerProgram(pSubParse, pTrigger->step_list, orconf);
|
|
+ codeTriggerProgram(&sSubParse, pTrigger->step_list, orconf);
|
|
|
|
/* Insert an OP_Halt at the end of the sub-program. */
|
|
if( iEndTrigger ){
|
|
@@ -135827,27 +147935,27 @@ static TriggerPrg *codeRowTrigger(
|
|
}
|
|
sqlite3VdbeAddOp0(v, OP_Halt);
|
|
VdbeComment((v, "End: %s.%s", pTrigger->zName, onErrorText(orconf)));
|
|
+ transferParseError(pParse, &sSubParse);
|
|
|
|
- transferParseError(pParse, pSubParse);
|
|
- if( db->mallocFailed==0 && pParse->nErr==0 ){
|
|
+ if( pParse->nErr==0 ){
|
|
+ assert( db->mallocFailed==0 );
|
|
pProgram->aOp = sqlite3VdbeTakeOpArray(v, &pProgram->nOp, &pTop->nMaxArg);
|
|
}
|
|
- pProgram->nMem = pSubParse->nMem;
|
|
- pProgram->nCsr = pSubParse->nTab;
|
|
+ pProgram->nMem = sSubParse.nMem;
|
|
+ pProgram->nCsr = sSubParse.nTab;
|
|
pProgram->token = (void *)pTrigger;
|
|
- pPrg->aColmask[0] = pSubParse->oldmask;
|
|
- pPrg->aColmask[1] = pSubParse->newmask;
|
|
+ pPrg->aColmask[0] = sSubParse.oldmask;
|
|
+ pPrg->aColmask[1] = sSubParse.newmask;
|
|
sqlite3VdbeDelete(v);
|
|
+ }else{
|
|
+ transferParseError(pParse, &sSubParse);
|
|
}
|
|
|
|
- assert( !pSubParse->pAinc && !pSubParse->pZombieTab );
|
|
- assert( !pSubParse->pTriggerPrg && !pSubParse->nMaxArg );
|
|
- sqlite3ParserReset(pSubParse);
|
|
- sqlite3StackFree(db, pSubParse);
|
|
-
|
|
+ assert( !sSubParse.pTriggerPrg && !sSubParse.nMaxArg );
|
|
+ sqlite3ParseObjectReset(&sSubParse);
|
|
return pPrg;
|
|
}
|
|
-
|
|
+
|
|
/*
|
|
** Return a pointer to a TriggerPrg object containing the sub-program for
|
|
** trigger pTrigger with default ON CONFLICT algorithm orconf. If no such
|
|
@@ -135869,21 +147977,22 @@ static TriggerPrg *getRowTrigger(
|
|
** process of being coded). If this is the case, then an entry with
|
|
** a matching TriggerPrg.pTrigger field will be present somewhere
|
|
** in the Parse.pTriggerPrg list. Search for such an entry. */
|
|
- for(pPrg=pRoot->pTriggerPrg;
|
|
- pPrg && (pPrg->pTrigger!=pTrigger || pPrg->orconf!=orconf);
|
|
+ for(pPrg=pRoot->pTriggerPrg;
|
|
+ pPrg && (pPrg->pTrigger!=pTrigger || pPrg->orconf!=orconf);
|
|
pPrg=pPrg->pNext
|
|
);
|
|
|
|
/* If an existing TriggerPrg could not be located, create a new one. */
|
|
if( !pPrg ){
|
|
pPrg = codeRowTrigger(pParse, pTrigger, pTab, orconf);
|
|
+ pParse->db->errByteOffset = -1;
|
|
}
|
|
|
|
return pPrg;
|
|
}
|
|
|
|
/*
|
|
-** Generate code for the trigger program associated with trigger p on
|
|
+** Generate code for the trigger program associated with trigger p on
|
|
** table pTab. The reg, orconf and ignoreJump parameters passed to this
|
|
** function are the same as those described in the header function for
|
|
** sqlite3CodeRowTrigger()
|
|
@@ -135899,9 +148008,9 @@ SQLITE_PRIVATE void sqlite3CodeRowTriggerDirect(
|
|
Vdbe *v = sqlite3GetVdbe(pParse); /* Main VM */
|
|
TriggerPrg *pPrg;
|
|
pPrg = getRowTrigger(pParse, p, pTab, orconf);
|
|
- assert( pPrg || pParse->nErr || pParse->db->mallocFailed );
|
|
+ assert( pPrg || pParse->nErr );
|
|
|
|
- /* Code the OP_Program opcode in the parent VDBE. P4 of the OP_Program
|
|
+ /* Code the OP_Program opcode in the parent VDBE. P4 of the OP_Program
|
|
** is a pointer to the sub-vdbe containing the trigger program. */
|
|
if( pPrg ){
|
|
int bRecursive = (p->zName && 0==(pParse->db->flags&SQLITE_RecTriggers));
|
|
@@ -135930,7 +148039,7 @@ SQLITE_PRIVATE void sqlite3CodeRowTriggerDirect(
|
|
** If there are no triggers that fire at the specified time for the specified
|
|
** operation on pTab, this function is a no-op.
|
|
**
|
|
-** The reg argument is the address of the first in an array of registers
|
|
+** The reg argument is the address of the first in an array of registers
|
|
** that contain the values substituted for the new.* and old.* references
|
|
** in the trigger program. If N is the number of columns in table pTab
|
|
** (a copy of pTab->nCol), then registers are populated as follows:
|
|
@@ -135942,17 +148051,17 @@ SQLITE_PRIVATE void sqlite3CodeRowTriggerDirect(
|
|
** ... ...
|
|
** reg+N OLD.* value of right-most column of pTab
|
|
** reg+N+1 NEW.rowid
|
|
-** reg+N+2 OLD.* value of left-most column of pTab
|
|
+** reg+N+2 NEW.* value of left-most column of pTab
|
|
** ... ...
|
|
** reg+N+N+1 NEW.* value of right-most column of pTab
|
|
**
|
|
** For ON DELETE triggers, the registers containing the NEW.* values will
|
|
-** never be accessed by the trigger program, so they are not allocated or
|
|
-** populated by the caller (there is no data to populate them with anyway).
|
|
+** never be accessed by the trigger program, so they are not allocated or
|
|
+** populated by the caller (there is no data to populate them with anyway).
|
|
** Similarly, for ON INSERT triggers the values stored in the OLD.* registers
|
|
** are never accessed, and so are not allocated by the caller. So, for an
|
|
** ON INSERT trigger, the value passed to this function as parameter reg
|
|
-** is not a readable register, although registers (reg+N) through
|
|
+** is not a readable register, although registers (reg+N) through
|
|
** (reg+N+N+1) are.
|
|
**
|
|
** Parameter orconf is the default conflict resolution algorithm for the
|
|
@@ -135984,23 +148093,31 @@ SQLITE_PRIVATE void sqlite3CodeRowTrigger(
|
|
** or else it must be a TEMP trigger. */
|
|
assert( p->pSchema!=0 );
|
|
assert( p->pTabSchema!=0 );
|
|
- assert( p->pSchema==p->pTabSchema
|
|
+ assert( p->pSchema==p->pTabSchema
|
|
|| p->pSchema==pParse->db->aDb[1].pSchema );
|
|
|
|
- /* Determine whether we should code this trigger */
|
|
- if( p->op==op
|
|
- && p->tr_tm==tr_tm
|
|
+ /* Determine whether we should code this trigger. One of two choices:
|
|
+ ** 1. The trigger is an exact match to the current DML statement
|
|
+ ** 2. This is a RETURNING trigger for INSERT but we are currently
|
|
+ ** doing the UPDATE part of an UPSERT.
|
|
+ */
|
|
+ if( (p->op==op || (p->bReturning && p->op==TK_INSERT && op==TK_UPDATE))
|
|
+ && p->tr_tm==tr_tm
|
|
&& checkColumnOverlap(p->pColumns, pChanges)
|
|
){
|
|
- sqlite3CodeRowTriggerDirect(pParse, p, pTab, reg, orconf, ignoreJump);
|
|
+ if( !p->bReturning ){
|
|
+ sqlite3CodeRowTriggerDirect(pParse, p, pTab, reg, orconf, ignoreJump);
|
|
+ }else if( sqlite3IsToplevel(pParse) ){
|
|
+ codeReturningTrigger(pParse, p, pTab, reg);
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
-** Triggers may access values stored in the old.* or new.* pseudo-table.
|
|
-** This function returns a 32-bit bitmask indicating which columns of the
|
|
-** old.* or new.* tables actually are used by triggers. This information
|
|
+** Triggers may access values stored in the old.* or new.* pseudo-table.
|
|
+** This function returns a 32-bit bitmask indicating which columns of the
|
|
+** old.* or new.* tables actually are used by triggers. This information
|
|
** may be used by the caller, for example, to avoid having to load the entire
|
|
** old.* record into memory when executing an UPDATE or DELETE command.
|
|
**
|
|
@@ -136010,7 +148127,7 @@ SQLITE_PRIVATE void sqlite3CodeRowTrigger(
|
|
** are more than 32 columns in the table, and at least one of the columns
|
|
** with an index greater than 32 may be accessed, 0xffffffff is returned.
|
|
**
|
|
-** It is not possible to determine if the old.rowid or new.rowid column is
|
|
+** It is not possible to determine if the old.rowid or new.rowid column is
|
|
** accessed by triggers. The caller must always assume that it is.
|
|
**
|
|
** Parameter isNew must be either 1 or 0. If it is 0, then the mask returned
|
|
@@ -136037,13 +148154,18 @@ SQLITE_PRIVATE u32 sqlite3TriggerColmask(
|
|
|
|
assert( isNew==1 || isNew==0 );
|
|
for(p=pTrigger; p; p=p->pNext){
|
|
- if( p->op==op && (tr_tm&p->tr_tm)
|
|
+ if( p->op==op
|
|
+ && (tr_tm&p->tr_tm)
|
|
&& checkColumnOverlap(p->pColumns,pChanges)
|
|
){
|
|
- TriggerPrg *pPrg;
|
|
- pPrg = getRowTrigger(pParse, p, pTab, orconf);
|
|
- if( pPrg ){
|
|
- mask |= pPrg->aColmask[isNew];
|
|
+ if( p->bReturning ){
|
|
+ mask = 0xffffffff;
|
|
+ }else{
|
|
+ TriggerPrg *pPrg;
|
|
+ pPrg = getRowTrigger(pParse, p, pTab, orconf);
|
|
+ if( pPrg ){
|
|
+ mask |= pPrg->aColmask[isNew];
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
@@ -136087,10 +148209,10 @@ static void updateVirtualTable(
|
|
|
|
/*
|
|
** The most recently coded instruction was an OP_Column to retrieve the
|
|
-** i-th column of table pTab. This routine sets the P4 parameter of the
|
|
+** i-th column of table pTab. This routine sets the P4 parameter of the
|
|
** OP_Column to the default value, if any.
|
|
**
|
|
-** The default value of a column is specified by a DEFAULT clause in the
|
|
+** The default value of a column is specified by a DEFAULT clause in the
|
|
** column definition. This was either supplied by the user when the table
|
|
** was created, or added later to the table definition by an ALTER TABLE
|
|
** command. If the latter, then the row-records in the table btree on disk
|
|
@@ -136099,38 +148221,42 @@ static void updateVirtualTable(
|
|
** If the former, then all row-records are guaranteed to include a value
|
|
** for the column and the P4 value is not required.
|
|
**
|
|
-** Column definitions created by an ALTER TABLE command may only have
|
|
+** Column definitions created by an ALTER TABLE command may only have
|
|
** literal default values specified: a number, null or a string. (If a more
|
|
-** complicated default expression value was provided, it is evaluated
|
|
+** complicated default expression value was provided, it is evaluated
|
|
** when the ALTER TABLE is executed and one of the literal values written
|
|
-** into the sqlite_master table.)
|
|
+** into the sqlite_schema table.)
|
|
**
|
|
** Therefore, the P4 parameter is only required if the default value for
|
|
** the column is a literal number, string or null. The sqlite3ValueFromExpr()
|
|
** function is capable of transforming these types of expressions into
|
|
** sqlite3_value objects.
|
|
**
|
|
-** If parameter iReg is not negative, code an OP_RealAffinity instruction
|
|
-** on register iReg. This is used when an equivalent integer value is
|
|
-** stored in place of an 8-byte floating point value in order to save
|
|
-** space.
|
|
+** If column as REAL affinity and the table is an ordinary b-tree table
|
|
+** (not a virtual table) then the value might have been stored as an
|
|
+** integer. In that case, add an OP_RealAffinity opcode to make sure
|
|
+** it has been converted into REAL.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i, int iReg){
|
|
+ Column *pCol;
|
|
assert( pTab!=0 );
|
|
- if( !pTab->pSelect ){
|
|
+ assert( pTab->nCol>i );
|
|
+ pCol = &pTab->aCol[i];
|
|
+ if( pCol->iDflt ){
|
|
sqlite3_value *pValue = 0;
|
|
u8 enc = ENC(sqlite3VdbeDb(v));
|
|
- Column *pCol = &pTab->aCol[i];
|
|
- VdbeComment((v, "%s.%s", pTab->zName, pCol->zName));
|
|
+ assert( !IsView(pTab) );
|
|
+ VdbeComment((v, "%s.%s", pTab->zName, pCol->zCnName));
|
|
assert( i<pTab->nCol );
|
|
- sqlite3ValueFromExpr(sqlite3VdbeDb(v), pCol->pDflt, enc,
|
|
+ sqlite3ValueFromExpr(sqlite3VdbeDb(v),
|
|
+ sqlite3ColumnExpr(pTab,pCol), enc,
|
|
pCol->affinity, &pValue);
|
|
if( pValue ){
|
|
sqlite3VdbeAppendP4(v, pValue, P4_MEM);
|
|
}
|
|
}
|
|
#ifndef SQLITE_OMIT_FLOATING_POINT
|
|
- if( pTab->aCol[i].affinity==SQLITE_AFF_REAL ){
|
|
+ if( pCol->affinity==SQLITE_AFF_REAL && !IsVirtual(pTab) ){
|
|
sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg);
|
|
}
|
|
#endif
|
|
@@ -136187,12 +148313,153 @@ static int indexWhereClauseMightChange(
|
|
aXRef, chngRowid);
|
|
}
|
|
|
|
+/*
|
|
+** Allocate and return a pointer to an expression of type TK_ROW with
|
|
+** Expr.iColumn set to value (iCol+1). The resolver will modify the
|
|
+** expression to be a TK_COLUMN reading column iCol of the first
|
|
+** table in the source-list (pSrc->a[0]).
|
|
+*/
|
|
+static Expr *exprRowColumn(Parse *pParse, int iCol){
|
|
+ Expr *pRet = sqlite3PExpr(pParse, TK_ROW, 0, 0);
|
|
+ if( pRet ) pRet->iColumn = iCol+1;
|
|
+ return pRet;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Assuming both the pLimit and pOrderBy parameters are NULL, this function
|
|
+** generates VM code to run the query:
|
|
+**
|
|
+** SELECT <other-columns>, pChanges FROM pTabList WHERE pWhere
|
|
+**
|
|
+** and write the results to the ephemeral table already opened as cursor
|
|
+** iEph. None of pChanges, pTabList or pWhere are modified or consumed by
|
|
+** this function, they must be deleted by the caller.
|
|
+**
|
|
+** Or, if pLimit and pOrderBy are not NULL, and pTab is not a view:
|
|
+**
|
|
+** SELECT <other-columns>, pChanges FROM pTabList
|
|
+** WHERE pWhere
|
|
+** GROUP BY <other-columns>
|
|
+** ORDER BY pOrderBy LIMIT pLimit
|
|
+**
|
|
+** If pTab is a view, the GROUP BY clause is omitted.
|
|
+**
|
|
+** Exactly how results are written to table iEph, and exactly what
|
|
+** the <other-columns> in the query above are is determined by the type
|
|
+** of table pTabList->a[0].pTab.
|
|
+**
|
|
+** If the table is a WITHOUT ROWID table, then argument pPk must be its
|
|
+** PRIMARY KEY. In this case <other-columns> are the primary key columns
|
|
+** of the table, in order. The results of the query are written to ephemeral
|
|
+** table iEph as index keys, using OP_IdxInsert.
|
|
+**
|
|
+** If the table is actually a view, then <other-columns> are all columns of
|
|
+** the view. The results are written to the ephemeral table iEph as records
|
|
+** with automatically assigned integer keys.
|
|
+**
|
|
+** If the table is a virtual or ordinary intkey table, then <other-columns>
|
|
+** is its rowid. For a virtual table, the results are written to iEph as
|
|
+** records with automatically assigned integer keys For intkey tables, the
|
|
+** rowid value in <other-columns> is used as the integer key, and the
|
|
+** remaining fields make up the table record.
|
|
+*/
|
|
+static void updateFromSelect(
|
|
+ Parse *pParse, /* Parse context */
|
|
+ int iEph, /* Cursor for open eph. table */
|
|
+ Index *pPk, /* PK if table 0 is WITHOUT ROWID */
|
|
+ ExprList *pChanges, /* List of expressions to return */
|
|
+ SrcList *pTabList, /* List of tables to select from */
|
|
+ Expr *pWhere, /* WHERE clause for query */
|
|
+ ExprList *pOrderBy, /* ORDER BY clause */
|
|
+ Expr *pLimit /* LIMIT clause */
|
|
+){
|
|
+ int i;
|
|
+ SelectDest dest;
|
|
+ Select *pSelect = 0;
|
|
+ ExprList *pList = 0;
|
|
+ ExprList *pGrp = 0;
|
|
+ Expr *pLimit2 = 0;
|
|
+ ExprList *pOrderBy2 = 0;
|
|
+ sqlite3 *db = pParse->db;
|
|
+ Table *pTab = pTabList->a[0].pTab;
|
|
+ SrcList *pSrc;
|
|
+ Expr *pWhere2;
|
|
+ int eDest;
|
|
+
|
|
+#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
|
|
+ if( pOrderBy && pLimit==0 ) {
|
|
+ sqlite3ErrorMsg(pParse, "ORDER BY without LIMIT on UPDATE");
|
|
+ return;
|
|
+ }
|
|
+ pOrderBy2 = sqlite3ExprListDup(db, pOrderBy, 0);
|
|
+ pLimit2 = sqlite3ExprDup(db, pLimit, 0);
|
|
+#else
|
|
+ UNUSED_PARAMETER(pOrderBy);
|
|
+ UNUSED_PARAMETER(pLimit);
|
|
+#endif
|
|
+
|
|
+ pSrc = sqlite3SrcListDup(db, pTabList, 0);
|
|
+ pWhere2 = sqlite3ExprDup(db, pWhere, 0);
|
|
+
|
|
+ assert( pTabList->nSrc>1 );
|
|
+ if( pSrc ){
|
|
+ pSrc->a[0].fg.notCte = 1;
|
|
+ pSrc->a[0].iCursor = -1;
|
|
+ pSrc->a[0].pTab->nTabRef--;
|
|
+ pSrc->a[0].pTab = 0;
|
|
+ }
|
|
+ if( pPk ){
|
|
+ for(i=0; i<pPk->nKeyCol; i++){
|
|
+ Expr *pNew = exprRowColumn(pParse, pPk->aiColumn[i]);
|
|
+#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
|
|
+ if( pLimit ){
|
|
+ pGrp = sqlite3ExprListAppend(pParse, pGrp, sqlite3ExprDup(db, pNew, 0));
|
|
+ }
|
|
+#endif
|
|
+ pList = sqlite3ExprListAppend(pParse, pList, pNew);
|
|
+ }
|
|
+ eDest = IsVirtual(pTab) ? SRT_Table : SRT_Upfrom;
|
|
+ }else if( IsView(pTab) ){
|
|
+ for(i=0; i<pTab->nCol; i++){
|
|
+ pList = sqlite3ExprListAppend(pParse, pList, exprRowColumn(pParse, i));
|
|
+ }
|
|
+ eDest = SRT_Table;
|
|
+ }else{
|
|
+ eDest = IsVirtual(pTab) ? SRT_Table : SRT_Upfrom;
|
|
+ pList = sqlite3ExprListAppend(pParse, 0, sqlite3PExpr(pParse,TK_ROW,0,0));
|
|
+#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
|
|
+ if( pLimit ){
|
|
+ pGrp = sqlite3ExprListAppend(pParse, 0, sqlite3PExpr(pParse,TK_ROW,0,0));
|
|
+ }
|
|
+#endif
|
|
+ }
|
|
+ assert( pChanges!=0 || pParse->db->mallocFailed );
|
|
+ if( pChanges ){
|
|
+ for(i=0; i<pChanges->nExpr; i++){
|
|
+ pList = sqlite3ExprListAppend(pParse, pList,
|
|
+ sqlite3ExprDup(db, pChanges->a[i].pExpr, 0)
|
|
+ );
|
|
+ }
|
|
+ }
|
|
+ pSelect = sqlite3SelectNew(pParse, pList,
|
|
+ pSrc, pWhere2, pGrp, 0, pOrderBy2,
|
|
+ SF_UFSrcCheck|SF_IncludeHidden|SF_UpdateFrom, pLimit2
|
|
+ );
|
|
+ if( pSelect ) pSelect->selFlags |= SF_OrderByReqd;
|
|
+ sqlite3SelectDestInit(&dest, eDest, iEph);
|
|
+ dest.iSDParm2 = (pPk ? pPk->nKeyCol : -1);
|
|
+ sqlite3Select(pParse, pSelect, &dest);
|
|
+ sqlite3SelectDelete(db, pSelect);
|
|
+}
|
|
+
|
|
/*
|
|
** Process an UPDATE statement.
|
|
**
|
|
-** UPDATE OR IGNORE table_wxyz SET a=b, c=d WHERE e<5 AND f NOT NULL;
|
|
-** \_______/ \________/ \______/ \________________/
|
|
-* onError pTabList pChanges pWhere
|
|
+** UPDATE OR IGNORE tbl SET a=b, c=d FROM tbl2... WHERE e<5 AND f NOT NULL;
|
|
+** \_______/ \_/ \______/ \_____/ \________________/
|
|
+** onError | pChanges | pWhere
|
|
+** \_______________________/
|
|
+** pTabList
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3Update(
|
|
Parse *pParse, /* The parser context */
|
|
@@ -136207,7 +148474,7 @@ SQLITE_PRIVATE void sqlite3Update(
|
|
int i, j, k; /* Loop counters */
|
|
Table *pTab; /* The table to be updated */
|
|
int addrTop = 0; /* VDBE instruction address of the start of the loop */
|
|
- WhereInfo *pWInfo; /* Information about the WHERE clause */
|
|
+ WhereInfo *pWInfo = 0; /* Information about the WHERE clause */
|
|
Vdbe *v; /* The virtual database engine */
|
|
Index *pIdx; /* For looping over indices */
|
|
Index *pPk; /* The PRIMARY KEY index for WITHOUT ROWID tables */
|
|
@@ -136226,6 +148493,7 @@ SQLITE_PRIVATE void sqlite3Update(
|
|
u8 chngRowid; /* Rowid changed in a normal table */
|
|
u8 chngKey; /* Either chngPk or chngRowid */
|
|
Expr *pRowidExpr = 0; /* Expression defining the new record number */
|
|
+ int iRowidExpr = -1; /* Index of "rowid=" (or IPK) assignment in pChanges */
|
|
AuthContext sContext; /* The authorization context */
|
|
NameContext sNC; /* The name-context to resolve expressions in */
|
|
int iDb; /* Database containing the table being updated */
|
|
@@ -136249,6 +148517,7 @@ SQLITE_PRIVATE void sqlite3Update(
|
|
i16 nPk = 0; /* Number of components of the PRIMARY KEY */
|
|
int bReplace = 0; /* True if REPLACE conflict resolution might happen */
|
|
int bFinishSeek = 1; /* The OP_FinishSeek opcode is needed */
|
|
+ int nChangeFrom = 0; /* If there is a FROM, pChanges->nExpr, else 0 */
|
|
|
|
/* Register Allocations */
|
|
int regRowCount = 0; /* A count of rows changed */
|
|
@@ -136261,12 +148530,13 @@ SQLITE_PRIVATE void sqlite3Update(
|
|
|
|
memset(&sContext, 0, sizeof(sContext));
|
|
db = pParse->db;
|
|
- if( pParse->nErr || db->mallocFailed ){
|
|
+ assert( db->pParse==pParse );
|
|
+ if( pParse->nErr ){
|
|
goto update_cleanup;
|
|
}
|
|
- assert( pTabList->nSrc==1 );
|
|
+ assert( db->mallocFailed==0 );
|
|
|
|
- /* Locate the table which we want to update.
|
|
+ /* Locate the table which we want to update.
|
|
*/
|
|
pTab = sqlite3SrcListLookup(pParse, pTabList);
|
|
if( pTab==0 ) goto update_cleanup;
|
|
@@ -136277,7 +148547,7 @@ SQLITE_PRIVATE void sqlite3Update(
|
|
*/
|
|
#ifndef SQLITE_OMIT_TRIGGER
|
|
pTrigger = sqlite3TriggersExist(pParse, pTab, TK_UPDATE, pChanges, &tmask);
|
|
- isView = pTab->pSelect!=0;
|
|
+ isView = IsView(pTab);
|
|
assert( pTrigger || tmask==0 );
|
|
#else
|
|
# define pTrigger 0
|
|
@@ -136289,8 +148559,23 @@ SQLITE_PRIVATE void sqlite3Update(
|
|
# define isView 0
|
|
#endif
|
|
|
|
+#if TREETRACE_ENABLED
|
|
+ if( sqlite3TreeTrace & 0x10000 ){
|
|
+ sqlite3TreeViewLine(0, "In sqlite3Update() at %s:%d", __FILE__, __LINE__);
|
|
+ sqlite3TreeViewUpdate(pParse->pWith, pTabList, pChanges, pWhere,
|
|
+ onError, pOrderBy, pLimit, pUpsert, pTrigger);
|
|
+ }
|
|
+#endif
|
|
+
|
|
+ /* If there was a FROM clause, set nChangeFrom to the number of expressions
|
|
+ ** in the change-list. Otherwise, set it to 0. There cannot be a FROM
|
|
+ ** clause if this function is being called to generate code for part of
|
|
+ ** an UPSERT statement. */
|
|
+ nChangeFrom = (pTabList->nSrc>1) ? pChanges->nExpr : 0;
|
|
+ assert( nChangeFrom==0 || pUpsert==0 );
|
|
+
|
|
#ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
|
|
- if( !isView ){
|
|
+ if( !isView && nChangeFrom==0 ){
|
|
pWhere = sqlite3LimitWhere(
|
|
pParse, pTabList, pWhere, pOrderBy, pLimit, "UPDATE"
|
|
);
|
|
@@ -136329,7 +148614,7 @@ SQLITE_PRIVATE void sqlite3Update(
|
|
}
|
|
pTabList->a[0].iCursor = iDataCur;
|
|
|
|
- /* Allocate space for aXRef[], aRegIdx[], and aToOpen[].
|
|
+ /* Allocate space for aXRef[], aRegIdx[], and aToOpen[].
|
|
** Initialize aXRef[] and aToOpen[] to their default values.
|
|
*/
|
|
aXRef = sqlite3DbMallocRawNN(db, sizeof(int) * (pTab->nCol+nIdx+1) + nIdx+2 );
|
|
@@ -136359,14 +148644,20 @@ SQLITE_PRIVATE void sqlite3Update(
|
|
*/
|
|
chngRowid = chngPk = 0;
|
|
for(i=0; i<pChanges->nExpr; i++){
|
|
- if( sqlite3ResolveExprNames(&sNC, pChanges->a[i].pExpr) ){
|
|
+ u8 hCol = sqlite3StrIHash(pChanges->a[i].zEName);
|
|
+ /* If this is an UPDATE with a FROM clause, do not resolve expressions
|
|
+ ** here. The call to sqlite3Select() below will do that. */
|
|
+ if( nChangeFrom==0 && sqlite3ResolveExprNames(&sNC, pChanges->a[i].pExpr) ){
|
|
goto update_cleanup;
|
|
}
|
|
for(j=0; j<pTab->nCol; j++){
|
|
- if( sqlite3StrICmp(pTab->aCol[j].zName, pChanges->a[i].zEName)==0 ){
|
|
+ if( pTab->aCol[j].hName==hCol
|
|
+ && sqlite3StrICmp(pTab->aCol[j].zCnName, pChanges->a[i].zEName)==0
|
|
+ ){
|
|
if( j==pTab->iPKey ){
|
|
chngRowid = 1;
|
|
pRowidExpr = pChanges->a[i].pExpr;
|
|
+ iRowidExpr = i;
|
|
}else if( pPk && (pTab->aCol[j].colFlags & COLFLAG_PRIMKEY)!=0 ){
|
|
chngPk = 1;
|
|
}
|
|
@@ -136374,9 +148665,9 @@ SQLITE_PRIVATE void sqlite3Update(
|
|
else if( pTab->aCol[j].colFlags & COLFLAG_GENERATED ){
|
|
testcase( pTab->aCol[j].colFlags & COLFLAG_VIRTUAL );
|
|
testcase( pTab->aCol[j].colFlags & COLFLAG_STORED );
|
|
- sqlite3ErrorMsg(pParse,
|
|
+ sqlite3ErrorMsg(pParse,
|
|
"cannot UPDATE generated column \"%s\"",
|
|
- pTab->aCol[j].zName);
|
|
+ pTab->aCol[j].zCnName);
|
|
goto update_cleanup;
|
|
}
|
|
#endif
|
|
@@ -136389,6 +148680,7 @@ SQLITE_PRIVATE void sqlite3Update(
|
|
j = -1;
|
|
chngRowid = 1;
|
|
pRowidExpr = pChanges->a[i].pExpr;
|
|
+ iRowidExpr = i;
|
|
}else{
|
|
sqlite3ErrorMsg(pParse, "no such column: %s", pChanges->a[i].zEName);
|
|
pParse->checkSchema = 1;
|
|
@@ -136399,7 +148691,7 @@ SQLITE_PRIVATE void sqlite3Update(
|
|
{
|
|
int rc;
|
|
rc = sqlite3AuthCheck(pParse, SQLITE_UPDATE, pTab->zName,
|
|
- j<0 ? "ROWID" : pTab->aCol[j].zName,
|
|
+ j<0 ? "ROWID" : pTab->aCol[j].zCnName,
|
|
db->aDb[iDb].zDbSName);
|
|
if( rc==SQLITE_DENY ){
|
|
goto update_cleanup;
|
|
@@ -136416,11 +148708,11 @@ SQLITE_PRIVATE void sqlite3Update(
|
|
|
|
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
|
|
/* Mark generated columns as changing if their generator expressions
|
|
- ** reference any changing column. The actual aXRef[] value for
|
|
+ ** reference any changing column. The actual aXRef[] value for
|
|
** generated expressions is not used, other than to check to see that it
|
|
** is non-negative, so the value of aXRef[] for generated columns can be
|
|
** set to any non-negative number. We use 99999 so that the value is
|
|
- ** obvious when looking at aXRef[] in a symbolic debugger.
|
|
+ ** obvious when looking at aXRef[] in a symbolic debugger.
|
|
*/
|
|
if( pTab->tabFlags & TF_HasGenerated ){
|
|
int bProgress;
|
|
@@ -136431,8 +148723,10 @@ SQLITE_PRIVATE void sqlite3Update(
|
|
for(i=0; i<pTab->nCol; i++){
|
|
if( aXRef[i]>=0 ) continue;
|
|
if( (pTab->aCol[i].colFlags & COLFLAG_GENERATED)==0 ) continue;
|
|
- if( sqlite3ExprReferencesUpdatedColumn(pTab->aCol[i].pDflt,
|
|
- aXRef, chngRowid) ){
|
|
+ if( sqlite3ExprReferencesUpdatedColumn(
|
|
+ sqlite3ColumnExpr(pTab, &pTab->aCol[i]),
|
|
+ aXRef, chngRowid)
|
|
+ ){
|
|
aXRef[i] = 99999;
|
|
bProgress = 1;
|
|
}
|
|
@@ -136441,7 +148735,7 @@ SQLITE_PRIVATE void sqlite3Update(
|
|
}
|
|
#endif
|
|
|
|
- /* The SET expressions are not actually used inside the WHERE loop.
|
|
+ /* The SET expressions are not actually used inside the WHERE loop.
|
|
** So reset the colUsed mask. Unless this is a virtual table. In that
|
|
** case, set all bits of the colUsed mask (to ensure that the virtual
|
|
** table implementation makes all columns available).
|
|
@@ -136480,7 +148774,7 @@ SQLITE_PRIVATE void sqlite3Update(
|
|
}
|
|
aRegIdx[nAllIdx] = ++pParse->nMem; /* Register storing the table record */
|
|
if( bReplace ){
|
|
- /* If REPLACE conflict resolution might be invoked, open cursors on all
|
|
+ /* If REPLACE conflict resolution might be invoked, open cursors on all
|
|
** indexes in case they are needed to delete records. */
|
|
memset(aToOpen, 1, nIdx+1);
|
|
}
|
|
@@ -136518,8 +148812,8 @@ SQLITE_PRIVATE void sqlite3Update(
|
|
** an ephemeral table.
|
|
*/
|
|
#if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER)
|
|
- if( isView ){
|
|
- sqlite3MaterializeView(pParse, pTab,
|
|
+ if( nChangeFrom==0 && isView ){
|
|
+ sqlite3MaterializeView(pParse, pTab,
|
|
pWhere, pOrderBy, pLimit, iDataCur
|
|
);
|
|
pOrderBy = 0;
|
|
@@ -136530,7 +148824,7 @@ SQLITE_PRIVATE void sqlite3Update(
|
|
/* Resolve the column names in all the expressions in the
|
|
** WHERE clause.
|
|
*/
|
|
- if( sqlite3ResolveExprNames(&sNC, pWhere) ){
|
|
+ if( nChangeFrom==0 && sqlite3ResolveExprNames(&sNC, pWhere) ){
|
|
goto update_cleanup;
|
|
}
|
|
|
|
@@ -136551,134 +148845,178 @@ SQLITE_PRIVATE void sqlite3Update(
|
|
if( (db->flags&SQLITE_CountRows)!=0
|
|
&& !pParse->pTriggerTab
|
|
&& !pParse->nested
|
|
+ && !pParse->bReturning
|
|
&& pUpsert==0
|
|
){
|
|
regRowCount = ++pParse->nMem;
|
|
sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount);
|
|
}
|
|
|
|
- if( HasRowid(pTab) ){
|
|
+ if( nChangeFrom==0 && HasRowid(pTab) ){
|
|
sqlite3VdbeAddOp3(v, OP_Null, 0, regRowSet, regOldRowid);
|
|
+ iEph = pParse->nTab++;
|
|
+ addrOpen = sqlite3VdbeAddOp3(v, OP_OpenEphemeral, iEph, 0, regRowSet);
|
|
}else{
|
|
- assert( pPk!=0 );
|
|
- nPk = pPk->nKeyCol;
|
|
+ assert( pPk!=0 || HasRowid(pTab) );
|
|
+ nPk = pPk ? pPk->nKeyCol : 0;
|
|
iPk = pParse->nMem+1;
|
|
pParse->nMem += nPk;
|
|
+ pParse->nMem += nChangeFrom;
|
|
regKey = ++pParse->nMem;
|
|
if( pUpsert==0 ){
|
|
+ int nEphCol = nPk + nChangeFrom + (isView ? pTab->nCol : 0);
|
|
iEph = pParse->nTab++;
|
|
- sqlite3VdbeAddOp3(v, OP_Null, 0, iPk, iPk+nPk-1);
|
|
- addrOpen = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iEph, nPk);
|
|
- sqlite3VdbeSetP4KeyInfo(pParse, pPk);
|
|
+ if( pPk ) sqlite3VdbeAddOp3(v, OP_Null, 0, iPk, iPk+nPk-1);
|
|
+ addrOpen = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iEph, nEphCol);
|
|
+ if( pPk ){
|
|
+ KeyInfo *pKeyInfo = sqlite3KeyInfoOfIndex(pParse, pPk);
|
|
+ if( pKeyInfo ){
|
|
+ pKeyInfo->nAllField = nEphCol;
|
|
+ sqlite3VdbeAppendP4(v, pKeyInfo, P4_KEYINFO);
|
|
+ }
|
|
+ }
|
|
+ if( nChangeFrom ){
|
|
+ updateFromSelect(
|
|
+ pParse, iEph, pPk, pChanges, pTabList, pWhere, pOrderBy, pLimit
|
|
+ );
|
|
+#ifndef SQLITE_OMIT_SUBQUERY
|
|
+ if( isView ) iDataCur = iEph;
|
|
+#endif
|
|
+ }
|
|
}
|
|
}
|
|
-
|
|
- if( pUpsert ){
|
|
- /* If this is an UPSERT, then all cursors have already been opened by
|
|
- ** the outer INSERT and the data cursor should be pointing at the row
|
|
- ** that is to be updated. So bypass the code that searches for the
|
|
- ** row(s) to be updated.
|
|
- */
|
|
- pWInfo = 0;
|
|
- eOnePass = ONEPASS_SINGLE;
|
|
- sqlite3ExprIfFalse(pParse, pWhere, labelBreak, SQLITE_JUMPIFNULL);
|
|
- bFinishSeek = 0;
|
|
+
|
|
+ if( nChangeFrom ){
|
|
+ sqlite3MultiWrite(pParse);
|
|
+ eOnePass = ONEPASS_OFF;
|
|
+ nKey = nPk;
|
|
+ regKey = iPk;
|
|
}else{
|
|
- /* 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. */
|
|
- flags = WHERE_ONEPASS_DESIRED|WHERE_SEEK_UNIQ_TABLE;
|
|
- if( !pParse->nested && !pTrigger && !hasFK && !chngKey && !bReplace ){
|
|
- flags |= WHERE_ONEPASS_MULTIROW;
|
|
- }
|
|
- pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0, flags, iIdxCur);
|
|
- if( pWInfo==0 ) goto update_cleanup;
|
|
-
|
|
- /* A one-pass strategy that might update more than one row may not
|
|
- ** be used if any column of the index used for the scan is being
|
|
- ** updated. Otherwise, if there is an index on "b", statements like
|
|
- ** the following could create an infinite loop:
|
|
- **
|
|
- ** UPDATE t1 SET b=b+1 WHERE b>?
|
|
- **
|
|
- ** Fall back to ONEPASS_OFF if where.c has selected a ONEPASS_MULTI
|
|
- ** strategy that uses an index for which one or more columns are being
|
|
- ** updated. */
|
|
- eOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);
|
|
- bFinishSeek = sqlite3WhereUsesDeferredSeek(pWInfo);
|
|
- if( eOnePass!=ONEPASS_SINGLE ){
|
|
- sqlite3MultiWrite(pParse);
|
|
- if( eOnePass==ONEPASS_MULTI ){
|
|
- int iCur = aiCurOnePass[1];
|
|
- if( iCur>=0 && iCur!=iDataCur && aToOpen[iCur-iBaseCur] ){
|
|
- eOnePass = ONEPASS_OFF;
|
|
+ if( pUpsert ){
|
|
+ /* If this is an UPSERT, then all cursors have already been opened by
|
|
+ ** the outer INSERT and the data cursor should be pointing at the row
|
|
+ ** that is to be updated. So bypass the code that searches for the
|
|
+ ** row(s) to be updated.
|
|
+ */
|
|
+ pWInfo = 0;
|
|
+ eOnePass = ONEPASS_SINGLE;
|
|
+ sqlite3ExprIfFalse(pParse, pWhere, labelBreak, SQLITE_JUMPIFNULL);
|
|
+ bFinishSeek = 0;
|
|
+ }else{
|
|
+ /* Begin the database scan.
|
|
+ **
|
|
+ ** Do not consider a single-pass strategy for a multi-row update if
|
|
+ ** there is anything that might disrupt the cursor being used to do
|
|
+ ** the UPDATE:
|
|
+ ** (1) This is a nested UPDATE
|
|
+ ** (2) There are triggers
|
|
+ ** (3) There are FOREIGN KEY constraints
|
|
+ ** (4) There are REPLACE conflict handlers
|
|
+ ** (5) There are subqueries in the WHERE clause
|
|
+ */
|
|
+ flags = WHERE_ONEPASS_DESIRED;
|
|
+ if( !pParse->nested
|
|
+ && !pTrigger
|
|
+ && !hasFK
|
|
+ && !chngKey
|
|
+ && !bReplace
|
|
+ && (sNC.ncFlags & NC_Subquery)==0
|
|
+ ){
|
|
+ flags |= WHERE_ONEPASS_MULTIROW;
|
|
+ }
|
|
+ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere,0,0,0,flags,iIdxCur);
|
|
+ if( pWInfo==0 ) goto update_cleanup;
|
|
+
|
|
+ /* A one-pass strategy that might update more than one row may not
|
|
+ ** be used if any column of the index used for the scan is being
|
|
+ ** updated. Otherwise, if there is an index on "b", statements like
|
|
+ ** the following could create an infinite loop:
|
|
+ **
|
|
+ ** UPDATE t1 SET b=b+1 WHERE b>?
|
|
+ **
|
|
+ ** Fall back to ONEPASS_OFF if where.c has selected a ONEPASS_MULTI
|
|
+ ** strategy that uses an index for which one or more columns are being
|
|
+ ** updated. */
|
|
+ eOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);
|
|
+ bFinishSeek = sqlite3WhereUsesDeferredSeek(pWInfo);
|
|
+ if( eOnePass!=ONEPASS_SINGLE ){
|
|
+ sqlite3MultiWrite(pParse);
|
|
+ if( eOnePass==ONEPASS_MULTI ){
|
|
+ int iCur = aiCurOnePass[1];
|
|
+ if( iCur>=0 && iCur!=iDataCur && aToOpen[iCur-iBaseCur] ){
|
|
+ eOnePass = ONEPASS_OFF;
|
|
+ }
|
|
+ assert( iCur!=iDataCur || !HasRowid(pTab) );
|
|
}
|
|
- assert( iCur!=iDataCur || !HasRowid(pTab) );
|
|
}
|
|
}
|
|
- }
|
|
|
|
- if( HasRowid(pTab) ){
|
|
- /* Read the rowid of the current row of the WHERE scan. In ONEPASS_OFF
|
|
- ** mode, write the rowid into the FIFO. In either of the one-pass modes,
|
|
- ** leave it in register regOldRowid. */
|
|
- sqlite3VdbeAddOp2(v, OP_Rowid, iDataCur, regOldRowid);
|
|
- if( eOnePass==ONEPASS_OFF ){
|
|
- /* We need to use regRowSet, so reallocate aRegIdx[nAllIdx] */
|
|
- aRegIdx[nAllIdx] = ++pParse->nMem;
|
|
- sqlite3VdbeAddOp2(v, OP_RowSetAdd, regRowSet, regOldRowid);
|
|
- }
|
|
- }else{
|
|
- /* Read the PK of the current row into an array of registers. In
|
|
- ** ONEPASS_OFF mode, serialize the array into a record and store it in
|
|
- ** the ephemeral table. Or, in ONEPASS_SINGLE or MULTI mode, change
|
|
- ** the OP_OpenEphemeral instruction to a Noop (the ephemeral table
|
|
- ** is not required) and leave the PK fields in the array of registers. */
|
|
- for(i=0; i<nPk; i++){
|
|
- assert( pPk->aiColumn[i]>=0 );
|
|
- sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur,
|
|
- pPk->aiColumn[i], iPk+i);
|
|
- }
|
|
- if( eOnePass ){
|
|
- if( addrOpen ) sqlite3VdbeChangeToNoop(v, addrOpen);
|
|
- nKey = nPk;
|
|
- regKey = iPk;
|
|
+ if( HasRowid(pTab) ){
|
|
+ /* Read the rowid of the current row of the WHERE scan. In ONEPASS_OFF
|
|
+ ** mode, write the rowid into the FIFO. In either of the one-pass modes,
|
|
+ ** leave it in register regOldRowid. */
|
|
+ sqlite3VdbeAddOp2(v, OP_Rowid, iDataCur, regOldRowid);
|
|
+ if( eOnePass==ONEPASS_OFF ){
|
|
+ aRegIdx[nAllIdx] = ++pParse->nMem;
|
|
+ sqlite3VdbeAddOp3(v, OP_Insert, iEph, regRowSet, regOldRowid);
|
|
+ }else{
|
|
+ if( ALWAYS(addrOpen) ) sqlite3VdbeChangeToNoop(v, addrOpen);
|
|
+ }
|
|
}else{
|
|
- sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, regKey,
|
|
- sqlite3IndexAffinityStr(db, pPk), nPk);
|
|
- sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iEph, regKey, iPk, nPk);
|
|
+ /* Read the PK of the current row into an array of registers. In
|
|
+ ** ONEPASS_OFF mode, serialize the array into a record and store it in
|
|
+ ** the ephemeral table. Or, in ONEPASS_SINGLE or MULTI mode, change
|
|
+ ** the OP_OpenEphemeral instruction to a Noop (the ephemeral table
|
|
+ ** is not required) and leave the PK fields in the array of registers. */
|
|
+ for(i=0; i<nPk; i++){
|
|
+ assert( pPk->aiColumn[i]>=0 );
|
|
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur,
|
|
+ pPk->aiColumn[i], iPk+i);
|
|
+ }
|
|
+ if( eOnePass ){
|
|
+ if( addrOpen ) sqlite3VdbeChangeToNoop(v, addrOpen);
|
|
+ nKey = nPk;
|
|
+ regKey = iPk;
|
|
+ }else{
|
|
+ sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, regKey,
|
|
+ sqlite3IndexAffinityStr(db, pPk), nPk);
|
|
+ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iEph, regKey, iPk, nPk);
|
|
+ }
|
|
}
|
|
}
|
|
|
|
if( pUpsert==0 ){
|
|
- if( eOnePass!=ONEPASS_MULTI ){
|
|
+ if( nChangeFrom==0 && eOnePass!=ONEPASS_MULTI ){
|
|
sqlite3WhereEnd(pWInfo);
|
|
}
|
|
-
|
|
+
|
|
if( !isView ){
|
|
int addrOnce = 0;
|
|
-
|
|
+
|
|
/* Open every index that needs updating. */
|
|
if( eOnePass!=ONEPASS_OFF ){
|
|
if( aiCurOnePass[0]>=0 ) aToOpen[aiCurOnePass[0]-iBaseCur] = 0;
|
|
if( aiCurOnePass[1]>=0 ) aToOpen[aiCurOnePass[1]-iBaseCur] = 0;
|
|
}
|
|
-
|
|
+
|
|
if( eOnePass==ONEPASS_MULTI && (nIdx-(aiCurOnePass[1]>=0))>0 ){
|
|
addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
|
|
}
|
|
sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, 0, iBaseCur,
|
|
aToOpen, 0, 0);
|
|
- if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce);
|
|
+ if( addrOnce ){
|
|
+ sqlite3VdbeJumpHereOrPopInst(v, addrOnce);
|
|
+ }
|
|
}
|
|
-
|
|
+
|
|
/* Top of the update loop */
|
|
if( eOnePass!=ONEPASS_OFF ){
|
|
- if( !isView && aiCurOnePass[0]!=iDataCur && aiCurOnePass[1]!=iDataCur ){
|
|
+ if( aiCurOnePass[0]!=iDataCur
|
|
+ && aiCurOnePass[1]!=iDataCur
|
|
+#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
|
|
+ && !isView
|
|
+#endif
|
|
+ ){
|
|
assert( pPk );
|
|
sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelBreak, regKey,nKey);
|
|
VdbeCoverage(v);
|
|
@@ -136689,15 +149027,35 @@ SQLITE_PRIVATE void sqlite3Update(
|
|
sqlite3VdbeAddOp2(v, OP_IsNull, pPk ? regKey : regOldRowid, labelBreak);
|
|
VdbeCoverageIf(v, pPk==0);
|
|
VdbeCoverageIf(v, pPk!=0);
|
|
- }else if( pPk ){
|
|
+ }else if( pPk || nChangeFrom ){
|
|
labelContinue = sqlite3VdbeMakeLabel(pParse);
|
|
sqlite3VdbeAddOp2(v, OP_Rewind, iEph, labelBreak); VdbeCoverage(v);
|
|
- addrTop = sqlite3VdbeAddOp2(v, OP_RowData, iEph, regKey);
|
|
- sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelContinue, regKey, 0);
|
|
- VdbeCoverage(v);
|
|
+ addrTop = sqlite3VdbeCurrentAddr(v);
|
|
+ if( nChangeFrom ){
|
|
+ if( !isView ){
|
|
+ if( pPk ){
|
|
+ for(i=0; i<nPk; i++){
|
|
+ sqlite3VdbeAddOp3(v, OP_Column, iEph, i, iPk+i);
|
|
+ }
|
|
+ sqlite3VdbeAddOp4Int(
|
|
+ v, OP_NotFound, iDataCur, labelContinue, iPk, nPk
|
|
+ ); VdbeCoverage(v);
|
|
+ }else{
|
|
+ sqlite3VdbeAddOp2(v, OP_Rowid, iEph, regOldRowid);
|
|
+ sqlite3VdbeAddOp3(
|
|
+ v, OP_NotExists, iDataCur, labelContinue, regOldRowid
|
|
+ ); VdbeCoverage(v);
|
|
+ }
|
|
+ }
|
|
+ }else{
|
|
+ sqlite3VdbeAddOp2(v, OP_RowData, iEph, regKey);
|
|
+ sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelContinue, regKey,0);
|
|
+ VdbeCoverage(v);
|
|
+ }
|
|
}else{
|
|
- labelContinue = sqlite3VdbeAddOp3(v, OP_RowSetRead, regRowSet,labelBreak,
|
|
- regOldRowid);
|
|
+ sqlite3VdbeAddOp2(v, OP_Rewind, iEph, labelBreak); VdbeCoverage(v);
|
|
+ labelContinue = sqlite3VdbeMakeLabel(pParse);
|
|
+ addrTop = sqlite3VdbeAddOp2(v, OP_Rowid, iEph, regOldRowid);
|
|
VdbeCoverage(v);
|
|
sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, labelContinue, regOldRowid);
|
|
VdbeCoverage(v);
|
|
@@ -136710,7 +149068,12 @@ SQLITE_PRIVATE void sqlite3Update(
|
|
** already populated. */
|
|
assert( chngKey || pTrigger || hasFK || regOldRowid==regNewRowid );
|
|
if( chngRowid ){
|
|
- sqlite3ExprCode(pParse, pRowidExpr, regNewRowid);
|
|
+ assert( iRowidExpr>=0 );
|
|
+ if( nChangeFrom==0 ){
|
|
+ sqlite3ExprCode(pParse, pRowidExpr, regNewRowid);
|
|
+ }else{
|
|
+ sqlite3VdbeAddOp3(v, OP_Column, iEph, iRowidExpr, regNewRowid);
|
|
+ }
|
|
sqlite3VdbeAddOp1(v, OP_MustBeInt, regNewRowid); VdbeCoverage(v);
|
|
}
|
|
|
|
@@ -136718,7 +149081,7 @@ SQLITE_PRIVATE void sqlite3Update(
|
|
** information is needed */
|
|
if( chngPk || hasFK || pTrigger ){
|
|
u32 oldmask = (hasFK ? sqlite3FkOldmask(pParse, pTab) : 0);
|
|
- oldmask |= sqlite3TriggerColmask(pParse,
|
|
+ oldmask |= sqlite3TriggerColmask(pParse,
|
|
pTrigger, pChanges, 0, TRIGGER_BEFORE|TRIGGER_AFTER, pTab, onError
|
|
);
|
|
for(i=0; i<pTab->nCol; i++){
|
|
@@ -136747,8 +149110,8 @@ SQLITE_PRIVATE void sqlite3Update(
|
|
** If there are one or more BEFORE triggers, then do not populate the
|
|
** registers associated with columns that are (a) not modified by
|
|
** this UPDATE statement and (b) not accessed by new.* references. The
|
|
- ** values for registers not modified by the UPDATE must be reloaded from
|
|
- ** the database after the BEFORE triggers are fired anyway (as the trigger
|
|
+ ** values for registers not modified by the UPDATE must be reloaded from
|
|
+ ** the database after the BEFORE triggers are fired anyway (as the trigger
|
|
** may have modified them). So not loading those that are not going to
|
|
** be used eliminates some redundant opcodes.
|
|
*/
|
|
@@ -136763,9 +149126,15 @@ SQLITE_PRIVATE void sqlite3Update(
|
|
}else{
|
|
j = aXRef[i];
|
|
if( j>=0 ){
|
|
- sqlite3ExprCode(pParse, pChanges->a[j].pExpr, k);
|
|
+ if( nChangeFrom ){
|
|
+ int nOff = (isView ? pTab->nCol : nPk);
|
|
+ assert( eOnePass==ONEPASS_OFF );
|
|
+ sqlite3VdbeAddOp3(v, OP_Column, iEph, nOff+j, k);
|
|
+ }else{
|
|
+ sqlite3ExprCode(pParse, pChanges->a[j].pExpr, k);
|
|
+ }
|
|
}else if( 0==(tmask&TRIGGER_BEFORE) || i>31 || (newmask & MASKBIT32(i)) ){
|
|
- /* This branch loads the value of a column that will not be changed
|
|
+ /* This branch loads the value of a column that will not be changed
|
|
** into a register. This is done if there are no BEFORE triggers, or
|
|
** if there are one or more BEFORE triggers that use this value via
|
|
** a new.* reference in a trigger program.
|
|
@@ -136792,46 +149161,48 @@ SQLITE_PRIVATE void sqlite3Update(
|
|
*/
|
|
if( tmask&TRIGGER_BEFORE ){
|
|
sqlite3TableAffinity(v, pTab, regNew);
|
|
- sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges,
|
|
+ sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges,
|
|
TRIGGER_BEFORE, pTab, regOldRowid, onError, labelContinue);
|
|
|
|
- /* The row-trigger may have deleted the row being updated. In this
|
|
- ** case, jump to the next row. No updates or AFTER triggers are
|
|
- ** required. This behavior - what happens when the row being updated
|
|
- ** is deleted or renamed by a BEFORE trigger - is left undefined in the
|
|
- ** documentation.
|
|
- */
|
|
- if( pPk ){
|
|
- sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelContinue,regKey,nKey);
|
|
- VdbeCoverage(v);
|
|
- }else{
|
|
- sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, labelContinue, regOldRowid);
|
|
- VdbeCoverage(v);
|
|
- }
|
|
+ if( !isView ){
|
|
+ /* The row-trigger may have deleted the row being updated. In this
|
|
+ ** case, jump to the next row. No updates or AFTER triggers are
|
|
+ ** required. This behavior - what happens when the row being updated
|
|
+ ** is deleted or renamed by a BEFORE trigger - is left undefined in the
|
|
+ ** documentation.
|
|
+ */
|
|
+ if( pPk ){
|
|
+ sqlite3VdbeAddOp4Int(v, OP_NotFound,iDataCur,labelContinue,regKey,nKey);
|
|
+ VdbeCoverage(v);
|
|
+ }else{
|
|
+ sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, labelContinue,regOldRowid);
|
|
+ VdbeCoverage(v);
|
|
+ }
|
|
|
|
- /* After-BEFORE-trigger-reload-loop:
|
|
- ** If it did not delete it, the BEFORE trigger may still have modified
|
|
- ** some of the columns of the row being updated. Load the values for
|
|
- ** all columns not modified by the update statement into their registers
|
|
- ** in case this has happened. Only unmodified columns are reloaded.
|
|
- ** The values computed for modified columns use the values before the
|
|
- ** BEFORE trigger runs. See test case trigger1-18.0 (added 2018-04-26)
|
|
- ** for an example.
|
|
- */
|
|
- for(i=0, k=regNew; i<pTab->nCol; i++, k++){
|
|
- if( pTab->aCol[i].colFlags & COLFLAG_GENERATED ){
|
|
- if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ) k--;
|
|
- }else if( aXRef[i]<0 && i!=pTab->iPKey ){
|
|
- sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, k);
|
|
+ /* After-BEFORE-trigger-reload-loop:
|
|
+ ** If it did not delete it, the BEFORE trigger may still have modified
|
|
+ ** some of the columns of the row being updated. Load the values for
|
|
+ ** all columns not modified by the update statement into their registers
|
|
+ ** in case this has happened. Only unmodified columns are reloaded.
|
|
+ ** The values computed for modified columns use the values before the
|
|
+ ** BEFORE trigger runs. See test case trigger1-18.0 (added 2018-04-26)
|
|
+ ** for an example.
|
|
+ */
|
|
+ for(i=0, k=regNew; i<pTab->nCol; i++, k++){
|
|
+ if( pTab->aCol[i].colFlags & COLFLAG_GENERATED ){
|
|
+ if( pTab->aCol[i].colFlags & COLFLAG_VIRTUAL ) k--;
|
|
+ }else if( aXRef[i]<0 && i!=pTab->iPKey ){
|
|
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, i, k);
|
|
+ }
|
|
}
|
|
- }
|
|
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
|
|
- if( pTab->tabFlags & TF_HasGenerated ){
|
|
- testcase( pTab->tabFlags & TF_HasVirtual );
|
|
- testcase( pTab->tabFlags & TF_HasStored );
|
|
- sqlite3ComputeGeneratedColumns(pParse, regNew, pTab);
|
|
+ if( pTab->tabFlags & TF_HasGenerated ){
|
|
+ testcase( pTab->tabFlags & TF_HasVirtual );
|
|
+ testcase( pTab->tabFlags & TF_HasStored );
|
|
+ sqlite3ComputeGeneratedColumns(pParse, regNew, pTab);
|
|
+ }
|
|
+#endif
|
|
}
|
|
-#endif
|
|
}
|
|
|
|
if( !isView ){
|
|
@@ -136850,7 +149221,7 @@ SQLITE_PRIVATE void sqlite3Update(
|
|
}else{
|
|
sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, labelContinue,regOldRowid);
|
|
}
|
|
- VdbeCoverageNeverTaken(v);
|
|
+ VdbeCoverage(v);
|
|
}
|
|
|
|
/* Do FK constraint checks. */
|
|
@@ -136874,7 +149245,7 @@ SQLITE_PRIVATE void sqlite3Update(
|
|
** to process, delete the old record. Otherwise, add a noop OP_Delete
|
|
** to invoke the pre-update hook.
|
|
**
|
|
- ** That (regNew==regnewRowid+1) is true is also important for the
|
|
+ ** That (regNew==regnewRowid+1) is true is also important for the
|
|
** pre-update hook. If the caller invokes preupdate_new(), the returned
|
|
** value is copied from memory cell (regNewRowid+1+iCol), where iCol
|
|
** is the column index supplied by the user.
|
|
@@ -136901,29 +149272,29 @@ SQLITE_PRIVATE void sqlite3Update(
|
|
if( hasFK ){
|
|
sqlite3FkCheck(pParse, pTab, 0, regNewRowid, aXRef, chngKey);
|
|
}
|
|
-
|
|
+
|
|
/* Insert the new index entries and the new record. */
|
|
sqlite3CompleteInsertion(
|
|
- pParse, pTab, iDataCur, iIdxCur, regNewRowid, aRegIdx,
|
|
- OPFLAG_ISUPDATE | (eOnePass==ONEPASS_MULTI ? OPFLAG_SAVEPOSITION : 0),
|
|
+ pParse, pTab, iDataCur, iIdxCur, regNewRowid, aRegIdx,
|
|
+ OPFLAG_ISUPDATE | (eOnePass==ONEPASS_MULTI ? OPFLAG_SAVEPOSITION : 0),
|
|
0, 0
|
|
);
|
|
|
|
/* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to
|
|
** handle rows (possibly in other tables) that refer via a foreign key
|
|
- ** to the row just updated. */
|
|
+ ** to the row just updated. */
|
|
if( hasFK ){
|
|
sqlite3FkActions(pParse, pTab, pChanges, regOldRowid, aXRef, chngKey);
|
|
}
|
|
}
|
|
|
|
- /* Increment the row counter
|
|
+ /* Increment the row counter
|
|
*/
|
|
if( regRowCount ){
|
|
sqlite3VdbeAddOp2(v, OP_AddImm, regRowCount, 1);
|
|
}
|
|
|
|
- sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges,
|
|
+ sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges,
|
|
TRIGGER_AFTER, pTab, regOldRowid, onError, labelContinue);
|
|
|
|
/* Repeat the above with the next record to be updated, until
|
|
@@ -136934,11 +149305,9 @@ SQLITE_PRIVATE void sqlite3Update(
|
|
}else if( eOnePass==ONEPASS_MULTI ){
|
|
sqlite3VdbeResolveLabel(v, labelContinue);
|
|
sqlite3WhereEnd(pWInfo);
|
|
- }else if( pPk ){
|
|
+ }else{
|
|
sqlite3VdbeResolveLabel(v, labelContinue);
|
|
sqlite3VdbeAddOp2(v, OP_Next, iEph, addrTop); VdbeCoverage(v);
|
|
- }else{
|
|
- sqlite3VdbeGoto(v, labelContinue);
|
|
}
|
|
sqlite3VdbeResolveLabel(v, labelBreak);
|
|
|
|
@@ -136955,9 +149324,7 @@ SQLITE_PRIVATE void sqlite3Update(
|
|
** that information.
|
|
*/
|
|
if( regRowCount ){
|
|
- sqlite3VdbeAddOp2(v, OP_ResultRow, regRowCount, 1);
|
|
- sqlite3VdbeSetNumCols(v, 1);
|
|
- sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows updated", SQLITE_STATIC);
|
|
+ sqlite3CodeChangeCount(v, regRowCount, "rows updated");
|
|
}
|
|
|
|
update_cleanup:
|
|
@@ -136966,7 +149333,7 @@ SQLITE_PRIVATE void sqlite3Update(
|
|
sqlite3SrcListDelete(db, pTabList);
|
|
sqlite3ExprListDelete(db, pChanges);
|
|
sqlite3ExprDelete(db, pWhere);
|
|
-#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT)
|
|
+#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT)
|
|
sqlite3ExprListDelete(db, pOrderBy);
|
|
sqlite3ExprDelete(db, pLimit);
|
|
#endif
|
|
@@ -136986,8 +149353,8 @@ SQLITE_PRIVATE void sqlite3Update(
|
|
/*
|
|
** Generate code for an UPDATE of a virtual table.
|
|
**
|
|
-** There are two possible strategies - the default and the special
|
|
-** "onepass" strategy. Onepass is only used if the virtual table
|
|
+** There are two possible strategies - the default and the special
|
|
+** "onepass" strategy. Onepass is only used if the virtual table
|
|
** implementation indicates that pWhere may match at most one row.
|
|
**
|
|
** The default strategy is to create an ephemeral table that contains
|
|
@@ -137019,7 +149386,7 @@ static void updateVirtualTable(
|
|
int i; /* Loop counter */
|
|
sqlite3 *db = pParse->db; /* Database connection */
|
|
const char *pVTab = (const char*)sqlite3GetVTable(db, pTab);
|
|
- WhereInfo *pWInfo;
|
|
+ WhereInfo *pWInfo = 0;
|
|
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 */
|
|
@@ -137037,74 +149404,117 @@ static void updateVirtualTable(
|
|
addr= sqlite3VdbeAddOp2(v, OP_OpenEphemeral, ephemTab, nArg);
|
|
regArg = pParse->nMem + 1;
|
|
pParse->nMem += nArg;
|
|
- regRec = ++pParse->nMem;
|
|
- regRowid = ++pParse->nMem;
|
|
+ if( pSrc->nSrc>1 ){
|
|
+ Index *pPk = 0;
|
|
+ Expr *pRow;
|
|
+ ExprList *pList;
|
|
+ if( HasRowid(pTab) ){
|
|
+ if( pRowid ){
|
|
+ pRow = sqlite3ExprDup(db, pRowid, 0);
|
|
+ }else{
|
|
+ pRow = sqlite3PExpr(pParse, TK_ROW, 0, 0);
|
|
+ }
|
|
+ }else{
|
|
+ i16 iPk; /* PRIMARY KEY column */
|
|
+ pPk = sqlite3PrimaryKeyIndex(pTab);
|
|
+ assert( pPk!=0 );
|
|
+ assert( pPk->nKeyCol==1 );
|
|
+ iPk = pPk->aiColumn[0];
|
|
+ if( aXRef[iPk]>=0 ){
|
|
+ pRow = sqlite3ExprDup(db, pChanges->a[aXRef[iPk]].pExpr, 0);
|
|
+ }else{
|
|
+ pRow = exprRowColumn(pParse, iPk);
|
|
+ }
|
|
+ }
|
|
+ pList = sqlite3ExprListAppend(pParse, 0, pRow);
|
|
|
|
- /* Start scanning the virtual table */
|
|
- pWInfo = sqlite3WhereBegin(pParse, pSrc, pWhere, 0,0,WHERE_ONEPASS_DESIRED,0);
|
|
- if( pWInfo==0 ) return;
|
|
+ for(i=0; i<pTab->nCol; i++){
|
|
+ if( aXRef[i]>=0 ){
|
|
+ pList = sqlite3ExprListAppend(pParse, pList,
|
|
+ sqlite3ExprDup(db, pChanges->a[aXRef[i]].pExpr, 0)
|
|
+ );
|
|
+ }else{
|
|
+ pList = sqlite3ExprListAppend(pParse, pList, exprRowColumn(pParse, i));
|
|
+ }
|
|
+ }
|
|
|
|
- /* Populate the argument registers. */
|
|
- for(i=0; i<pTab->nCol; i++){
|
|
- assert( (pTab->aCol[i].colFlags & COLFLAG_GENERATED)==0 );
|
|
- if( aXRef[i]>=0 ){
|
|
- sqlite3ExprCode(pParse, pChanges->a[aXRef[i]].pExpr, regArg+2+i);
|
|
- }else{
|
|
- sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, i, regArg+2+i);
|
|
- sqlite3VdbeChangeP5(v, OPFLAG_NOCHNG);/* Enable sqlite3_vtab_nochange() */
|
|
+ updateFromSelect(pParse, ephemTab, pPk, pList, pSrc, pWhere, 0, 0);
|
|
+ sqlite3ExprListDelete(db, pList);
|
|
+ eOnePass = ONEPASS_OFF;
|
|
+ }else{
|
|
+ regRec = ++pParse->nMem;
|
|
+ regRowid = ++pParse->nMem;
|
|
+
|
|
+ /* Start scanning the virtual table */
|
|
+ pWInfo = sqlite3WhereBegin(
|
|
+ pParse, pSrc, pWhere, 0, 0, 0, WHERE_ONEPASS_DESIRED, 0
|
|
+ );
|
|
+ if( pWInfo==0 ) return;
|
|
+
|
|
+ /* Populate the argument registers. */
|
|
+ for(i=0; i<pTab->nCol; i++){
|
|
+ assert( (pTab->aCol[i].colFlags & COLFLAG_GENERATED)==0 );
|
|
+ if( aXRef[i]>=0 ){
|
|
+ sqlite3ExprCode(pParse, pChanges->a[aXRef[i]].pExpr, regArg+2+i);
|
|
+ }else{
|
|
+ sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, i, regArg+2+i);
|
|
+ sqlite3VdbeChangeP5(v, OPFLAG_NOCHNG);/* For sqlite3_vtab_nochange() */
|
|
+ }
|
|
}
|
|
- }
|
|
- if( HasRowid(pTab) ){
|
|
- sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg);
|
|
- if( pRowid ){
|
|
- sqlite3ExprCode(pParse, pRowid, regArg+1);
|
|
+ if( HasRowid(pTab) ){
|
|
+ sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg);
|
|
+ if( pRowid ){
|
|
+ sqlite3ExprCode(pParse, pRowid, regArg+1);
|
|
+ }else{
|
|
+ sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg+1);
|
|
+ }
|
|
}else{
|
|
- sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg+1);
|
|
+ Index *pPk; /* PRIMARY KEY index */
|
|
+ i16 iPk; /* PRIMARY KEY column */
|
|
+ pPk = sqlite3PrimaryKeyIndex(pTab);
|
|
+ assert( pPk!=0 );
|
|
+ assert( pPk->nKeyCol==1 );
|
|
+ iPk = pPk->aiColumn[0];
|
|
+ sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, iPk, regArg);
|
|
+ sqlite3VdbeAddOp2(v, OP_SCopy, regArg+2+iPk, regArg+1);
|
|
}
|
|
- }else{
|
|
- Index *pPk; /* PRIMARY KEY index */
|
|
- i16 iPk; /* PRIMARY KEY column */
|
|
- pPk = sqlite3PrimaryKeyIndex(pTab);
|
|
- assert( pPk!=0 );
|
|
- assert( pPk->nKeyCol==1 );
|
|
- iPk = pPk->aiColumn[0];
|
|
- sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, iPk, regArg);
|
|
- sqlite3VdbeAddOp2(v, OP_SCopy, regArg+2+iPk, regArg+1);
|
|
- }
|
|
|
|
- eOnePass = sqlite3WhereOkOnePass(pWInfo, aDummy);
|
|
+ eOnePass = sqlite3WhereOkOnePass(pWInfo, aDummy);
|
|
|
|
- /* There is no ONEPASS_MULTI on virtual tables */
|
|
- assert( eOnePass==ONEPASS_OFF || eOnePass==ONEPASS_SINGLE );
|
|
+ /* There is no ONEPASS_MULTI on virtual tables */
|
|
+ assert( eOnePass==ONEPASS_OFF || eOnePass==ONEPASS_SINGLE );
|
|
|
|
- if( eOnePass ){
|
|
- /* If using the onepass strategy, no-op out the OP_OpenEphemeral coded
|
|
- ** above. */
|
|
- sqlite3VdbeChangeToNoop(v, addr);
|
|
- sqlite3VdbeAddOp1(v, OP_Close, iCsr);
|
|
- }else{
|
|
- /* Create a record from the argument register contents and insert it into
|
|
- ** the ephemeral table. */
|
|
- sqlite3MultiWrite(pParse);
|
|
- sqlite3VdbeAddOp3(v, OP_MakeRecord, regArg, nArg, regRec);
|
|
-#ifdef SQLITE_DEBUG
|
|
- /* Signal an assert() within OP_MakeRecord that it is allowed to
|
|
- ** accept no-change records with serial_type 10 */
|
|
- sqlite3VdbeChangeP5(v, OPFLAG_NOCHNG_MAGIC);
|
|
+ if( eOnePass ){
|
|
+ /* If using the onepass strategy, no-op out the OP_OpenEphemeral coded
|
|
+ ** above. */
|
|
+ sqlite3VdbeChangeToNoop(v, addr);
|
|
+ sqlite3VdbeAddOp1(v, OP_Close, iCsr);
|
|
+ }else{
|
|
+ /* Create a record from the argument register contents and insert it into
|
|
+ ** the ephemeral table. */
|
|
+ sqlite3MultiWrite(pParse);
|
|
+ sqlite3VdbeAddOp3(v, OP_MakeRecord, regArg, nArg, regRec);
|
|
+#if defined(SQLITE_DEBUG) && !defined(SQLITE_ENABLE_NULL_TRIM)
|
|
+ /* Signal an assert() within OP_MakeRecord that it is allowed to
|
|
+ ** accept no-change records with serial_type 10 */
|
|
+ sqlite3VdbeChangeP5(v, OPFLAG_NOCHNG_MAGIC);
|
|
#endif
|
|
- sqlite3VdbeAddOp2(v, OP_NewRowid, ephemTab, regRowid);
|
|
- sqlite3VdbeAddOp3(v, OP_Insert, ephemTab, regRec, regRowid);
|
|
+ sqlite3VdbeAddOp2(v, OP_NewRowid, ephemTab, regRowid);
|
|
+ sqlite3VdbeAddOp3(v, OP_Insert, ephemTab, regRec, regRowid);
|
|
+ }
|
|
}
|
|
|
|
|
|
if( eOnePass==ONEPASS_OFF ){
|
|
/* End the virtual table scan */
|
|
- sqlite3WhereEnd(pWInfo);
|
|
+ if( pSrc->nSrc==1 ){
|
|
+ sqlite3WhereEnd(pWInfo);
|
|
+ }
|
|
|
|
/* Begin scannning through the ephemeral table. */
|
|
addr = sqlite3VdbeAddOp1(v, OP_Rewind, ephemTab); VdbeCoverage(v);
|
|
|
|
- /* Extract arguments from the current row of the ephemeral table and
|
|
+ /* Extract arguments from the current row of the ephemeral table and
|
|
** invoke the VUpdate method. */
|
|
for(i=0; i<nArg; i++){
|
|
sqlite3VdbeAddOp3(v, OP_Column, ephemTab, i, regArg+i);
|
|
@@ -137149,16 +149559,23 @@ static void updateVirtualTable(
|
|
/*
|
|
** Free a list of Upsert objects
|
|
*/
|
|
-SQLITE_PRIVATE void sqlite3UpsertDelete(sqlite3 *db, Upsert *p){
|
|
- if( p ){
|
|
+static void SQLITE_NOINLINE upsertDelete(sqlite3 *db, Upsert *p){
|
|
+ do{
|
|
+ Upsert *pNext = p->pNextUpsert;
|
|
sqlite3ExprListDelete(db, p->pUpsertTarget);
|
|
sqlite3ExprDelete(db, p->pUpsertTargetWhere);
|
|
sqlite3ExprListDelete(db, p->pUpsertSet);
|
|
sqlite3ExprDelete(db, p->pUpsertWhere);
|
|
+ sqlite3DbFree(db, p->pToFree);
|
|
sqlite3DbFree(db, p);
|
|
- }
|
|
+ p = pNext;
|
|
+ }while( p );
|
|
+}
|
|
+SQLITE_PRIVATE void sqlite3UpsertDelete(sqlite3 *db, Upsert *p){
|
|
+ if( p ) upsertDelete(db, p);
|
|
}
|
|
|
|
+
|
|
/*
|
|
** Duplicate an Upsert object.
|
|
*/
|
|
@@ -137168,7 +149585,8 @@ SQLITE_PRIVATE Upsert *sqlite3UpsertDup(sqlite3 *db, Upsert *p){
|
|
sqlite3ExprListDup(db, p->pUpsertTarget, 0),
|
|
sqlite3ExprDup(db, p->pUpsertTargetWhere, 0),
|
|
sqlite3ExprListDup(db, p->pUpsertSet, 0),
|
|
- sqlite3ExprDup(db, p->pUpsertWhere, 0)
|
|
+ sqlite3ExprDup(db, p->pUpsertWhere, 0),
|
|
+ sqlite3UpsertDup(db, p->pNextUpsert)
|
|
);
|
|
}
|
|
|
|
@@ -137180,22 +149598,25 @@ SQLITE_PRIVATE Upsert *sqlite3UpsertNew(
|
|
ExprList *pTarget, /* Target argument to ON CONFLICT, or NULL */
|
|
Expr *pTargetWhere, /* Optional WHERE clause on the target */
|
|
ExprList *pSet, /* UPDATE columns, or NULL for a DO NOTHING */
|
|
- Expr *pWhere /* WHERE clause for the ON CONFLICT UPDATE */
|
|
+ Expr *pWhere, /* WHERE clause for the ON CONFLICT UPDATE */
|
|
+ Upsert *pNext /* Next ON CONFLICT clause in the list */
|
|
){
|
|
Upsert *pNew;
|
|
- pNew = sqlite3DbMallocRaw(db, sizeof(Upsert));
|
|
+ pNew = sqlite3DbMallocZero(db, sizeof(Upsert));
|
|
if( pNew==0 ){
|
|
sqlite3ExprListDelete(db, pTarget);
|
|
sqlite3ExprDelete(db, pTargetWhere);
|
|
sqlite3ExprListDelete(db, pSet);
|
|
sqlite3ExprDelete(db, pWhere);
|
|
+ sqlite3UpsertDelete(db, pNext);
|
|
return 0;
|
|
}else{
|
|
pNew->pUpsertTarget = pTarget;
|
|
pNew->pUpsertTargetWhere = pTargetWhere;
|
|
pNew->pUpsertSet = pSet;
|
|
pNew->pUpsertWhere = pWhere;
|
|
- pNew->pUpsertIdx = 0;
|
|
+ pNew->isDoUpdate = pSet!=0;
|
|
+ pNew->pNextUpsert = pNext;
|
|
}
|
|
return pNew;
|
|
}
|
|
@@ -137220,6 +149641,7 @@ SQLITE_PRIVATE int sqlite3UpsertAnalyzeTarget(
|
|
Expr *pTerm; /* One term of the conflict-target clause */
|
|
NameContext sNC; /* Context for resolving symbolic names */
|
|
Expr sCol[2]; /* Index column converted into an Expr */
|
|
+ int nClause = 0; /* Counter of ON CONFLICT clauses */
|
|
|
|
assert( pTabList->nSrc==1 );
|
|
assert( pTabList->a[0].pTab!=0 );
|
|
@@ -137233,87 +149655,132 @@ SQLITE_PRIVATE int sqlite3UpsertAnalyzeTarget(
|
|
memset(&sNC, 0, sizeof(sNC));
|
|
sNC.pParse = pParse;
|
|
sNC.pSrcList = pTabList;
|
|
- rc = sqlite3ResolveExprListNames(&sNC, pUpsert->pUpsertTarget);
|
|
- if( rc ) return rc;
|
|
- rc = sqlite3ResolveExprNames(&sNC, pUpsert->pUpsertTargetWhere);
|
|
- if( rc ) return rc;
|
|
+ for(; pUpsert && pUpsert->pUpsertTarget;
|
|
+ pUpsert=pUpsert->pNextUpsert, nClause++){
|
|
+ rc = sqlite3ResolveExprListNames(&sNC, pUpsert->pUpsertTarget);
|
|
+ if( rc ) return rc;
|
|
+ rc = sqlite3ResolveExprNames(&sNC, pUpsert->pUpsertTargetWhere);
|
|
+ if( rc ) return rc;
|
|
|
|
- /* Check to see if the conflict target matches the rowid. */
|
|
- pTab = pTabList->a[0].pTab;
|
|
- pTarget = pUpsert->pUpsertTarget;
|
|
- iCursor = pTabList->a[0].iCursor;
|
|
- if( HasRowid(pTab)
|
|
- && pTarget->nExpr==1
|
|
- && (pTerm = pTarget->a[0].pExpr)->op==TK_COLUMN
|
|
- && pTerm->iColumn==XN_ROWID
|
|
- ){
|
|
- /* The conflict-target is the rowid of the primary table */
|
|
- assert( pUpsert->pUpsertIdx==0 );
|
|
- return SQLITE_OK;
|
|
- }
|
|
+ /* Check to see if the conflict target matches the rowid. */
|
|
+ pTab = pTabList->a[0].pTab;
|
|
+ pTarget = pUpsert->pUpsertTarget;
|
|
+ iCursor = pTabList->a[0].iCursor;
|
|
+ if( HasRowid(pTab)
|
|
+ && pTarget->nExpr==1
|
|
+ && (pTerm = pTarget->a[0].pExpr)->op==TK_COLUMN
|
|
+ && pTerm->iColumn==XN_ROWID
|
|
+ ){
|
|
+ /* The conflict-target is the rowid of the primary table */
|
|
+ assert( pUpsert->pUpsertIdx==0 );
|
|
+ continue;
|
|
+ }
|
|
|
|
- /* Initialize sCol[0..1] to be an expression parse tree for a
|
|
- ** single column of an index. The sCol[0] node will be the TK_COLLATE
|
|
- ** operator and sCol[1] will be the TK_COLUMN operator. Code below
|
|
- ** will populate the specific collation and column number values
|
|
- ** prior to comparing against the conflict-target expression.
|
|
- */
|
|
- memset(sCol, 0, sizeof(sCol));
|
|
- sCol[0].op = TK_COLLATE;
|
|
- sCol[0].pLeft = &sCol[1];
|
|
- sCol[1].op = TK_COLUMN;
|
|
- sCol[1].iTable = pTabList->a[0].iCursor;
|
|
+ /* Initialize sCol[0..1] to be an expression parse tree for a
|
|
+ ** single column of an index. The sCol[0] node will be the TK_COLLATE
|
|
+ ** operator and sCol[1] will be the TK_COLUMN operator. Code below
|
|
+ ** will populate the specific collation and column number values
|
|
+ ** prior to comparing against the conflict-target expression.
|
|
+ */
|
|
+ memset(sCol, 0, sizeof(sCol));
|
|
+ sCol[0].op = TK_COLLATE;
|
|
+ sCol[0].pLeft = &sCol[1];
|
|
+ sCol[1].op = TK_COLUMN;
|
|
+ sCol[1].iTable = pTabList->a[0].iCursor;
|
|
|
|
- /* Check for matches against other indexes */
|
|
- for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
|
- int ii, jj, nn;
|
|
- if( !IsUniqueIndex(pIdx) ) continue;
|
|
- if( pTarget->nExpr!=pIdx->nKeyCol ) continue;
|
|
- if( pIdx->pPartIdxWhere ){
|
|
- if( pUpsert->pUpsertTargetWhere==0 ) continue;
|
|
- if( sqlite3ExprCompare(pParse, pUpsert->pUpsertTargetWhere,
|
|
- pIdx->pPartIdxWhere, iCursor)!=0 ){
|
|
- continue;
|
|
+ /* Check for matches against other indexes */
|
|
+ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
|
+ int ii, jj, nn;
|
|
+ if( !IsUniqueIndex(pIdx) ) continue;
|
|
+ if( pTarget->nExpr!=pIdx->nKeyCol ) continue;
|
|
+ if( pIdx->pPartIdxWhere ){
|
|
+ if( pUpsert->pUpsertTargetWhere==0 ) continue;
|
|
+ if( sqlite3ExprCompare(pParse, pUpsert->pUpsertTargetWhere,
|
|
+ pIdx->pPartIdxWhere, iCursor)!=0 ){
|
|
+ continue;
|
|
+ }
|
|
}
|
|
- }
|
|
- nn = pIdx->nKeyCol;
|
|
- for(ii=0; ii<nn; ii++){
|
|
- Expr *pExpr;
|
|
- sCol[0].u.zToken = (char*)pIdx->azColl[ii];
|
|
- if( pIdx->aiColumn[ii]==XN_EXPR ){
|
|
- assert( pIdx->aColExpr!=0 );
|
|
- assert( pIdx->aColExpr->nExpr>ii );
|
|
- pExpr = pIdx->aColExpr->a[ii].pExpr;
|
|
- if( pExpr->op!=TK_COLLATE ){
|
|
- sCol[0].pLeft = pExpr;
|
|
+ nn = pIdx->nKeyCol;
|
|
+ for(ii=0; ii<nn; ii++){
|
|
+ Expr *pExpr;
|
|
+ sCol[0].u.zToken = (char*)pIdx->azColl[ii];
|
|
+ if( pIdx->aiColumn[ii]==XN_EXPR ){
|
|
+ assert( pIdx->aColExpr!=0 );
|
|
+ assert( pIdx->aColExpr->nExpr>ii );
|
|
+ assert( pIdx->bHasExpr );
|
|
+ pExpr = pIdx->aColExpr->a[ii].pExpr;
|
|
+ if( pExpr->op!=TK_COLLATE ){
|
|
+ sCol[0].pLeft = pExpr;
|
|
+ pExpr = &sCol[0];
|
|
+ }
|
|
+ }else{
|
|
+ sCol[0].pLeft = &sCol[1];
|
|
+ sCol[1].iColumn = pIdx->aiColumn[ii];
|
|
pExpr = &sCol[0];
|
|
}
|
|
- }else{
|
|
- sCol[0].pLeft = &sCol[1];
|
|
- sCol[1].iColumn = pIdx->aiColumn[ii];
|
|
- pExpr = &sCol[0];
|
|
- }
|
|
- for(jj=0; jj<nn; jj++){
|
|
- if( sqlite3ExprCompare(pParse, pTarget->a[jj].pExpr, pExpr,iCursor)<2 ){
|
|
- break; /* Column ii of the index matches column jj of target */
|
|
+ for(jj=0; jj<nn; jj++){
|
|
+ if( sqlite3ExprCompare(pParse,pTarget->a[jj].pExpr,pExpr,iCursor)<2 ){
|
|
+ break; /* Column ii of the index matches column jj of target */
|
|
+ }
|
|
+ }
|
|
+ if( jj>=nn ){
|
|
+ /* The target contains no match for column jj of the index */
|
|
+ break;
|
|
}
|
|
}
|
|
- if( jj>=nn ){
|
|
- /* The target contains no match for column jj of the index */
|
|
- break;
|
|
+ if( ii<nn ){
|
|
+ /* Column ii of the index did not match any term of the conflict target.
|
|
+ ** Continue the search with the next index. */
|
|
+ continue;
|
|
}
|
|
+ pUpsert->pUpsertIdx = pIdx;
|
|
+ break;
|
|
}
|
|
- if( ii<nn ){
|
|
- /* Column ii of the index did not match any term of the conflict target.
|
|
- ** Continue the search with the next index. */
|
|
- continue;
|
|
+ if( pUpsert->pUpsertIdx==0 ){
|
|
+ char zWhich[16];
|
|
+ if( nClause==0 && pUpsert->pNextUpsert==0 ){
|
|
+ zWhich[0] = 0;
|
|
+ }else{
|
|
+ sqlite3_snprintf(sizeof(zWhich),zWhich,"%r ", nClause+1);
|
|
+ }
|
|
+ sqlite3ErrorMsg(pParse, "%sON CONFLICT clause does not match any "
|
|
+ "PRIMARY KEY or UNIQUE constraint", zWhich);
|
|
+ return SQLITE_ERROR;
|
|
}
|
|
- pUpsert->pUpsertIdx = pIdx;
|
|
- return SQLITE_OK;
|
|
}
|
|
- sqlite3ErrorMsg(pParse, "ON CONFLICT clause does not match any "
|
|
- "PRIMARY KEY or UNIQUE constraint");
|
|
- return SQLITE_ERROR;
|
|
+ return SQLITE_OK;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Return true if pUpsert is the last ON CONFLICT clause with a
|
|
+** conflict target, or if pUpsert is followed by another ON CONFLICT
|
|
+** clause that targets the INTEGER PRIMARY KEY.
|
|
+*/
|
|
+SQLITE_PRIVATE int sqlite3UpsertNextIsIPK(Upsert *pUpsert){
|
|
+ Upsert *pNext;
|
|
+ if( NEVER(pUpsert==0) ) return 0;
|
|
+ pNext = pUpsert->pNextUpsert;
|
|
+ if( pNext==0 ) return 1;
|
|
+ if( pNext->pUpsertTarget==0 ) return 1;
|
|
+ if( pNext->pUpsertIdx==0 ) return 1;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Given the list of ON CONFLICT clauses described by pUpsert, and
|
|
+** a particular index pIdx, return a pointer to the particular ON CONFLICT
|
|
+** clause that applies to the index. Or, if the index is not subject to
|
|
+** any ON CONFLICT clause, return NULL.
|
|
+*/
|
|
+SQLITE_PRIVATE Upsert *sqlite3UpsertOfIndex(Upsert *pUpsert, Index *pIdx){
|
|
+ while(
|
|
+ pUpsert
|
|
+ && pUpsert->pUpsertTarget!=0
|
|
+ && pUpsert->pUpsertIdx!=pIdx
|
|
+ ){
|
|
+ pUpsert = pUpsert->pNextUpsert;
|
|
+ }
|
|
+ return pUpsert;
|
|
}
|
|
|
|
/*
|
|
@@ -137337,11 +149804,13 @@ SQLITE_PRIVATE void sqlite3UpsertDoUpdate(
|
|
SrcList *pSrc; /* FROM clause for the UPDATE */
|
|
int iDataCur;
|
|
int i;
|
|
+ Upsert *pTop = pUpsert;
|
|
|
|
assert( v!=0 );
|
|
assert( pUpsert!=0 );
|
|
- VdbeNoopComment((v, "Begin DO UPDATE of UPSERT"));
|
|
iDataCur = pUpsert->iDataCur;
|
|
+ pUpsert = sqlite3UpsertOfIndex(pTop, pIdx);
|
|
+ VdbeNoopComment((v, "Begin DO UPDATE of UPSERT"));
|
|
if( pIdx && iCur!=iDataCur ){
|
|
if( HasRowid(pTab) ){
|
|
int regRowid = sqlite3GetTempReg(pParse);
|
|
@@ -137360,30 +149829,28 @@ SQLITE_PRIVATE void sqlite3UpsertDoUpdate(
|
|
k = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[i]);
|
|
sqlite3VdbeAddOp3(v, OP_Column, iCur, k, iPk+i);
|
|
VdbeComment((v, "%s.%s", pIdx->zName,
|
|
- pTab->aCol[pPk->aiColumn[i]].zName));
|
|
+ pTab->aCol[pPk->aiColumn[i]].zCnName));
|
|
}
|
|
sqlite3VdbeVerifyAbortable(v, OE_Abort);
|
|
i = sqlite3VdbeAddOp4Int(v, OP_Found, iDataCur, 0, iPk, nPk);
|
|
VdbeCoverage(v);
|
|
- sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CORRUPT, OE_Abort, 0,
|
|
+ sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CORRUPT, OE_Abort, 0,
|
|
"corrupt database", P4_STATIC);
|
|
sqlite3MayAbort(pParse);
|
|
sqlite3VdbeJumpHere(v, i);
|
|
}
|
|
}
|
|
- /* pUpsert does not own pUpsertSrc - the outer INSERT statement does. So
|
|
- ** we have to make a copy before passing it down into sqlite3Update() */
|
|
- pSrc = sqlite3SrcListDup(db, pUpsert->pUpsertSrc, 0);
|
|
+ /* pUpsert does not own pTop->pUpsertSrc - the outer INSERT statement does.
|
|
+ ** So we have to make a copy before passing it down into sqlite3Update() */
|
|
+ pSrc = sqlite3SrcListDup(db, pTop->pUpsertSrc, 0);
|
|
/* excluded.* columns of type REAL need to be converted to a hard real */
|
|
for(i=0; i<pTab->nCol; i++){
|
|
if( pTab->aCol[i].affinity==SQLITE_AFF_REAL ){
|
|
- sqlite3VdbeAddOp1(v, OP_RealAffinity, pUpsert->regData+i);
|
|
+ sqlite3VdbeAddOp1(v, OP_RealAffinity, pTop->regData+i);
|
|
}
|
|
}
|
|
- sqlite3Update(pParse, pSrc, pUpsert->pUpsertSet,
|
|
- pUpsert->pUpsertWhere, OE_Abort, 0, 0, pUpsert);
|
|
- pUpsert->pUpsertSet = 0; /* Will have been deleted by sqlite3Update() */
|
|
- pUpsert->pUpsertWhere = 0; /* Will have been deleted by sqlite3Update() */
|
|
+ sqlite3Update(pParse, pSrc, sqlite3ExprListDup(db,pUpsert->pUpsertSet,0),
|
|
+ sqlite3ExprDup(db,pUpsert->pUpsertWhere,0), OE_Abort, 0, 0, pUpsert);
|
|
VdbeNoopComment((v, "End DO UPDATE of UPSERT"));
|
|
}
|
|
|
|
@@ -137434,7 +149901,7 @@ static int execSql(sqlite3 *db, char **pzErrMsg, const char *zSql){
|
|
assert( sqlite3_strnicmp(zSql,"SELECT",6)==0 );
|
|
/* The secondary SQL must be one of CREATE TABLE, CREATE INDEX,
|
|
** or INSERT. Historically there have been attacks that first
|
|
- ** corrupt the sqlite_master.sql field with other kinds of statements
|
|
+ ** corrupt the sqlite_schema.sql field with other kinds of statements
|
|
** then run VACUUM to get those statements to execute at inappropriate
|
|
** times. */
|
|
if( zSubSql
|
|
@@ -137544,8 +150011,8 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum(
|
|
Btree *pTemp; /* The temporary database we vacuum into */
|
|
u32 saved_mDbFlags; /* Saved value of db->mDbFlags */
|
|
u64 saved_flags; /* Saved value of db->flags */
|
|
- int saved_nChange; /* Saved value of db->nChange */
|
|
- int saved_nTotalChange; /* Saved value of db->nTotalChange */
|
|
+ i64 saved_nChange; /* Saved value of db->nChange */
|
|
+ i64 saved_nTotalChange; /* Saved value of db->nTotalChange */
|
|
u32 saved_openFlags; /* Saved value of db->openFlags */
|
|
u8 saved_mTrace; /* Saved trace settings */
|
|
Db *pDb = 0; /* Database to detach at end of vacuum */
|
|
@@ -137554,6 +150021,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum(
|
|
int nDb; /* Number of attached databases */
|
|
const char *zDbMain; /* Schema name of database to vacuum */
|
|
const char *zOut; /* Name of output file */
|
|
+ u32 pgflags = PAGER_SYNCHRONOUS_OFF; /* sync flags for output db */
|
|
|
|
if( !db->autoCommit ){
|
|
sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction");
|
|
@@ -137576,7 +150044,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum(
|
|
zOut = "";
|
|
}
|
|
|
|
- /* Save the current value of the database flags so that it can be
|
|
+ /* Save the current value of the database flags so that it can be
|
|
** restored before returning. Then set the writable-schema flag, and
|
|
** disable CHECK and foreign key constraints. */
|
|
saved_flags = db->flags;
|
|
@@ -137625,23 +150093,17 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum(
|
|
goto end_of_vacuum;
|
|
}
|
|
db->mDbFlags |= DBFLAG_VacuumInto;
|
|
- }
|
|
- nRes = sqlite3BtreeGetOptimalReserve(pMain);
|
|
|
|
- /* A VACUUM cannot change the pagesize of an encrypted database. */
|
|
-#ifdef SQLITE_HAS_CODEC
|
|
- if( db->nextPagesize ){
|
|
- extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*);
|
|
- int nKey;
|
|
- char *zKey;
|
|
- sqlite3CodecGetKey(db, iDb, (void**)&zKey, &nKey);
|
|
- if( nKey ) db->nextPagesize = 0;
|
|
+ /* For a VACUUM INTO, the pager-flags are set to the same values as
|
|
+ ** they are for the database being vacuumed, except that PAGER_CACHESPILL
|
|
+ ** is always set. */
|
|
+ pgflags = db->aDb[iDb].safety_level | (db->flags & PAGER_FLAGS_MASK);
|
|
}
|
|
-#endif
|
|
+ nRes = sqlite3BtreeGetRequestedReserve(pMain);
|
|
|
|
sqlite3BtreeSetCacheSize(pTemp, db->aDb[iDb].pSchema->cache_size);
|
|
sqlite3BtreeSetSpillSize(pTemp, sqlite3BtreeSetSpillSize(pMain,0));
|
|
- sqlite3BtreeSetPagerFlags(pTemp, PAGER_SYNCHRONOUS_OFF|PAGER_CACHESPILL);
|
|
+ sqlite3BtreeSetPagerFlags(pTemp, pgflags|PAGER_CACHESPILL);
|
|
|
|
/* Begin a transaction and take an exclusive lock on the main database
|
|
** file. This is done before the sqlite3BtreeGetPageSize(pMain) call below,
|
|
@@ -137654,7 +150116,9 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum(
|
|
|
|
/* Do not attempt to change the page size for a WAL database */
|
|
if( sqlite3PagerGetJournalMode(sqlite3BtreePager(pMain))
|
|
- ==PAGER_JOURNALMODE_WAL ){
|
|
+ ==PAGER_JOURNALMODE_WAL
|
|
+ && pOut==0
|
|
+ ){
|
|
db->nextPagesize = 0;
|
|
}
|
|
|
|
@@ -137676,14 +150140,14 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum(
|
|
*/
|
|
db->init.iDb = nDb; /* force new CREATE statements into vacuum_db */
|
|
rc = execSqlF(db, pzErrMsg,
|
|
- "SELECT sql FROM \"%w\".sqlite_master"
|
|
+ "SELECT sql FROM \"%w\".sqlite_schema"
|
|
" WHERE type='table'AND name<>'sqlite_sequence'"
|
|
" AND coalesce(rootpage,1)>0",
|
|
zDbMain
|
|
);
|
|
if( rc!=SQLITE_OK ) goto end_of_vacuum;
|
|
rc = execSqlF(db, pzErrMsg,
|
|
- "SELECT sql FROM \"%w\".sqlite_master"
|
|
+ "SELECT sql FROM \"%w\".sqlite_schema"
|
|
" WHERE type='index'",
|
|
zDbMain
|
|
);
|
|
@@ -137697,7 +150161,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum(
|
|
rc = execSqlF(db, pzErrMsg,
|
|
"SELECT'INSERT INTO vacuum_db.'||quote(name)"
|
|
"||' SELECT*FROM\"%w\".'||quote(name)"
|
|
- "FROM vacuum_db.sqlite_master "
|
|
+ "FROM vacuum_db.sqlite_schema "
|
|
"WHERE type='table'AND coalesce(rootpage,1)>0",
|
|
zDbMain
|
|
);
|
|
@@ -137708,18 +150172,18 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum(
|
|
/* Copy the triggers, views, and virtual tables from the main database
|
|
** over to the temporary database. None of these objects has any
|
|
** associated storage, so all we have to do is copy their entries
|
|
- ** from the SQLITE_MASTER table.
|
|
+ ** from the schema table.
|
|
*/
|
|
rc = execSqlF(db, pzErrMsg,
|
|
- "INSERT INTO vacuum_db.sqlite_master"
|
|
- " SELECT*FROM \"%w\".sqlite_master"
|
|
+ "INSERT INTO vacuum_db.sqlite_schema"
|
|
+ " SELECT*FROM \"%w\".sqlite_schema"
|
|
" WHERE type IN('view','trigger')"
|
|
" OR(type='table'AND rootpage=0)",
|
|
zDbMain
|
|
);
|
|
if( rc ) goto end_of_vacuum;
|
|
|
|
- /* At this point, there is a write transaction open on both the
|
|
+ /* At this point, there is a write transaction open on both the
|
|
** vacuum database and the main database. Assuming no error occurs,
|
|
** both transactions are closed by this block - the main database
|
|
** transaction by sqlite3BtreeCopyFile() and the other by an explicit
|
|
@@ -137743,8 +150207,8 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum(
|
|
BTREE_APPLICATION_ID, 0, /* Preserve the application id */
|
|
};
|
|
|
|
- assert( 1==sqlite3BtreeIsInTrans(pTemp) );
|
|
- assert( pOut!=0 || 1==sqlite3BtreeIsInTrans(pMain) );
|
|
+ assert( SQLITE_TXN_WRITE==sqlite3BtreeTxnState(pTemp) );
|
|
+ assert( pOut!=0 || SQLITE_TXN_WRITE==sqlite3BtreeTxnState(pMain) );
|
|
|
|
/* Copy Btree meta values */
|
|
for(i=0; i<ArraySize(aCopy); i+=2){
|
|
@@ -137770,6 +150234,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum(
|
|
|
|
assert( rc==SQLITE_OK );
|
|
if( pOut==0 ){
|
|
+ nRes = sqlite3BtreeGetRequestedReserve(pTemp);
|
|
rc = sqlite3BtreeSetPageSize(pMain, sqlite3BtreeGetPageSize(pTemp), nRes,1);
|
|
}
|
|
|
|
@@ -137781,7 +150246,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum(
|
|
db->nChange = saved_nChange;
|
|
db->nTotalChange = saved_nTotalChange;
|
|
db->mTrace = saved_mTrace;
|
|
- sqlite3BtreeSetPageSize(pMain, -1, -1, 1);
|
|
+ sqlite3BtreeSetPageSize(pMain, -1, 0, 1);
|
|
|
|
/* Currently there is an SQL level transaction open on the vacuum
|
|
** database. No locks are held on any other files (since the main file
|
|
@@ -137799,7 +150264,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum(
|
|
}
|
|
|
|
/* This both clears the schemas and reduces the size of the db->aDb[]
|
|
- ** array. */
|
|
+ ** array. */
|
|
sqlite3ResetAllSchemasOfConnection(db);
|
|
|
|
return rc;
|
|
@@ -137828,7 +150293,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum(
|
|
/*
|
|
** Before a virtual table xCreate() or xConnect() method is invoked, the
|
|
** sqlite3.pVtabCtx member variable is set to point to an instance of
|
|
-** this struct allocated on the stack. It is used by the implementation of
|
|
+** this struct allocated on the stack. It is used by the implementation of
|
|
** the sqlite3_declare_vtab() and sqlite3_vtab_config() APIs, both of which
|
|
** are invoked only from within xCreate and xConnect methods.
|
|
*/
|
|
@@ -137985,7 +150450,7 @@ SQLITE_PRIVATE void sqlite3VtabModuleUnref(sqlite3 *db, Module *pMod){
|
|
/*
|
|
** Lock the virtual table so that it cannot be disconnected.
|
|
** Locks nest. Every lock should have a corresponding unlock.
|
|
-** If an unlock is omitted, resources leaks will occur.
|
|
+** If an unlock is omitted, resources leaks will occur.
|
|
**
|
|
** If a disconnect is attempted while a virtual table is locked,
|
|
** the disconnect is deferred until all locks have been removed.
|
|
@@ -137997,13 +150462,13 @@ SQLITE_PRIVATE void sqlite3VtabLock(VTable *pVTab){
|
|
|
|
/*
|
|
** pTab is a pointer to a Table structure representing a virtual-table.
|
|
-** Return a pointer to the VTable object used by connection db to access
|
|
+** Return a pointer to the VTable object used by connection db to access
|
|
** this virtual-table, if one has been created, or NULL otherwise.
|
|
*/
|
|
SQLITE_PRIVATE VTable *sqlite3GetVTable(sqlite3 *db, Table *pTab){
|
|
VTable *pVtab;
|
|
assert( IsVirtual(pTab) );
|
|
- for(pVtab=pTab->pVTable; pVtab && pVtab->db!=db; pVtab=pVtab->pNext);
|
|
+ for(pVtab=pTab->u.vtab.p; pVtab && pVtab->db!=db; pVtab=pVtab->pNext);
|
|
return pVtab;
|
|
}
|
|
|
|
@@ -138016,36 +150481,40 @@ SQLITE_PRIVATE void sqlite3VtabUnlock(VTable *pVTab){
|
|
|
|
assert( db );
|
|
assert( pVTab->nRef>0 );
|
|
- assert( db->magic==SQLITE_MAGIC_OPEN || db->magic==SQLITE_MAGIC_ZOMBIE );
|
|
+ assert( db->eOpenState==SQLITE_STATE_OPEN
|
|
+ || db->eOpenState==SQLITE_STATE_ZOMBIE );
|
|
|
|
pVTab->nRef--;
|
|
if( pVTab->nRef==0 ){
|
|
sqlite3_vtab *p = pVTab->pVtab;
|
|
- sqlite3VtabModuleUnref(pVTab->db, pVTab->pMod);
|
|
if( p ){
|
|
p->pModule->xDisconnect(p);
|
|
}
|
|
+ sqlite3VtabModuleUnref(pVTab->db, pVTab->pMod);
|
|
sqlite3DbFree(db, pVTab);
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Table p is a virtual table. This function moves all elements in the
|
|
-** p->pVTable list to the sqlite3.pDisconnect lists of their associated
|
|
-** database connections to be disconnected at the next opportunity.
|
|
+** p->u.vtab.p list to the sqlite3.pDisconnect lists of their associated
|
|
+** database connections to be disconnected at the next opportunity.
|
|
** Except, if argument db is not NULL, then the entry associated with
|
|
-** connection db is left in the p->pVTable list.
|
|
+** connection db is left in the p->u.vtab.p list.
|
|
*/
|
|
static VTable *vtabDisconnectAll(sqlite3 *db, Table *p){
|
|
VTable *pRet = 0;
|
|
- VTable *pVTable = p->pVTable;
|
|
- p->pVTable = 0;
|
|
+ VTable *pVTable;
|
|
|
|
- /* Assert that the mutex (if any) associated with the BtShared database
|
|
- ** that contains table p is held by the caller. See header comments
|
|
+ assert( IsVirtual(p) );
|
|
+ pVTable = p->u.vtab.p;
|
|
+ p->u.vtab.p = 0;
|
|
+
|
|
+ /* Assert that the mutex (if any) associated with the BtShared database
|
|
+ ** that contains table p is held by the caller. See header comments
|
|
** above function sqlite3VtabUnlockList() for an explanation of why
|
|
** this makes it safe to access the sqlite3.pDisconnect list of any
|
|
- ** database connection that may have an entry in the p->pVTable list.
|
|
+ ** database connection that may have an entry in the p->u.vtab.p list.
|
|
*/
|
|
assert( db==0 || sqlite3SchemaMutexHeld(db, 0, p->pSchema) );
|
|
|
|
@@ -138055,7 +150524,7 @@ static VTable *vtabDisconnectAll(sqlite3 *db, Table *p){
|
|
assert( db2 );
|
|
if( db2==db ){
|
|
pRet = pVTable;
|
|
- p->pVTable = pRet;
|
|
+ p->u.vtab.p = pRet;
|
|
pRet->pNext = 0;
|
|
}else{
|
|
pVTable->pNext = db2->pDisconnect;
|
|
@@ -138083,7 +150552,7 @@ SQLITE_PRIVATE void sqlite3VtabDisconnect(sqlite3 *db, Table *p){
|
|
assert( sqlite3BtreeHoldsAllMutexes(db) );
|
|
assert( sqlite3_mutex_held(db->mutex) );
|
|
|
|
- for(ppVTab=&p->pVTable; *ppVTab; ppVTab=&(*ppVTab)->pNext){
|
|
+ for(ppVTab=&p->u.vtab.p; *ppVTab; ppVTab=&(*ppVTab)->pNext){
|
|
if( (*ppVTab)->db==db ){
|
|
VTable *pVTab = *ppVTab;
|
|
*ppVTab = pVTab->pNext;
|
|
@@ -138098,7 +150567,7 @@ SQLITE_PRIVATE void sqlite3VtabDisconnect(sqlite3 *db, Table *p){
|
|
** Disconnect all the virtual table objects in the sqlite3.pDisconnect list.
|
|
**
|
|
** This function may only be called when the mutexes associated with all
|
|
-** shared b-tree databases opened using connection db are held by the
|
|
+** shared b-tree databases opened using connection db are held by the
|
|
** caller. This is done to protect the sqlite3.pDisconnect list. The
|
|
** sqlite3.pDisconnect list is accessed only as follows:
|
|
**
|
|
@@ -138111,7 +150580,7 @@ SQLITE_PRIVATE void sqlite3VtabDisconnect(sqlite3 *db, Table *p){
|
|
** or, if the virtual table is stored in a non-sharable database, then
|
|
** the database handle mutex is held.
|
|
**
|
|
-** As a result, a sqlite3.pDisconnect cannot be accessed simultaneously
|
|
+** As a result, a sqlite3.pDisconnect cannot be accessed simultaneously
|
|
** by multiple threads. It is thread-safe.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3VtabUnlockList(sqlite3 *db){
|
|
@@ -138137,46 +150606,51 @@ SQLITE_PRIVATE void sqlite3VtabUnlockList(sqlite3 *db){
|
|
** record.
|
|
**
|
|
** Since it is a virtual-table, the Table structure contains a pointer
|
|
-** to the head of a linked list of VTable structures. Each VTable
|
|
+** to the head of a linked list of VTable structures. Each VTable
|
|
** structure is associated with a single sqlite3* user of the schema.
|
|
-** The reference count of the VTable structure associated with database
|
|
-** connection db is decremented immediately (which may lead to the
|
|
+** The reference count of the VTable structure associated with database
|
|
+** connection db is decremented immediately (which may lead to the
|
|
** structure being xDisconnected and free). Any other VTable structures
|
|
-** in the list are moved to the sqlite3.pDisconnect list of the associated
|
|
+** in the list are moved to the sqlite3.pDisconnect list of the associated
|
|
** database connection.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3VtabClear(sqlite3 *db, Table *p){
|
|
- if( !db || db->pnBytesFreed==0 ) vtabDisconnectAll(0, p);
|
|
- if( p->azModuleArg ){
|
|
+ assert( IsVirtual(p) );
|
|
+ assert( db!=0 );
|
|
+ if( db->pnBytesFreed==0 ) vtabDisconnectAll(0, p);
|
|
+ if( p->u.vtab.azArg ){
|
|
int i;
|
|
- for(i=0; i<p->nModuleArg; i++){
|
|
- if( i!=1 ) sqlite3DbFree(db, p->azModuleArg[i]);
|
|
+ for(i=0; i<p->u.vtab.nArg; i++){
|
|
+ if( i!=1 ) sqlite3DbFree(db, p->u.vtab.azArg[i]);
|
|
}
|
|
- sqlite3DbFree(db, p->azModuleArg);
|
|
+ sqlite3DbFree(db, p->u.vtab.azArg);
|
|
}
|
|
}
|
|
|
|
/*
|
|
-** Add a new module argument to pTable->azModuleArg[].
|
|
+** Add a new module argument to pTable->u.vtab.azArg[].
|
|
** The string is not copied - the pointer is stored. The
|
|
** string will be freed automatically when the table is
|
|
** deleted.
|
|
*/
|
|
static void addModuleArgument(Parse *pParse, Table *pTable, char *zArg){
|
|
- sqlite3_int64 nBytes = sizeof(char *)*(2+pTable->nModuleArg);
|
|
+ sqlite3_int64 nBytes;
|
|
char **azModuleArg;
|
|
sqlite3 *db = pParse->db;
|
|
- if( pTable->nModuleArg+3>=db->aLimit[SQLITE_LIMIT_COLUMN] ){
|
|
+
|
|
+ assert( IsVirtual(pTable) );
|
|
+ nBytes = sizeof(char *)*(2+pTable->u.vtab.nArg);
|
|
+ if( pTable->u.vtab.nArg+3>=db->aLimit[SQLITE_LIMIT_COLUMN] ){
|
|
sqlite3ErrorMsg(pParse, "too many columns on %s", pTable->zName);
|
|
}
|
|
- azModuleArg = sqlite3DbRealloc(db, pTable->azModuleArg, nBytes);
|
|
+ azModuleArg = sqlite3DbRealloc(db, pTable->u.vtab.azArg, nBytes);
|
|
if( azModuleArg==0 ){
|
|
sqlite3DbFree(db, zArg);
|
|
}else{
|
|
- int i = pTable->nModuleArg++;
|
|
+ int i = pTable->u.vtab.nArg++;
|
|
azModuleArg[i] = zArg;
|
|
azModuleArg[i+1] = 0;
|
|
- pTable->azModuleArg = azModuleArg;
|
|
+ pTable->u.vtab.azArg = azModuleArg;
|
|
}
|
|
}
|
|
|
|
@@ -138199,10 +150673,11 @@ SQLITE_PRIVATE void sqlite3VtabBeginParse(
|
|
pTable = pParse->pNewTable;
|
|
if( pTable==0 ) return;
|
|
assert( 0==pTable->pIndex );
|
|
+ pTable->eTabType = TABTYP_VTAB;
|
|
|
|
db = pParse->db;
|
|
|
|
- assert( pTable->nModuleArg==0 );
|
|
+ assert( pTable->u.vtab.nArg==0 );
|
|
addModuleArgument(pParse, pTable, sqlite3NameFromToken(db, pModuleName));
|
|
addModuleArgument(pParse, pTable, 0);
|
|
addModuleArgument(pParse, pTable, sqlite3DbStrDup(db, pTable->zName));
|
|
@@ -138216,14 +150691,14 @@ SQLITE_PRIVATE void sqlite3VtabBeginParse(
|
|
#ifndef SQLITE_OMIT_AUTHORIZATION
|
|
/* Creating a virtual table invokes the authorization callback twice.
|
|
** The first invocation, to obtain permission to INSERT a row into the
|
|
- ** sqlite_master table, has already been made by sqlite3StartTable().
|
|
+ ** sqlite_schema table, has already been made by sqlite3StartTable().
|
|
** The second call, to obtain permission to create the table, is made now.
|
|
*/
|
|
- if( pTable->azModuleArg ){
|
|
+ if( pTable->u.vtab.azArg ){
|
|
int iDb = sqlite3SchemaToIndex(db, pTable->pSchema);
|
|
assert( iDb>=0 ); /* The database the table is being created in */
|
|
- sqlite3AuthCheck(pParse, SQLITE_CREATE_VTABLE, pTable->zName,
|
|
- pTable->azModuleArg[0], pParse->db->aDb[iDb].zDbSName);
|
|
+ sqlite3AuthCheck(pParse, SQLITE_CREATE_VTABLE, pTable->zName,
|
|
+ pTable->u.vtab.azArg[0], pParse->db->aDb[iDb].zDbSName);
|
|
}
|
|
#endif
|
|
}
|
|
@@ -138251,15 +150726,16 @@ SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
|
|
sqlite3 *db = pParse->db; /* The database connection */
|
|
|
|
if( pTab==0 ) return;
|
|
+ assert( IsVirtual(pTab) );
|
|
addArgumentToVtab(pParse);
|
|
pParse->sArg.z = 0;
|
|
- if( pTab->nModuleArg<1 ) return;
|
|
-
|
|
+ if( pTab->u.vtab.nArg<1 ) return;
|
|
+
|
|
/* If the CREATE VIRTUAL TABLE statement is being entered for the
|
|
** first time (in other words if the virtual table is actually being
|
|
- ** created now instead of just being read out of sqlite_master) then
|
|
+ ** created now instead of just being read out of sqlite_schema) then
|
|
** do additional initialization work and store the statement text
|
|
- ** in the sqlite_master table.
|
|
+ ** in the sqlite_schema table.
|
|
*/
|
|
if( !db->init.busy ){
|
|
char *zStmt;
|
|
@@ -138276,20 +150752,20 @@ SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
|
|
}
|
|
zStmt = sqlite3MPrintf(db, "CREATE VIRTUAL TABLE %T", &pParse->sNameToken);
|
|
|
|
- /* A slot for the record has already been allocated in the
|
|
- ** SQLITE_MASTER table. We just need to update that slot with all
|
|
- ** the information we've collected.
|
|
+ /* A slot for the record has already been allocated in the
|
|
+ ** schema table. We just need to update that slot with all
|
|
+ ** the information we've collected.
|
|
**
|
|
** The VM register number pParse->regRowid holds the rowid of an
|
|
- ** entry in the sqlite_master table tht was created for this vtab
|
|
+ ** entry in the sqlite_schema table tht was created for this vtab
|
|
** by sqlite3StartTable().
|
|
*/
|
|
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
|
sqlite3NestedParse(pParse,
|
|
- "UPDATE %Q.%s "
|
|
+ "UPDATE %Q." LEGACY_SCHEMA_TABLE " "
|
|
"SET type='table', name=%Q, tbl_name=%Q, rootpage=0, sql=%Q "
|
|
"WHERE rowid=#%d",
|
|
- db->aDb[iDb].zDbSName, MASTER_NAME,
|
|
+ db->aDb[iDb].zDbSName,
|
|
pTab->zName,
|
|
pTab->zName,
|
|
zStmt,
|
|
@@ -138300,24 +150776,20 @@ SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
|
|
|
|
sqlite3VdbeAddOp0(v, OP_Expire);
|
|
zWhere = sqlite3MPrintf(db, "name=%Q AND sql=%Q", pTab->zName, zStmt);
|
|
- sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere);
|
|
+ sqlite3VdbeAddParseSchemaOp(v, iDb, zWhere, 0);
|
|
sqlite3DbFree(db, zStmt);
|
|
|
|
iReg = ++pParse->nMem;
|
|
sqlite3VdbeLoadString(v, iReg, pTab->zName);
|
|
sqlite3VdbeAddOp2(v, OP_VCreate, iDb, iReg);
|
|
- }
|
|
-
|
|
- /* If we are rereading the sqlite_master table create the in-memory
|
|
- ** record of the table. The xConnect() method is not called until
|
|
- ** the first time the virtual table is used in an SQL statement. This
|
|
- ** allows a schema that contains virtual tables to be loaded before
|
|
- ** the required virtual table implementations are registered. */
|
|
- else {
|
|
+ }else{
|
|
+ /* If we are rereading the sqlite_schema table create the in-memory
|
|
+ ** record of the table. */
|
|
Table *pOld;
|
|
Schema *pSchema = pTab->pSchema;
|
|
const char *zName = pTab->zName;
|
|
- assert( sqlite3SchemaMutexHeld(db, 0, pSchema) );
|
|
+ assert( zName!=0 );
|
|
+ sqlite3MarkAllShadowTablesOf(db, pTab);
|
|
pOld = sqlite3HashInsert(&pSchema->tblHash, zName, pTab);
|
|
if( pOld ){
|
|
sqlite3OomFault(db);
|
|
@@ -138359,7 +150831,7 @@ SQLITE_PRIVATE void sqlite3VtabArgExtend(Parse *pParse, Token *p){
|
|
** to this procedure.
|
|
*/
|
|
static int vtabCallConstructor(
|
|
- sqlite3 *db,
|
|
+ sqlite3 *db,
|
|
Table *pTab,
|
|
Module *pMod,
|
|
int (*xConstruct)(sqlite3*,void*,int,const char*const*,sqlite3_vtab**,char**),
|
|
@@ -138368,17 +150840,20 @@ static int vtabCallConstructor(
|
|
VtabCtx sCtx;
|
|
VTable *pVTable;
|
|
int rc;
|
|
- const char *const*azArg = (const char *const*)pTab->azModuleArg;
|
|
- int nArg = pTab->nModuleArg;
|
|
+ const char *const*azArg;
|
|
+ int nArg = pTab->u.vtab.nArg;
|
|
char *zErr = 0;
|
|
char *zModuleName;
|
|
int iDb;
|
|
VtabCtx *pCtx;
|
|
|
|
+ assert( IsVirtual(pTab) );
|
|
+ azArg = (const char *const*)pTab->u.vtab.azArg;
|
|
+
|
|
/* Check that the virtual-table is not already being initialized */
|
|
for(pCtx=db->pVtabCtx; pCtx; pCtx=pCtx->pPrior){
|
|
if( pCtx->pTab==pTab ){
|
|
- *pzErr = sqlite3MPrintf(db,
|
|
+ *pzErr = sqlite3MPrintf(db,
|
|
"vtable constructor called recursively: %s", pTab->zName
|
|
);
|
|
return SQLITE_LOCKED;
|
|
@@ -138401,7 +150876,7 @@ static int vtabCallConstructor(
|
|
pVTable->eVtabRisk = SQLITE_VTABRISK_Normal;
|
|
|
|
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
|
- pTab->azModuleArg[1] = db->aDb[iDb].zDbSName;
|
|
+ pTab->u.vtab.azArg[1] = db->aDb[iDb].zDbSName;
|
|
|
|
/* Invoke the virtual table constructor */
|
|
assert( &db->pVtabCtx );
|
|
@@ -138411,7 +150886,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 );
|
|
@@ -138440,12 +150917,12 @@ static int vtabCallConstructor(
|
|
int iCol;
|
|
u16 oooHidden = 0;
|
|
/* If everything went according to plan, link the new VTable structure
|
|
- ** into the linked list headed by pTab->pVTable. Then loop through the
|
|
+ ** into the linked list headed by pTab->u.vtab.p. Then loop through the
|
|
** columns of the table to see if any of them contain the token "hidden".
|
|
** If so, set the Column COLFLAG_HIDDEN flag and remove the token from
|
|
** the type string. */
|
|
- pVTable->pNext = pTab->pVTable;
|
|
- pTab->pVTable = pVTable;
|
|
+ pVTable->pNext = pTab->u.vtab.p;
|
|
+ pTab->u.vtab.p = pVTable;
|
|
|
|
for(iCol=0; iCol<pTab->nCol; iCol++){
|
|
char *zType = sqlite3ColumnType(&pTab->aCol[iCol], "");
|
|
@@ -138471,6 +150948,7 @@ static int vtabCallConstructor(
|
|
zType[i-1] = '\0';
|
|
}
|
|
pTab->aCol[iCol].colFlags |= COLFLAG_HIDDEN;
|
|
+ pTab->tabFlags |= TF_HasHidden;
|
|
oooHidden = TF_OOOHidden;
|
|
}else{
|
|
pTab->tabFlags |= oooHidden;
|
|
@@ -138485,7 +150963,7 @@ static int vtabCallConstructor(
|
|
|
|
/*
|
|
** This function is invoked by the parser to call the xConnect() method
|
|
-** of the virtual table pTab. If an error occurs, an error code is returned
|
|
+** of the virtual table pTab. If an error occurs, an error code is returned
|
|
** and an error left in pParse.
|
|
**
|
|
** This call is a no-op if table pTab is not a virtual table.
|
|
@@ -138497,16 +150975,17 @@ SQLITE_PRIVATE int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){
|
|
int rc;
|
|
|
|
assert( pTab );
|
|
- if( !IsVirtual(pTab) || sqlite3GetVTable(db, pTab) ){
|
|
+ assert( IsVirtual(pTab) );
|
|
+ if( sqlite3GetVTable(db, pTab) ){
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
/* Locate the required virtual table module */
|
|
- zMod = pTab->azModuleArg[0];
|
|
+ zMod = pTab->u.vtab.azArg[0];
|
|
pMod = (Module*)sqlite3HashFind(&db->aModule, zMod);
|
|
|
|
if( !pMod ){
|
|
- const char *zModule = pTab->azModuleArg[0];
|
|
+ const char *zModule = pTab->u.vtab.azArg[0];
|
|
sqlite3ErrorMsg(pParse, "no such module: %s", zModule);
|
|
rc = SQLITE_ERROR;
|
|
}else{
|
|
@@ -138556,7 +151035,7 @@ static void addToVTrans(sqlite3 *db, VTable *pVTab){
|
|
|
|
/*
|
|
** This function is invoked by the vdbe to call the xCreate method
|
|
-** of the virtual table named zTab in database iDb.
|
|
+** of the virtual table named zTab in database iDb.
|
|
**
|
|
** If an error occurs, *pzErr is set to point to an English language
|
|
** description of the error and an SQLITE_XXX error code is returned.
|
|
@@ -138569,14 +151048,14 @@ SQLITE_PRIVATE int sqlite3VtabCallCreate(sqlite3 *db, int iDb, const char *zTab,
|
|
const char *zMod;
|
|
|
|
pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zDbSName);
|
|
- assert( pTab && IsVirtual(pTab) && !pTab->pVTable );
|
|
+ assert( pTab && IsVirtual(pTab) && !pTab->u.vtab.p );
|
|
|
|
/* Locate the required virtual table module */
|
|
- zMod = pTab->azModuleArg[0];
|
|
+ zMod = pTab->u.vtab.azArg[0];
|
|
pMod = (Module*)sqlite3HashFind(&db->aModule, zMod);
|
|
|
|
- /* If the module has been registered and includes a Create method,
|
|
- ** invoke it now. If the module has not been registered, return an
|
|
+ /* If the module has been registered and includes a Create method,
|
|
+ ** invoke it now. If the module has not been registered, return an
|
|
** error. Otherwise, do nothing.
|
|
*/
|
|
if( pMod==0 || pMod->pModule->xCreate==0 || pMod->pModule->xDestroy==0 ){
|
|
@@ -138607,8 +151086,8 @@ SQLITE_API int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
|
|
VtabCtx *pCtx;
|
|
int rc = SQLITE_OK;
|
|
Table *pTab;
|
|
- char *zErr = 0;
|
|
Parse sParse;
|
|
+ int initBusy;
|
|
|
|
#ifdef SQLITE_ENABLE_API_ARMOR
|
|
if( !sqlite3SafetyCheckOk(db) || zCreateTable==0 ){
|
|
@@ -138625,21 +151104,28 @@ SQLITE_API int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
|
|
pTab = pCtx->pTab;
|
|
assert( IsVirtual(pTab) );
|
|
|
|
- memset(&sParse, 0, sizeof(sParse));
|
|
+ sqlite3ParseObjectInit(&sParse, db);
|
|
sParse.eParseMode = PARSE_MODE_DECLARE_VTAB;
|
|
- sParse.db = db;
|
|
+ sParse.disableTriggers = 1;
|
|
+ /* We should never be able to reach this point while loading the
|
|
+ ** schema. Nevertheless, defend against that (turn off db->init.busy)
|
|
+ ** in case a bug arises. */
|
|
+ assert( db->init.busy==0 );
|
|
+ initBusy = db->init.busy;
|
|
+ db->init.busy = 0;
|
|
sParse.nQueryLoop = 1;
|
|
- if( SQLITE_OK==sqlite3RunParser(&sParse, zCreateTable, &zErr)
|
|
- && sParse.pNewTable
|
|
- && !db->mallocFailed
|
|
- && !sParse.pNewTable->pSelect
|
|
- && !IsVirtual(sParse.pNewTable)
|
|
+ if( SQLITE_OK==sqlite3RunParser(&sParse, zCreateTable)
|
|
+ && ALWAYS(sParse.pNewTable!=0)
|
|
+ && ALWAYS(!db->mallocFailed)
|
|
+ && IsOrdinaryTable(sParse.pNewTable)
|
|
){
|
|
+ assert( sParse.zErrMsg==0 );
|
|
if( !pTab->aCol ){
|
|
Table *pNew = sParse.pNewTable;
|
|
Index *pIdx;
|
|
pTab->aCol = pNew->aCol;
|
|
- pTab->nCol = pNew->nCol;
|
|
+ sqlite3ExprListDelete(db, pNew->u.tab.pDfltList);
|
|
+ pTab->nNVCol = pTab->nCol = pNew->nCol;
|
|
pTab->tabFlags |= pNew->tabFlags & (TF_WithoutRowid|TF_NoVisibleRowid);
|
|
pNew->nCol = 0;
|
|
pNew->aCol = 0;
|
|
@@ -138663,8 +151149,9 @@ SQLITE_API int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
|
|
}
|
|
pCtx->bDeclared = 1;
|
|
}else{
|
|
- sqlite3ErrorWithMsg(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr);
|
|
- sqlite3DbFree(db, zErr);
|
|
+ sqlite3ErrorWithMsg(db, SQLITE_ERROR,
|
|
+ (sParse.zErrMsg ? "%s" : 0), sParse.zErrMsg);
|
|
+ sqlite3DbFree(db, sParse.zErrMsg);
|
|
rc = SQLITE_ERROR;
|
|
}
|
|
sParse.eParseMode = PARSE_MODE_NORMAL;
|
|
@@ -138673,7 +151160,8 @@ SQLITE_API int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
|
|
sqlite3VdbeFinalize(sParse.pVdbe);
|
|
}
|
|
sqlite3DeleteTable(db, sParse.pNewTable);
|
|
- sqlite3ParserReset(&sParse);
|
|
+ sqlite3ParseObjectReset(&sParse);
|
|
+ db->init.busy = initBusy;
|
|
|
|
assert( (rc&0xff)==rc );
|
|
rc = sqlite3ApiExit(db, rc);
|
|
@@ -138693,10 +151181,13 @@ SQLITE_PRIVATE int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab
|
|
Table *pTab;
|
|
|
|
pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zDbSName);
|
|
- if( pTab!=0 && ALWAYS(pTab->pVTable!=0) ){
|
|
+ if( ALWAYS(pTab!=0)
|
|
+ && ALWAYS(IsVirtual(pTab))
|
|
+ && ALWAYS(pTab->u.vtab.p!=0)
|
|
+ ){
|
|
VTable *p;
|
|
int (*xDestroy)(sqlite3_vtab *);
|
|
- for(p=pTab->pVTable; p; p=p->pNext){
|
|
+ for(p=pTab->u.vtab.p; p; p=p->pNext){
|
|
assert( p->pVtab );
|
|
if( p->pVtab->nRef>0 ){
|
|
return SQLITE_LOCKED;
|
|
@@ -138710,9 +151201,9 @@ SQLITE_PRIVATE int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab
|
|
rc = xDestroy(p->pVtab);
|
|
/* Remove the sqlite3_vtab* from the aVTrans[] array, if applicable */
|
|
if( rc==SQLITE_OK ){
|
|
- assert( pTab->pVTable==p && p->pNext==0 );
|
|
+ assert( pTab->u.vtab.p==p && p->pNext==0 );
|
|
p->pVtab = 0;
|
|
- pTab->pVTable = 0;
|
|
+ pTab->u.vtab.p = 0;
|
|
sqlite3VtabUnlock(p);
|
|
}
|
|
sqlite3DeleteTable(db, pTab);
|
|
@@ -138727,7 +151218,7 @@ SQLITE_PRIVATE int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab
|
|
** called is identified by the second argument, "offset", which is
|
|
** the offset of the method to call in the sqlite3_module structure.
|
|
**
|
|
-** The array is cleared after invoking the callbacks.
|
|
+** The array is cleared after invoking the callbacks.
|
|
*/
|
|
static void callFinaliser(sqlite3 *db, int offset){
|
|
int i;
|
|
@@ -138776,7 +151267,7 @@ SQLITE_PRIVATE int sqlite3VtabSync(sqlite3 *db, Vdbe *p){
|
|
}
|
|
|
|
/*
|
|
-** Invoke the xRollback method of all virtual tables in the
|
|
+** Invoke the xRollback method of all virtual tables in the
|
|
** sqlite3.aVTrans array. Then clear the array itself.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3VtabRollback(sqlite3 *db){
|
|
@@ -138785,7 +151276,7 @@ SQLITE_PRIVATE int sqlite3VtabRollback(sqlite3 *db){
|
|
}
|
|
|
|
/*
|
|
-** Invoke the xCommit method of all virtual tables in the
|
|
+** Invoke the xCommit method of all virtual tables in the
|
|
** sqlite3.aVTrans array. Then clear the array itself.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3VtabCommit(sqlite3 *db){
|
|
@@ -138807,7 +151298,7 @@ SQLITE_PRIVATE int sqlite3VtabBegin(sqlite3 *db, VTable *pVTab){
|
|
|
|
/* Special case: If db->aVTrans is NULL and db->nVTrans is greater
|
|
** than zero, then this function is being called from within a
|
|
- ** virtual module xSync() callback. It is illegal to write to
|
|
+ ** virtual module xSync() callback. It is illegal to write to
|
|
** virtual module tables in this case, so return SQLITE_LOCKED.
|
|
*/
|
|
if( sqlite3VtabInSync(db) ){
|
|
@@ -138815,7 +151306,7 @@ SQLITE_PRIVATE int sqlite3VtabBegin(sqlite3 *db, VTable *pVTab){
|
|
}
|
|
if( !pVTab ){
|
|
return SQLITE_OK;
|
|
- }
|
|
+ }
|
|
pModule = pVTab->pVtab->pModule;
|
|
|
|
if( pModule->xBegin ){
|
|
@@ -138828,7 +151319,7 @@ SQLITE_PRIVATE int sqlite3VtabBegin(sqlite3 *db, VTable *pVTab){
|
|
}
|
|
}
|
|
|
|
- /* Invoke the xBegin method. If successful, add the vtab to the
|
|
+ /* Invoke the xBegin method. If successful, add the vtab to the
|
|
** sqlite3.aVTrans[] array. */
|
|
rc = growVTrans(db);
|
|
if( rc==SQLITE_OK ){
|
|
@@ -138852,11 +151343,11 @@ SQLITE_PRIVATE int sqlite3VtabBegin(sqlite3 *db, VTable *pVTab){
|
|
** as the second argument to the virtual table method invoked.
|
|
**
|
|
** If op is SAVEPOINT_BEGIN, the xSavepoint method is invoked. If it is
|
|
-** SAVEPOINT_ROLLBACK, the xRollbackTo method. Otherwise, if op is
|
|
+** SAVEPOINT_ROLLBACK, the xRollbackTo method. Otherwise, if op is
|
|
** SAVEPOINT_RELEASE, then the xRelease method of each virtual table with
|
|
** an open transaction is invoked.
|
|
**
|
|
-** If any virtual table method returns an error code other than SQLITE_OK,
|
|
+** If any virtual table method returns an error code other than SQLITE_OK,
|
|
** processing is abandoned and the error returned to the caller of this
|
|
** function immediately. If all calls to virtual table methods are successful,
|
|
** SQLITE_OK is returned.
|
|
@@ -138905,7 +151396,7 @@ SQLITE_PRIVATE int sqlite3VtabSavepoint(sqlite3 *db, int op, int iSavepoint){
|
|
** This routine is used to allow virtual table implementations to
|
|
** overload MATCH, LIKE, GLOB, and REGEXP operators.
|
|
**
|
|
-** Return either the pDef argument (indicating no change) or a
|
|
+** Return either the pDef argument (indicating no change) or a
|
|
** new FuncDef structure that is marked as ephemeral using the
|
|
** SQLITE_FUNC_EPHEM flag.
|
|
*/
|
|
@@ -138926,15 +151417,16 @@ SQLITE_PRIVATE FuncDef *sqlite3VtabOverloadFunction(
|
|
/* Check to see the left operand is a column in a virtual table */
|
|
if( NEVER(pExpr==0) ) return pDef;
|
|
if( pExpr->op!=TK_COLUMN ) return pDef;
|
|
+ assert( ExprUseYTab(pExpr) );
|
|
pTab = pExpr->y.pTab;
|
|
- if( pTab==0 ) return pDef;
|
|
+ if( NEVER(pTab==0) ) return pDef;
|
|
if( !IsVirtual(pTab) ) return pDef;
|
|
pVtab = sqlite3GetVTable(db, pTab)->pVtab;
|
|
assert( pVtab!=0 );
|
|
assert( pVtab->pModule!=0 );
|
|
pMod = (sqlite3_module *)pVtab->pModule;
|
|
if( pMod->xFindFunction==0 ) return pDef;
|
|
-
|
|
+
|
|
/* Call the xFindFunction method on the virtual table implementation
|
|
** to see if the implementation wants to overload this function.
|
|
**
|
|
@@ -138988,7 +151480,7 @@ SQLITE_PRIVATE void sqlite3VtabMakeWritable(Parse *pParse, Table *pTab){
|
|
if( pTab==pToplevel->apVtabLock[i] ) return;
|
|
}
|
|
n = (pToplevel->nVtabLock+1)*sizeof(pToplevel->apVtabLock[0]);
|
|
- apVtabLock = sqlite3_realloc64(pToplevel->apVtabLock, n);
|
|
+ apVtabLock = sqlite3Realloc(pToplevel->apVtabLock, n);
|
|
if( apVtabLock ){
|
|
pToplevel->apVtabLock = apVtabLock;
|
|
pToplevel->apVtabLock[pToplevel->nVtabLock++] = pTab;
|
|
@@ -139000,8 +151492,9 @@ SQLITE_PRIVATE void sqlite3VtabMakeWritable(Parse *pParse, Table *pTab){
|
|
/*
|
|
** Check to see if virtual table module pMod can be have an eponymous
|
|
** virtual table instance. If it can, create one if one does not already
|
|
-** exist. Return non-zero if the eponymous virtual table instance exists
|
|
-** when this routine returns, and return zero if it does not exist.
|
|
+** exist. Return non-zero if either the eponymous virtual table instance
|
|
+** exists when this routine returns or if an attempt to create it failed
|
|
+** and an error message was left in pParse.
|
|
**
|
|
** An eponymous virtual table instance is one that is named after its
|
|
** module, and more importantly, does not require a CREATE VIRTUAL TABLE
|
|
@@ -139028,9 +151521,11 @@ SQLITE_PRIVATE int sqlite3VtabEponymousTableInit(Parse *pParse, Module *pMod){
|
|
}
|
|
pMod->pEpoTab = pTab;
|
|
pTab->nTabRef = 1;
|
|
+ pTab->eTabType = TABTYP_VTAB;
|
|
pTab->pSchema = db->aDb[0].pSchema;
|
|
- assert( pTab->nModuleArg==0 );
|
|
+ assert( pTab->u.vtab.nArg==0 );
|
|
pTab->iPKey = -1;
|
|
+ pTab->tabFlags |= TF_Eponymous;
|
|
addModuleArgument(pParse, pTab, sqlite3DbStrDup(db, pTab->zName));
|
|
addModuleArgument(pParse, pTab, 0);
|
|
addModuleArgument(pParse, pTab, sqlite3DbStrDup(db, pTab->zName));
|
|
@@ -139039,7 +151534,6 @@ SQLITE_PRIVATE int sqlite3VtabEponymousTableInit(Parse *pParse, Module *pMod){
|
|
sqlite3ErrorMsg(pParse, "%s", zErr);
|
|
sqlite3DbFree(db, zErr);
|
|
sqlite3VtabEponymousTableClear(db, pMod);
|
|
- return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
@@ -139052,7 +151546,7 @@ SQLITE_PRIVATE void sqlite3VtabEponymousTableClear(sqlite3 *db, Module *pMod){
|
|
Table *pTab = pMod->pEpoTab;
|
|
if( pTab!=0 ){
|
|
/* Mark the table as Ephemeral prior to deleting it, so that the
|
|
- ** sqlite3DeleteTable() routine will know that it is not stored in
|
|
+ ** sqlite3DeleteTable() routine will know that it is not stored in
|
|
** the schema. */
|
|
pTab->tabFlags |= TF_Ephemeral;
|
|
sqlite3DeleteTable(db, pTab);
|
|
@@ -139068,8 +151562,8 @@ SQLITE_PRIVATE void sqlite3VtabEponymousTableClear(sqlite3 *db, Module *pMod){
|
|
** within an xUpdate method.
|
|
*/
|
|
SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *db){
|
|
- static const unsigned char aMap[] = {
|
|
- SQLITE_ROLLBACK, SQLITE_ABORT, SQLITE_FAIL, SQLITE_IGNORE, SQLITE_REPLACE
|
|
+ static const unsigned char aMap[] = {
|
|
+ SQLITE_ROLLBACK, SQLITE_ABORT, SQLITE_FAIL, SQLITE_IGNORE, SQLITE_REPLACE
|
|
};
|
|
#ifdef SQLITE_ENABLE_API_ARMOR
|
|
if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
|
|
@@ -139081,7 +151575,7 @@ SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *db){
|
|
}
|
|
|
|
/*
|
|
-** Call from within the xCreate() or xConnect() methods to provide
|
|
+** Call from within the xCreate() or xConnect() methods to provide
|
|
** the SQLite core with additional information about the behavior
|
|
** of the virtual table being implemented.
|
|
*/
|
|
@@ -139171,19 +151665,6 @@ SQLITE_API int sqlite3_vtab_config(sqlite3 *db, int op, ...){
|
|
#ifndef SQLITE_WHEREINT_H
|
|
#define SQLITE_WHEREINT_H
|
|
|
|
-/*
|
|
-** Trace output macros
|
|
-*/
|
|
-#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
|
|
-/***/ extern int sqlite3WhereTrace;
|
|
-#endif
|
|
-#if defined(SQLITE_DEBUG) \
|
|
- && (defined(SQLITE_TEST) || defined(SQLITE_ENABLE_WHERETRACE))
|
|
-# define WHERETRACE(K,X) if(sqlite3WhereTrace&(K)) sqlite3DebugPrintf X
|
|
-# define WHERETRACE_ENABLED 1
|
|
-#else
|
|
-# define WHERETRACE(K,X)
|
|
-#endif
|
|
|
|
/* Forward references
|
|
*/
|
|
@@ -139199,6 +151680,28 @@ typedef struct WhereLoopBuilder WhereLoopBuilder;
|
|
typedef struct WhereScan WhereScan;
|
|
typedef struct WhereOrCost WhereOrCost;
|
|
typedef struct WhereOrSet WhereOrSet;
|
|
+typedef struct WhereMemBlock WhereMemBlock;
|
|
+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.
|
|
+*/
|
|
+struct WhereMemBlock {
|
|
+ WhereMemBlock *pNext; /* Next block in the chain */
|
|
+ u64 sz; /* Bytes of space */
|
|
+};
|
|
+
|
|
+/*
|
|
+** Extra information attached to a WhereLevel that is a RIGHT JOIN.
|
|
+*/
|
|
+struct WhereRightJoin {
|
|
+ int iMatch; /* Cursor used to determine prior matched rows */
|
|
+ int regBloom; /* Bloom filter for iRJMatch */
|
|
+ int regReturn; /* Return register for the interior subroutine */
|
|
+ int addrSubrtn; /* Starting address for the interior subroutine */
|
|
+ int endSubrtn; /* The last opcode in the interior subroutine */
|
|
+};
|
|
|
|
/*
|
|
** This object contains information needed to implement a single nested
|
|
@@ -139231,6 +151734,8 @@ struct WhereLevel {
|
|
u32 iLikeRepCntr; /* LIKE range processing counter register (times 2) */
|
|
int addrLikeRep; /* LIKE range processing address */
|
|
#endif
|
|
+ int regFilter; /* Bloom filter */
|
|
+ WhereRightJoin *pRJ; /* Extra information for RIGHT JOIN */
|
|
u8 iFrom; /* Which entry in the FROM clause */
|
|
u8 op, p3, p5; /* Opcode, P3 & P5 of the opcode that ends the loop */
|
|
int p1, p2; /* Operands of the opcode used to end the loop */
|
|
@@ -139245,7 +151750,7 @@ struct WhereLevel {
|
|
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 */
|
|
- Index *pCovidx; /* Possible covering index for WHERE_MULTI_OR */
|
|
+ Index *pCoveringIdx; /* Possible covering index for WHERE_MULTI_OR */
|
|
} u;
|
|
struct WhereLoop *pWLoop; /* The selected WhereLoop object */
|
|
Bitmask notReady; /* FROM entries not usable at this level */
|
|
@@ -139289,10 +151794,12 @@ struct WhereLoop {
|
|
} btree;
|
|
struct { /* Information for virtual tables */
|
|
int idxNum; /* Index number */
|
|
- u8 needFree; /* True if sqlite3_free(idxStr) is needed */
|
|
+ u32 needFree : 1; /* True if sqlite3_free(idxStr) is needed */
|
|
+ u32 bOmitOffset : 1; /* True to let virtual table handle offset */
|
|
i8 isOrdered; /* True if satisfies ORDER BY */
|
|
u16 omitMask; /* Terms that may be omitted */
|
|
char *idxStr; /* Index identifier string */
|
|
+ u32 mHandleIn; /* Terms to handle as IN(...) instead of == */
|
|
} vtab;
|
|
} u;
|
|
u32 wsFlags; /* WHERE_* flags describing the plan */
|
|
@@ -139308,7 +151815,7 @@ struct WhereLoop {
|
|
|
|
/* This object holds the prerequisites and the cost of running a
|
|
** subquery on one operand of an OR operator in the WHERE clause.
|
|
-** See WhereOrSet for additional information
|
|
+** See WhereOrSet for additional information
|
|
*/
|
|
struct WhereOrCost {
|
|
Bitmask prereq; /* Prerequisites */
|
|
@@ -139360,7 +151867,7 @@ struct WherePath {
|
|
** clause subexpression is separated from the others by AND operators,
|
|
** usually, or sometimes subexpressions separated by OR.
|
|
**
|
|
-** All WhereTerms are collected into a single WhereClause structure.
|
|
+** All WhereTerms are collected into a single WhereClause structure.
|
|
** The following identity holds:
|
|
**
|
|
** WhereTerm.pWC->a[WhereTerm.idx] == WhereTerm
|
|
@@ -139415,9 +151922,11 @@ struct WhereTerm {
|
|
u8 eMatchOp; /* Op for vtab MATCH/LIKE/GLOB/REGEXP terms */
|
|
int iParent; /* Disable pWC->a[iParent] when this term disabled */
|
|
int leftCursor; /* Cursor number of X in "X <op> <expr>" */
|
|
- int iField; /* Field in (?,?,?) IN (SELECT...) vector */
|
|
union {
|
|
- int leftColumn; /* Column number of X in "X <op> <expr>" */
|
|
+ struct {
|
|
+ int leftColumn; /* Column number of X in "X <op> <expr>" */
|
|
+ int iField; /* Field in (?,?,?) IN (SELECT...) vector */
|
|
+ } x; /* Opcode other than OP_OR or OP_AND */
|
|
WhereOrInfo *pOrInfo; /* Extra information if (eOperator & WO_OR)!=0 */
|
|
WhereAndInfo *pAndInfo; /* Extra information if (eOperator& WO_AND)!=0 */
|
|
} u;
|
|
@@ -139434,17 +151943,20 @@ struct WhereTerm {
|
|
#define TERM_COPIED 0x0008 /* Has a child */
|
|
#define TERM_ORINFO 0x0010 /* Need to free the WhereTerm.u.pOrInfo object */
|
|
#define TERM_ANDINFO 0x0020 /* Need to free the WhereTerm.u.pAndInfo obj */
|
|
-#define TERM_OR_OK 0x0040 /* Used during OR-clause processing */
|
|
-#ifdef SQLITE_ENABLE_STAT4
|
|
-# define TERM_VNULL 0x0080 /* Manufactured x>NULL or x<=NULL term */
|
|
-#else
|
|
-# define TERM_VNULL 0x0000 /* Disabled if not using stat4 */
|
|
-#endif
|
|
+#define TERM_OK 0x0040 /* Used during OR-clause processing */
|
|
+#define TERM_VNULL 0x0080 /* Manufactured x>NULL or x<=NULL term */
|
|
#define TERM_LIKEOPT 0x0100 /* Virtual terms from the LIKE optimization */
|
|
#define TERM_LIKECOND 0x0200 /* Conditionally this LIKE operator term */
|
|
#define TERM_LIKE 0x0400 /* The original LIKE operator */
|
|
#define TERM_IS 0x0800 /* Term.pExpr is an IS operator */
|
|
#define TERM_VARSELECT 0x1000 /* Term.pExpr contains a correlated sub-query */
|
|
+#define TERM_HEURTRUTH 0x2000 /* Heuristic truthProb used */
|
|
+#ifdef SQLITE_ENABLE_STAT4
|
|
+# define TERM_HIGHTRUTH 0x4000 /* Term excludes few rows */
|
|
+#else
|
|
+# define TERM_HIGHTRUTH 0 /* Only used with STAT4 */
|
|
+#endif
|
|
+#define TERM_SLICE 0x8000 /* One slice of a row-value/vector comparison */
|
|
|
|
/*
|
|
** An instance of the WhereScan object is used as an iterator for locating
|
|
@@ -139455,11 +151967,11 @@ struct WhereScan {
|
|
WhereClause *pWC; /* WhereClause currently being scanned */
|
|
const char *zCollName; /* Required collating sequence, if not NULL */
|
|
Expr *pIdxExpr; /* Search for this index expression */
|
|
- char idxaff; /* Must match this affinity, if zCollName!=NULL */
|
|
- unsigned char nEquiv; /* Number of entries in aEquiv[] */
|
|
- unsigned char iEquiv; /* Next unused slot in aEquiv[] */
|
|
- u32 opMask; /* Acceptable operators */
|
|
int k; /* Resume scanning at this->pWC->a[this->k] */
|
|
+ u32 opMask; /* Acceptable operators */
|
|
+ char idxaff; /* Must match this affinity, if zCollName!=NULL */
|
|
+ unsigned char iEquiv; /* Current slot in aiCur[] and aiColumn[] */
|
|
+ unsigned char nEquiv; /* Number of entries in aiCur[] and aiColumn[] */
|
|
int aiCur[11]; /* Cursors in the equivalence class */
|
|
i16 aiColumn[11]; /* Corresponding column number in the eq-class */
|
|
};
|
|
@@ -139483,6 +151995,7 @@ struct WhereClause {
|
|
u8 hasOr; /* True if any a[].eOperator is WO_OR */
|
|
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 */
|
|
#if defined(SQLITE_SMALL_STACK)
|
|
WhereTerm aStatic[1]; /* Initial static space for a[] */
|
|
@@ -139512,8 +152025,8 @@ struct WhereAndInfo {
|
|
** An instance of the following structure keeps track of a mapping
|
|
** between VDBE cursor numbers and bits of the bitmasks in WhereTerm.
|
|
**
|
|
-** The VDBE cursor numbers are small integers contained in
|
|
-** SrcList_item.iCursor and Expr.iTable fields. For any given WHERE
|
|
+** The VDBE cursor numbers are small integers contained in
|
|
+** SrcItem.iCursor and Expr.iTable fields. For any given WHERE
|
|
** clause, the cursor numbers might not begin with 0 and they might
|
|
** contain gaps in the numbering sequence. But we want to make maximum
|
|
** use of the bits in our bitmasks. This structure provides a mapping
|
|
@@ -139540,11 +152053,6 @@ struct WhereMaskSet {
|
|
int ix[BMS]; /* Cursor assigned to each bit */
|
|
};
|
|
|
|
-/*
|
|
-** Initialize a WhereMaskSet object
|
|
-*/
|
|
-#define initMaskSet(P) (P)->n=0
|
|
-
|
|
/*
|
|
** This object is a convenience wrapper holding all information needed
|
|
** to construct WhereLoop objects for a particular query.
|
|
@@ -139552,20 +152060,22 @@ struct WhereMaskSet {
|
|
struct WhereLoopBuilder {
|
|
WhereInfo *pWInfo; /* Information about this WHERE */
|
|
WhereClause *pWC; /* WHERE clause terms */
|
|
- ExprList *pOrderBy; /* ORDER BY clause */
|
|
WhereLoop *pNew; /* Template WhereLoop */
|
|
WhereOrSet *pOrSet; /* Record best loops here, if not NULL */
|
|
#ifdef SQLITE_ENABLE_STAT4
|
|
UnpackedRecord *pRec; /* Probe for stat4 (if required) */
|
|
int nRecValid; /* Number of valid fields currently in pRec */
|
|
#endif
|
|
- unsigned int bldFlags; /* SQLITE_BLDF_* flags */
|
|
+ unsigned char bldFlags1; /* First set of SQLITE_BLDF_* flags */
|
|
+ unsigned char bldFlags2; /* Second set of SQLITE_BLDF_* flags */
|
|
unsigned int iPlanLimit; /* Search limiter */
|
|
};
|
|
|
|
/* Allowed values for WhereLoopBuider.bldFlags */
|
|
-#define SQLITE_BLDF_INDEXED 0x0001 /* An index is used */
|
|
-#define SQLITE_BLDF_UNIQUE 0x0002 /* All keys of a UNIQUE index used */
|
|
+#define SQLITE_BLDF1_INDEXED 0x0001 /* An index is used */
|
|
+#define SQLITE_BLDF1_UNIQUE 0x0002 /* All keys of a UNIQUE index used */
|
|
+
|
|
+#define SQLITE_BLDF2_2NDPASS 0x0004 /* Second builder pass needed */
|
|
|
|
/* The WhereLoopBuilder.iPlanLimit is used to limit the number of
|
|
** index+constraint combinations the query planner will consider for a
|
|
@@ -139587,20 +152097,6 @@ struct WhereLoopBuilder {
|
|
# define SQLITE_QUERY_PLANNER_LIMIT_INCR 1000
|
|
#endif
|
|
|
|
-/*
|
|
-** Each instance of this object records a change to a single node
|
|
-** in an expression tree to cause that node to point to a column
|
|
-** of an index rather than an expression or a virtual column. All
|
|
-** such transformations need to be undone at the end of WHERE clause
|
|
-** processing.
|
|
-*/
|
|
-typedef struct WhereExprMod WhereExprMod;
|
|
-struct WhereExprMod {
|
|
- WhereExprMod *pNext; /* Next translation on a list of them all */
|
|
- Expr *pExpr; /* The Expr node that was transformed */
|
|
- Expr orig; /* Original value of the Expr node */
|
|
-};
|
|
-
|
|
/*
|
|
** The WHERE clause processing routine has two halves. The
|
|
** first part does the start of the WHERE loop and the second
|
|
@@ -139616,7 +152112,10 @@ struct WhereInfo {
|
|
SrcList *pTabList; /* List of tables in the join */
|
|
ExprList *pOrderBy; /* The ORDER BY clause or NULL */
|
|
ExprList *pResultSet; /* Result set of the query */
|
|
+#if WHERETRACE_ENABLED
|
|
Expr *pWhere; /* The complete WHERE clause */
|
|
+#endif
|
|
+ Select *pSelect; /* The entire SELECT statement containing WHERE */
|
|
int aiCurOnePass[2]; /* OP_OpenWrite cursors for the ONEPASS opt */
|
|
int iContinue; /* Jump here to continue with next record */
|
|
int iBreak; /* Jump here to break out of the loop */
|
|
@@ -139633,8 +152132,9 @@ struct WhereInfo {
|
|
unsigned sorted :1; /* True if really sorted (not just grouped) */
|
|
LogEst nRowOut; /* Estimated number of output rows */
|
|
int iTop; /* The very beginning of the WHERE loop */
|
|
+ int iEndWhere; /* End of the WHERE clause itself */
|
|
WhereLoop *pLoops; /* List of all WhereLoop objects */
|
|
- WhereExprMod *pExprMods; /* Expression modifications */
|
|
+ WhereMemBlock *pMemToFree;/* Memory to free when this object destroyed */
|
|
Bitmask revMask; /* Mask of ORDER BY terms that need reversing */
|
|
WhereClause sWC; /* Decomposition of the WHERE clause */
|
|
WhereMaskSet sMaskSet; /* Map cursor numbers to bitmasks */
|
|
@@ -139660,6 +152160,8 @@ SQLITE_PRIVATE WhereTerm *sqlite3WhereFindTerm(
|
|
u32 op, /* Mask of WO_xx values describing operator */
|
|
Index *pIdx /* Must be compatible with this index, if not NULL */
|
|
);
|
|
+SQLITE_PRIVATE void *sqlite3WhereMalloc(WhereInfo *pWInfo, u64 nByte);
|
|
+SQLITE_PRIVATE void *sqlite3WhereRealloc(WhereInfo *pWInfo, void *pOld, u64 nByte);
|
|
|
|
/* wherecode.c: */
|
|
#ifndef SQLITE_OMIT_EXPLAIN
|
|
@@ -139669,8 +152171,14 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan(
|
|
WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */
|
|
u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */
|
|
);
|
|
+SQLITE_PRIVATE int sqlite3WhereExplainBloomFilter(
|
|
+ const Parse *pParse, /* Parse context */
|
|
+ const WhereInfo *pWInfo, /* WHERE clause */
|
|
+ const WhereLevel *pLevel /* Bloom filter on this level */
|
|
+);
|
|
#else
|
|
# define sqlite3WhereExplainOneScan(u,v,w,x) 0
|
|
+# define sqlite3WhereExplainBloomFilter(u,v,w) 0
|
|
#endif /* SQLITE_OMIT_EXPLAIN */
|
|
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
|
|
SQLITE_PRIVATE void sqlite3WhereAddScanStatus(
|
|
@@ -139690,16 +152198,22 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
|
|
WhereLevel *pLevel, /* The current level pointer */
|
|
Bitmask notReady /* Which tables are currently available */
|
|
);
|
|
+SQLITE_PRIVATE SQLITE_NOINLINE void sqlite3WhereRightJoinLoop(
|
|
+ WhereInfo *pWInfo,
|
|
+ int iLevel,
|
|
+ WhereLevel *pLevel
|
|
+);
|
|
|
|
/* whereexpr.c: */
|
|
SQLITE_PRIVATE void sqlite3WhereClauseInit(WhereClause*,WhereInfo*);
|
|
SQLITE_PRIVATE void sqlite3WhereClauseClear(WhereClause*);
|
|
SQLITE_PRIVATE void sqlite3WhereSplit(WhereClause*,Expr*,u8);
|
|
+SQLITE_PRIVATE void sqlite3WhereAddLimit(WhereClause*, Select*);
|
|
SQLITE_PRIVATE Bitmask sqlite3WhereExprUsage(WhereMaskSet*, Expr*);
|
|
SQLITE_PRIVATE Bitmask sqlite3WhereExprUsageNN(WhereMaskSet*, Expr*);
|
|
SQLITE_PRIVATE Bitmask sqlite3WhereExprListUsage(WhereMaskSet*, ExprList*);
|
|
SQLITE_PRIVATE void sqlite3WhereExprAnalyze(SrcList*, WhereClause*);
|
|
-SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereClause*);
|
|
+SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, SrcItem*, WhereClause*);
|
|
|
|
|
|
|
|
@@ -139731,8 +152245,9 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereC
|
|
#define WO_AND 0x0400 /* Two or more AND-connected terms */
|
|
#define WO_EQUIV 0x0800 /* Of the form A==B, both columns */
|
|
#define WO_NOOP 0x1000 /* This term does not restrict search space */
|
|
+#define WO_ROWVAL 0x2000 /* A row-value term */
|
|
|
|
-#define WO_ALL 0x1fff /* Mask of all possible WO_* values */
|
|
+#define WO_ALL 0x3fff /* Mask of all possible WO_* values */
|
|
#define WO_SINGLE 0x01ff /* Mask of all non-compound WO_* values */
|
|
|
|
/*
|
|
@@ -139761,6 +152276,13 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereC
|
|
#define WHERE_PARTIALIDX 0x00020000 /* The automatic index is partial */
|
|
#define WHERE_IN_EARLYOUT 0x00040000 /* Perhaps quit IN loops early */
|
|
#define WHERE_BIGNULL_SORT 0x00080000 /* Column nEq of index is BIGNULL */
|
|
+#define WHERE_IN_SEEKSCAN 0x00100000 /* Seek-scan optimization for IN */
|
|
+#define WHERE_TRANSCONS 0x00200000 /* Uses a transitive constraint */
|
|
+#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 */
|
|
+#define WHERE_EXPRIDX 0x04000000 /* Uses an index-on-expressions */
|
|
|
|
#endif /* !defined(SQLITE_WHEREINT_H) */
|
|
|
|
@@ -139776,7 +152298,7 @@ static const char *explainIndexColumnName(Index *pIdx, int i){
|
|
i = pIdx->aiColumn[i];
|
|
if( i==XN_EXPR ) return "<expr>";
|
|
if( i==XN_ROWID ) return "rowid";
|
|
- return pIdx->pTable->aCol[i].zName;
|
|
+ return pIdx->pTable->aCol[i].zCnName;
|
|
}
|
|
|
|
/*
|
|
@@ -139818,7 +152340,7 @@ static void explainAppendTerm(
|
|
}
|
|
|
|
/*
|
|
-** Argument pLevel describes a strategy for scanning table pTab. This
|
|
+** Argument pLevel describes a strategy for scanning table pTab. This
|
|
** function appends text to pStr that describes the subset of table
|
|
** rows scanned by the strategy in the form of an SQL expression.
|
|
**
|
|
@@ -139859,7 +152381,7 @@ static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop){
|
|
/*
|
|
** This function is a no-op unless currently processing an EXPLAIN QUERY PLAN
|
|
** command, or if either SQLITE_DEBUG or SQLITE_ENABLE_STMT_SCANSTATUS was
|
|
-** defined at compile-time. If it is not a no-op, a single OP_Explain opcode
|
|
+** defined at compile-time. If it is not a no-op, a single OP_Explain opcode
|
|
** is added to the output to describe the table scan strategy in pLevel.
|
|
**
|
|
** If an OP_Explain opcode is added to the VM, its address is returned.
|
|
@@ -139876,7 +152398,7 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan(
|
|
if( sqlite3ParseToplevel(pParse)->explain==2 )
|
|
#endif
|
|
{
|
|
- struct SrcList_item *pItem = &pTabList->a[pLevel->iFrom];
|
|
+ SrcItem *pItem = &pTabList->a[pLevel->iFrom];
|
|
Vdbe *v = pParse->pVdbe; /* VM being constructed */
|
|
sqlite3 *db = pParse->db; /* Database handle */
|
|
int isSearch; /* True for a SEARCH. False for SCAN. */
|
|
@@ -139895,16 +152417,8 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan(
|
|
|| (wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX));
|
|
|
|
sqlite3StrAccumInit(&str, db, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH);
|
|
- sqlite3_str_appendall(&str, isSearch ? "SEARCH" : "SCAN");
|
|
- if( pItem->pSelect ){
|
|
- sqlite3_str_appendf(&str, " SUBQUERY %u", pItem->pSelect->selId);
|
|
- }else{
|
|
- sqlite3_str_appendf(&str, " TABLE %s", pItem->zName);
|
|
- }
|
|
-
|
|
- if( pItem->zAlias ){
|
|
- sqlite3_str_appendf(&str, " AS %s", pItem->zAlias);
|
|
- }
|
|
+ str.printfFlags = SQLITE_PRINTF_INTERNAL;
|
|
+ sqlite3_str_appendf(&str, "%s %S", isSearch ? "SEARCH" : "SCAN", pItem);
|
|
if( (flags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0 ){
|
|
const char *zFmt = 0;
|
|
Index *pIdx;
|
|
@@ -139931,19 +152445,27 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan(
|
|
explainIndexRange(&str, pLoop);
|
|
}
|
|
}else if( (flags & WHERE_IPK)!=0 && (flags & WHERE_CONSTRAINT)!=0 ){
|
|
- const char *zRangeOp;
|
|
+ char cRangeOp;
|
|
+#if 0 /* Better output, but breaks many tests */
|
|
+ const Table *pTab = pItem->pTab;
|
|
+ const char *zRowid = pTab->iPKey>=0 ? pTab->aCol[pTab->iPKey].zCnName:
|
|
+ "rowid";
|
|
+#else
|
|
+ const char *zRowid = "rowid";
|
|
+#endif
|
|
+ sqlite3_str_appendf(&str, " USING INTEGER PRIMARY KEY (%s", zRowid);
|
|
if( flags&(WHERE_COLUMN_EQ|WHERE_COLUMN_IN) ){
|
|
- zRangeOp = "=";
|
|
+ cRangeOp = '=';
|
|
}else if( (flags&WHERE_BOTH_LIMIT)==WHERE_BOTH_LIMIT ){
|
|
- zRangeOp = ">? AND rowid<";
|
|
+ sqlite3_str_appendf(&str, ">? AND %s", zRowid);
|
|
+ cRangeOp = '<';
|
|
}else if( flags&WHERE_BTM_LIMIT ){
|
|
- zRangeOp = ">";
|
|
+ cRangeOp = '>';
|
|
}else{
|
|
assert( flags&WHERE_TOP_LIMIT);
|
|
- zRangeOp = "<";
|
|
+ cRangeOp = '<';
|
|
}
|
|
- sqlite3_str_appendf(&str,
|
|
- " USING INTEGER PRIMARY KEY (rowid%s?)",zRangeOp);
|
|
+ sqlite3_str_appendf(&str, "%c?)", cRangeOp);
|
|
}
|
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
|
else if( (flags & WHERE_VIRTUALTABLE)!=0 ){
|
|
@@ -139951,6 +152473,9 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan(
|
|
pLoop->u.vtab.idxNum, pLoop->u.vtab.idxStr);
|
|
}
|
|
#endif
|
|
+ if( pItem->fg.jointype & JT_LEFT ){
|
|
+ sqlite3_str_appendf(&str, " LEFT-JOIN");
|
|
+ }
|
|
#ifdef SQLITE_EXPLAIN_ESTIMATED_ROWS
|
|
if( pLoop->nOut>=10 ){
|
|
sqlite3_str_appendf(&str, " (~%llu rows)",
|
|
@@ -139966,16 +152491,68 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan(
|
|
}
|
|
return ret;
|
|
}
|
|
+
|
|
+/*
|
|
+** Add a single OP_Explain opcode that describes a Bloom filter.
|
|
+**
|
|
+** Or if not processing EXPLAIN QUERY PLAN and not in a SQLITE_DEBUG and/or
|
|
+** SQLITE_ENABLE_STMT_SCANSTATUS build, then OP_Explain opcodes are not
|
|
+** required and this routine is a no-op.
|
|
+**
|
|
+** If an OP_Explain opcode is added to the VM, its address is returned.
|
|
+** Otherwise, if no OP_Explain is coded, zero is returned.
|
|
+*/
|
|
+SQLITE_PRIVATE int sqlite3WhereExplainBloomFilter(
|
|
+ const Parse *pParse, /* Parse context */
|
|
+ const WhereInfo *pWInfo, /* WHERE clause */
|
|
+ const WhereLevel *pLevel /* Bloom filter on this level */
|
|
+){
|
|
+ int ret = 0;
|
|
+ SrcItem *pItem = &pWInfo->pTabList->a[pLevel->iFrom];
|
|
+ Vdbe *v = pParse->pVdbe; /* VM being constructed */
|
|
+ sqlite3 *db = pParse->db; /* Database handle */
|
|
+ char *zMsg; /* Text to add to EQP output */
|
|
+ int i; /* Loop counter */
|
|
+ WhereLoop *pLoop; /* The where loop */
|
|
+ StrAccum str; /* EQP output string */
|
|
+ char zBuf[100]; /* Initial space for EQP output string */
|
|
+
|
|
+ sqlite3StrAccumInit(&str, db, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH);
|
|
+ str.printfFlags = SQLITE_PRINTF_INTERNAL;
|
|
+ sqlite3_str_appendf(&str, "BLOOM FILTER ON %S (", pItem);
|
|
+ pLoop = pLevel->pWLoop;
|
|
+ if( pLoop->wsFlags & WHERE_IPK ){
|
|
+ const Table *pTab = pItem->pTab;
|
|
+ if( pTab->iPKey>=0 ){
|
|
+ sqlite3_str_appendf(&str, "%s=?", pTab->aCol[pTab->iPKey].zCnName);
|
|
+ }else{
|
|
+ sqlite3_str_appendf(&str, "rowid=?");
|
|
+ }
|
|
+ }else{
|
|
+ for(i=pLoop->nSkip; i<pLoop->u.btree.nEq; i++){
|
|
+ const char *z = explainIndexColumnName(pLoop->u.btree.pIndex, i);
|
|
+ if( i>pLoop->nSkip ) sqlite3_str_append(&str, " AND ", 5);
|
|
+ sqlite3_str_appendf(&str, "%s=?", z);
|
|
+ }
|
|
+ }
|
|
+ sqlite3_str_append(&str, ")", 1);
|
|
+ zMsg = sqlite3StrAccumFinish(&str);
|
|
+ ret = sqlite3VdbeAddOp4(v, OP_Explain, sqlite3VdbeCurrentAddr(v),
|
|
+ pParse->addrExplain, 0, zMsg,P4_DYNAMIC);
|
|
+
|
|
+ sqlite3VdbeScanStatus(v, sqlite3VdbeCurrentAddr(v)-1, 0, 0, 0, 0);
|
|
+ return ret;
|
|
+}
|
|
#endif /* SQLITE_OMIT_EXPLAIN */
|
|
|
|
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
|
|
/*
|
|
** Configure the VM passed as the first argument with an
|
|
-** sqlite3_stmt_scanstatus() entry corresponding to the scan used to
|
|
-** implement level pLvl. Argument pSrclist is a pointer to the FROM
|
|
+** sqlite3_stmt_scanstatus() entry corresponding to the scan used to
|
|
+** implement level pLvl. Argument pSrclist is a pointer to the FROM
|
|
** clause that the scan reads data from.
|
|
**
|
|
-** If argument addrExplain is not 0, it must be the address of an
|
|
+** If argument addrExplain is not 0, it must be the address of an
|
|
** OP_Explain instruction that describes the same loop.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3WhereAddScanStatus(
|
|
@@ -139986,14 +152563,27 @@ SQLITE_PRIVATE void sqlite3WhereAddScanStatus(
|
|
){
|
|
const char *zObj = 0;
|
|
WhereLoop *pLoop = pLvl->pWLoop;
|
|
- if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 && pLoop->u.btree.pIndex!=0 ){
|
|
+ int wsFlags = pLoop->wsFlags;
|
|
+ int viaCoroutine = 0;
|
|
+
|
|
+ if( (wsFlags & WHERE_VIRTUALTABLE)==0 && pLoop->u.btree.pIndex!=0 ){
|
|
zObj = pLoop->u.btree.pIndex->zName;
|
|
}else{
|
|
zObj = pSrclist->a[pLvl->iFrom].zName;
|
|
+ viaCoroutine = pSrclist->a[pLvl->iFrom].fg.viaCoroutine;
|
|
}
|
|
sqlite3VdbeScanStatus(
|
|
v, addrExplain, pLvl->addrBody, pLvl->addrVisit, pLoop->nOut, zObj
|
|
);
|
|
+
|
|
+ if( viaCoroutine==0 ){
|
|
+ if( (wsFlags & (WHERE_MULTI_OR|WHERE_AUTO_INDEX))==0 ){
|
|
+ sqlite3VdbeScanStatusRange(v, addrExplain, -1, pLvl->iTabCur);
|
|
+ }
|
|
+ if( wsFlags & WHERE_INDEXED ){
|
|
+ sqlite3VdbeScanStatusRange(v, addrExplain, -1, pLvl->iIdxCur);
|
|
+ }
|
|
+ }
|
|
}
|
|
#endif
|
|
|
|
@@ -140031,7 +152621,7 @@ SQLITE_PRIVATE void sqlite3WhereAddScanStatus(
|
|
**
|
|
** Only the parent term was in the original WHERE clause. The child1
|
|
** and child2 terms were added by the LIKE optimization. If both of
|
|
-** the virtual child terms are valid, then testing of the parent can be
|
|
+** the virtual child terms are valid, then testing of the parent can be
|
|
** skipped.
|
|
**
|
|
** Usually the parent term is marked as TERM_CODED. But if the parent
|
|
@@ -140044,7 +152634,7 @@ static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
|
|
int nLoop = 0;
|
|
assert( pTerm!=0 );
|
|
while( (pTerm->wtFlags & TERM_CODED)==0
|
|
- && (pLevel->iLeftJoin==0 || ExprHasProperty(pTerm->pExpr, EP_FromJoin))
|
|
+ && (pLevel->iLeftJoin==0 || ExprHasProperty(pTerm->pExpr, EP_OuterON))
|
|
&& (pLevel->notReady & pTerm->prereqAll)==0
|
|
){
|
|
if( nLoop && (pTerm->wtFlags & TERM_LIKE)!=0 ){
|
|
@@ -140052,6 +152642,12 @@ static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
|
|
}else{
|
|
pTerm->wtFlags |= TERM_CODED;
|
|
}
|
|
+#ifdef WHERETRACE_ENABLED
|
|
+ if( (sqlite3WhereTrace & 0x4001)==0x4001 ){
|
|
+ sqlite3DebugPrintf("DISABLE-");
|
|
+ sqlite3WhereTermPrint(pTerm, (int)(pTerm - (pTerm->pWC->a)));
|
|
+ }
|
|
+#endif
|
|
if( pTerm->iParent<0 ) break;
|
|
pTerm = &pTerm->pWC->a[pTerm->iParent];
|
|
assert( pTerm!=0 );
|
|
@@ -140063,7 +152659,7 @@ static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
|
|
|
|
/*
|
|
** Code an OP_Affinity opcode to apply the column affinity string zAff
|
|
-** to the n registers starting at base.
|
|
+** to the n registers starting at base.
|
|
**
|
|
** As an optimization, SQLITE_AFF_BLOB and SQLITE_AFF_NONE entries (which
|
|
** are no-ops) at the beginning and end of zAff are ignored. If all entries
|
|
@@ -140100,7 +152696,7 @@ static void codeApplyAffinity(Parse *pParse, int base, int n, char *zAff){
|
|
}
|
|
|
|
/*
|
|
-** Expression pRight, which is the RHS of a comparison operation, is
|
|
+** Expression pRight, which is the RHS of a comparison operation, is
|
|
** either a vector of n elements or, if n==1, a scalar expression.
|
|
** Before the comparison operation, affinity zAff is to be applied
|
|
** to the pRight values. This function modifies characters within the
|
|
@@ -140162,61 +152758,75 @@ static Expr *removeUnindexableInClauseTerms(
|
|
Expr *pX /* The IN expression to be reduced */
|
|
){
|
|
sqlite3 *db = pParse->db;
|
|
+ Select *pSelect; /* Pointer to the SELECT on the RHS */
|
|
Expr *pNew;
|
|
pNew = sqlite3ExprDup(db, pX, 0);
|
|
if( db->mallocFailed==0 ){
|
|
- ExprList *pOrigRhs = pNew->x.pSelect->pEList; /* Original unmodified RHS */
|
|
- ExprList *pOrigLhs = pNew->pLeft->x.pList; /* Original unmodified LHS */
|
|
- ExprList *pRhs = 0; /* New RHS after modifications */
|
|
- ExprList *pLhs = 0; /* New LHS after mods */
|
|
- int i; /* Loop counter */
|
|
- Select *pSelect; /* Pointer to the SELECT on the RHS */
|
|
-
|
|
- for(i=iEq; i<pLoop->nLTerm; i++){
|
|
- if( pLoop->aLTerm[i]->pExpr==pX ){
|
|
- int iField = pLoop->aLTerm[i]->iField - 1;
|
|
- if( pOrigRhs->a[iField].pExpr==0 ) continue; /* Duplicate PK column */
|
|
- pRhs = sqlite3ExprListAppend(pParse, pRhs, pOrigRhs->a[iField].pExpr);
|
|
- pOrigRhs->a[iField].pExpr = 0;
|
|
- assert( pOrigLhs->a[iField].pExpr!=0 );
|
|
- pLhs = sqlite3ExprListAppend(pParse, pLhs, pOrigLhs->a[iField].pExpr);
|
|
- pOrigLhs->a[iField].pExpr = 0;
|
|
- }
|
|
- }
|
|
- sqlite3ExprListDelete(db, pOrigRhs);
|
|
- sqlite3ExprListDelete(db, pOrigLhs);
|
|
- pNew->pLeft->x.pList = pLhs;
|
|
- pNew->x.pSelect->pEList = pRhs;
|
|
- if( pLhs && pLhs->nExpr==1 ){
|
|
- /* Take care here not to generate a TK_VECTOR containing only a
|
|
- ** single value. Since the parser never creates such a vector, some
|
|
- ** of the subroutines do not handle this case. */
|
|
- Expr *p = pLhs->a[0].pExpr;
|
|
- pLhs->a[0].pExpr = 0;
|
|
- sqlite3ExprDelete(db, pNew->pLeft);
|
|
- pNew->pLeft = p;
|
|
- }
|
|
- pSelect = pNew->x.pSelect;
|
|
- if( pSelect->pOrderBy ){
|
|
- /* If the SELECT statement has an ORDER BY clause, zero the
|
|
- ** iOrderByCol variables. These are set to non-zero when an
|
|
- ** ORDER BY term exactly matches one of the terms of the
|
|
- ** result-set. Since the result-set of the SELECT statement may
|
|
- ** have been modified or reordered, these variables are no longer
|
|
- ** set correctly. Since setting them is just an optimization,
|
|
- ** it's easiest just to zero them here. */
|
|
- ExprList *pOrderBy = pSelect->pOrderBy;
|
|
- for(i=0; i<pOrderBy->nExpr; i++){
|
|
- pOrderBy->a[i].u.x.iOrderByCol = 0;
|
|
+ for(pSelect=pNew->x.pSelect; pSelect; pSelect=pSelect->pPrior){
|
|
+ ExprList *pOrigRhs; /* Original unmodified RHS */
|
|
+ ExprList *pOrigLhs = 0; /* Original unmodified LHS */
|
|
+ ExprList *pRhs = 0; /* New RHS after modifications */
|
|
+ ExprList *pLhs = 0; /* New LHS after mods */
|
|
+ int i; /* Loop counter */
|
|
+
|
|
+ assert( ExprUseXSelect(pNew) );
|
|
+ pOrigRhs = pSelect->pEList;
|
|
+ assert( pNew->pLeft!=0 );
|
|
+ assert( ExprUseXList(pNew->pLeft) );
|
|
+ if( pSelect==pNew->x.pSelect ){
|
|
+ pOrigLhs = pNew->pLeft->x.pList;
|
|
+ }
|
|
+ for(i=iEq; i<pLoop->nLTerm; i++){
|
|
+ if( pLoop->aLTerm[i]->pExpr==pX ){
|
|
+ int iField;
|
|
+ assert( (pLoop->aLTerm[i]->eOperator & (WO_OR|WO_AND))==0 );
|
|
+ iField = pLoop->aLTerm[i]->u.x.iField - 1;
|
|
+ if( pOrigRhs->a[iField].pExpr==0 ) continue; /* Duplicate PK column */
|
|
+ pRhs = sqlite3ExprListAppend(pParse, pRhs, pOrigRhs->a[iField].pExpr);
|
|
+ pOrigRhs->a[iField].pExpr = 0;
|
|
+ if( pOrigLhs ){
|
|
+ assert( pOrigLhs->a[iField].pExpr!=0 );
|
|
+ pLhs = sqlite3ExprListAppend(pParse,pLhs,pOrigLhs->a[iField].pExpr);
|
|
+ pOrigLhs->a[iField].pExpr = 0;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ sqlite3ExprListDelete(db, pOrigRhs);
|
|
+ if( pOrigLhs ){
|
|
+ sqlite3ExprListDelete(db, pOrigLhs);
|
|
+ pNew->pLeft->x.pList = pLhs;
|
|
+ }
|
|
+ pSelect->pEList = pRhs;
|
|
+ if( pLhs && pLhs->nExpr==1 ){
|
|
+ /* Take care here not to generate a TK_VECTOR containing only a
|
|
+ ** single value. Since the parser never creates such a vector, some
|
|
+ ** of the subroutines do not handle this case. */
|
|
+ Expr *p = pLhs->a[0].pExpr;
|
|
+ pLhs->a[0].pExpr = 0;
|
|
+ sqlite3ExprDelete(db, pNew->pLeft);
|
|
+ pNew->pLeft = p;
|
|
+ }
|
|
+ if( pSelect->pOrderBy ){
|
|
+ /* If the SELECT statement has an ORDER BY clause, zero the
|
|
+ ** iOrderByCol variables. These are set to non-zero when an
|
|
+ ** ORDER BY term exactly matches one of the terms of the
|
|
+ ** result-set. Since the result-set of the SELECT statement may
|
|
+ ** have been modified or reordered, these variables are no longer
|
|
+ ** set correctly. Since setting them is just an optimization,
|
|
+ ** it's easiest just to zero them here. */
|
|
+ ExprList *pOrderBy = pSelect->pOrderBy;
|
|
+ for(i=0; i<pOrderBy->nExpr; i++){
|
|
+ pOrderBy->a[i].u.x.iOrderByCol = 0;
|
|
+ }
|
|
}
|
|
- }
|
|
|
|
#if 0
|
|
- printf("For indexing, change the IN expr:\n");
|
|
- sqlite3TreeViewExpr(0, pX, 0);
|
|
- printf("Into:\n");
|
|
- sqlite3TreeViewExpr(0, pNew, 0);
|
|
+ printf("For indexing, change the IN expr:\n");
|
|
+ sqlite3TreeViewExpr(0, pX, 0);
|
|
+ printf("Into:\n");
|
|
+ sqlite3TreeViewExpr(0, pNew, 0);
|
|
#endif
|
|
+ }
|
|
}
|
|
return pNew;
|
|
}
|
|
@@ -140224,7 +152834,7 @@ static Expr *removeUnindexableInClauseTerms(
|
|
|
|
/*
|
|
** Generate code for a single equality term of the WHERE clause. An equality
|
|
-** term can be either X=expr or X IN (...). pTerm is the term to be
|
|
+** term can be either X=expr or X IN (...). pTerm is the term to be
|
|
** coded.
|
|
**
|
|
** The current value for the constraint is left in a register, the index
|
|
@@ -140289,19 +152899,25 @@ static int codeEqualityTerm(
|
|
}
|
|
|
|
iTab = 0;
|
|
- if( (pX->flags & EP_xIsSelect)==0 || pX->x.pSelect->pEList->nExpr==1 ){
|
|
+ if( !ExprUseXSelect(pX) || pX->x.pSelect->pEList->nExpr==1 ){
|
|
eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, 0, &iTab);
|
|
}else{
|
|
- sqlite3 *db = pParse->db;
|
|
- pX = removeUnindexableInClauseTerms(pParse, iEq, pLoop, pX);
|
|
-
|
|
- if( !db->mallocFailed ){
|
|
- aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*nEq);
|
|
+ Expr *pExpr = pTerm->pExpr;
|
|
+ if( pExpr->iTable==0 || !ExprHasProperty(pExpr, EP_Subrtn) ){
|
|
+ sqlite3 *db = pParse->db;
|
|
+ pX = removeUnindexableInClauseTerms(pParse, iEq, pLoop, pX);
|
|
+ if( !db->mallocFailed ){
|
|
+ aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*nEq);
|
|
+ eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap,&iTab);
|
|
+ pExpr->iTable = iTab;
|
|
+ }
|
|
+ sqlite3ExprDelete(db, pX);
|
|
+ }else{
|
|
+ int n = sqlite3ExprVectorSize(pX->pLeft);
|
|
+ aiMap = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*MAX(nEq,n));
|
|
eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0, aiMap, &iTab);
|
|
- pTerm->pExpr->iTable = iTab;
|
|
}
|
|
- sqlite3ExprDelete(db, pX);
|
|
- pX = pTerm->pExpr;
|
|
+ pX = pExpr;
|
|
}
|
|
|
|
if( eType==IN_INDEX_INDEX_DESC ){
|
|
@@ -140311,18 +152927,22 @@ static int codeEqualityTerm(
|
|
sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iTab, 0);
|
|
VdbeCoverageIf(v, bRev);
|
|
VdbeCoverageIf(v, !bRev);
|
|
- assert( (pLoop->wsFlags & WHERE_MULTI_OR)==0 );
|
|
|
|
+ assert( (pLoop->wsFlags & WHERE_MULTI_OR)==0 );
|
|
pLoop->wsFlags |= WHERE_IN_ABLE;
|
|
if( pLevel->u.in.nIn==0 ){
|
|
pLevel->addrNxt = sqlite3VdbeMakeLabel(pParse);
|
|
}
|
|
+ if( iEq>0 && (pLoop->wsFlags & WHERE_IN_SEEKSCAN)==0 ){
|
|
+ pLoop->wsFlags |= WHERE_IN_EARLYOUT;
|
|
+ }
|
|
|
|
i = pLevel->u.in.nIn;
|
|
pLevel->u.in.nIn += nEq;
|
|
pLevel->u.in.aInLoop =
|
|
- sqlite3DbReallocOrFree(pParse->db, pLevel->u.in.aInLoop,
|
|
- sizeof(pLevel->u.in.aInLoop[0])*pLevel->u.in.nIn);
|
|
+ sqlite3WhereRealloc(pTerm->pWC->pWInfo,
|
|
+ pLevel->u.in.aInLoop,
|
|
+ sizeof(pLevel->u.in.aInLoop[0])*pLevel->u.in.nIn);
|
|
pIn = pLevel->u.in.aInLoop;
|
|
if( pIn ){
|
|
int iMap = 0; /* Index in aiMap[] */
|
|
@@ -140343,7 +152963,6 @@ static int codeEqualityTerm(
|
|
if( iEq>0 ){
|
|
pIn->iBase = iReg - i;
|
|
pIn->nPrefix = i;
|
|
- pLoop->wsFlags |= WHERE_IN_EARLYOUT;
|
|
}else{
|
|
pIn->nPrefix = 0;
|
|
}
|
|
@@ -140353,13 +152972,36 @@ static int codeEqualityTerm(
|
|
pIn++;
|
|
}
|
|
}
|
|
+ testcase( iEq>0
|
|
+ && (pLoop->wsFlags & WHERE_IN_SEEKSCAN)==0
|
|
+ && (pLoop->wsFlags & WHERE_VIRTUALTABLE)!=0 );
|
|
+ if( iEq>0
|
|
+ && (pLoop->wsFlags & (WHERE_IN_SEEKSCAN|WHERE_VIRTUALTABLE))==0
|
|
+ ){
|
|
+ sqlite3VdbeAddOp3(v, OP_SeekHit, pLevel->iIdxCur, 0, iEq);
|
|
+ }
|
|
}else{
|
|
pLevel->u.in.nIn = 0;
|
|
}
|
|
sqlite3DbFree(pParse->db, aiMap);
|
|
#endif
|
|
}
|
|
- disableTerm(pLevel, pTerm);
|
|
+
|
|
+ /* As an optimization, try to disable the WHERE clause term that is
|
|
+ ** driving the index as it will always be true. The correct answer is
|
|
+ ** obtained regardless, but we might get the answer with fewer CPU cycles
|
|
+ ** by omitting the term.
|
|
+ **
|
|
+ ** But do not disable the term unless we are certain that the term is
|
|
+ ** not a transitive constraint. For an example of where that does not
|
|
+ ** work, see https://sqlite.org/forum/forumpost/eb8613976a (2021-05-04)
|
|
+ */
|
|
+ if( (pLevel->pWLoop->wsFlags & WHERE_TRANSCONS)==0
|
|
+ || (pTerm->eOperator & WO_EQUIV)==0
|
|
+ ){
|
|
+ disableTerm(pLevel, pTerm);
|
|
+ }
|
|
+
|
|
return iReg;
|
|
}
|
|
|
|
@@ -140370,7 +153012,7 @@ static int codeEqualityTerm(
|
|
** For example, consider table t1(a,b,c,d,e,f) with index i1(a,b,c).
|
|
** Suppose the WHERE clause is this: a==5 AND b IN (1,2,3) AND c>5 AND c<10
|
|
** The index has as many as three equality constraints, but in this
|
|
-** example, the third "c" value is an inequality. So only two
|
|
+** example, the third "c" value is an inequality. So only two
|
|
** constraints are coded. This routine will generate code to evaluate
|
|
** a==5 and b IN (1,2,3). The current values for a and b will be stored
|
|
** in consecutive registers and the index of the first register is returned.
|
|
@@ -140445,11 +153087,13 @@ static int codeAllEqualityTerms(
|
|
|
|
if( nSkip ){
|
|
int iIdxCur = pLevel->iIdxCur;
|
|
+ sqlite3VdbeAddOp3(v, OP_Null, 0, regBase, regBase+nSkip-1);
|
|
sqlite3VdbeAddOp1(v, (bRev?OP_Last:OP_Rewind), iIdxCur);
|
|
VdbeCoverageIf(v, bRev==0);
|
|
VdbeCoverageIf(v, bRev!=0);
|
|
VdbeComment((v, "begin skip-scan on %s", pIdx->zName));
|
|
j = sqlite3VdbeAddOp0(v, OP_Goto);
|
|
+ assert( pLevel->addrSkip==0 );
|
|
pLevel->addrSkip = sqlite3VdbeAddOp4Int(v, (bRev?OP_SeekLT:OP_SeekGT),
|
|
iIdxCur, 0, regBase, nSkip);
|
|
VdbeCoverageIf(v, bRev==0);
|
|
@@ -140460,7 +153104,7 @@ static int codeAllEqualityTerms(
|
|
testcase( pIdx->aiColumn[j]==XN_EXPR );
|
|
VdbeComment((v, "%s", explainIndexColumnName(pIdx, j)));
|
|
}
|
|
- }
|
|
+ }
|
|
|
|
/* Evaluate the equality constraints
|
|
*/
|
|
@@ -140469,7 +153113,7 @@ static int codeAllEqualityTerms(
|
|
int r1;
|
|
pTerm = pLoop->aLTerm[j];
|
|
assert( pTerm!=0 );
|
|
- /* The following testcase is true for indices with redundant columns.
|
|
+ /* The following testcase is true for indices with redundant columns.
|
|
** Ex: CREATE INDEX i1 ON t1(a,b,a); SELECT * FROM t1 WHERE a=0 AND b=0; */
|
|
testcase( (pTerm->wtFlags & TERM_CODED)!=0 );
|
|
testcase( pTerm->wtFlags & TERM_VIRTUAL );
|
|
@@ -140479,14 +153123,17 @@ static int codeAllEqualityTerms(
|
|
sqlite3ReleaseTempReg(pParse, regBase);
|
|
regBase = r1;
|
|
}else{
|
|
- sqlite3VdbeAddOp2(v, OP_SCopy, r1, regBase+j);
|
|
+ sqlite3VdbeAddOp2(v, OP_Copy, r1, regBase+j);
|
|
}
|
|
}
|
|
+ }
|
|
+ for(j=nSkip; j<nEq; j++){
|
|
+ pTerm = pLoop->aLTerm[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
|
|
- ** from the RHS of an "? IN (SELECT ...)" expression. The
|
|
- ** sqlite3FindInIndex() routine has already ensured that the
|
|
+ ** from the RHS of an "? IN (SELECT ...)" expression. The
|
|
+ ** sqlite3FindInIndex() routine has already ensured that the
|
|
** affinity of the comparison has been applied to the value. */
|
|
if( zAff ) zAff[j] = SQLITE_AFF_BLOB;
|
|
}
|
|
@@ -140496,7 +153143,8 @@ static int codeAllEqualityTerms(
|
|
sqlite3VdbeAddOp2(v, OP_IsNull, regBase+j, pLevel->addrBrk);
|
|
VdbeCoverage(v);
|
|
}
|
|
- if( zAff ){
|
|
+ if( pParse->nErr==0 ){
|
|
+ assert( pParse->db->mallocFailed==0 );
|
|
if( sqlite3CompareAffinity(pRight, zAff[j])==SQLITE_AFF_BLOB ){
|
|
zAff[j] = SQLITE_AFF_BLOB;
|
|
}
|
|
@@ -140513,7 +153161,7 @@ static int codeAllEqualityTerms(
|
|
#ifndef SQLITE_LIKE_DOESNT_MATCH_BLOBS
|
|
/*
|
|
** If the most recently coded instruction is a constant range constraint
|
|
-** (a string literal) that originated from the LIKE optimization, then
|
|
+** (a string literal) that originated from the LIKE optimization, then
|
|
** set P3 and P5 on the OP_String opcode so that the string will be cast
|
|
** to a BLOB at appropriate times.
|
|
**
|
|
@@ -140536,9 +153184,9 @@ static void whereLikeOptimizationStringFixup(
|
|
if( pTerm->wtFlags & TERM_LIKEOPT ){
|
|
VdbeOp *pOp;
|
|
assert( pLevel->iLikeRepCntr>0 );
|
|
- pOp = sqlite3VdbeGetOp(v, -1);
|
|
+ pOp = sqlite3VdbeGetLastOp(v);
|
|
assert( pOp!=0 );
|
|
- assert( pOp->opcode==OP_String8
|
|
+ assert( pOp->opcode==OP_String8
|
|
|| pTerm->pWC->pWInfo->pParse->db->mallocFailed );
|
|
pOp->p3 = (int)(pLevel->iLikeRepCntr>>1); /* Register holding counter */
|
|
pOp->p5 = (u8)(pLevel->iLikeRepCntr&1); /* ASC or DESC */
|
|
@@ -140581,7 +153229,7 @@ static int codeCursorHintCheckExpr(Walker *pWalker, Expr *pExpr){
|
|
/*
|
|
** Test whether or not expression pExpr, which was part of a WHERE clause,
|
|
** should be included in the cursor-hint for a table that is on the rhs
|
|
-** of a LEFT JOIN. Set Walker.eCode to non-zero before returning if the
|
|
+** of a LEFT JOIN. Set Walker.eCode to non-zero before returning if the
|
|
** expression is not suitable.
|
|
**
|
|
** An expression is unsuitable if it might evaluate to non NULL even if
|
|
@@ -140594,9 +153242,9 @@ static int codeCursorHintCheckExpr(Walker *pWalker, Expr *pExpr){
|
|
** CASE WHEN col THEN 0 ELSE 1 END
|
|
*/
|
|
static int codeCursorHintIsOrFunction(Walker *pWalker, Expr *pExpr){
|
|
- if( pExpr->op==TK_IS
|
|
- || pExpr->op==TK_ISNULL || pExpr->op==TK_ISNOT
|
|
- || pExpr->op==TK_NOTNULL || pExpr->op==TK_CASE
|
|
+ if( pExpr->op==TK_IS
|
|
+ || pExpr->op==TK_ISNULL || pExpr->op==TK_ISNOT
|
|
+ || pExpr->op==TK_NOTNULL || pExpr->op==TK_CASE
|
|
){
|
|
pWalker->eCode = 1;
|
|
}else if( pExpr->op==TK_FUNCTION ){
|
|
@@ -140617,10 +153265,10 @@ static int codeCursorHintIsOrFunction(Walker *pWalker, Expr *pExpr){
|
|
** that accesses any table other than the one identified by
|
|
** CCurHint.iTabCur, then do the following:
|
|
**
|
|
-** 1) allocate a register and code an OP_Column instruction to read
|
|
+** 1) allocate a register and code an OP_Column instruction to read
|
|
** the specified column into the new register, and
|
|
**
|
|
-** 2) transform the expression node to a TK_REGISTER node that reads
|
|
+** 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
|
|
@@ -140648,7 +153296,7 @@ static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){
|
|
** 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
|
|
+ ** expression, as the result of the expression must be stored in a
|
|
** register at this point. The same holds for TK_AGG_COLUMN nodes. */
|
|
rc = WRC_Prune;
|
|
}
|
|
@@ -140659,7 +153307,7 @@ static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){
|
|
** Insert an OP_CursorHint instruction if it is appropriate to do so.
|
|
*/
|
|
static void codeCursorHint(
|
|
- struct SrcList_item *pTabItem, /* FROM clause item */
|
|
+ SrcItem *pTabItem, /* FROM clause item */
|
|
WhereInfo *pWInfo, /* The where clause */
|
|
WhereLevel *pLevel, /* Which loop to provide hints for */
|
|
WhereTerm *pEndRange /* Hint this end-of-scan boundary term if not NULL */
|
|
@@ -140686,23 +153334,23 @@ static void codeCursorHint(
|
|
sWalker.pParse = pParse;
|
|
sWalker.u.pCCurHint = &sHint;
|
|
pWC = &pWInfo->sWC;
|
|
- for(i=0; i<pWC->nTerm; i++){
|
|
+ for(i=0; i<pWC->nBase; i++){
|
|
pTerm = &pWC->a[i];
|
|
if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
|
|
if( pTerm->prereqAll & pLevel->notReady ) continue;
|
|
|
|
- /* Any terms specified as part of the ON(...) clause for any LEFT
|
|
+ /* Any terms specified as part of the ON(...) clause for any LEFT
|
|
** JOIN for which the current table is not the rhs are omitted
|
|
- ** from the cursor-hint.
|
|
+ ** from the cursor-hint.
|
|
**
|
|
- ** If this table is the rhs of a LEFT JOIN, "IS" or "IS NULL" terms
|
|
+ ** If this table is the rhs of a LEFT JOIN, "IS" or "IS NULL" terms
|
|
** that were specified as part of the WHERE clause must be excluded.
|
|
** This is to address the following:
|
|
**
|
|
** SELECT ... t1 LEFT JOIN t2 ON (t1.a=t2.b) WHERE t2.c IS NULL;
|
|
**
|
|
** Say there is a single row in t2 that matches (t1.a=t2.b), but its
|
|
- ** t2.c values is not NULL. If the (t2.c IS NULL) constraint is
|
|
+ ** t2.c values is not NULL. If the (t2.c IS NULL) constraint is
|
|
** pushed down to the cursor, this row is filtered out, causing
|
|
** SQLite to synthesize a row of NULL values. Which does match the
|
|
** WHERE clause, and so the query returns a row. Which is incorrect.
|
|
@@ -140715,8 +153363,8 @@ static void codeCursorHint(
|
|
*/
|
|
if( pTabItem->fg.jointype & JT_LEFT ){
|
|
Expr *pExpr = pTerm->pExpr;
|
|
- if( !ExprHasProperty(pExpr, EP_FromJoin)
|
|
- || pExpr->iRightJoinTable!=pTabItem->iCursor
|
|
+ if( !ExprHasProperty(pExpr, EP_OuterON)
|
|
+ || pExpr->w.iJoin!=pTabItem->iCursor
|
|
){
|
|
sWalker.eCode = 0;
|
|
sWalker.xExprCallback = codeCursorHintIsOrFunction;
|
|
@@ -140724,7 +153372,7 @@ static void codeCursorHint(
|
|
if( sWalker.eCode ) continue;
|
|
}
|
|
}else{
|
|
- if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) continue;
|
|
+ if( ExprHasProperty(pTerm->pExpr, EP_OuterON) ) continue;
|
|
}
|
|
|
|
/* All terms in pWLoop->aLTerm[] except pEndRange are used to initialize
|
|
@@ -140753,7 +153401,7 @@ static void codeCursorHint(
|
|
if( pExpr!=0 ){
|
|
sWalker.xExprCallback = codeCursorHintFixExpr;
|
|
sqlite3WalkExpr(&sWalker, pExpr);
|
|
- sqlite3VdbeAddOp4(v, OP_CursorHint,
|
|
+ sqlite3VdbeAddOp4(v, OP_CursorHint,
|
|
(sHint.pIdx ? sHint.iIdxCur : sHint.iTabCur), 0, 0,
|
|
(const char*)pExpr, P4_EXPR);
|
|
}
|
|
@@ -140765,20 +153413,28 @@ static void codeCursorHint(
|
|
/*
|
|
** Cursor iCur is open on an intkey b-tree (a table). Register iRowid contains
|
|
** a rowid value just read from cursor iIdxCur, open on index pIdx. This
|
|
-** function generates code to do a deferred seek of cursor iCur to the
|
|
+** function generates code to do a deferred seek of cursor iCur to the
|
|
** rowid stored in register iRowid.
|
|
**
|
|
** Normally, this is just:
|
|
**
|
|
** OP_DeferredSeek $iCur $iRowid
|
|
**
|
|
+** Which causes a seek on $iCur to the row with rowid $iRowid.
|
|
+**
|
|
** However, if the scan currently being coded is a branch of an OR-loop and
|
|
-** the statement currently being coded is a SELECT, then P3 of OP_DeferredSeek
|
|
-** is set to iIdxCur and P4 is set to point to an array of integers
|
|
-** containing one entry for each column of the table cursor iCur is open
|
|
-** on. For each table column, if the column is the i'th column of the
|
|
-** index, then the corresponding array entry is set to (i+1). If the column
|
|
-** does not appear in the index at all, the array entry is set to 0.
|
|
+** the statement currently being coded is a SELECT, then additional information
|
|
+** is added that might allow OP_Column to omit the seek and instead do its
|
|
+** lookup on the index, thus avoiding an expensive seek operation. To
|
|
+** enable this optimization, the P3 of OP_DeferredSeek is set to iIdxCur
|
|
+** and P4 is set to an array of integers containing one entry for each column
|
|
+** in the table. For each table column, if the column is the i'th
|
|
+** column of the index, then the corresponding array entry is set to (i+1).
|
|
+** If the column does not appear in the index at all, the array entry is set
|
|
+** to 0. The OP_Column opcode can check this array to see if the column it
|
|
+** wants is in the index and if it is, it will substitute the index cursor
|
|
+** and column number and continue with those new values, rather than seeking
|
|
+** the table cursor.
|
|
*/
|
|
static void codeDeferredSeek(
|
|
WhereInfo *pWInfo, /* Where clause context */
|
|
@@ -140791,15 +153447,15 @@ static void codeDeferredSeek(
|
|
|
|
assert( iIdxCur>0 );
|
|
assert( pIdx->aiColumn[pIdx->nColumn-1]==-1 );
|
|
-
|
|
+
|
|
pWInfo->bDeferredSeek = 1;
|
|
sqlite3VdbeAddOp3(v, OP_DeferredSeek, iIdxCur, 0, iCur);
|
|
- if( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)
|
|
+ if( (pWInfo->wctrlFlags & (WHERE_OR_SUBCLAUSE|WHERE_RIGHT_JOIN))
|
|
&& DbMaskAllZero(sqlite3ParseToplevel(pParse)->writeMask)
|
|
){
|
|
int i;
|
|
Table *pTab = pIdx->pTable;
|
|
- int *ai = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*(pTab->nCol+1));
|
|
+ u32 *ai = (u32*)sqlite3DbMallocZero(pParse->db, sizeof(u32)*(pTab->nCol+1));
|
|
if( ai ){
|
|
ai[0] = pTab->nCol;
|
|
for(i=0; i<pIdx->nColumn-1; i++){
|
|
@@ -140828,7 +153484,7 @@ static void codeExprOrVector(Parse *pParse, Expr *p, int iReg, int nReg){
|
|
assert( nReg>0 );
|
|
if( p && sqlite3ExprIsVector(p) ){
|
|
#ifndef SQLITE_OMIT_SUBQUERY
|
|
- if( (p->flags & EP_xIsSelect) ){
|
|
+ if( ExprUseXSelect(p) ){
|
|
Vdbe *v = pParse->pVdbe;
|
|
int iSelect;
|
|
assert( p->op==TK_SELECT );
|
|
@@ -140838,154 +153494,20 @@ static void codeExprOrVector(Parse *pParse, Expr *p, int iReg, int nReg){
|
|
#endif
|
|
{
|
|
int i;
|
|
- ExprList *pList = p->x.pList;
|
|
+ const ExprList *pList;
|
|
+ assert( ExprUseXList(p) );
|
|
+ pList = p->x.pList;
|
|
assert( nReg<=pList->nExpr );
|
|
for(i=0; i<nReg; i++){
|
|
sqlite3ExprCode(pParse, pList->a[i].pExpr, iReg+i);
|
|
}
|
|
}
|
|
}else{
|
|
- assert( nReg==1 );
|
|
+ assert( nReg==1 || pParse->nErr );
|
|
sqlite3ExprCode(pParse, p, iReg);
|
|
}
|
|
}
|
|
|
|
-/* An instance of the IdxExprTrans object carries information about a
|
|
-** mapping from an expression on table columns into a column in an index
|
|
-** down through the Walker.
|
|
-*/
|
|
-typedef struct IdxExprTrans {
|
|
- Expr *pIdxExpr; /* The index expression */
|
|
- int iTabCur; /* The cursor of the corresponding table */
|
|
- int iIdxCur; /* The cursor for the index */
|
|
- int iIdxCol; /* The column for the index */
|
|
- int iTabCol; /* The column for the table */
|
|
- WhereInfo *pWInfo; /* Complete WHERE clause information */
|
|
- sqlite3 *db; /* Database connection (for malloc()) */
|
|
-} IdxExprTrans;
|
|
-
|
|
-/*
|
|
-** Preserve pExpr on the WhereETrans list of the WhereInfo.
|
|
-*/
|
|
-static void preserveExpr(IdxExprTrans *pTrans, Expr *pExpr){
|
|
- WhereExprMod *pNew;
|
|
- pNew = sqlite3DbMallocRaw(pTrans->db, sizeof(*pNew));
|
|
- if( pNew==0 ) return;
|
|
- pNew->pNext = pTrans->pWInfo->pExprMods;
|
|
- pTrans->pWInfo->pExprMods = pNew;
|
|
- pNew->pExpr = pExpr;
|
|
- memcpy(&pNew->orig, pExpr, sizeof(*pExpr));
|
|
-}
|
|
-
|
|
-/* The walker node callback used to transform matching expressions into
|
|
-** a reference to an index column for an index on an expression.
|
|
-**
|
|
-** If pExpr matches, then transform it into a reference to the index column
|
|
-** that contains the value of pExpr.
|
|
-*/
|
|
-static int whereIndexExprTransNode(Walker *p, Expr *pExpr){
|
|
- IdxExprTrans *pX = p->u.pIdxTrans;
|
|
- if( sqlite3ExprCompare(0, pExpr, pX->pIdxExpr, pX->iTabCur)==0 ){
|
|
- preserveExpr(pX, pExpr);
|
|
- pExpr->affExpr = sqlite3ExprAffinity(pExpr);
|
|
- pExpr->op = TK_COLUMN;
|
|
- pExpr->iTable = pX->iIdxCur;
|
|
- pExpr->iColumn = pX->iIdxCol;
|
|
- pExpr->y.pTab = 0;
|
|
- testcase( ExprHasProperty(pExpr, EP_Skip) );
|
|
- testcase( ExprHasProperty(pExpr, EP_Unlikely) );
|
|
- ExprClearProperty(pExpr, EP_Skip|EP_Unlikely);
|
|
- return WRC_Prune;
|
|
- }else{
|
|
- return WRC_Continue;
|
|
- }
|
|
-}
|
|
-
|
|
-#ifndef SQLITE_OMIT_GENERATED_COLUMNS
|
|
-/* A walker node callback that translates a column reference to a table
|
|
-** into a corresponding column reference of an index.
|
|
-*/
|
|
-static int whereIndexExprTransColumn(Walker *p, Expr *pExpr){
|
|
- if( pExpr->op==TK_COLUMN ){
|
|
- IdxExprTrans *pX = p->u.pIdxTrans;
|
|
- if( pExpr->iTable==pX->iTabCur && pExpr->iColumn==pX->iTabCol ){
|
|
- assert( pExpr->y.pTab!=0 );
|
|
- preserveExpr(pX, pExpr);
|
|
- pExpr->affExpr = sqlite3TableColumnAffinity(pExpr->y.pTab,pExpr->iColumn);
|
|
- pExpr->iTable = pX->iIdxCur;
|
|
- pExpr->iColumn = pX->iIdxCol;
|
|
- pExpr->y.pTab = 0;
|
|
- }
|
|
- }
|
|
- return WRC_Continue;
|
|
-}
|
|
-#endif /* SQLITE_OMIT_GENERATED_COLUMNS */
|
|
-
|
|
-/*
|
|
-** For an indexes on expression X, locate every instance of expression X
|
|
-** in pExpr and change that subexpression into a reference to the appropriate
|
|
-** column of the index.
|
|
-**
|
|
-** 2019-10-24: Updated to also translate references to a VIRTUAL column in
|
|
-** the table into references to the corresponding (stored) column of the
|
|
-** index.
|
|
-*/
|
|
-static void whereIndexExprTrans(
|
|
- Index *pIdx, /* The Index */
|
|
- int iTabCur, /* Cursor of the table that is being indexed */
|
|
- int iIdxCur, /* Cursor of the index itself */
|
|
- WhereInfo *pWInfo /* Transform expressions in this WHERE clause */
|
|
-){
|
|
- int iIdxCol; /* Column number of the index */
|
|
- ExprList *aColExpr; /* Expressions that are indexed */
|
|
- Table *pTab;
|
|
- Walker w;
|
|
- IdxExprTrans x;
|
|
- aColExpr = pIdx->aColExpr;
|
|
- if( aColExpr==0 && !pIdx->bHasVCol ){
|
|
- /* The index does not reference any expressions or virtual columns
|
|
- ** so no translations are needed. */
|
|
- return;
|
|
- }
|
|
- pTab = pIdx->pTable;
|
|
- memset(&w, 0, sizeof(w));
|
|
- w.u.pIdxTrans = &x;
|
|
- x.iTabCur = iTabCur;
|
|
- x.iIdxCur = iIdxCur;
|
|
- x.pWInfo = pWInfo;
|
|
- x.db = pWInfo->pParse->db;
|
|
- for(iIdxCol=0; iIdxCol<pIdx->nColumn; iIdxCol++){
|
|
- i16 iRef = pIdx->aiColumn[iIdxCol];
|
|
- if( iRef==XN_EXPR ){
|
|
- assert( aColExpr->a[iIdxCol].pExpr!=0 );
|
|
- x.pIdxExpr = aColExpr->a[iIdxCol].pExpr;
|
|
- if( sqlite3ExprIsConstant(x.pIdxExpr) ) continue;
|
|
- w.xExprCallback = whereIndexExprTransNode;
|
|
-#ifndef SQLITE_OMIT_GENERATED_COLUMNS
|
|
- }else if( iRef>=0
|
|
- && (pTab->aCol[iRef].colFlags & COLFLAG_VIRTUAL)!=0
|
|
- && (pTab->aCol[iRef].zColl==0
|
|
- || sqlite3StrICmp(pTab->aCol[iRef].zColl, sqlite3StrBINARY)==0)
|
|
- ){
|
|
- /* Check to see if there are direct references to generated columns
|
|
- ** that are contained in the index. Pulling the generated column
|
|
- ** out of the index is an optimization only - the main table is always
|
|
- ** available if the index cannot be used. To avoid unnecessary
|
|
- ** complication, omit this optimization if the collating sequence for
|
|
- ** the column is non-standard */
|
|
- x.iTabCol = iRef;
|
|
- w.xExprCallback = whereIndexExprTransColumn;
|
|
-#endif /* SQLITE_OMIT_GENERATED_COLUMNS */
|
|
- }else{
|
|
- continue;
|
|
- }
|
|
- x.iIdxCol = iIdxCol;
|
|
- sqlite3WalkExpr(&w, pWInfo->pWhere);
|
|
- sqlite3WalkExprList(&w, pWInfo->pOrderBy);
|
|
- sqlite3WalkExprList(&w, pWInfo->pResultSet);
|
|
- }
|
|
-}
|
|
-
|
|
/*
|
|
** The pTruth expression is always true because it is the WHERE clause
|
|
** a partial index that is driving a query loop. Look through all of the
|
|
@@ -141014,6 +153536,70 @@ static void whereApplyPartialIndexConstraints(
|
|
}
|
|
}
|
|
|
|
+/*
|
|
+** This routine is called right after An OP_Filter has been generated and
|
|
+** before the corresponding index search has been performed. This routine
|
|
+** checks to see if there are additional Bloom filters in inner loops that
|
|
+** can be checked prior to doing the index lookup. If there are available
|
|
+** inner-loop Bloom filters, then evaluate those filters now, before the
|
|
+** index lookup. The idea is that a Bloom filter check is way faster than
|
|
+** an index lookup, and the Bloom filter might return false, meaning that
|
|
+** the index lookup can be skipped.
|
|
+**
|
|
+** We know that an inner loop uses a Bloom filter because it has the
|
|
+** WhereLevel.regFilter set. If an inner-loop Bloom filter is checked,
|
|
+** then clear the WhereLevel.regFilter value to prevent the Bloom filter
|
|
+** from being checked a second time when the inner loop is evaluated.
|
|
+*/
|
|
+static SQLITE_NOINLINE void filterPullDown(
|
|
+ Parse *pParse, /* Parsing context */
|
|
+ WhereInfo *pWInfo, /* Complete information about the WHERE clause */
|
|
+ int iLevel, /* Which level of pWInfo->a[] should be coded */
|
|
+ int addrNxt, /* Jump here to bypass inner loops */
|
|
+ Bitmask notReady /* Loops that are not ready */
|
|
+){
|
|
+ while( ++iLevel < pWInfo->nLevel ){
|
|
+ WhereLevel *pLevel = &pWInfo->a[iLevel];
|
|
+ WhereLoop *pLoop = pLevel->pWLoop;
|
|
+ if( pLevel->regFilter==0 ) continue;
|
|
+ if( pLevel->pWLoop->nSkip ) continue;
|
|
+ /* ,--- Because sqlite3ConstructBloomFilter() has will not have set
|
|
+ ** vvvvv--' pLevel->regFilter if this were true. */
|
|
+ if( NEVER(pLoop->prereq & notReady) ) continue;
|
|
+ assert( pLevel->addrBrk==0 );
|
|
+ pLevel->addrBrk = addrNxt;
|
|
+ if( pLoop->wsFlags & WHERE_IPK ){
|
|
+ WhereTerm *pTerm = pLoop->aLTerm[0];
|
|
+ int regRowid;
|
|
+ assert( pTerm!=0 );
|
|
+ assert( pTerm->pExpr!=0 );
|
|
+ testcase( pTerm->wtFlags & TERM_VIRTUAL );
|
|
+ regRowid = sqlite3GetTempReg(pParse);
|
|
+ regRowid = codeEqualityTerm(pParse, pTerm, pLevel, 0, 0, regRowid);
|
|
+ sqlite3VdbeAddOp2(pParse->pVdbe, OP_MustBeInt, regRowid, addrNxt);
|
|
+ VdbeCoverage(pParse->pVdbe);
|
|
+ sqlite3VdbeAddOp4Int(pParse->pVdbe, OP_Filter, pLevel->regFilter,
|
|
+ addrNxt, regRowid, 1);
|
|
+ VdbeCoverage(pParse->pVdbe);
|
|
+ }else{
|
|
+ u16 nEq = pLoop->u.btree.nEq;
|
|
+ int r1;
|
|
+ char *zStartAff;
|
|
+
|
|
+ assert( pLoop->wsFlags & WHERE_INDEXED );
|
|
+ assert( (pLoop->wsFlags & WHERE_COLUMN_IN)==0 );
|
|
+ r1 = codeAllEqualityTerms(pParse,pLevel,0,0,&zStartAff);
|
|
+ codeApplyAffinity(pParse, r1, nEq, zStartAff);
|
|
+ sqlite3DbFree(pParse->db, zStartAff);
|
|
+ sqlite3VdbeAddOp4Int(pParse->pVdbe, OP_Filter, pLevel->regFilter,
|
|
+ addrNxt, r1, nEq);
|
|
+ VdbeCoverage(pParse->pVdbe);
|
|
+ }
|
|
+ pLevel->regFilter = 0;
|
|
+ pLevel->addrBrk = 0;
|
|
+ }
|
|
+}
|
|
+
|
|
/*
|
|
** Generate code for the start of the iLevel-th loop in the WHERE clause
|
|
** implementation described by pWInfo.
|
|
@@ -141034,7 +153620,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
|
|
WhereClause *pWC; /* Decomposition of the entire WHERE clause */
|
|
WhereTerm *pTerm; /* A WHERE clause term */
|
|
sqlite3 *db; /* Database connection */
|
|
- struct SrcList_item *pTabItem; /* FROM clause term being coded */
|
|
+ SrcItem *pTabItem; /* FROM clause term being coded */
|
|
int addrBrk; /* Jump here to break out of the loop */
|
|
int addrHalt; /* addrBrk for the outermost loop */
|
|
int addrCont; /* Jump here to continue with next cycle */
|
|
@@ -141051,13 +153637,15 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
|
|
pLevel->notReady = notReady & ~sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur);
|
|
bRev = (pWInfo->revMask>>iLevel)&1;
|
|
VdbeModuleComment((v, "Begin WHERE-loop%d: %s",iLevel,pTabItem->pTab->zName));
|
|
-#if WHERETRACE_ENABLED /* 0x20800 */
|
|
- if( sqlite3WhereTrace & 0x800 ){
|
|
+#if WHERETRACE_ENABLED /* 0x4001 */
|
|
+ if( sqlite3WhereTrace & 0x1 ){
|
|
sqlite3DebugPrintf("Coding level %d of %d: notReady=%llx iFrom=%d\n",
|
|
iLevel, pWInfo->nLevel, (u64)notReady, pLevel->iFrom);
|
|
- sqlite3WhereLoopPrint(pLoop, pWC);
|
|
+ if( sqlite3WhereTrace & 0x1000 ){
|
|
+ sqlite3WhereLoopPrint(pLoop, pWC);
|
|
+ }
|
|
}
|
|
- if( sqlite3WhereTrace & 0x20000 ){
|
|
+ if( (sqlite3WhereTrace & 0x4001)==0x4001 ){
|
|
if( iLevel==0 ){
|
|
sqlite3DebugPrintf("WHERE clause being coded:\n");
|
|
sqlite3TreeViewExpr(0, pWInfo->pWhere, 0);
|
|
@@ -141084,7 +153672,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
|
|
** initialize a memory cell that records if this table matches any
|
|
** row of the left table of the join.
|
|
*/
|
|
- assert( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)
|
|
+ assert( (pWInfo->wctrlFlags & (WHERE_OR_SUBCLAUSE|WHERE_RIGHT_JOIN))
|
|
|| pLevel->iFrom>0 || (pTabItem[0].fg.jointype & JT_LEFT)==0
|
|
);
|
|
if( pLevel->iFrom>0 && (pTabItem[0].fg.jointype & JT_LEFT)!=0 ){
|
|
@@ -141095,7 +153683,10 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
|
|
|
|
/* Compute a safe address to jump to if we discover that the table for
|
|
** this loop is empty and can never contribute content. */
|
|
- for(j=iLevel; j>0 && pWInfo->a[j].iLeftJoin==0; j--){}
|
|
+ for(j=iLevel; j>0; j--){
|
|
+ if( pWInfo->a[j].iLeftJoin ) break;
|
|
+ if( pWInfo->a[j].pRJ ) break;
|
|
+ }
|
|
addrHalt = pWInfo->a[j].addrBrk;
|
|
|
|
/* Special case of a FROM clause subquery implemented as a co-routine */
|
|
@@ -141116,7 +153707,6 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
|
|
int iReg; /* P3 Value for OP_VFilter */
|
|
int addrNotFound;
|
|
int nConstraint = pLoop->nLTerm;
|
|
- int iIn; /* Counter for IN constraints */
|
|
|
|
iReg = sqlite3GetTempRange(pParse, nConstraint+2);
|
|
addrNotFound = pLevel->addrBrk;
|
|
@@ -141125,11 +153715,27 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
|
|
pTerm = pLoop->aLTerm[j];
|
|
if( NEVER(pTerm==0) ) continue;
|
|
if( pTerm->eOperator & WO_IN ){
|
|
- codeEqualityTerm(pParse, pTerm, pLevel, j, bRev, iTarget);
|
|
- addrNotFound = pLevel->addrNxt;
|
|
+ if( SMASKBIT32(j) & pLoop->u.vtab.mHandleIn ){
|
|
+ int iTab = pParse->nTab++;
|
|
+ int iCache = ++pParse->nMem;
|
|
+ sqlite3CodeRhsOfIN(pParse, pTerm->pExpr, iTab);
|
|
+ sqlite3VdbeAddOp3(v, OP_VInitIn, iTab, iTarget, iCache);
|
|
+ }else{
|
|
+ codeEqualityTerm(pParse, pTerm, pLevel, j, bRev, iTarget);
|
|
+ addrNotFound = pLevel->addrNxt;
|
|
+ }
|
|
}else{
|
|
Expr *pRight = pTerm->pExpr->pRight;
|
|
codeExprOrVector(pParse, pRight, iTarget, 1);
|
|
+ if( pTerm->eMatchOp==SQLITE_INDEX_CONSTRAINT_OFFSET
|
|
+ && pLoop->u.vtab.bOmitOffset
|
|
+ ){
|
|
+ assert( pTerm->eOperator==WO_AUX );
|
|
+ assert( pWInfo->pSelect!=0 );
|
|
+ assert( pWInfo->pSelect->iOffset>0 );
|
|
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, pWInfo->pSelect->iOffset);
|
|
+ VdbeComment((v,"Zero OFFSET counter"));
|
|
+ }
|
|
}
|
|
}
|
|
sqlite3VdbeAddOp2(v, OP_Integer, pLoop->u.vtab.idxNum, iReg);
|
|
@@ -141139,54 +153745,74 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
|
|
pLoop->u.vtab.needFree ? P4_DYNAMIC : P4_STATIC);
|
|
VdbeCoverage(v);
|
|
pLoop->u.vtab.needFree = 0;
|
|
+ /* An OOM inside of AddOp4(OP_VFilter) instruction above might have freed
|
|
+ ** the u.vtab.idxStr. NULL it out to prevent a use-after-free */
|
|
+ if( db->mallocFailed ) pLoop->u.vtab.idxStr = 0;
|
|
pLevel->p1 = iCur;
|
|
pLevel->op = pWInfo->eOnePass ? OP_Noop : OP_VNext;
|
|
pLevel->p2 = sqlite3VdbeCurrentAddr(v);
|
|
- iIn = pLevel->u.in.nIn;
|
|
- for(j=nConstraint-1; j>=0; j--){
|
|
+ assert( (pLoop->wsFlags & WHERE_MULTI_OR)==0 );
|
|
+
|
|
+ for(j=0; j<nConstraint; j++){
|
|
pTerm = pLoop->aLTerm[j];
|
|
- if( (pTerm->eOperator & WO_IN)!=0 ) iIn--;
|
|
if( j<16 && (pLoop->u.vtab.omitMask>>j)&1 ){
|
|
disableTerm(pLevel, pTerm);
|
|
- }else if( (pTerm->eOperator & WO_IN)!=0
|
|
- && sqlite3ExprVectorSize(pTerm->pExpr->pLeft)==1
|
|
+ continue;
|
|
+ }
|
|
+ if( (pTerm->eOperator & WO_IN)!=0
|
|
+ && (SMASKBIT32(j) & pLoop->u.vtab.mHandleIn)==0
|
|
+ && !db->mallocFailed
|
|
){
|
|
Expr *pCompare; /* The comparison operator */
|
|
Expr *pRight; /* RHS of the comparison */
|
|
VdbeOp *pOp; /* Opcode to access the value of the IN constraint */
|
|
+ int iIn; /* IN loop corresponding to the j-th constraint */
|
|
|
|
/* Reload the constraint value into reg[iReg+j+2]. The same value
|
|
** was loaded into the same register prior to the OP_VFilter, but
|
|
** the xFilter implementation might have changed the datatype or
|
|
- ** encoding of the value in the register, so it *must* be reloaded. */
|
|
- assert( pLevel->u.in.aInLoop!=0 || db->mallocFailed );
|
|
- if( !db->mallocFailed ){
|
|
- assert( iIn>=0 && iIn<pLevel->u.in.nIn );
|
|
+ ** encoding of the value in the register, so it *must* be reloaded.
|
|
+ */
|
|
+ for(iIn=0; ALWAYS(iIn<pLevel->u.in.nIn); iIn++){
|
|
pOp = sqlite3VdbeGetOp(v, pLevel->u.in.aInLoop[iIn].addrInTop);
|
|
- assert( pOp->opcode==OP_Column || pOp->opcode==OP_Rowid );
|
|
- assert( pOp->opcode!=OP_Column || pOp->p3==iReg+j+2 );
|
|
- assert( pOp->opcode!=OP_Rowid || pOp->p2==iReg+j+2 );
|
|
- testcase( pOp->opcode==OP_Rowid );
|
|
- sqlite3VdbeAddOp3(v, pOp->opcode, pOp->p1, pOp->p2, pOp->p3);
|
|
+ if( (pOp->opcode==OP_Column && pOp->p3==iReg+j+2)
|
|
+ || (pOp->opcode==OP_Rowid && pOp->p2==iReg+j+2)
|
|
+ ){
|
|
+ testcase( pOp->opcode==OP_Rowid );
|
|
+ sqlite3VdbeAddOp3(v, pOp->opcode, pOp->p1, pOp->p2, pOp->p3);
|
|
+ break;
|
|
+ }
|
|
}
|
|
|
|
- /* Generate code that will continue to the next row if
|
|
- ** the IN constraint is not satisfied */
|
|
+ /* Generate code that will continue to the next row if
|
|
+ ** the IN constraint is not satisfied
|
|
+ */
|
|
pCompare = sqlite3PExpr(pParse, TK_EQ, 0, 0);
|
|
- assert( pCompare!=0 || db->mallocFailed );
|
|
- if( pCompare ){
|
|
- pCompare->pLeft = pTerm->pExpr->pLeft;
|
|
+ if( !db->mallocFailed ){
|
|
+ int iFld = pTerm->u.x.iField;
|
|
+ Expr *pLeft = pTerm->pExpr->pLeft;
|
|
+ assert( pLeft!=0 );
|
|
+ if( iFld>0 ){
|
|
+ assert( pLeft->op==TK_VECTOR );
|
|
+ assert( ExprUseXList(pLeft) );
|
|
+ assert( iFld<=pLeft->x.pList->nExpr );
|
|
+ pCompare->pLeft = pLeft->x.pList->a[iFld-1].pExpr;
|
|
+ }else{
|
|
+ pCompare->pLeft = pLeft;
|
|
+ }
|
|
pCompare->pRight = pRight = sqlite3Expr(db, TK_REGISTER, 0);
|
|
if( pRight ){
|
|
pRight->iTable = iReg+j+2;
|
|
- sqlite3ExprIfFalse(pParse, pCompare, pLevel->addrCont, 0);
|
|
+ sqlite3ExprIfFalse(
|
|
+ pParse, pCompare, pLevel->addrCont, SQLITE_JUMPIFNULL
|
|
+ );
|
|
}
|
|
pCompare->pLeft = 0;
|
|
- sqlite3ExprDelete(db, pCompare);
|
|
}
|
|
+ sqlite3ExprDelete(db, pCompare);
|
|
}
|
|
}
|
|
- assert( iIn==0 || db->mallocFailed );
|
|
+
|
|
/* These registers need to be preserved in case there is an IN operator
|
|
** loop. So we could deallocate the registers here (and potentially
|
|
** reuse them later) if (pLoop->wsFlags & WHERE_IN_ABLE)==0. But it seems
|
|
@@ -141214,12 +153840,17 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
|
|
iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, 0, bRev, iReleaseReg);
|
|
if( iRowidReg!=iReleaseReg ) sqlite3ReleaseTempReg(pParse, iReleaseReg);
|
|
addrNxt = pLevel->addrNxt;
|
|
+ if( pLevel->regFilter ){
|
|
+ sqlite3VdbeAddOp2(v, OP_MustBeInt, iRowidReg, addrNxt);
|
|
+ VdbeCoverage(v);
|
|
+ sqlite3VdbeAddOp4Int(v, OP_Filter, pLevel->regFilter, addrNxt,
|
|
+ iRowidReg, 1);
|
|
+ VdbeCoverage(v);
|
|
+ filterPullDown(pParse, pWInfo, iLevel, addrNxt, notReady);
|
|
+ }
|
|
sqlite3VdbeAddOp3(v, OP_SeekRowid, iCur, addrNxt, iRowidReg);
|
|
VdbeCoverage(v);
|
|
pLevel->op = OP_Noop;
|
|
- if( (pTerm->prereqAll & pLevel->notReady)==0 ){
|
|
- pTerm->wtFlags |= TERM_CODED;
|
|
- }
|
|
}else if( (pLoop->wsFlags & WHERE_IPK)!=0
|
|
&& (pLoop->wsFlags & WHERE_COLUMN_RANGE)!=0
|
|
){
|
|
@@ -141246,7 +153877,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
|
|
int r1, rTemp; /* Registers for holding the start boundary */
|
|
int op; /* Cursor seek operation */
|
|
|
|
- /* The following constant maps TK_xx codes into corresponding
|
|
+ /* The following constant maps TK_xx codes into corresponding
|
|
** seek opcodes. It depends on a particular ordering of TK_xx
|
|
*/
|
|
const u8 aMoveOp[] = {
|
|
@@ -141302,8 +153933,8 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
|
|
testcase( pEnd->wtFlags & TERM_VIRTUAL );
|
|
memEndValue = ++pParse->nMem;
|
|
codeExprOrVector(pParse, pX->pRight, memEndValue, 1);
|
|
- if( 0==sqlite3ExprIsVector(pX->pRight)
|
|
- && (pX->op==TK_LT || pX->op==TK_GT)
|
|
+ if( 0==sqlite3ExprIsVector(pX->pRight)
|
|
+ && (pX->op==TK_LT || pX->op==TK_GT)
|
|
){
|
|
testOp = bRev ? OP_Le : OP_Ge;
|
|
}else{
|
|
@@ -141331,14 +153962,14 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
|
|
}else if( pLoop->wsFlags & WHERE_INDEXED ){
|
|
/* Case 4: A scan using an index.
|
|
**
|
|
- ** The WHERE clause may contain zero or more equality
|
|
+ ** The WHERE clause may contain zero or more equality
|
|
** terms ("==" or "IN" operators) that refer to the N
|
|
** left-most columns of the index. It may also contain
|
|
** inequality constraints (>, <, >= or <=) on the indexed
|
|
- ** column that immediately follows the N equalities. Only
|
|
+ ** column that immediately follows the N equalities. Only
|
|
** the right-most column can be an inequality - the rest must
|
|
- ** use the "==" and "IN" operators. For example, if the
|
|
- ** index is on (x,y,z), then the following clauses are all
|
|
+ ** use the "==" and "IN" operators. For example, if the
|
|
+ ** index is on (x,y,z), then the following clauses are all
|
|
** optimized:
|
|
**
|
|
** x=5
|
|
@@ -141359,7 +153990,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
|
|
** This case is also used when there are no WHERE clause
|
|
** constraints but an index is selected anyway, in order
|
|
** to force the output order to conform to an ORDER BY.
|
|
- */
|
|
+ */
|
|
static const u8 aStartOp[] = {
|
|
0,
|
|
0,
|
|
@@ -141395,20 +154026,21 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
|
|
u8 bStopAtNull = 0; /* Add condition to terminate at NULLs */
|
|
int omitTable; /* True if we use the index only */
|
|
int regBignull = 0; /* big-null flag register */
|
|
+ int addrSeekScan = 0; /* Opcode of the OP_SeekScan, if any */
|
|
|
|
pIdx = pLoop->u.btree.pIndex;
|
|
iIdxCur = pLevel->iIdxCur;
|
|
assert( nEq>=pLoop->nSkip );
|
|
|
|
- /* Find any inequality constraint terms for the start and end
|
|
- ** of the range.
|
|
+ /* Find any inequality constraint terms for the start and end
|
|
+ ** of the range.
|
|
*/
|
|
j = nEq;
|
|
if( pLoop->wsFlags & WHERE_BTM_LIMIT ){
|
|
pRangeStart = pLoop->aLTerm[j++];
|
|
nExtraReg = MAX(nExtraReg, pLoop->u.btree.nBtm);
|
|
/* Like optimization range constraints always occur in pairs */
|
|
- assert( (pRangeStart->wtFlags & TERM_LIKEOPT)==0 ||
|
|
+ assert( (pRangeStart->wtFlags & TERM_LIKEOPT)==0 ||
|
|
(pLoop->wsFlags & WHERE_TOP_LIMIT)!=0 );
|
|
}
|
|
if( pLoop->wsFlags & WHERE_TOP_LIMIT ){
|
|
@@ -141441,7 +154073,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
|
|
assert( pRangeEnd==0 || (pRangeEnd->wtFlags & TERM_VNULL)==0 );
|
|
|
|
/* If the WHERE_BIGNULL_SORT flag is set, then index column nEq uses
|
|
- ** a non-default "big-null" sort (either ASC NULLS LAST or DESC NULLS
|
|
+ ** a non-default "big-null" sort (either ASC NULLS LAST or DESC NULLS
|
|
** FIRST). In both cases separate ordered scans are made of those
|
|
** index entries for which the column is null and for those for which
|
|
** it is not. For an ASC sort, the non-NULL entries are scanned first.
|
|
@@ -141456,21 +154088,28 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
|
|
nExtraReg = 1;
|
|
bSeekPastNull = 1;
|
|
pLevel->regBignull = regBignull = ++pParse->nMem;
|
|
+ if( pLevel->iLeftJoin ){
|
|
+ sqlite3VdbeAddOp2(v, OP_Integer, 0, regBignull);
|
|
+ }
|
|
pLevel->addrBignull = sqlite3VdbeMakeLabel(pParse);
|
|
}
|
|
|
|
/* If we are doing a reverse order scan on an ascending index, or
|
|
- ** a forward order scan on a descending index, interchange the
|
|
+ ** a forward order scan on a descending index, interchange the
|
|
** start and end terms (pRangeStart and pRangeEnd).
|
|
*/
|
|
- if( (nEq<pIdx->nKeyCol && bRev==(pIdx->aSortOrder[nEq]==SQLITE_SO_ASC))
|
|
- || (bRev && pIdx->nKeyCol==nEq)
|
|
- ){
|
|
+ if( (nEq<pIdx->nColumn && bRev==(pIdx->aSortOrder[nEq]==SQLITE_SO_ASC)) ){
|
|
SWAP(WhereTerm *, pRangeEnd, pRangeStart);
|
|
SWAP(u8, bSeekPastNull, bStopAtNull);
|
|
SWAP(u8, nBtm, nTop);
|
|
}
|
|
|
|
+ if( iLevel>0 && (pLoop->wsFlags & WHERE_IN_SEEKSCAN)!=0 ){
|
|
+ /* In case OP_SeekScan is used, ensure that the index cursor does not
|
|
+ ** point to a valid row for the first iteration of this loop. */
|
|
+ sqlite3VdbeAddOp1(v, OP_NullRow, iIdxCur);
|
|
+ }
|
|
+
|
|
/* Generate code to evaluate all constraint terms using == or IN
|
|
** and store the values of those terms in an array of registers
|
|
** starting at regBase.
|
|
@@ -141505,7 +154144,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
|
|
}
|
|
if( zStartAff ){
|
|
updateRangeAffinityStr(pRight, nBtm, &zStartAff[nEq]);
|
|
- }
|
|
+ }
|
|
nConstraint += nBtm;
|
|
testcase( pRangeStart->wtFlags & TERM_VIRTUAL );
|
|
if( sqlite3ExprIsVector(pRight)==0 ){
|
|
@@ -141530,16 +154169,38 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
|
|
** above has already left the cursor sitting on the correct row,
|
|
** so no further seeking is needed */
|
|
}else{
|
|
- if( pLoop->wsFlags & WHERE_IN_EARLYOUT ){
|
|
- sqlite3VdbeAddOp1(v, OP_SeekHit, iIdxCur);
|
|
- }
|
|
if( regBignull ){
|
|
sqlite3VdbeAddOp2(v, OP_Integer, 1, regBignull);
|
|
VdbeComment((v, "NULL-scan pass ctr"));
|
|
}
|
|
+ if( pLevel->regFilter ){
|
|
+ sqlite3VdbeAddOp4Int(v, OP_Filter, pLevel->regFilter, addrNxt,
|
|
+ regBase, nEq);
|
|
+ VdbeCoverage(v);
|
|
+ filterPullDown(pParse, pWInfo, iLevel, addrNxt, notReady);
|
|
+ }
|
|
|
|
op = aStartOp[(start_constraints<<2) + (startEq<<1) + bRev];
|
|
assert( op!=0 );
|
|
+ if( (pLoop->wsFlags & WHERE_IN_SEEKSCAN)!=0 && op==OP_SeekGE ){
|
|
+ assert( regBignull==0 );
|
|
+ /* TUNING: The OP_SeekScan opcode seeks to reduce the number
|
|
+ ** of expensive seek operations by replacing a single seek with
|
|
+ ** 1 or more step operations. The question is, how many steps
|
|
+ ** should we try before giving up and going with a seek. The cost
|
|
+ ** of a seek is proportional to the logarithm of the of the number
|
|
+ ** of entries in the tree, so basing the number of steps to try
|
|
+ ** on the estimated number of rows in the btree seems like a good
|
|
+ ** guess. */
|
|
+ addrSeekScan = sqlite3VdbeAddOp1(v, OP_SeekScan,
|
|
+ (pIdx->aiRowLogEst[0]+9)/10);
|
|
+ if( pRangeStart ){
|
|
+ sqlite3VdbeChangeP5(v, 1);
|
|
+ sqlite3VdbeChangeP2(v, addrSeekScan, sqlite3VdbeCurrentAddr(v)+1);
|
|
+ addrSeekScan = 0;
|
|
+ }
|
|
+ VdbeCoverage(v);
|
|
+ }
|
|
sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint);
|
|
VdbeCoverage(v);
|
|
VdbeCoverageIf(v, op==OP_Rewind); testcase( op==OP_Rewind );
|
|
@@ -141556,7 +154217,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
|
|
assert( bStopAtNull==startEq );
|
|
sqlite3VdbeAddOp2(v, OP_Goto, 0, sqlite3VdbeCurrentAddr(v)+2);
|
|
op = aStartOp[(nConstraint>1)*4 + 2 + bRev];
|
|
- sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase,
|
|
+ sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase,
|
|
nConstraint-startEq);
|
|
VdbeCoverage(v);
|
|
VdbeCoverageIf(v, op==OP_Rewind); testcase( op==OP_Rewind );
|
|
@@ -141571,8 +154232,19 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
|
|
** range (if any).
|
|
*/
|
|
nConstraint = nEq;
|
|
+ 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);
|
|
+ }
|
|
codeExprOrVector(pParse, pRight, regBase+nEq, nTop);
|
|
whereLikeOptimizationStringFixup(v, pLevel, pRangeEnd);
|
|
if( (pRangeEnd->wtFlags & TERM_VNULL)==0
|
|
@@ -141602,11 +154274,11 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
|
|
}
|
|
nConstraint++;
|
|
}
|
|
- sqlite3DbFree(db, zStartAff);
|
|
- sqlite3DbFree(db, zEndAff);
|
|
+ if( zStartAff ) sqlite3DbNNFreeNN(db, zStartAff);
|
|
+ if( zEndAff ) sqlite3DbNNFreeNN(db, zEndAff);
|
|
|
|
/* Top of the loop body */
|
|
- pLevel->p2 = sqlite3VdbeCurrentAddr(v);
|
|
+ if( pLevel->p2==0 ) pLevel->p2 = sqlite3VdbeCurrentAddr(v);
|
|
|
|
/* Check if the index cursor is past the end of the range. */
|
|
if( nConstraint ){
|
|
@@ -141622,6 +154294,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
|
|
testcase( op==OP_IdxGE ); VdbeCoverageIf(v, op==OP_IdxGE );
|
|
testcase( op==OP_IdxLT ); VdbeCoverageIf(v, op==OP_IdxLT );
|
|
testcase( op==OP_IdxLE ); VdbeCoverageIf(v, op==OP_IdxLE );
|
|
+ if( addrSeekScan ) sqlite3VdbeJumpHere(v, addrSeekScan);
|
|
}
|
|
if( regBignull ){
|
|
/* During a NULL-scan, check to see if we have reached the end of
|
|
@@ -141641,27 +154314,17 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
|
|
testcase( op==OP_IdxLE ); VdbeCoverageIf(v, op==OP_IdxLE );
|
|
}
|
|
|
|
- if( pLoop->wsFlags & WHERE_IN_EARLYOUT ){
|
|
- sqlite3VdbeAddOp2(v, OP_SeekHit, iIdxCur, 1);
|
|
+ if( (pLoop->wsFlags & WHERE_IN_EARLYOUT)!=0 ){
|
|
+ sqlite3VdbeAddOp3(v, OP_SeekHit, iIdxCur, nEq, nEq);
|
|
}
|
|
|
|
/* Seek the table cursor, if required */
|
|
- omitTable = (pLoop->wsFlags & WHERE_IDX_ONLY)!=0
|
|
- && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0;
|
|
+ omitTable = (pLoop->wsFlags & WHERE_IDX_ONLY)!=0
|
|
+ && (pWInfo->wctrlFlags & (WHERE_OR_SUBCLAUSE|WHERE_RIGHT_JOIN))==0;
|
|
if( omitTable ){
|
|
/* pIdx is a covering index. No need to access the main table. */
|
|
}else if( HasRowid(pIdx->pTable) ){
|
|
- if( (pWInfo->wctrlFlags & WHERE_SEEK_TABLE)
|
|
- || ( (pWInfo->wctrlFlags & WHERE_SEEK_UNIQ_TABLE)!=0
|
|
- && (pWInfo->eOnePass==ONEPASS_SINGLE || pLoop->nLTerm==0) )
|
|
- ){
|
|
- iRowidReg = ++pParse->nMem;
|
|
- sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, iRowidReg);
|
|
- sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, iRowidReg);
|
|
- VdbeCoverage(v);
|
|
- }else{
|
|
- codeDeferredSeek(pWInfo, pIdx, iCur, iIdxCur);
|
|
- }
|
|
+ codeDeferredSeek(pWInfo, pIdx, iCur, iIdxCur);
|
|
}else if( iCur!=iIdxCur ){
|
|
Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable);
|
|
iRowidReg = sqlite3GetTempRange(pParse, pPk->nKeyCol);
|
|
@@ -141674,27 +154337,6 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
|
|
}
|
|
|
|
if( pLevel->iLeftJoin==0 ){
|
|
- /* If pIdx is an index on one or more expressions, then look through
|
|
- ** all the expressions in pWInfo and try to transform matching expressions
|
|
- ** into reference to index columns. Also attempt to translate references
|
|
- ** to virtual columns in the table into references to (stored) columns
|
|
- ** of the index.
|
|
- **
|
|
- ** Do not do this for the RHS of a LEFT JOIN. This is because the
|
|
- ** expression may be evaluated after OP_NullRow has been executed on
|
|
- ** the cursor. In this case it is important to do the full evaluation,
|
|
- ** as the result of the expression may not be NULL, even if all table
|
|
- ** column values are. https://www.sqlite.org/src/info/7fa8049685b50b5a
|
|
- **
|
|
- ** Also, do not do this when processing one index an a multi-index
|
|
- ** OR clause, since the transformation will become invalid once we
|
|
- ** move forward to the next index.
|
|
- ** https://sqlite.org/src/info/4e8e4857d32d401f
|
|
- */
|
|
- if( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0 ){
|
|
- whereIndexExprTrans(pIdx, iCur, iIdxCur, pWInfo);
|
|
- }
|
|
-
|
|
/* If a partial index is driving the loop, try to eliminate WHERE clause
|
|
** terms from the query that must be true due to the WHERE clause of
|
|
** the partial index.
|
|
@@ -141710,9 +154352,9 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
|
|
/* The following assert() is not a requirement, merely an observation:
|
|
** The OR-optimization doesn't work for the right hand table of
|
|
** a LEFT JOIN: */
|
|
- assert( (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0 );
|
|
+ assert( (pWInfo->wctrlFlags & (WHERE_OR_SUBCLAUSE|WHERE_RIGHT_JOIN))==0 );
|
|
}
|
|
-
|
|
+
|
|
/* Record the instruction used to terminate the loop. */
|
|
if( pLoop->wsFlags & WHERE_ONEROW ){
|
|
pLevel->op = OP_Noop;
|
|
@@ -141788,7 +154430,6 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
|
|
int iRetInit; /* Address of regReturn init */
|
|
int untestedTerms = 0; /* Some terms not completely tested */
|
|
int ii; /* Loop counter */
|
|
- u16 wctrlFlags; /* Flags for sub-WHERE clause */
|
|
Expr *pAndExpr = 0; /* An ".. AND (...)" expression */
|
|
Table *pTab = pTabItem->pTab;
|
|
|
|
@@ -141806,9 +154447,9 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
|
|
*/
|
|
if( pWInfo->nLevel>1 ){
|
|
int nNotReady; /* The number of notReady tables */
|
|
- struct SrcList_item *origSrc; /* Original list of tables */
|
|
+ SrcItem *origSrc; /* Original list of tables */
|
|
nNotReady = pWInfo->nLevel - iLevel - 1;
|
|
- pOrTab = sqlite3StackAllocRaw(db,
|
|
+ pOrTab = sqlite3DbMallocRawNN(db,
|
|
sizeof(*pOrTab)+ nNotReady*sizeof(pOrTab->a[0]));
|
|
if( pOrTab==0 ) return notReady;
|
|
pOrTab->nAlloc = (u8)(nNotReady + 1);
|
|
@@ -141822,15 +154463,15 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
|
|
pOrTab = pWInfo->pTabList;
|
|
}
|
|
|
|
- /* Initialize the rowset register to contain NULL. An SQL NULL is
|
|
+ /* Initialize the rowset register to contain NULL. An SQL NULL is
|
|
** equivalent to an empty rowset. Or, create an ephemeral index
|
|
** capable of holding primary keys in the case of a WITHOUT ROWID.
|
|
**
|
|
- ** Also initialize regReturn to contain the address of the instruction
|
|
+ ** Also initialize regReturn to contain the address of the instruction
|
|
** immediately following the OP_Return at the bottom of the loop. This
|
|
** is required in a few obscure LEFT JOIN cases where control jumps
|
|
- ** over the top of the loop into the body of it. In this case the
|
|
- ** correct response for the end-of-loop code (the OP_Return) is to
|
|
+ ** over the top of the loop into the body of it. In this case the
|
|
+ ** correct response for the end-of-loop code (the OP_Return) is to
|
|
** fall through to the next instruction, just as an OP_Next does if
|
|
** called on an uninitialized cursor.
|
|
*/
|
|
@@ -141849,18 +154490,32 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
|
|
iRetInit = sqlite3VdbeAddOp2(v, OP_Integer, 0, regReturn);
|
|
|
|
/* If the original WHERE clause is z of the form: (x1 OR x2 OR ...) AND y
|
|
- ** Then for every term xN, evaluate as the subexpression: xN AND z
|
|
+ ** Then for every term xN, evaluate as the subexpression: xN AND y
|
|
** That way, terms in y that are factored into the disjunction will
|
|
** be picked up by the recursive calls to sqlite3WhereBegin() below.
|
|
**
|
|
** Actually, each subexpression is converted to "xN AND w" where w is
|
|
** the "interesting" terms of z - terms that did not originate in the
|
|
- ** ON or USING clause of a LEFT JOIN, and terms that are usable as
|
|
+ ** ON or USING clause of a LEFT JOIN, and terms that are usable as
|
|
** indices.
|
|
**
|
|
** This optimization also only applies if the (x1 OR x2 OR ...) term
|
|
** is not contained in the ON clause of a LEFT JOIN.
|
|
** See ticket http://www.sqlite.org/src/info/f2369304e4
|
|
+ **
|
|
+ ** 2022-02-04: Do not push down slices of a row-value comparison.
|
|
+ ** In other words, "w" or "y" may not be a slice of a vector. Otherwise,
|
|
+ ** the initialization of the right-hand operand of the vector comparison
|
|
+ ** might not occur, or might occur only in an OR branch that is not
|
|
+ ** taken. dbsqlfuzz 80a9fade844b4fb43564efc972bcb2c68270f5d1.
|
|
+ **
|
|
+ ** 2022-03-03: Do not push down expressions that involve subqueries.
|
|
+ ** The subquery might get coded as a subroutine. Any table-references
|
|
+ ** in the subquery might be resolved to index-references for the index on
|
|
+ ** the OR branch in which the subroutine is coded. But if the subroutine
|
|
+ ** is invoked from a different OR branch that uses a different index, such
|
|
+ ** index-references will not work. tag-20220303a
|
|
+ ** https://sqlite.org/forum/forumpost/36937b197273d403
|
|
*/
|
|
if( pWC->nTerm>1 ){
|
|
int iTerm;
|
|
@@ -141869,9 +154524,12 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
|
|
if( &pWC->a[iTerm] == pTerm ) continue;
|
|
testcase( pWC->a[iTerm].wtFlags & TERM_VIRTUAL );
|
|
testcase( pWC->a[iTerm].wtFlags & TERM_CODED );
|
|
- if( (pWC->a[iTerm].wtFlags & (TERM_VIRTUAL|TERM_CODED))!=0 ) continue;
|
|
+ testcase( pWC->a[iTerm].wtFlags & TERM_SLICE );
|
|
+ if( (pWC->a[iTerm].wtFlags & (TERM_VIRTUAL|TERM_CODED|TERM_SLICE))!=0 ){
|
|
+ continue;
|
|
+ }
|
|
if( (pWC->a[iTerm].eOperator & WO_ALL)==0 ) continue;
|
|
- testcase( pWC->a[iTerm].wtFlags & TERM_ORINFO );
|
|
+ if( ExprHasProperty(pExpr, EP_Subquery) ) continue; /* tag-20220303a */
|
|
pExpr = sqlite3ExprDup(db, pExpr, 0);
|
|
pAndExpr = sqlite3ExprAnd(pParse, pAndExpr, pExpr);
|
|
}
|
|
@@ -141879,7 +154537,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
|
|
/* The extra 0x10000 bit on the opcode is masked off and does not
|
|
** become part of the new Expr.op. However, it does make the
|
|
** op==TK_AND comparison inside of sqlite3PExpr() false, and this
|
|
- ** prevents sqlite3PExpr() from implementing AND short-circuit
|
|
+ ** prevents sqlite3PExpr() from applying the AND short-circuit
|
|
** optimization, which we do not want here. */
|
|
pAndExpr = sqlite3PExpr(pParse, TK_AND|0x10000, 0, pAndExpr);
|
|
}
|
|
@@ -141889,27 +154547,32 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
|
|
** eliminating duplicates from other WHERE clauses, the action for each
|
|
** sub-WHERE clause is to to invoke the main loop body as a subroutine.
|
|
*/
|
|
- wctrlFlags = WHERE_OR_SUBCLAUSE | (pWInfo->wctrlFlags & WHERE_SEEK_TABLE);
|
|
ExplainQueryPlan((pParse, 1, "MULTI-INDEX OR"));
|
|
for(ii=0; ii<pOrWc->nTerm; ii++){
|
|
WhereTerm *pOrTerm = &pOrWc->a[ii];
|
|
if( pOrTerm->leftCursor==iCur || (pOrTerm->eOperator & WO_AND)!=0 ){
|
|
WhereInfo *pSubWInfo; /* Info for single OR-term scan */
|
|
Expr *pOrExpr = pOrTerm->pExpr; /* Current OR clause term */
|
|
+ Expr *pDelete; /* Local copy of OR clause term */
|
|
int jmp1 = 0; /* Address of jump operation */
|
|
testcase( (pTabItem[0].fg.jointype & JT_LEFT)!=0
|
|
- && !ExprHasProperty(pOrExpr, EP_FromJoin)
|
|
+ && !ExprHasProperty(pOrExpr, EP_OuterON)
|
|
); /* See TH3 vtab25.400 and ticket 614b25314c766238 */
|
|
+ pDelete = pOrExpr = sqlite3ExprDup(db, pOrExpr, 0);
|
|
+ if( db->mallocFailed ){
|
|
+ sqlite3ExprDelete(db, pDelete);
|
|
+ continue;
|
|
+ }
|
|
if( pAndExpr ){
|
|
pAndExpr->pLeft = pOrExpr;
|
|
pOrExpr = pAndExpr;
|
|
}
|
|
/* Loop through table entries that match term pOrTerm. */
|
|
ExplainQueryPlan((pParse, 1, "INDEX %d", ii+1));
|
|
- WHERETRACE(0xffff, ("Subplan for OR-clause:\n"));
|
|
- pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrExpr, 0, 0,
|
|
- wctrlFlags, iCovCur);
|
|
- assert( pSubWInfo || pParse->nErr || db->mallocFailed );
|
|
+ WHERETRACE(0xffffffff, ("Subplan for OR-clause:\n"));
|
|
+ pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrExpr, 0, 0, 0,
|
|
+ WHERE_OR_SUBCLAUSE, iCovCur);
|
|
+ assert( pSubWInfo || pParse->nErr );
|
|
if( pSubWInfo ){
|
|
WhereLoop *pSubLoop;
|
|
int addrExplain = sqlite3WhereExplainOneScan(
|
|
@@ -141950,9 +154613,9 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
|
|
**
|
|
** Use some of the same optimizations as OP_RowSetTest: If iSet
|
|
** is zero, assume that the key cannot already be present in
|
|
- ** the temp table. And if iSet is -1, assume that there is no
|
|
- ** need to insert the key into the temp table, as it will never
|
|
- ** be tested for. */
|
|
+ ** the temp table. And if iSet is -1, assume that there is no
|
|
+ ** need to insert the key into the temp table, as it will never
|
|
+ ** be tested for. */
|
|
if( iSet ){
|
|
jmp1 = sqlite3VdbeAddOp4Int(v, OP_Found, regRowset, 0, r, nPk);
|
|
VdbeCoverage(v);
|
|
@@ -141991,8 +154654,8 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
|
|
** If the call to sqlite3WhereBegin() above resulted in a scan that
|
|
** uses an index, and this is either the first OR-connected term
|
|
** processed or the index is the same as that used by all previous
|
|
- ** terms, set pCov to the candidate covering index. Otherwise, set
|
|
- ** pCov to NULL to indicate that no candidate covering index will
|
|
+ ** terms, set pCov to the candidate covering index. Otherwise, set
|
|
+ ** pCov to NULL to indicate that no candidate covering index will
|
|
** be available.
|
|
*/
|
|
pSubLoop = pSubWInfo->a[0].pWLoop;
|
|
@@ -142006,15 +154669,22 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
|
|
}else{
|
|
pCov = 0;
|
|
}
|
|
+ if( sqlite3WhereUsesDeferredSeek(pSubWInfo) ){
|
|
+ pWInfo->bDeferredSeek = 1;
|
|
+ }
|
|
|
|
/* Finish the loop through table entries that match term pOrTerm. */
|
|
sqlite3WhereEnd(pSubWInfo);
|
|
ExplainQueryPlanPop(pParse);
|
|
}
|
|
+ sqlite3ExprDelete(db, pDelete);
|
|
}
|
|
}
|
|
ExplainQueryPlanPop(pParse);
|
|
- pLevel->u.pCovidx = pCov;
|
|
+ assert( pLevel->pWLoop==pLoop );
|
|
+ assert( (pLoop->wsFlags & WHERE_MULTI_OR)!=0 );
|
|
+ assert( (pLoop->wsFlags & WHERE_IN_ABLE)==0 );
|
|
+ pLevel->u.pCoveringIdx = pCov;
|
|
if( pCov ) pLevel->iIdxCur = iCovCur;
|
|
if( pAndExpr ){
|
|
pAndExpr->pLeft = 0;
|
|
@@ -142024,7 +154694,15 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
|
|
sqlite3VdbeGoto(v, pLevel->addrBrk);
|
|
sqlite3VdbeResolveLabel(v, iLoopBody);
|
|
|
|
- if( pWInfo->nLevel>1 ){ sqlite3StackFree(db, pOrTab); }
|
|
+ /* Set the P2 operand of the OP_Return opcode that will end the current
|
|
+ ** loop to point to this spot, which is the top of the next containing
|
|
+ ** loop. The byte-code formatter will use that P2 value as a hint to
|
|
+ ** indent everything in between the this point and the final OP_Return.
|
|
+ ** See tag-20220407a in vdbe.c and shell.c */
|
|
+ assert( pLevel->op==OP_Return );
|
|
+ pLevel->p2 = sqlite3VdbeCurrentAddr(v);
|
|
+
|
|
+ if( pWInfo->nLevel>1 ){ sqlite3DbFreeNN(db, pOrTab); }
|
|
if( !untestedTerms ) disableTerm(pLevel, pTerm);
|
|
}else
|
|
#endif /* SQLITE_OMIT_OR_OPTIMIZATION */
|
|
@@ -142064,7 +154742,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
|
|
**
|
|
** iLoop==1: Code only expressions that are entirely covered by pIdx.
|
|
** iLoop==2: Code remaining expressions that do not contain correlated
|
|
- ** sub-queries.
|
|
+ ** sub-queries.
|
|
** iLoop==3: Code all remaining expressions.
|
|
**
|
|
** An effort is made to skip unnecessary iterations of the loop.
|
|
@@ -142086,10 +154764,22 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
|
|
}
|
|
pE = pTerm->pExpr;
|
|
assert( pE!=0 );
|
|
- if( (pTabItem->fg.jointype&JT_LEFT) && !ExprHasProperty(pE,EP_FromJoin) ){
|
|
- continue;
|
|
+ if( pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT) ){
|
|
+ if( !ExprHasProperty(pE,EP_OuterON|EP_InnerON) ){
|
|
+ /* Defer processing WHERE clause constraints until after outer
|
|
+ ** join processing. tag-20220513a */
|
|
+ continue;
|
|
+ }else if( (pTabItem->fg.jointype & JT_LEFT)==JT_LEFT
|
|
+ && !ExprHasProperty(pE,EP_OuterON) ){
|
|
+ continue;
|
|
+ }else{
|
|
+ Bitmask m = sqlite3WhereGetMask(&pWInfo->sMaskSet, pE->w.iJoin);
|
|
+ if( m & pLevel->notReady ){
|
|
+ /* An ON clause that is not ripe */
|
|
+ continue;
|
|
+ }
|
|
+ }
|
|
}
|
|
-
|
|
if( iLoop==1 && !sqlite3ExprCoveredByIndex(pE, pLevel->iTabCur, pIdx) ){
|
|
iNext = 2;
|
|
continue;
|
|
@@ -142116,12 +154806,12 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
|
|
}
|
|
#endif
|
|
}
|
|
-#ifdef WHERETRACE_ENABLED /* 0xffff */
|
|
+#ifdef WHERETRACE_ENABLED /* 0xffffffff */
|
|
if( sqlite3WhereTrace ){
|
|
VdbeNoopComment((v, "WhereTerm[%d] (%p) priority=%d",
|
|
pWC->nTerm-j, pTerm, iLoop));
|
|
}
|
|
- if( sqlite3WhereTrace & 0x800 ){
|
|
+ if( sqlite3WhereTrace & 0x4000 ){
|
|
sqlite3DebugPrintf("Coding auxiliary constraint:\n");
|
|
sqlite3WhereTermPrint(pTerm, pWC->nTerm-j);
|
|
}
|
|
@@ -142141,29 +154831,30 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
|
|
** then we cannot use the "t1.a=t2.b" constraint, but we can code
|
|
** the implied "t1.a=123" constraint.
|
|
*/
|
|
- for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){
|
|
+ for(pTerm=pWC->a, j=pWC->nBase; j>0; j--, pTerm++){
|
|
Expr *pE, sEAlt;
|
|
WhereTerm *pAlt;
|
|
if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
|
|
if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) continue;
|
|
if( (pTerm->eOperator & WO_EQUIV)==0 ) continue;
|
|
if( pTerm->leftCursor!=iCur ) continue;
|
|
- if( pTabItem->fg.jointype & JT_LEFT ) continue;
|
|
+ if( pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT) ) continue;
|
|
pE = pTerm->pExpr;
|
|
-#ifdef WHERETRACE_ENABLED /* 0x800 */
|
|
- if( sqlite3WhereTrace & 0x800 ){
|
|
+#ifdef WHERETRACE_ENABLED /* 0x4001 */
|
|
+ if( (sqlite3WhereTrace & 0x4001)==0x4001 ){
|
|
sqlite3DebugPrintf("Coding transitive constraint:\n");
|
|
sqlite3WhereTermPrint(pTerm, pWC->nTerm-j);
|
|
}
|
|
#endif
|
|
- assert( !ExprHasProperty(pE, EP_FromJoin) );
|
|
+ assert( !ExprHasProperty(pE, EP_OuterON) );
|
|
assert( (pTerm->prereqRight & pLevel->notReady)!=0 );
|
|
- pAlt = sqlite3WhereFindTerm(pWC, iCur, pTerm->u.leftColumn, notReady,
|
|
+ assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 );
|
|
+ pAlt = sqlite3WhereFindTerm(pWC, iCur, pTerm->u.x.leftColumn, notReady,
|
|
WO_EQ|WO_IN|WO_IS, 0);
|
|
if( pAlt==0 ) continue;
|
|
if( pAlt->wtFlags & (TERM_CODED) ) continue;
|
|
- if( (pAlt->eOperator & WO_IN)
|
|
- && (pAlt->pExpr->flags & EP_xIsSelect)
|
|
+ if( (pAlt->eOperator & WO_IN)
|
|
+ && ExprUseXSelect(pAlt->pExpr)
|
|
&& (pAlt->pExpr->x.pSelect->pEList->nExpr>1)
|
|
){
|
|
continue;
|
|
@@ -142175,16 +154866,82 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
|
|
sEAlt = *pAlt->pExpr;
|
|
sEAlt.pLeft = pE->pLeft;
|
|
sqlite3ExprIfFalse(pParse, &sEAlt, addrCont, SQLITE_JUMPIFNULL);
|
|
+ pAlt->wtFlags |= TERM_CODED;
|
|
+ }
|
|
+
|
|
+ /* For a RIGHT OUTER JOIN, record the fact that the current row has
|
|
+ ** been matched at least once.
|
|
+ */
|
|
+ if( pLevel->pRJ ){
|
|
+ Table *pTab;
|
|
+ int nPk;
|
|
+ int r;
|
|
+ int jmp1 = 0;
|
|
+ WhereRightJoin *pRJ = pLevel->pRJ;
|
|
+
|
|
+ /* pTab is the right-hand table of the RIGHT JOIN. Generate code that
|
|
+ ** will record that the current row of that table has been matched at
|
|
+ ** least once. This is accomplished by storing the PK for the row in
|
|
+ ** both the iMatch index and the regBloom Bloom filter.
|
|
+ */
|
|
+ pTab = pWInfo->pTabList->a[pLevel->iFrom].pTab;
|
|
+ if( HasRowid(pTab) ){
|
|
+ r = sqlite3GetTempRange(pParse, 2);
|
|
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, pLevel->iTabCur, -1, r+1);
|
|
+ nPk = 1;
|
|
+ }else{
|
|
+ int iPk;
|
|
+ Index *pPk = sqlite3PrimaryKeyIndex(pTab);
|
|
+ nPk = pPk->nKeyCol;
|
|
+ r = sqlite3GetTempRange(pParse, nPk+1);
|
|
+ for(iPk=0; iPk<nPk; iPk++){
|
|
+ int iCol = pPk->aiColumn[iPk];
|
|
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, iCol,r+1+iPk);
|
|
+ }
|
|
+ }
|
|
+ jmp1 = sqlite3VdbeAddOp4Int(v, OP_Found, pRJ->iMatch, 0, r+1, nPk);
|
|
+ VdbeCoverage(v);
|
|
+ VdbeComment((v, "match against %s", pTab->zName));
|
|
+ sqlite3VdbeAddOp3(v, OP_MakeRecord, r+1, nPk, r);
|
|
+ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pRJ->iMatch, r, r+1, nPk);
|
|
+ sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pRJ->regBloom, 0, r+1, nPk);
|
|
+ sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
|
|
+ sqlite3VdbeJumpHere(v, jmp1);
|
|
+ sqlite3ReleaseTempRange(pParse, r, nPk+1);
|
|
}
|
|
|
|
/* For a LEFT OUTER JOIN, generate code that will record the fact that
|
|
- ** at least one row of the right table has matched the left table.
|
|
+ ** at least one row of the right table has matched the left table.
|
|
*/
|
|
if( pLevel->iLeftJoin ){
|
|
pLevel->addrFirst = sqlite3VdbeCurrentAddr(v);
|
|
sqlite3VdbeAddOp2(v, OP_Integer, 1, pLevel->iLeftJoin);
|
|
VdbeComment((v, "record LEFT JOIN hit"));
|
|
- for(pTerm=pWC->a, j=0; j<pWC->nTerm; j++, pTerm++){
|
|
+ if( pLevel->pRJ==0 ){
|
|
+ goto code_outer_join_constraints; /* WHERE clause constraints */
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if( pLevel->pRJ ){
|
|
+ /* Create a subroutine used to process all interior loops and code
|
|
+ ** of the RIGHT JOIN. During normal operation, the subroutine will
|
|
+ ** be in-line with the rest of the code. But at the end, a separate
|
|
+ ** loop will run that invokes this subroutine for unmatched rows
|
|
+ ** of pTab, with all tables to left begin set to NULL.
|
|
+ */
|
|
+ WhereRightJoin *pRJ = pLevel->pRJ;
|
|
+ sqlite3VdbeAddOp2(v, OP_BeginSubrtn, 0, pRJ->regReturn);
|
|
+ pRJ->addrSubrtn = sqlite3VdbeCurrentAddr(v);
|
|
+ assert( pParse->withinRJSubrtn < 255 );
|
|
+ pParse->withinRJSubrtn++;
|
|
+
|
|
+ /* WHERE clause constraints must be deferred until after outer join
|
|
+ ** row elimination has completed, since WHERE clause constraints apply
|
|
+ ** to the results of the OUTER JOIN. The following loop generates the
|
|
+ ** appropriate WHERE clause constraint checks. tag-20220513a.
|
|
+ */
|
|
+ code_outer_join_constraints:
|
|
+ for(pTerm=pWC->a, j=0; j<pWC->nBase; j++, pTerm++){
|
|
testcase( pTerm->wtFlags & TERM_VIRTUAL );
|
|
testcase( pTerm->wtFlags & TERM_CODED );
|
|
if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
|
|
@@ -142192,19 +154949,20 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
|
|
assert( pWInfo->untestedTerms );
|
|
continue;
|
|
}
|
|
+ if( pTabItem->fg.jointype & JT_LTORJ ) continue;
|
|
assert( pTerm->pExpr );
|
|
sqlite3ExprIfFalse(pParse, pTerm->pExpr, addrCont, SQLITE_JUMPIFNULL);
|
|
pTerm->wtFlags |= TERM_CODED;
|
|
}
|
|
}
|
|
|
|
-#if WHERETRACE_ENABLED /* 0x20800 */
|
|
- if( sqlite3WhereTrace & 0x20000 ){
|
|
+#if WHERETRACE_ENABLED /* 0x4001 */
|
|
+ if( sqlite3WhereTrace & 0x4000 ){
|
|
sqlite3DebugPrintf("All WHERE-clause terms after coding level %d:\n",
|
|
iLevel);
|
|
sqlite3WhereClausePrint(pWC);
|
|
}
|
|
- if( sqlite3WhereTrace & 0x800 ){
|
|
+ if( sqlite3WhereTrace & 0x1 ){
|
|
sqlite3DebugPrintf("End Coding level %d: notReady=%llx\n",
|
|
iLevel, (u64)pLevel->notReady);
|
|
}
|
|
@@ -142212,6 +154970,96 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
|
|
return pLevel->notReady;
|
|
}
|
|
|
|
+/*
|
|
+** Generate the code for the loop that finds all non-matched terms
|
|
+** for a RIGHT JOIN.
|
|
+*/
|
|
+SQLITE_PRIVATE SQLITE_NOINLINE void sqlite3WhereRightJoinLoop(
|
|
+ WhereInfo *pWInfo,
|
|
+ int iLevel,
|
|
+ WhereLevel *pLevel
|
|
+){
|
|
+ Parse *pParse = pWInfo->pParse;
|
|
+ Vdbe *v = pParse->pVdbe;
|
|
+ WhereRightJoin *pRJ = pLevel->pRJ;
|
|
+ Expr *pSubWhere = 0;
|
|
+ WhereClause *pWC = &pWInfo->sWC;
|
|
+ WhereInfo *pSubWInfo;
|
|
+ WhereLoop *pLoop = pLevel->pWLoop;
|
|
+ SrcItem *pTabItem = &pWInfo->pTabList->a[pLevel->iFrom];
|
|
+ SrcList sFrom;
|
|
+ Bitmask mAll = 0;
|
|
+ int k;
|
|
+
|
|
+ ExplainQueryPlan((pParse, 1, "RIGHT-JOIN %s", pTabItem->pTab->zName));
|
|
+ sqlite3VdbeNoJumpsOutsideSubrtn(v, pRJ->addrSubrtn, pRJ->endSubrtn,
|
|
+ pRJ->regReturn);
|
|
+ for(k=0; k<iLevel; k++){
|
|
+ int iIdxCur;
|
|
+ mAll |= pWInfo->a[k].pWLoop->maskSelf;
|
|
+ sqlite3VdbeAddOp1(v, OP_NullRow, pWInfo->a[k].iTabCur);
|
|
+ iIdxCur = pWInfo->a[k].iIdxCur;
|
|
+ if( iIdxCur ){
|
|
+ sqlite3VdbeAddOp1(v, OP_NullRow, iIdxCur);
|
|
+ }
|
|
+ }
|
|
+ if( (pTabItem->fg.jointype & JT_LTORJ)==0 ){
|
|
+ mAll |= pLoop->maskSelf;
|
|
+ for(k=0; k<pWC->nTerm; k++){
|
|
+ WhereTerm *pTerm = &pWC->a[k];
|
|
+ if( (pTerm->wtFlags & (TERM_VIRTUAL|TERM_SLICE))!=0
|
|
+ && pTerm->eOperator!=WO_ROWVAL
|
|
+ ){
|
|
+ break;
|
|
+ }
|
|
+ if( pTerm->prereqAll & ~mAll ) continue;
|
|
+ if( ExprHasProperty(pTerm->pExpr, EP_OuterON|EP_InnerON) ) continue;
|
|
+ pSubWhere = sqlite3ExprAnd(pParse, pSubWhere,
|
|
+ sqlite3ExprDup(pParse->db, pTerm->pExpr, 0));
|
|
+ }
|
|
+ }
|
|
+ sFrom.nSrc = 1;
|
|
+ sFrom.nAlloc = 1;
|
|
+ memcpy(&sFrom.a[0], pTabItem, sizeof(SrcItem));
|
|
+ sFrom.a[0].fg.jointype = 0;
|
|
+ assert( pParse->withinRJSubrtn < 100 );
|
|
+ pParse->withinRJSubrtn++;
|
|
+ pSubWInfo = sqlite3WhereBegin(pParse, &sFrom, pSubWhere, 0, 0, 0,
|
|
+ WHERE_RIGHT_JOIN, 0);
|
|
+ if( pSubWInfo ){
|
|
+ int iCur = pLevel->iTabCur;
|
|
+ int r = ++pParse->nMem;
|
|
+ int nPk;
|
|
+ int jmp;
|
|
+ int addrCont = sqlite3WhereContinueLabel(pSubWInfo);
|
|
+ Table *pTab = pTabItem->pTab;
|
|
+ if( HasRowid(pTab) ){
|
|
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, -1, r);
|
|
+ nPk = 1;
|
|
+ }else{
|
|
+ int iPk;
|
|
+ Index *pPk = sqlite3PrimaryKeyIndex(pTab);
|
|
+ nPk = pPk->nKeyCol;
|
|
+ pParse->nMem += nPk - 1;
|
|
+ for(iPk=0; iPk<nPk; iPk++){
|
|
+ int iCol = pPk->aiColumn[iPk];
|
|
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, iCol,r+iPk);
|
|
+ }
|
|
+ }
|
|
+ jmp = sqlite3VdbeAddOp4Int(v, OP_Filter, pRJ->regBloom, 0, r, nPk);
|
|
+ VdbeCoverage(v);
|
|
+ sqlite3VdbeAddOp4Int(v, OP_Found, pRJ->iMatch, addrCont, r, nPk);
|
|
+ VdbeCoverage(v);
|
|
+ sqlite3VdbeJumpHere(v, jmp);
|
|
+ sqlite3VdbeAddOp2(v, OP_Gosub, pRJ->regReturn, pRJ->addrSubrtn);
|
|
+ sqlite3WhereEnd(pSubWInfo);
|
|
+ }
|
|
+ sqlite3ExprDelete(pParse->db, pSubWhere);
|
|
+ ExplainQueryPlanPop(pParse);
|
|
+ assert( pParse->withinRJSubrtn>0 );
|
|
+ pParse->withinRJSubrtn--;
|
|
+}
|
|
+
|
|
/************** End of wherecode.c *******************************************/
|
|
/************** Begin file whereexpr.c ***************************************/
|
|
/*
|
|
@@ -142280,7 +155128,7 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, u16 wtFlags){
|
|
if( pWC->nTerm>=pWC->nSlot ){
|
|
WhereTerm *pOld = pWC->a;
|
|
sqlite3 *db = pWC->pWInfo->pParse->db;
|
|
- pWC->a = sqlite3DbMallocRawNN(db, sizeof(pWC->a[0])*pWC->nSlot*2 );
|
|
+ pWC->a = sqlite3WhereMalloc(pWC->pWInfo, sizeof(pWC->a[0])*pWC->nSlot*2 );
|
|
if( pWC->a==0 ){
|
|
if( wtFlags & TERM_DYNAMIC ){
|
|
sqlite3ExprDelete(db, p);
|
|
@@ -142289,12 +155137,10 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, u16 wtFlags){
|
|
return 0;
|
|
}
|
|
memcpy(pWC->a, pOld, sizeof(pWC->a[0])*pWC->nTerm);
|
|
- if( pOld!=pWC->aStatic ){
|
|
- sqlite3DbFree(db, pOld);
|
|
- }
|
|
- pWC->nSlot = sqlite3DbMallocSize(db, pWC->a)/sizeof(pWC->a[0]);
|
|
+ pWC->nSlot = pWC->nSlot*2;
|
|
}
|
|
pTerm = &pWC->a[idx = pWC->nTerm++];
|
|
+ if( (wtFlags & TERM_VIRTUAL)==0 ) pWC->nBase = pWC->nTerm;
|
|
if( p && ExprHasProperty(p, EP_Unlikely) ){
|
|
pTerm->truthProb = sqlite3LogEst(p->iTable) - 270;
|
|
}else{
|
|
@@ -142411,6 +155257,7 @@ static int isLikeOrGlob(
|
|
#ifdef SQLITE_EBCDIC
|
|
if( *pnoCase ) return 0;
|
|
#endif
|
|
+ assert( ExprUseXList(pExpr) );
|
|
pList = pExpr->x.pList;
|
|
pLeft = pList->a[1].pExpr;
|
|
|
|
@@ -142426,7 +155273,8 @@ static int isLikeOrGlob(
|
|
sqlite3VdbeSetVarmask(pParse->pVdbe, iCol);
|
|
assert( pRight->op==TK_VARIABLE || pRight->op==TK_REGISTER );
|
|
}else if( op==TK_STRING ){
|
|
- z = (u8*)pRight->u.zToken;
|
|
+ assert( !ExprHasProperty(pRight, EP_IntValue) );
|
|
+ z = (u8*)pRight->u.zToken;
|
|
}
|
|
if( z ){
|
|
|
|
@@ -142455,7 +155303,9 @@ static int isLikeOrGlob(
|
|
pPrefix = sqlite3Expr(db, TK_STRING, (char*)z);
|
|
if( pPrefix ){
|
|
int iFrom, iTo;
|
|
- char *zNew = pPrefix->u.zToken;
|
|
+ char *zNew;
|
|
+ assert( !ExprHasProperty(pPrefix, EP_IntValue) );
|
|
+ zNew = pPrefix->u.zToken;
|
|
zNew[cnt] = 0;
|
|
for(iFrom=iTo=0; iFrom<cnt; iFrom++){
|
|
if( zNew[iFrom]==wc[3] ) iFrom++;
|
|
@@ -142477,9 +155327,11 @@ static int isLikeOrGlob(
|
|
** 2019-06-14 https://sqlite.org/src/info/ce8717f0885af975
|
|
** 2019-09-03 https://sqlite.org/src/info/0f0428096f17252a
|
|
*/
|
|
- if( pLeft->op!=TK_COLUMN
|
|
- || sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT
|
|
- || IsVirtual(pLeft->y.pTab) /* Value might be numeric */
|
|
+ if( pLeft->op!=TK_COLUMN
|
|
+ || sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT
|
|
+ || (ALWAYS( ExprUseYTab(pLeft) )
|
|
+ && ALWAYS(pLeft->y.pTab)
|
|
+ && IsVirtual(pLeft->y.pTab)) /* Might be numeric */
|
|
){
|
|
int isNum;
|
|
double rDummy;
|
|
@@ -142507,13 +155359,14 @@ static int isLikeOrGlob(
|
|
if( op==TK_VARIABLE ){
|
|
Vdbe *v = pParse->pVdbe;
|
|
sqlite3VdbeSetVarmask(v, pRight->iColumn);
|
|
+ assert( !ExprHasProperty(pRight, EP_IntValue) );
|
|
if( *pisComplete && pRight->u.zToken[1] ){
|
|
/* If the rhs of the LIKE expression is a variable, and the current
|
|
** value of the variable means there is no need to invoke the LIKE
|
|
** function, then no OP_Variable will be added to the program.
|
|
** This causes problems for the sqlite3_bind_parameter_name()
|
|
** API. To work around them, add a dummy OP_Variable here.
|
|
- */
|
|
+ */
|
|
int r1 = sqlite3GetTempReg(pParse);
|
|
sqlite3ExprCodeTarget(pParse, pRight, r1);
|
|
sqlite3VdbeChangeP3(v, sqlite3VdbeCurrentAddr(v)-1, 0);
|
|
@@ -142550,7 +155403,7 @@ static int isLikeOrGlob(
|
|
** 9. column IS NOT NULL SQLITE_INDEX_CONSTRAINT_ISNOTNULL
|
|
**
|
|
** In every case, "column" must be a column of a virtual table. If there
|
|
-** is a match, set *ppLeft to the "column" expression, set *ppRight to the
|
|
+** is a match, set *ppLeft to the "column" expression, set *ppRight to the
|
|
** "expr" expression (even though in forms (6) and (8) the column is on the
|
|
** right and the expression is on the left). Also set *peOp2 to the
|
|
** appropriate virtual table operator. The return value is 1 or 2 if there
|
|
@@ -142580,6 +155433,7 @@ static int isAuxiliaryVtabOperator(
|
|
Expr *pCol; /* Column reference */
|
|
int i;
|
|
|
|
+ assert( ExprUseXList(pExpr) );
|
|
pList = pExpr->x.pList;
|
|
if( pList==0 || pList->nExpr!=2 ){
|
|
return 0;
|
|
@@ -142593,8 +155447,10 @@ static int isAuxiliaryVtabOperator(
|
|
** MATCH(expression,vtab_column)
|
|
*/
|
|
pCol = pList->a[1].pExpr;
|
|
- if( pCol->op==TK_COLUMN && IsVirtual(pCol->y.pTab) ){
|
|
+ assert( pCol->op!=TK_COLUMN || (ExprUseYTab(pCol) && pCol->y.pTab!=0) );
|
|
+ if( ExprIsVtab(pCol) ){
|
|
for(i=0; i<ArraySize(aOp); i++){
|
|
+ assert( !ExprHasProperty(pExpr, EP_IntValue) );
|
|
if( sqlite3StrICmp(pExpr->u.zToken, aOp[i].zOp)==0 ){
|
|
*peOp2 = aOp[i].eOp2;
|
|
*ppRight = pList->a[0].pExpr;
|
|
@@ -142615,7 +155471,9 @@ static int isAuxiliaryVtabOperator(
|
|
** with function names in an arbitrary case.
|
|
*/
|
|
pCol = pList->a[0].pExpr;
|
|
- if( pCol->op==TK_COLUMN && IsVirtual(pCol->y.pTab) ){
|
|
+ assert( pCol->op!=TK_COLUMN || ExprUseYTab(pCol) );
|
|
+ assert( pCol->op!=TK_COLUMN || (ExprUseYTab(pCol) && pCol->y.pTab!=0) );
|
|
+ if( ExprIsVtab(pCol) ){
|
|
sqlite3_vtab *pVtab;
|
|
sqlite3_module *pMod;
|
|
void (*xNotUsed)(sqlite3_context*,int,sqlite3_value**);
|
|
@@ -142623,6 +155481,7 @@ static int isAuxiliaryVtabOperator(
|
|
pVtab = sqlite3GetVTable(db, pCol->y.pTab)->pVtab;
|
|
assert( pVtab!=0 );
|
|
assert( pVtab->pModule!=0 );
|
|
+ assert( !ExprHasProperty(pExpr, EP_IntValue) );
|
|
pMod = (sqlite3_module *)pVtab->pModule;
|
|
if( pMod->xFindFunction!=0 ){
|
|
i = pMod->xFindFunction(pVtab,2, pExpr->u.zToken, &xNotUsed, &pNotUsed);
|
|
@@ -142638,10 +155497,13 @@ static int isAuxiliaryVtabOperator(
|
|
int res = 0;
|
|
Expr *pLeft = pExpr->pLeft;
|
|
Expr *pRight = pExpr->pRight;
|
|
- if( pLeft->op==TK_COLUMN && IsVirtual(pLeft->y.pTab) ){
|
|
+ assert( pLeft->op!=TK_COLUMN || (ExprUseYTab(pLeft) && pLeft->y.pTab!=0) );
|
|
+ if( ExprIsVtab(pLeft) ){
|
|
res++;
|
|
}
|
|
- if( pRight && pRight->op==TK_COLUMN && IsVirtual(pRight->y.pTab) ){
|
|
+ assert( pRight==0 || pRight->op!=TK_COLUMN
|
|
+ || (ExprUseYTab(pRight) && pRight->y.pTab!=0) );
|
|
+ if( pRight && ExprIsVtab(pRight) ){
|
|
res++;
|
|
SWAP(Expr*, pLeft, pRight);
|
|
}
|
|
@@ -142661,9 +155523,9 @@ static int isAuxiliaryVtabOperator(
|
|
** a join, then transfer the appropriate markings over to derived.
|
|
*/
|
|
static void transferJoinMarkings(Expr *pDerived, Expr *pBase){
|
|
- if( pDerived ){
|
|
- pDerived->flags |= pBase->flags & EP_FromJoin;
|
|
- pDerived->iRightJoinTable = pBase->iRightJoinTable;
|
|
+ if( pDerived && ExprHasProperty(pBase, EP_OuterON|EP_InnerON) ){
|
|
+ pDerived->flags |= pBase->flags & (EP_OuterON|EP_InnerON);
|
|
+ pDerived->w.iJoin = pBase->w.iJoin;
|
|
}
|
|
}
|
|
|
|
@@ -142709,7 +155571,7 @@ static WhereTerm *whereNthSubterm(WhereTerm *pTerm, int N){
|
|
**
|
|
** The following is NOT generated:
|
|
**
|
|
-** x<y OR x>y --> x!=y
|
|
+** x<y OR x>y --> x!=y
|
|
*/
|
|
static void whereCombineDisjuncts(
|
|
SrcList *pSrc, /* the FROM clause */
|
|
@@ -142723,6 +155585,7 @@ static void whereCombineDisjuncts(
|
|
int op; /* Operator for the combined expression */
|
|
int idxNew; /* Index in pWC of the next virtual term */
|
|
|
|
+ if( (pOne->wtFlags | pTwo->wtFlags) & TERM_VNULL ) return;
|
|
if( (pOne->eOperator & (WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE))==0 ) return;
|
|
if( (pTwo->eOperator & (WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE))==0 ) return;
|
|
if( (eOp & (WO_EQ|WO_LT|WO_LE))!=eOp
|
|
@@ -142806,10 +155669,10 @@ static void whereCombineDisjuncts(
|
|
** WhereTerm.u.pOrInfo->indexable |= the cursor number for table T
|
|
**
|
|
** A subterm is "indexable" if it is of the form
|
|
-** "T.C <op> <expr>" where C is any column of table T and
|
|
+** "T.C <op> <expr>" where C is any column of table T and
|
|
** <op> is one of "=", "<", "<=", ">", ">=", "IS NULL", or "IN".
|
|
** A subterm is also indexable if it is an AND of two or more
|
|
-** subsubterms at least one of which is indexable. Indexable AND
|
|
+** subsubterms at least one of which is indexable. Indexable AND
|
|
** subterms have their eOperator set to WO_AND and they have
|
|
** u.pAndInfo set to a dynamically allocated WhereAndTerm object.
|
|
**
|
|
@@ -142891,6 +155754,7 @@ static void exprAnalyzeOrTerm(
|
|
pOrTerm->u.pAndInfo = pAndInfo;
|
|
pOrTerm->wtFlags |= TERM_ANDINFO;
|
|
pOrTerm->eOperator = WO_AND;
|
|
+ pOrTerm->leftCursor = -1;
|
|
pAndWC = &pAndInfo->wc;
|
|
memset(pAndWC->aStatic, 0, sizeof(pAndWC->aStatic));
|
|
sqlite3WhereClauseInit(pAndWC, pWC->pWInfo);
|
|
@@ -142900,7 +155764,7 @@ static void exprAnalyzeOrTerm(
|
|
if( !db->mallocFailed ){
|
|
for(j=0, pAndTerm=pAndWC->a; j<pAndWC->nTerm; j++, pAndTerm++){
|
|
assert( pAndTerm->pExpr );
|
|
- if( allowedOp(pAndTerm->pExpr->op)
|
|
+ if( allowedOp(pAndTerm->pExpr->op)
|
|
|| pAndTerm->eOperator==WO_AUX
|
|
){
|
|
b |= sqlite3WhereGetMask(&pWInfo->sMaskSet, pAndTerm->leftCursor);
|
|
@@ -142933,11 +155797,10 @@ static void exprAnalyzeOrTerm(
|
|
** empty.
|
|
*/
|
|
pOrInfo->indexable = indexable;
|
|
+ pTerm->eOperator = WO_OR;
|
|
+ pTerm->leftCursor = -1;
|
|
if( indexable ){
|
|
- pTerm->eOperator = WO_OR;
|
|
pWC->hasOr = 1;
|
|
- }else{
|
|
- pTerm->eOperator = WO_OR;
|
|
}
|
|
|
|
/* For a two-way OR, attempt to implementation case 2.
|
|
@@ -142992,7 +155855,7 @@ static void exprAnalyzeOrTerm(
|
|
pOrTerm = pOrWc->a;
|
|
for(i=pOrWc->nTerm-1; i>=0; i--, pOrTerm++){
|
|
assert( pOrTerm->eOperator & WO_EQ );
|
|
- pOrTerm->wtFlags &= ~TERM_OR_OK;
|
|
+ pOrTerm->wtFlags &= ~TERM_OK;
|
|
if( pOrTerm->leftCursor==iCursor ){
|
|
/* This is the 2-bit case and we are on the second iteration and
|
|
** current term is from the first iteration. So skip this term. */
|
|
@@ -143003,14 +155866,15 @@ 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 follwed by an inverted copy (t2.b==t1.a). Skip this term
|
|
** and use its inversion. */
|
|
testcase( pOrTerm->wtFlags & TERM_COPIED );
|
|
testcase( pOrTerm->wtFlags & TERM_VIRTUAL );
|
|
assert( pOrTerm->wtFlags & (TERM_COPIED|TERM_VIRTUAL) );
|
|
continue;
|
|
}
|
|
- iColumn = pOrTerm->u.leftColumn;
|
|
+ assert( (pOrTerm->eOperator & (WO_OR|WO_AND))==0 );
|
|
+ iColumn = pOrTerm->u.x.leftColumn;
|
|
iCursor = pOrTerm->leftCursor;
|
|
pLeft = pOrTerm->pExpr->pLeft;
|
|
break;
|
|
@@ -143030,9 +155894,10 @@ static void exprAnalyzeOrTerm(
|
|
okToChngToIN = 1;
|
|
for(; i>=0 && okToChngToIN; i--, pOrTerm++){
|
|
assert( pOrTerm->eOperator & WO_EQ );
|
|
+ assert( (pOrTerm->eOperator & (WO_OR|WO_AND))==0 );
|
|
if( pOrTerm->leftCursor!=iCursor ){
|
|
- pOrTerm->wtFlags &= ~TERM_OR_OK;
|
|
- }else if( pOrTerm->u.leftColumn!=iColumn || (iColumn==XN_EXPR
|
|
+ pOrTerm->wtFlags &= ~TERM_OK;
|
|
+ }else if( pOrTerm->u.x.leftColumn!=iColumn || (iColumn==XN_EXPR
|
|
&& sqlite3ExprCompare(pParse, pOrTerm->pExpr->pLeft, pLeft, -1)
|
|
)){
|
|
okToChngToIN = 0;
|
|
@@ -143047,14 +155912,14 @@ static void exprAnalyzeOrTerm(
|
|
if( affRight!=0 && affRight!=affLeft ){
|
|
okToChngToIN = 0;
|
|
}else{
|
|
- pOrTerm->wtFlags |= TERM_OR_OK;
|
|
+ pOrTerm->wtFlags |= TERM_OK;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* At this point, okToChngToIN is true if original pTerm satisfies
|
|
- ** case 1. In that case, construct a new virtual term that is
|
|
+ ** case 1. In that case, construct a new virtual term that is
|
|
** pTerm converted into an IN operator.
|
|
*/
|
|
if( okToChngToIN ){
|
|
@@ -143064,10 +155929,11 @@ static void exprAnalyzeOrTerm(
|
|
Expr *pNew; /* The complete IN operator */
|
|
|
|
for(i=pOrWc->nTerm-1, pOrTerm=pOrWc->a; i>=0; i--, pOrTerm++){
|
|
- if( (pOrTerm->wtFlags & TERM_OR_OK)==0 ) continue;
|
|
+ if( (pOrTerm->wtFlags & TERM_OK)==0 ) continue;
|
|
assert( pOrTerm->eOperator & WO_EQ );
|
|
+ assert( (pOrTerm->eOperator & (WO_OR|WO_AND))==0 );
|
|
assert( pOrTerm->leftCursor==iCursor );
|
|
- assert( pOrTerm->u.leftColumn==iColumn );
|
|
+ assert( pOrTerm->u.x.leftColumn==iColumn );
|
|
pDup = sqlite3ExprDup(db, pOrTerm->pExpr->pRight, 0);
|
|
pList = sqlite3ExprListAppend(pWInfo->pParse, pList, pDup);
|
|
pLeft = pOrTerm->pExpr->pLeft;
|
|
@@ -143078,12 +155944,12 @@ static void exprAnalyzeOrTerm(
|
|
if( pNew ){
|
|
int idxNew;
|
|
transferJoinMarkings(pNew, pExpr);
|
|
- assert( !ExprHasProperty(pNew, EP_xIsSelect) );
|
|
+ assert( ExprUseXList(pNew) );
|
|
pNew->x.pList = pList;
|
|
idxNew = whereClauseInsert(pWC, pNew, TERM_VIRTUAL|TERM_DYNAMIC);
|
|
testcase( idxNew==0 );
|
|
exprAnalyze(pSrc, pWC, idxNew);
|
|
- /* pTerm = &pWC->a[idxTerm]; // would be needed if pTerm where used again */
|
|
+ /* pTerm = &pWC->a[idxTerm]; // would be needed if pTerm where reused */
|
|
markTermAsChild(pWC, idxNew, idxTerm);
|
|
}else{
|
|
sqlite3ExprListDelete(db, pList);
|
|
@@ -143113,7 +155979,7 @@ static int termIsEquivalence(Parse *pParse, Expr *pExpr){
|
|
CollSeq *pColl;
|
|
if( !OptimizationEnabled(pParse->db, SQLITE_Transitive) ) return 0;
|
|
if( pExpr->op!=TK_EQ && pExpr->op!=TK_IS ) return 0;
|
|
- if( ExprHasProperty(pExpr, EP_FromJoin) ) return 0;
|
|
+ if( ExprHasProperty(pExpr, EP_OuterON) ) return 0;
|
|
aff1 = sqlite3ExprAffinity(pExpr->pLeft);
|
|
aff2 = sqlite3ExprAffinity(pExpr->pRight);
|
|
if( aff1!=aff2
|
|
@@ -143144,7 +156010,9 @@ static Bitmask exprSelectUsage(WhereMaskSet *pMaskSet, Select *pS){
|
|
int i;
|
|
for(i=0; i<pSrc->nSrc; i++){
|
|
mask |= exprSelectUsage(pMaskSet, pSrc->a[i].pSelect);
|
|
- mask |= sqlite3WhereExprUsage(pMaskSet, pSrc->a[i].pOn);
|
|
+ if( pSrc->a[i].fg.isUsing==0 ){
|
|
+ mask |= sqlite3WhereExprUsage(pMaskSet, pSrc->a[i].u3.pOn);
|
|
+ }
|
|
if( pSrc->a[i].fg.isTabFunc ){
|
|
mask |= sqlite3WhereExprListUsage(pMaskSet, pSrc->a[i].u1.pFuncArg);
|
|
}
|
|
@@ -143170,42 +156038,48 @@ static Bitmask exprSelectUsage(WhereMaskSet *pMaskSet, Select *pS){
|
|
*/
|
|
static SQLITE_NOINLINE int exprMightBeIndexed2(
|
|
SrcList *pFrom, /* The FROM clause */
|
|
- Bitmask mPrereq, /* Bitmask of FROM clause terms referenced by pExpr */
|
|
int *aiCurCol, /* Write the referenced table cursor and column here */
|
|
- Expr *pExpr /* An operand of a comparison operator */
|
|
+ Expr *pExpr, /* An operand of a comparison operator */
|
|
+ int j /* Start looking with the j-th pFrom entry */
|
|
){
|
|
Index *pIdx;
|
|
int i;
|
|
int iCur;
|
|
- for(i=0; mPrereq>1; i++, mPrereq>>=1){}
|
|
- iCur = pFrom->a[i].iCursor;
|
|
- for(pIdx=pFrom->a[i].pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
|
- if( pIdx->aColExpr==0 ) continue;
|
|
- for(i=0; i<pIdx->nKeyCol; i++){
|
|
- if( pIdx->aiColumn[i]!=XN_EXPR ) continue;
|
|
- if( sqlite3ExprCompareSkip(pExpr, pIdx->aColExpr->a[i].pExpr, iCur)==0 ){
|
|
- aiCurCol[0] = iCur;
|
|
- aiCurCol[1] = XN_EXPR;
|
|
- return 1;
|
|
+ do{
|
|
+ iCur = pFrom->a[j].iCursor;
|
|
+ for(pIdx=pFrom->a[j].pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
|
+ if( pIdx->aColExpr==0 ) continue;
|
|
+ for(i=0; i<pIdx->nKeyCol; i++){
|
|
+ if( pIdx->aiColumn[i]!=XN_EXPR ) continue;
|
|
+ assert( pIdx->bHasExpr );
|
|
+ if( sqlite3ExprCompareSkip(pExpr,pIdx->aColExpr->a[i].pExpr,iCur)==0
|
|
+ && pExpr->op!=TK_STRING
|
|
+ ){
|
|
+ aiCurCol[0] = iCur;
|
|
+ aiCurCol[1] = XN_EXPR;
|
|
+ return 1;
|
|
+ }
|
|
}
|
|
}
|
|
- }
|
|
+ }while( ++j < pFrom->nSrc );
|
|
return 0;
|
|
}
|
|
static int exprMightBeIndexed(
|
|
SrcList *pFrom, /* The FROM clause */
|
|
- Bitmask mPrereq, /* Bitmask of FROM clause terms referenced by pExpr */
|
|
int *aiCurCol, /* Write the referenced table cursor & column here */
|
|
Expr *pExpr, /* An operand of a comparison operator */
|
|
int op /* The specific comparison operator */
|
|
){
|
|
- /* If this expression is a vector to the left or right of a
|
|
- ** inequality constraint (>, <, >= or <=), perform the processing
|
|
+ int i;
|
|
+
|
|
+ /* If this expression is a vector to the left or right of a
|
|
+ ** inequality constraint (>, <, >= or <=), perform the processing
|
|
** on the first element of the vector. */
|
|
assert( TK_GT+1==TK_LE && TK_GT+2==TK_LT && TK_GT+3==TK_GE );
|
|
assert( TK_IS<TK_GE && TK_ISNULL<TK_GE && TK_IN<TK_GE );
|
|
assert( op<=TK_GE );
|
|
if( pExpr->op==TK_VECTOR && (op>=TK_GT && ALWAYS(op<=TK_GE)) ){
|
|
+ assert( ExprUseXList(pExpr) );
|
|
pExpr = pExpr->x.pList->a[0].pExpr;
|
|
}
|
|
|
|
@@ -143214,11 +156088,19 @@ static int exprMightBeIndexed(
|
|
aiCurCol[1] = pExpr->iColumn;
|
|
return 1;
|
|
}
|
|
- if( mPrereq==0 ) return 0; /* No table references */
|
|
- if( (mPrereq&(mPrereq-1))!=0 ) return 0; /* Refs more than one table */
|
|
- return exprMightBeIndexed2(pFrom,mPrereq,aiCurCol,pExpr);
|
|
+
|
|
+ for(i=0; i<pFrom->nSrc; i++){
|
|
+ Index *pIdx;
|
|
+ for(pIdx=pFrom->a[i].pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
|
+ if( pIdx->aColExpr ){
|
|
+ return exprMightBeIndexed2(pFrom,aiCurCol,pExpr,i);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ return 0;
|
|
}
|
|
|
|
+
|
|
/*
|
|
** The input to this routine is an WhereTerm structure with only the
|
|
** "pExpr" field filled in. The job of this routine is to analyze the
|
|
@@ -143261,36 +156143,67 @@ static void exprAnalyze(
|
|
if( db->mallocFailed ){
|
|
return;
|
|
}
|
|
+ assert( pWC->nTerm > idxTerm );
|
|
pTerm = &pWC->a[idxTerm];
|
|
pMaskSet = &pWInfo->sMaskSet;
|
|
pExpr = pTerm->pExpr;
|
|
+ assert( pExpr!=0 ); /* Because malloc() has not failed */
|
|
assert( pExpr->op!=TK_AS && pExpr->op!=TK_COLLATE );
|
|
+ pMaskSet->bVarSelect = 0;
|
|
prereqLeft = sqlite3WhereExprUsage(pMaskSet, pExpr->pLeft);
|
|
op = pExpr->op;
|
|
if( op==TK_IN ){
|
|
assert( pExpr->pRight==0 );
|
|
if( sqlite3ExprCheckIN(pParse, pExpr) ) return;
|
|
- if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
|
+ if( ExprUseXSelect(pExpr) ){
|
|
pTerm->prereqRight = exprSelectUsage(pMaskSet, pExpr->x.pSelect);
|
|
}else{
|
|
pTerm->prereqRight = sqlite3WhereExprListUsage(pMaskSet, pExpr->x.pList);
|
|
}
|
|
- }else if( op==TK_ISNULL ){
|
|
- pTerm->prereqRight = 0;
|
|
+ prereqAll = prereqLeft | pTerm->prereqRight;
|
|
}else{
|
|
pTerm->prereqRight = sqlite3WhereExprUsage(pMaskSet, pExpr->pRight);
|
|
+ if( pExpr->pLeft==0
|
|
+ || ExprHasProperty(pExpr, EP_xIsSelect|EP_IfNullRow)
|
|
+ || pExpr->x.pList!=0
|
|
+ ){
|
|
+ prereqAll = sqlite3WhereExprUsageNN(pMaskSet, pExpr);
|
|
+ }else{
|
|
+ prereqAll = prereqLeft | pTerm->prereqRight;
|
|
+ }
|
|
}
|
|
- pMaskSet->bVarSelect = 0;
|
|
- prereqAll = sqlite3WhereExprUsageNN(pMaskSet, pExpr);
|
|
if( pMaskSet->bVarSelect ) pTerm->wtFlags |= TERM_VARSELECT;
|
|
- if( ExprHasProperty(pExpr, EP_FromJoin) ){
|
|
- Bitmask x = sqlite3WhereGetMask(pMaskSet, pExpr->iRightJoinTable);
|
|
- prereqAll |= x;
|
|
- extraRight = x-1; /* ON clause terms may not be used with an index
|
|
- ** on left table of a LEFT JOIN. Ticket #3015 */
|
|
- if( (prereqAll>>1)>=x ){
|
|
- sqlite3ErrorMsg(pParse, "ON clause references tables to its right");
|
|
- return;
|
|
+
|
|
+#ifdef SQLITE_DEBUG
|
|
+ if( prereqAll!=sqlite3WhereExprUsageNN(pMaskSet, pExpr) ){
|
|
+ printf("\n*** Incorrect prereqAll computed for:\n");
|
|
+ sqlite3TreeViewExpr(0,pExpr,0);
|
|
+ assert( 0 );
|
|
+ }
|
|
+#endif
|
|
+
|
|
+ if( ExprHasProperty(pExpr, EP_OuterON|EP_InnerON) ){
|
|
+ Bitmask x = sqlite3WhereGetMask(pMaskSet, pExpr->w.iJoin);
|
|
+ if( ExprHasProperty(pExpr, EP_OuterON) ){
|
|
+ prereqAll |= x;
|
|
+ extraRight = x-1; /* ON clause terms may not be used with an index
|
|
+ ** on left table of a LEFT JOIN. Ticket #3015 */
|
|
+ if( (prereqAll>>1)>=x ){
|
|
+ sqlite3ErrorMsg(pParse, "ON clause references tables to its right");
|
|
+ return;
|
|
+ }
|
|
+ }else if( (prereqAll>>1)>=x ){
|
|
+ /* The ON clause of an INNER JOIN references a table to its right.
|
|
+ ** Most other SQL database engines raise an error. But SQLite versions
|
|
+ ** 3.0 through 3.38 just put the ON clause constraint into the WHERE
|
|
+ ** clause and carried on. Beginning with 3.39, raise an error only
|
|
+ ** if there is a RIGHT or FULL JOIN in the query. This makes SQLite
|
|
+ ** more like other systems, and also preserves legacy. */
|
|
+ if( ALWAYS(pSrc->nSrc>0) && (pSrc->a[0].fg.jointype & JT_LTORJ)!=0 ){
|
|
+ sqlite3ErrorMsg(pParse, "ON clause references tables to its right");
|
|
+ return;
|
|
+ }
|
|
+ ExprClearProperty(pExpr, EP_InnerON);
|
|
}
|
|
}
|
|
pTerm->prereqAll = prereqAll;
|
|
@@ -143303,25 +156216,28 @@ static void exprAnalyze(
|
|
Expr *pRight = sqlite3ExprSkipCollate(pExpr->pRight);
|
|
u16 opMask = (pTerm->prereqRight & prereqLeft)==0 ? WO_ALL : WO_EQUIV;
|
|
|
|
- if( pTerm->iField>0 ){
|
|
+ if( pTerm->u.x.iField>0 ){
|
|
assert( op==TK_IN );
|
|
assert( pLeft->op==TK_VECTOR );
|
|
- pLeft = pLeft->x.pList->a[pTerm->iField-1].pExpr;
|
|
+ assert( ExprUseXList(pLeft) );
|
|
+ pLeft = pLeft->x.pList->a[pTerm->u.x.iField-1].pExpr;
|
|
}
|
|
|
|
- if( exprMightBeIndexed(pSrc, prereqLeft, aiCurCol, pLeft, op) ){
|
|
+ if( exprMightBeIndexed(pSrc, aiCurCol, pLeft, op) ){
|
|
pTerm->leftCursor = aiCurCol[0];
|
|
- pTerm->u.leftColumn = aiCurCol[1];
|
|
+ assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 );
|
|
+ pTerm->u.x.leftColumn = aiCurCol[1];
|
|
pTerm->eOperator = operatorMask(op) & opMask;
|
|
}
|
|
if( op==TK_IS ) pTerm->wtFlags |= TERM_IS;
|
|
- if( pRight
|
|
- && exprMightBeIndexed(pSrc, pTerm->prereqRight, aiCurCol, pRight, op)
|
|
+ if( pRight
|
|
+ && exprMightBeIndexed(pSrc, aiCurCol, pRight, op)
|
|
+ && !ExprHasProperty(pRight, EP_FixedCol)
|
|
){
|
|
WhereTerm *pNew;
|
|
Expr *pDup;
|
|
u16 eExtraOp = 0; /* Extra bits for pNew->eOperator */
|
|
- assert( pTerm->iField==0 );
|
|
+ assert( pTerm->u.x.iField==0 );
|
|
if( pTerm->leftCursor>=0 ){
|
|
int idxNew;
|
|
pDup = sqlite3ExprDup(db, pExpr, 0);
|
|
@@ -143347,11 +156263,23 @@ static void exprAnalyze(
|
|
}
|
|
pNew->wtFlags |= exprCommute(pParse, pDup);
|
|
pNew->leftCursor = aiCurCol[0];
|
|
- pNew->u.leftColumn = aiCurCol[1];
|
|
+ assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 );
|
|
+ pNew->u.x.leftColumn = aiCurCol[1];
|
|
testcase( (prereqLeft | extraRight) != prereqLeft );
|
|
pNew->prereqRight = prereqLeft | extraRight;
|
|
pNew->prereqAll = prereqAll;
|
|
pNew->eOperator = (operatorMask(pDup->op) + eExtraOp) & opMask;
|
|
+ }else
|
|
+ if( op==TK_ISNULL
|
|
+ && !ExprHasProperty(pExpr,EP_OuterON)
|
|
+ && 0==sqlite3ExprCanBeNull(pLeft)
|
|
+ ){
|
|
+ assert( !ExprHasProperty(pExpr, EP_IntValue) );
|
|
+ pExpr->op = TK_TRUEFALSE;
|
|
+ pExpr->u.zToken = "false";
|
|
+ ExprSetProperty(pExpr, EP_IsFalse);
|
|
+ pTerm->prereqAll = 0;
|
|
+ pTerm->eOperator = 0;
|
|
}
|
|
}
|
|
|
|
@@ -143372,15 +156300,17 @@ static void exprAnalyze(
|
|
** BETWEEN term is skipped.
|
|
*/
|
|
else if( pExpr->op==TK_BETWEEN && pWC->op==TK_AND ){
|
|
- ExprList *pList = pExpr->x.pList;
|
|
+ ExprList *pList;
|
|
int i;
|
|
static const u8 ops[] = {TK_GE, TK_LE};
|
|
+ assert( ExprUseXList(pExpr) );
|
|
+ pList = pExpr->x.pList;
|
|
assert( pList!=0 );
|
|
assert( pList->nExpr==2 );
|
|
for(i=0; i<2; i++){
|
|
Expr *pNewExpr;
|
|
int idxNew;
|
|
- pNewExpr = sqlite3PExpr(pParse, ops[i],
|
|
+ pNewExpr = sqlite3PExpr(pParse, ops[i],
|
|
sqlite3ExprDup(db, pExpr->pLeft, 0),
|
|
sqlite3ExprDup(db, pList->a[i].pExpr, 0));
|
|
transferJoinMarkings(pNewExpr, pExpr);
|
|
@@ -143403,6 +156333,42 @@ static void exprAnalyze(
|
|
pTerm = &pWC->a[idxTerm];
|
|
}
|
|
#endif /* SQLITE_OMIT_OR_OPTIMIZATION */
|
|
+ /* The form "x IS NOT NULL" can sometimes be evaluated more efficiently
|
|
+ ** as "x>NULL" if x is not an INTEGER PRIMARY KEY. So construct a
|
|
+ ** virtual term of that form.
|
|
+ **
|
|
+ ** The virtual term must be tagged with TERM_VNULL.
|
|
+ */
|
|
+ else if( pExpr->op==TK_NOTNULL ){
|
|
+ if( pExpr->pLeft->op==TK_COLUMN
|
|
+ && pExpr->pLeft->iColumn>=0
|
|
+ && !ExprHasProperty(pExpr, EP_OuterON)
|
|
+ ){
|
|
+ Expr *pNewExpr;
|
|
+ Expr *pLeft = pExpr->pLeft;
|
|
+ int idxNew;
|
|
+ WhereTerm *pNewTerm;
|
|
+
|
|
+ pNewExpr = sqlite3PExpr(pParse, TK_GT,
|
|
+ sqlite3ExprDup(db, pLeft, 0),
|
|
+ sqlite3ExprAlloc(db, TK_NULL, 0, 0));
|
|
+
|
|
+ idxNew = whereClauseInsert(pWC, pNewExpr,
|
|
+ TERM_VIRTUAL|TERM_DYNAMIC|TERM_VNULL);
|
|
+ if( idxNew ){
|
|
+ pNewTerm = &pWC->a[idxNew];
|
|
+ pNewTerm->prereqRight = 0;
|
|
+ pNewTerm->leftCursor = pLeft->iTable;
|
|
+ pNewTerm->u.x.leftColumn = pLeft->iColumn;
|
|
+ pNewTerm->eOperator = WO_GT;
|
|
+ markTermAsChild(pWC, idxNew, idxTerm);
|
|
+ pTerm = &pWC->a[idxTerm];
|
|
+ pTerm->wtFlags |= TERM_COPIED;
|
|
+ pNewTerm->prereqAll = pTerm->prereqAll;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
|
|
#ifndef SQLITE_OMIT_LIKE_OPTIMIZATION
|
|
/* Add constraints to reduce the search space on a LIKE or GLOB
|
|
@@ -143418,7 +156384,8 @@ static void exprAnalyze(
|
|
** bound is made all lowercase so that the bounds also work when comparing
|
|
** BLOBs.
|
|
*/
|
|
- if( pWC->op==TK_AND
|
|
+ else if( pExpr->op==TK_FUNCTION
|
|
+ && pWC->op==TK_AND
|
|
&& isLikeOrGlob(pParse, pExpr, &pStr1, &isComplete, &noCase)
|
|
){
|
|
Expr *pLeft; /* LHS of LIKE/GLOB operator */
|
|
@@ -143430,8 +156397,12 @@ static void exprAnalyze(
|
|
const char *zCollSeqName; /* Name of collating sequence */
|
|
const u16 wtFlags = TERM_LIKEOPT | TERM_VIRTUAL | TERM_DYNAMIC;
|
|
|
|
+ assert( ExprUseXList(pExpr) );
|
|
pLeft = pExpr->x.pList->a[1].pExpr;
|
|
pStr2 = sqlite3ExprDup(db, pStr1, 0);
|
|
+ assert( pStr1==0 || !ExprHasProperty(pStr1, EP_IntValue) );
|
|
+ assert( pStr2==0 || !ExprHasProperty(pStr2, EP_IntValue) );
|
|
+
|
|
|
|
/* Convert the lower bound to upper-case and the upper bound to
|
|
** lower-case (upper-case is less than lower-case in ASCII) so that
|
|
@@ -143454,7 +156425,7 @@ static void exprAnalyze(
|
|
if( noCase ){
|
|
/* The point is to increment the last character before the first
|
|
** wildcard. But if we increment '@', that will push it into the
|
|
- ** alphabetic range where case conversions will mess up the
|
|
+ ** alphabetic range where case conversions will mess up the
|
|
** inequality. To avoid this, make sure to also run the full
|
|
** LIKE on all candidate expressions by clearing the isComplete flag
|
|
*/
|
|
@@ -143471,7 +156442,6 @@ static void exprAnalyze(
|
|
transferJoinMarkings(pNewExpr1, pExpr);
|
|
idxNew1 = whereClauseInsert(pWC, pNewExpr1, wtFlags);
|
|
testcase( idxNew1==0 );
|
|
- exprAnalyze(pSrc, pWC, idxNew1);
|
|
pNewExpr2 = sqlite3ExprDup(db, pLeft, 0);
|
|
pNewExpr2 = sqlite3PExpr(pParse, TK_LT,
|
|
sqlite3ExprAddCollateString(pParse,pNewExpr2,zCollSeqName),
|
|
@@ -143479,6 +156449,7 @@ static void exprAnalyze(
|
|
transferJoinMarkings(pNewExpr2, pExpr);
|
|
idxNew2 = whereClauseInsert(pWC, pNewExpr2, wtFlags);
|
|
testcase( idxNew2==0 );
|
|
+ exprAnalyze(pSrc, pWC, idxNew1);
|
|
exprAnalyze(pSrc, pWC, idxNew2);
|
|
pTerm = &pWC->a[idxTerm];
|
|
if( isComplete ){
|
|
@@ -143488,147 +156459,114 @@ static void exprAnalyze(
|
|
}
|
|
#endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */
|
|
|
|
-#ifndef SQLITE_OMIT_VIRTUALTABLE
|
|
- /* Add a WO_AUX auxiliary term to the constraint set if the
|
|
- ** current expression is of the form "column OP expr" where OP
|
|
- ** is an operator that gets passed into virtual tables but which is
|
|
- ** not normally optimized for ordinary tables. In other words, OP
|
|
- ** is one of MATCH, LIKE, GLOB, REGEXP, !=, IS, IS NOT, or NOT NULL.
|
|
- ** This information is used by the xBestIndex methods of
|
|
- ** virtual tables. The native query optimizer does not attempt
|
|
- ** to do anything with MATCH functions.
|
|
- */
|
|
- if( pWC->op==TK_AND ){
|
|
- Expr *pRight = 0, *pLeft = 0;
|
|
- int res = isAuxiliaryVtabOperator(db, pExpr, &eOp2, &pLeft, &pRight);
|
|
- while( res-- > 0 ){
|
|
- int idxNew;
|
|
- WhereTerm *pNewTerm;
|
|
- Bitmask prereqColumn, prereqExpr;
|
|
-
|
|
- prereqExpr = sqlite3WhereExprUsage(pMaskSet, pRight);
|
|
- prereqColumn = sqlite3WhereExprUsage(pMaskSet, pLeft);
|
|
- if( (prereqExpr & prereqColumn)==0 ){
|
|
- Expr *pNewExpr;
|
|
- pNewExpr = sqlite3PExpr(pParse, TK_MATCH,
|
|
- 0, sqlite3ExprDup(db, pRight, 0));
|
|
- if( ExprHasProperty(pExpr, EP_FromJoin) && pNewExpr ){
|
|
- ExprSetProperty(pNewExpr, EP_FromJoin);
|
|
- pNewExpr->iRightJoinTable = pExpr->iRightJoinTable;
|
|
- }
|
|
- idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC);
|
|
- testcase( idxNew==0 );
|
|
- pNewTerm = &pWC->a[idxNew];
|
|
- pNewTerm->prereqRight = prereqExpr;
|
|
- pNewTerm->leftCursor = pLeft->iTable;
|
|
- pNewTerm->u.leftColumn = pLeft->iColumn;
|
|
- pNewTerm->eOperator = WO_AUX;
|
|
- pNewTerm->eMatchOp = eOp2;
|
|
- markTermAsChild(pWC, idxNew, idxTerm);
|
|
- pTerm = &pWC->a[idxTerm];
|
|
- pTerm->wtFlags |= TERM_COPIED;
|
|
- pNewTerm->prereqAll = pTerm->prereqAll;
|
|
- }
|
|
- SWAP(Expr*, pLeft, pRight);
|
|
- }
|
|
- }
|
|
-#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
|
-
|
|
/* If there is a vector == or IS term - e.g. "(a, b) == (?, ?)" - create
|
|
** new terms for each component comparison - "a = ?" and "b = ?". The
|
|
** new terms completely replace the original vector comparison, which is
|
|
** no longer used.
|
|
**
|
|
** This is only required if at least one side of the comparison operation
|
|
- ** is not a sub-select. */
|
|
- if( pWC->op==TK_AND
|
|
- && (pExpr->op==TK_EQ || pExpr->op==TK_IS)
|
|
- && (nLeft = sqlite3ExprVectorSize(pExpr->pLeft))>1
|
|
- && sqlite3ExprVectorSize(pExpr->pRight)==nLeft
|
|
- && ( (pExpr->pLeft->flags & EP_xIsSelect)==0
|
|
- || (pExpr->pRight->flags & EP_xIsSelect)==0)
|
|
+ ** is not a sub-select.
|
|
+ **
|
|
+ ** tag-20220128a
|
|
+ */
|
|
+ if( (pExpr->op==TK_EQ || pExpr->op==TK_IS)
|
|
+ && (nLeft = sqlite3ExprVectorSize(pExpr->pLeft))>1
|
|
+ && sqlite3ExprVectorSize(pExpr->pRight)==nLeft
|
|
+ && ( (pExpr->pLeft->flags & EP_xIsSelect)==0
|
|
+ || (pExpr->pRight->flags & EP_xIsSelect)==0)
|
|
+ && pWC->op==TK_AND
|
|
){
|
|
int i;
|
|
for(i=0; i<nLeft; i++){
|
|
int idxNew;
|
|
Expr *pNew;
|
|
- Expr *pLeft = sqlite3ExprForVectorField(pParse, pExpr->pLeft, i);
|
|
- Expr *pRight = sqlite3ExprForVectorField(pParse, pExpr->pRight, i);
|
|
+ Expr *pLeft = sqlite3ExprForVectorField(pParse, pExpr->pLeft, i, nLeft);
|
|
+ Expr *pRight = sqlite3ExprForVectorField(pParse, pExpr->pRight, i, nLeft);
|
|
|
|
pNew = sqlite3PExpr(pParse, pExpr->op, pLeft, pRight);
|
|
transferJoinMarkings(pNew, pExpr);
|
|
- idxNew = whereClauseInsert(pWC, pNew, TERM_DYNAMIC);
|
|
+ idxNew = whereClauseInsert(pWC, pNew, TERM_DYNAMIC|TERM_SLICE);
|
|
exprAnalyze(pSrc, pWC, idxNew);
|
|
}
|
|
pTerm = &pWC->a[idxTerm];
|
|
pTerm->wtFlags |= TERM_CODED|TERM_VIRTUAL; /* Disable the original */
|
|
- pTerm->eOperator = 0;
|
|
+ pTerm->eOperator = WO_ROWVAL;
|
|
}
|
|
|
|
/* If there is a vector IN term - e.g. "(a, b) IN (SELECT ...)" - create
|
|
** a virtual term for each vector component. The expression object
|
|
- ** used by each such virtual term is pExpr (the full vector IN(...)
|
|
- ** expression). The WhereTerm.iField variable identifies the index within
|
|
+ ** used by each such virtual term is pExpr (the full vector IN(...)
|
|
+ ** expression). The WhereTerm.u.x.iField variable identifies the index within
|
|
** the vector on the LHS that the virtual term represents.
|
|
**
|
|
** This only works if the RHS is a simple SELECT (not a compound) that does
|
|
** not use window functions.
|
|
*/
|
|
- if( pWC->op==TK_AND && pExpr->op==TK_IN && pTerm->iField==0
|
|
+ else if( pExpr->op==TK_IN
|
|
+ && pTerm->u.x.iField==0
|
|
&& pExpr->pLeft->op==TK_VECTOR
|
|
- && pExpr->x.pSelect->pPrior==0
|
|
+ && ALWAYS( ExprUseXSelect(pExpr) )
|
|
+ && (pExpr->x.pSelect->pPrior==0 || (pExpr->x.pSelect->selFlags & SF_Values))
|
|
#ifndef SQLITE_OMIT_WINDOWFUNC
|
|
&& pExpr->x.pSelect->pWin==0
|
|
#endif
|
|
+ && pWC->op==TK_AND
|
|
){
|
|
int i;
|
|
for(i=0; i<sqlite3ExprVectorSize(pExpr->pLeft); i++){
|
|
int idxNew;
|
|
- idxNew = whereClauseInsert(pWC, pExpr, TERM_VIRTUAL);
|
|
- pWC->a[idxNew].iField = i+1;
|
|
+ idxNew = whereClauseInsert(pWC, pExpr, TERM_VIRTUAL|TERM_SLICE);
|
|
+ pWC->a[idxNew].u.x.iField = i+1;
|
|
exprAnalyze(pSrc, pWC, idxNew);
|
|
markTermAsChild(pWC, idxNew, idxTerm);
|
|
}
|
|
}
|
|
|
|
-#ifdef SQLITE_ENABLE_STAT4
|
|
- /* When sqlite_stat4 histogram data is available an operator of the
|
|
- ** form "x IS NOT NULL" can sometimes be evaluated more efficiently
|
|
- ** as "x>NULL" if x is not an INTEGER PRIMARY KEY. So construct a
|
|
- ** virtual term of that form.
|
|
- **
|
|
- ** Note that the virtual term must be tagged with TERM_VNULL.
|
|
+#ifndef SQLITE_OMIT_VIRTUALTABLE
|
|
+ /* Add a WO_AUX auxiliary term to the constraint set if the
|
|
+ ** current expression is of the form "column OP expr" where OP
|
|
+ ** is an operator that gets passed into virtual tables but which is
|
|
+ ** not normally optimized for ordinary tables. In other words, OP
|
|
+ ** is one of MATCH, LIKE, GLOB, REGEXP, !=, IS, IS NOT, or NOT NULL.
|
|
+ ** This information is used by the xBestIndex methods of
|
|
+ ** virtual tables. The native query optimizer does not attempt
|
|
+ ** to do anything with MATCH functions.
|
|
*/
|
|
- if( pExpr->op==TK_NOTNULL
|
|
- && pExpr->pLeft->op==TK_COLUMN
|
|
- && pExpr->pLeft->iColumn>=0
|
|
- && !ExprHasProperty(pExpr, EP_FromJoin)
|
|
- && OptimizationEnabled(db, SQLITE_Stat4)
|
|
- ){
|
|
- Expr *pNewExpr;
|
|
- Expr *pLeft = pExpr->pLeft;
|
|
- int idxNew;
|
|
- WhereTerm *pNewTerm;
|
|
-
|
|
- pNewExpr = sqlite3PExpr(pParse, TK_GT,
|
|
- sqlite3ExprDup(db, pLeft, 0),
|
|
- sqlite3ExprAlloc(db, TK_NULL, 0, 0));
|
|
-
|
|
- idxNew = whereClauseInsert(pWC, pNewExpr,
|
|
- TERM_VIRTUAL|TERM_DYNAMIC|TERM_VNULL);
|
|
- if( idxNew ){
|
|
- pNewTerm = &pWC->a[idxNew];
|
|
- pNewTerm->prereqRight = 0;
|
|
- pNewTerm->leftCursor = pLeft->iTable;
|
|
- pNewTerm->u.leftColumn = pLeft->iColumn;
|
|
- pNewTerm->eOperator = WO_GT;
|
|
- markTermAsChild(pWC, idxNew, idxTerm);
|
|
- pTerm = &pWC->a[idxTerm];
|
|
- pTerm->wtFlags |= TERM_COPIED;
|
|
- pNewTerm->prereqAll = pTerm->prereqAll;
|
|
+ else if( pWC->op==TK_AND ){
|
|
+ Expr *pRight = 0, *pLeft = 0;
|
|
+ int res = isAuxiliaryVtabOperator(db, pExpr, &eOp2, &pLeft, &pRight);
|
|
+ while( res-- > 0 ){
|
|
+ int idxNew;
|
|
+ WhereTerm *pNewTerm;
|
|
+ Bitmask prereqColumn, prereqExpr;
|
|
+
|
|
+ prereqExpr = sqlite3WhereExprUsage(pMaskSet, pRight);
|
|
+ prereqColumn = sqlite3WhereExprUsage(pMaskSet, pLeft);
|
|
+ if( (prereqExpr & prereqColumn)==0 ){
|
|
+ Expr *pNewExpr;
|
|
+ pNewExpr = sqlite3PExpr(pParse, TK_MATCH,
|
|
+ 0, sqlite3ExprDup(db, pRight, 0));
|
|
+ if( ExprHasProperty(pExpr, EP_OuterON) && pNewExpr ){
|
|
+ ExprSetProperty(pNewExpr, EP_OuterON);
|
|
+ pNewExpr->w.iJoin = pExpr->w.iJoin;
|
|
+ }
|
|
+ idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC);
|
|
+ testcase( idxNew==0 );
|
|
+ pNewTerm = &pWC->a[idxNew];
|
|
+ pNewTerm->prereqRight = prereqExpr;
|
|
+ pNewTerm->leftCursor = pLeft->iTable;
|
|
+ pNewTerm->u.x.leftColumn = pLeft->iColumn;
|
|
+ pNewTerm->eOperator = WO_AUX;
|
|
+ pNewTerm->eMatchOp = eOp2;
|
|
+ markTermAsChild(pWC, idxNew, idxTerm);
|
|
+ pTerm = &pWC->a[idxTerm];
|
|
+ pTerm->wtFlags |= TERM_COPIED;
|
|
+ pNewTerm->prereqAll = pTerm->prereqAll;
|
|
+ }
|
|
+ SWAP(Expr*, pLeft, pRight);
|
|
}
|
|
}
|
|
-#endif /* SQLITE_ENABLE_STAT4 */
|
|
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
|
|
|
/* Prevent ON clause terms of a LEFT JOIN from being used to drive
|
|
** an index for tables to the left of the join.
|
|
@@ -143663,6 +156601,7 @@ static void exprAnalyze(
|
|
SQLITE_PRIVATE void sqlite3WhereSplit(WhereClause *pWC, Expr *pExpr, u8 op){
|
|
Expr *pE2 = sqlite3ExprSkipCollateAndLikely(pExpr);
|
|
pWC->op = op;
|
|
+ assert( pE2!=0 || pExpr==0 );
|
|
if( pE2==0 ) return;
|
|
if( pE2->op!=op ){
|
|
whereClauseInsert(pWC, pExpr, 0);
|
|
@@ -143672,6 +156611,120 @@ SQLITE_PRIVATE void sqlite3WhereSplit(WhereClause *pWC, Expr *pExpr, u8 op){
|
|
}
|
|
}
|
|
|
|
+/*
|
|
+** Add either a LIMIT (if eMatchOp==SQLITE_INDEX_CONSTRAINT_LIMIT) or
|
|
+** OFFSET (if eMatchOp==SQLITE_INDEX_CONSTRAINT_OFFSET) term to the
|
|
+** where-clause passed as the first argument. The value for the term
|
|
+** is found in register iReg.
|
|
+**
|
|
+** In the common case where the value is a simple integer
|
|
+** (example: "LIMIT 5 OFFSET 10") then the expression codes as a
|
|
+** TK_INTEGER so that it will be available to sqlite3_vtab_rhs_value().
|
|
+** If not, then it codes as a TK_REGISTER expression.
|
|
+*/
|
|
+static void whereAddLimitExpr(
|
|
+ WhereClause *pWC, /* Add the constraint to this WHERE clause */
|
|
+ int iReg, /* Register that will hold value of the limit/offset */
|
|
+ Expr *pExpr, /* Expression that defines the limit/offset */
|
|
+ int iCsr, /* Cursor to which the constraint applies */
|
|
+ int eMatchOp /* SQLITE_INDEX_CONSTRAINT_LIMIT or _OFFSET */
|
|
+){
|
|
+ Parse *pParse = pWC->pWInfo->pParse;
|
|
+ sqlite3 *db = pParse->db;
|
|
+ Expr *pNew;
|
|
+ int iVal = 0;
|
|
+
|
|
+ if( sqlite3ExprIsInteger(pExpr, &iVal) && iVal>=0 ){
|
|
+ Expr *pVal = sqlite3Expr(db, TK_INTEGER, 0);
|
|
+ if( pVal==0 ) return;
|
|
+ ExprSetProperty(pVal, EP_IntValue);
|
|
+ pVal->u.iValue = iVal;
|
|
+ pNew = sqlite3PExpr(pParse, TK_MATCH, 0, pVal);
|
|
+ }else{
|
|
+ Expr *pVal = sqlite3Expr(db, TK_REGISTER, 0);
|
|
+ if( pVal==0 ) return;
|
|
+ pVal->iTable = iReg;
|
|
+ pNew = sqlite3PExpr(pParse, TK_MATCH, 0, pVal);
|
|
+ }
|
|
+ if( pNew ){
|
|
+ WhereTerm *pTerm;
|
|
+ int idx;
|
|
+ idx = whereClauseInsert(pWC, pNew, TERM_DYNAMIC|TERM_VIRTUAL);
|
|
+ pTerm = &pWC->a[idx];
|
|
+ pTerm->leftCursor = iCsr;
|
|
+ pTerm->eOperator = WO_AUX;
|
|
+ pTerm->eMatchOp = eMatchOp;
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+** Possibly add terms corresponding to the LIMIT and OFFSET clauses of the
|
|
+** SELECT statement passed as the second argument. These terms are only
|
|
+** added if:
|
|
+**
|
|
+** 1. The SELECT statement has a LIMIT clause, and
|
|
+** 2. The SELECT statement is not an aggregate or DISTINCT query, and
|
|
+** 3. The SELECT statement has exactly one object in its from clause, and
|
|
+** that object is a virtual table, and
|
|
+** 4. There are no terms in the WHERE clause that will not be passed
|
|
+** to the virtual table xBestIndex method.
|
|
+** 5. The ORDER BY clause, if any, will be made available to the xBestIndex
|
|
+** method.
|
|
+**
|
|
+** LIMIT and OFFSET terms are ignored by most of the planner code. They
|
|
+** exist only so that they may be passed to the xBestIndex method of the
|
|
+** single virtual table in the FROM clause of the SELECT.
|
|
+*/
|
|
+SQLITE_PRIVATE void SQLITE_NOINLINE sqlite3WhereAddLimit(WhereClause *pWC, Select *p){
|
|
+ assert( p!=0 && p->pLimit!=0 ); /* 1 -- checked by caller */
|
|
+ if( p->pGroupBy==0
|
|
+ && (p->selFlags & (SF_Distinct|SF_Aggregate))==0 /* 2 */
|
|
+ && (p->pSrc->nSrc==1 && IsVirtual(p->pSrc->a[0].pTab)) /* 3 */
|
|
+ ){
|
|
+ ExprList *pOrderBy = p->pOrderBy;
|
|
+ int iCsr = p->pSrc->a[0].iCursor;
|
|
+ int ii;
|
|
+
|
|
+ /* Check condition (4). Return early if it is not met. */
|
|
+ for(ii=0; ii<pWC->nTerm; ii++){
|
|
+ if( pWC->a[ii].wtFlags & TERM_CODED ){
|
|
+ /* This term is a vector operation that has been decomposed into
|
|
+ ** other, subsequent terms. It can be ignored. See tag-20220128a */
|
|
+ assert( pWC->a[ii].wtFlags & TERM_VIRTUAL );
|
|
+ assert( pWC->a[ii].eOperator==WO_ROWVAL );
|
|
+ continue;
|
|
+ }
|
|
+ if( pWC->a[ii].nChild ){
|
|
+ /* If this term has child terms, then they are also part of the
|
|
+ ** pWC->a[] array. So this term can be ignored, as a LIMIT clause
|
|
+ ** will only be added if each of the child terms passes the
|
|
+ ** (leftCursor==iCsr) test below. */
|
|
+ continue;
|
|
+ }
|
|
+ if( pWC->a[ii].leftCursor!=iCsr ) return;
|
|
+ }
|
|
+
|
|
+ /* Check condition (5). Return early if it is not met. */
|
|
+ if( pOrderBy ){
|
|
+ for(ii=0; ii<pOrderBy->nExpr; ii++){
|
|
+ Expr *pExpr = pOrderBy->a[ii].pExpr;
|
|
+ if( pExpr->op!=TK_COLUMN ) return;
|
|
+ if( pExpr->iTable!=iCsr ) return;
|
|
+ if( pOrderBy->a[ii].fg.sortFlags & KEYINFO_ORDER_BIGNULL ) return;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* All conditions are met. Add the terms to the where-clause object. */
|
|
+ assert( p->pLimit->op==TK_LIMIT );
|
|
+ whereAddLimitExpr(pWC, p->iLimit, p->pLimit->pLeft,
|
|
+ iCsr, SQLITE_INDEX_CONSTRAINT_LIMIT);
|
|
+ if( p->iOffset>0 ){
|
|
+ whereAddLimitExpr(pWC, p->iOffset, p->pLimit->pRight,
|
|
+ iCsr, SQLITE_INDEX_CONSTRAINT_OFFSET);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
/*
|
|
** Initialize a preallocated WhereClause structure.
|
|
*/
|
|
@@ -143683,6 +156736,7 @@ SQLITE_PRIVATE void sqlite3WhereClauseInit(
|
|
pWC->hasOr = 0;
|
|
pWC->pOuter = 0;
|
|
pWC->nTerm = 0;
|
|
+ pWC->nBase = 0;
|
|
pWC->nSlot = ArraySize(pWC->aStatic);
|
|
pWC->a = pWC->aStatic;
|
|
}
|
|
@@ -143693,22 +156747,36 @@ SQLITE_PRIVATE void sqlite3WhereClauseInit(
|
|
** sqlite3WhereClauseInit().
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3WhereClauseClear(WhereClause *pWC){
|
|
- int i;
|
|
- WhereTerm *a;
|
|
sqlite3 *db = pWC->pWInfo->pParse->db;
|
|
- for(i=pWC->nTerm-1, a=pWC->a; i>=0; i--, a++){
|
|
- if( a->wtFlags & TERM_DYNAMIC ){
|
|
- sqlite3ExprDelete(db, a->pExpr);
|
|
+ assert( pWC->nTerm>=pWC->nBase );
|
|
+ if( pWC->nTerm>0 ){
|
|
+ WhereTerm *a = pWC->a;
|
|
+ WhereTerm *aLast = &pWC->a[pWC->nTerm-1];
|
|
+#ifdef SQLITE_DEBUG
|
|
+ int i;
|
|
+ /* Verify that every term past pWC->nBase is virtual */
|
|
+ for(i=pWC->nBase; i<pWC->nTerm; i++){
|
|
+ assert( (pWC->a[i].wtFlags & TERM_VIRTUAL)!=0 );
|
|
}
|
|
- if( a->wtFlags & TERM_ORINFO ){
|
|
- whereOrInfoDelete(db, a->u.pOrInfo);
|
|
- }else if( a->wtFlags & TERM_ANDINFO ){
|
|
- whereAndInfoDelete(db, a->u.pAndInfo);
|
|
+#endif
|
|
+ while(1){
|
|
+ assert( a->eMatchOp==0 || a->eOperator==WO_AUX );
|
|
+ if( a->wtFlags & TERM_DYNAMIC ){
|
|
+ sqlite3ExprDelete(db, a->pExpr);
|
|
+ }
|
|
+ if( a->wtFlags & (TERM_ORINFO|TERM_ANDINFO) ){
|
|
+ if( a->wtFlags & TERM_ORINFO ){
|
|
+ assert( (a->wtFlags & TERM_ANDINFO)==0 );
|
|
+ whereOrInfoDelete(db, a->u.pOrInfo);
|
|
+ }else{
|
|
+ assert( (a->wtFlags & TERM_ANDINFO)!=0 );
|
|
+ whereAndInfoDelete(db, a->u.pAndInfo);
|
|
+ }
|
|
+ }
|
|
+ if( a==aLast ) break;
|
|
+ a++;
|
|
}
|
|
}
|
|
- if( pWC->a!=pWC->aStatic ){
|
|
- sqlite3DbFree(db, pWC->a);
|
|
- }
|
|
}
|
|
|
|
|
|
@@ -143716,28 +156784,52 @@ SQLITE_PRIVATE void sqlite3WhereClauseClear(WhereClause *pWC){
|
|
** These routines walk (recursively) an expression tree and generate
|
|
** a bitmask indicating which tables are used in that expression
|
|
** tree.
|
|
+**
|
|
+** sqlite3WhereExprUsage(MaskSet, Expr) ->
|
|
+**
|
|
+** Return a Bitmask of all tables referenced by Expr. Expr can be
|
|
+** be NULL, in which case 0 is returned.
|
|
+**
|
|
+** sqlite3WhereExprUsageNN(MaskSet, Expr) ->
|
|
+**
|
|
+** Same as sqlite3WhereExprUsage() except that Expr must not be
|
|
+** NULL. The "NN" suffix on the name stands for "Not Null".
|
|
+**
|
|
+** sqlite3WhereExprListUsage(MaskSet, ExprList) ->
|
|
+**
|
|
+** Return a Bitmask of all tables referenced by every expression
|
|
+** in the expression list ExprList. ExprList can be NULL, in which
|
|
+** case 0 is returned.
|
|
+**
|
|
+** sqlite3WhereExprUsageFull(MaskSet, ExprList) ->
|
|
+**
|
|
+** Internal use only. Called only by sqlite3WhereExprUsageNN() for
|
|
+** complex expressions that require pushing register values onto
|
|
+** the stack. Many calls to sqlite3WhereExprUsageNN() do not need
|
|
+** the more complex analysis done by this routine. Hence, the
|
|
+** computations done by this routine are broken out into a separate
|
|
+** "no-inline" function to avoid the stack push overhead in the
|
|
+** common case where it is not needed.
|
|
*/
|
|
-SQLITE_PRIVATE Bitmask sqlite3WhereExprUsageNN(WhereMaskSet *pMaskSet, Expr *p){
|
|
+static SQLITE_NOINLINE Bitmask sqlite3WhereExprUsageFull(
|
|
+ WhereMaskSet *pMaskSet,
|
|
+ Expr *p
|
|
+){
|
|
Bitmask mask;
|
|
- if( p->op==TK_COLUMN && !ExprHasProperty(p, EP_FixedCol) ){
|
|
- return sqlite3WhereGetMask(pMaskSet, p->iTable);
|
|
- }else if( ExprHasProperty(p, EP_TokenOnly|EP_Leaf) ){
|
|
- assert( p->op!=TK_IF_NULL_ROW );
|
|
- return 0;
|
|
- }
|
|
mask = (p->op==TK_IF_NULL_ROW) ? sqlite3WhereGetMask(pMaskSet, p->iTable) : 0;
|
|
if( p->pLeft ) mask |= sqlite3WhereExprUsageNN(pMaskSet, p->pLeft);
|
|
if( p->pRight ){
|
|
mask |= sqlite3WhereExprUsageNN(pMaskSet, p->pRight);
|
|
assert( p->x.pList==0 );
|
|
- }else if( ExprHasProperty(p, EP_xIsSelect) ){
|
|
+ }else if( ExprUseXSelect(p) ){
|
|
if( ExprHasProperty(p, EP_VarSelect) ) pMaskSet->bVarSelect = 1;
|
|
mask |= exprSelectUsage(pMaskSet, p->x.pSelect);
|
|
}else if( p->x.pList ){
|
|
mask |= sqlite3WhereExprListUsage(pMaskSet, p->x.pList);
|
|
}
|
|
#ifndef SQLITE_OMIT_WINDOWFUNC
|
|
- if( (p->op==TK_FUNCTION || p->op==TK_AGG_FUNCTION) && p->y.pWin ){
|
|
+ if( (p->op==TK_FUNCTION || p->op==TK_AGG_FUNCTION) && ExprUseYWin(p) ){
|
|
+ assert( p->y.pWin!=0 );
|
|
mask |= sqlite3WhereExprListUsage(pMaskSet, p->y.pWin->pPartition);
|
|
mask |= sqlite3WhereExprListUsage(pMaskSet, p->y.pWin->pOrderBy);
|
|
mask |= sqlite3WhereExprUsage(pMaskSet, p->y.pWin->pFilter);
|
|
@@ -143745,6 +156837,15 @@ SQLITE_PRIVATE Bitmask sqlite3WhereExprUsageNN(WhereMaskSet *pMaskSet, Expr *p){
|
|
#endif
|
|
return mask;
|
|
}
|
|
+SQLITE_PRIVATE Bitmask sqlite3WhereExprUsageNN(WhereMaskSet *pMaskSet, Expr *p){
|
|
+ if( p->op==TK_COLUMN && !ExprHasProperty(p, EP_FixedCol) ){
|
|
+ return sqlite3WhereGetMask(pMaskSet, p->iTable);
|
|
+ }else if( ExprHasProperty(p, EP_TokenOnly|EP_Leaf) ){
|
|
+ assert( p->op!=TK_IF_NULL_ROW );
|
|
+ return 0;
|
|
+ }
|
|
+ return sqlite3WhereExprUsageFull(pMaskSet, p);
|
|
+}
|
|
SQLITE_PRIVATE Bitmask sqlite3WhereExprUsage(WhereMaskSet *pMaskSet, Expr *p){
|
|
return p ? sqlite3WhereExprUsageNN(pMaskSet,p) : 0;
|
|
}
|
|
@@ -143761,7 +156862,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereExprListUsage(WhereMaskSet *pMaskSet, ExprLis
|
|
|
|
|
|
/*
|
|
-** Call exprAnalyze on all terms in a WHERE clause.
|
|
+** Call exprAnalyze on all terms in a WHERE clause.
|
|
**
|
|
** Note that exprAnalyze() might add new virtual terms onto the
|
|
** end of the WHERE clause. We do not want to analyze these new
|
|
@@ -143780,14 +156881,14 @@ SQLITE_PRIVATE void sqlite3WhereExprAnalyze(
|
|
|
|
/*
|
|
** For table-valued-functions, transform the function arguments into
|
|
-** new WHERE clause terms.
|
|
+** new WHERE clause terms.
|
|
**
|
|
** Each function argument translates into an equality constraint against
|
|
** a HIDDEN column in the table.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(
|
|
Parse *pParse, /* Parsing context */
|
|
- struct SrcList_item *pItem, /* The FROM clause term to process */
|
|
+ SrcItem *pItem, /* The FROM clause term to process */
|
|
WhereClause *pWC /* Xfer function arguments to here */
|
|
){
|
|
Table *pTab;
|
|
@@ -143802,6 +156903,7 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(
|
|
if( pArgs==0 ) return;
|
|
for(j=k=0; j<pArgs->nExpr; j++){
|
|
Expr *pRhs;
|
|
+ u32 joinType;
|
|
while( k<pTab->nCol && (pTab->aCol[k].colFlags & COLFLAG_HIDDEN)==0 ){k++;}
|
|
if( k>=pTab->nCol ){
|
|
sqlite3ErrorMsg(pParse, "too many arguments on %s() - max %d",
|
|
@@ -143812,13 +156914,18 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(
|
|
if( pColRef==0 ) return;
|
|
pColRef->iTable = pItem->iCursor;
|
|
pColRef->iColumn = k++;
|
|
+ assert( ExprUseYTab(pColRef) );
|
|
pColRef->y.pTab = pTab;
|
|
- pRhs = sqlite3PExpr(pParse, TK_UPLUS,
|
|
+ pItem->colUsed |= sqlite3ExprColUsed(pColRef);
|
|
+ pRhs = sqlite3PExpr(pParse, TK_UPLUS,
|
|
sqlite3ExprDup(pParse->db, pArgs->a[j].pExpr, 0), 0);
|
|
pTerm = sqlite3PExpr(pParse, TK_EQ, pColRef, pRhs);
|
|
- if( pItem->fg.jointype & JT_LEFT ){
|
|
- sqlite3SetJoinExpr(pTerm, pItem->iCursor);
|
|
+ if( pItem->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT) ){
|
|
+ joinType = EP_OuterON;
|
|
+ }else{
|
|
+ joinType = EP_InnerON;
|
|
}
|
|
+ sqlite3SetJoinExpr(pTerm, pItem->iCursor, joinType);
|
|
whereClauseInsert(pWC, pTerm, TERM_DYNAMIC);
|
|
}
|
|
}
|
|
@@ -143857,19 +156964,19 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(
|
|
*/
|
|
typedef struct HiddenIndexInfo HiddenIndexInfo;
|
|
struct HiddenIndexInfo {
|
|
- WhereClause *pWC; /* The Where clause being analyzed */
|
|
- Parse *pParse; /* The parsing context */
|
|
+ WhereClause *pWC; /* The Where clause being analyzed */
|
|
+ Parse *pParse; /* The parsing context */
|
|
+ int eDistinct; /* Value to return from sqlite3_vtab_distinct() */
|
|
+ u32 mIn; /* Mask of terms that are <col> IN (...) */
|
|
+ u32 mHandleIn; /* Terms that vtab will handle as <col> IN (...) */
|
|
+ sqlite3_value *aRhs[1]; /* RHS values for constraints. MUST BE LAST
|
|
+ ** because extra space is allocated to hold up
|
|
+ ** to nTerm such values */
|
|
};
|
|
|
|
/* Forward declaration of methods */
|
|
static int whereLoopResize(sqlite3*, WhereLoop*, int);
|
|
|
|
-/* Test variable that can be set to enable WHERE tracing */
|
|
-#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
|
|
-/***/ int sqlite3WhereTrace = 0;
|
|
-#endif
|
|
-
|
|
-
|
|
/*
|
|
** Return the estimated number of output rows from a WHERE clause
|
|
*/
|
|
@@ -143886,11 +156993,15 @@ SQLITE_PRIVATE int sqlite3WhereIsDistinct(WhereInfo *pWInfo){
|
|
}
|
|
|
|
/*
|
|
-** Return TRUE if the WHERE clause returns rows in ORDER BY order.
|
|
-** Return FALSE if the output needs to be sorted.
|
|
+** Return the number of ORDER BY terms that are satisfied by the
|
|
+** WHERE clause. A return of 0 means that the output must be
|
|
+** completely sorted. A return equal to the number of ORDER BY
|
|
+** terms means that no sorting is needed at all. A return that
|
|
+** is positive but less than the number of ORDER BY terms means that
|
|
+** block sorting is required.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3WhereIsOrdered(WhereInfo *pWInfo){
|
|
- return pWInfo->nOBSat;
|
|
+ return pWInfo->nOBSat<0 ? 0 : pWInfo->nOBSat;
|
|
}
|
|
|
|
/*
|
|
@@ -143911,7 +157022,7 @@ SQLITE_PRIVATE int sqlite3WhereIsOrdered(WhereInfo *pWInfo){
|
|
** be the continuation for the inner-most loop.
|
|
**
|
|
** It is always safe for this routine to return the continuation of the
|
|
-** inner-most loop, in the sense that a correct answer will result.
|
|
+** inner-most loop, in the sense that a correct answer will result.
|
|
** Returning the continuation the second inner loop is an optimization
|
|
** that might make the code run a little faster, but should not change
|
|
** the final answer.
|
|
@@ -143919,13 +157030,39 @@ SQLITE_PRIVATE int sqlite3WhereIsOrdered(WhereInfo *pWInfo){
|
|
SQLITE_PRIVATE int sqlite3WhereOrderByLimitOptLabel(WhereInfo *pWInfo){
|
|
WhereLevel *pInner;
|
|
if( !pWInfo->bOrderedInnerLoop ){
|
|
- /* The ORDER BY LIMIT optimization does not apply. Jump to the
|
|
+ /* The ORDER BY LIMIT optimization does not apply. Jump to the
|
|
** continuation of the inner-most loop. */
|
|
return pWInfo->iContinue;
|
|
}
|
|
pInner = &pWInfo->a[pWInfo->nLevel-1];
|
|
assert( pInner->addrNxt!=0 );
|
|
- return pInner->addrNxt;
|
|
+ return pInner->pRJ ? pWInfo->iContinue : pInner->addrNxt;
|
|
+}
|
|
+
|
|
+/*
|
|
+** While generating code for the min/max optimization, after handling
|
|
+** the aggregate-step call to min() or max(), check to see if any
|
|
+** additional looping is required. If the output order is such that
|
|
+** we are certain that the correct answer has already been found, then
|
|
+** code an OP_Goto to by pass subsequent processing.
|
|
+**
|
|
+** Any extra OP_Goto that is coded here is an optimization. The
|
|
+** correct answer should be obtained regardless. This OP_Goto just
|
|
+** makes the answer appear faster.
|
|
+*/
|
|
+SQLITE_PRIVATE void sqlite3WhereMinMaxOptEarlyOut(Vdbe *v, WhereInfo *pWInfo){
|
|
+ WhereLevel *pInner;
|
|
+ int i;
|
|
+ if( !pWInfo->bOrderedInnerLoop ) return;
|
|
+ if( pWInfo->nOBSat==0 ) return;
|
|
+ for(i=pWInfo->nLevel-1; i>=0; i--){
|
|
+ pInner = &pWInfo->a[i];
|
|
+ if( (pInner->pWLoop->wsFlags & WHERE_COLUMN_IN)!=0 ){
|
|
+ sqlite3VdbeGoto(v, pInner->addrNxt);
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+ sqlite3VdbeGoto(v, pWInfo->iBreak);
|
|
}
|
|
|
|
/*
|
|
@@ -143950,7 +157087,7 @@ SQLITE_PRIVATE int sqlite3WhereBreakLabel(WhereInfo *pWInfo){
|
|
** operate directly on the rowids returned by a WHERE clause. Return
|
|
** ONEPASS_SINGLE (1) if the statement can operation directly because only
|
|
** a single row is to be changed. Return ONEPASS_MULTI (2) if the one-pass
|
|
-** optimization can be used on multiple
|
|
+** optimization can be used on multiple
|
|
**
|
|
** If the ONEPASS optimization is used (if this routine returns true)
|
|
** then also write the indices of open cursors used by ONEPASS
|
|
@@ -144037,7 +157174,12 @@ static int whereOrInsert(
|
|
SQLITE_PRIVATE Bitmask sqlite3WhereGetMask(WhereMaskSet *pMaskSet, int iCursor){
|
|
int i;
|
|
assert( pMaskSet->n<=(int)sizeof(Bitmask)*8 );
|
|
- for(i=0; i<pMaskSet->n; i++){
|
|
+ assert( pMaskSet->n>0 || pMaskSet->ix[0]<0 );
|
|
+ assert( iCursor>=-1 );
|
|
+ if( pMaskSet->ix[0]==iCursor ){
|
|
+ return 1;
|
|
+ }
|
|
+ for(i=1; i<pMaskSet->n; i++){
|
|
if( pMaskSet->ix[i]==iCursor ){
|
|
return MASKBIT(i);
|
|
}
|
|
@@ -144045,6 +157187,30 @@ SQLITE_PRIVATE Bitmask sqlite3WhereGetMask(WhereMaskSet *pMaskSet, int iCursor){
|
|
return 0;
|
|
}
|
|
|
|
+/* Allocate memory that is automatically freed when pWInfo is freed.
|
|
+*/
|
|
+SQLITE_PRIVATE void *sqlite3WhereMalloc(WhereInfo *pWInfo, u64 nByte){
|
|
+ WhereMemBlock *pBlock;
|
|
+ pBlock = sqlite3DbMallocRawNN(pWInfo->pParse->db, nByte+sizeof(*pBlock));
|
|
+ if( pBlock ){
|
|
+ pBlock->pNext = pWInfo->pMemToFree;
|
|
+ pBlock->sz = nByte;
|
|
+ pWInfo->pMemToFree = pBlock;
|
|
+ pBlock++;
|
|
+ }
|
|
+ return (void*)pBlock;
|
|
+}
|
|
+SQLITE_PRIVATE void *sqlite3WhereRealloc(WhereInfo *pWInfo, void *pOld, u64 nByte){
|
|
+ void *pNew = sqlite3WhereMalloc(pWInfo, nByte);
|
|
+ if( pNew && pOld ){
|
|
+ WhereMemBlock *pOldBlk = (WhereMemBlock*)pOld;
|
|
+ pOldBlk--;
|
|
+ assert( pOldBlk->sz<nByte );
|
|
+ memcpy(pNew, pOld, pOldBlk->sz);
|
|
+ }
|
|
+ return pNew;
|
|
+}
|
|
+
|
|
/*
|
|
** Create a new mask for cursor iCursor.
|
|
**
|
|
@@ -144058,6 +157224,18 @@ static void createMask(WhereMaskSet *pMaskSet, int iCursor){
|
|
pMaskSet->ix[pMaskSet->n++] = iCursor;
|
|
}
|
|
|
|
+/*
|
|
+** If the right-hand branch of the expression is a TK_COLUMN, then return
|
|
+** a pointer to the right-hand branch. Otherwise, return NULL.
|
|
+*/
|
|
+static Expr *whereRightSubexprIsColumn(Expr *p){
|
|
+ p = sqlite3ExprSkipCollateAndLikely(p->pRight);
|
|
+ if( ALWAYS(p!=0) && p->op==TK_COLUMN && !ExprHasProperty(p, EP_FixedCol) ){
|
|
+ return p;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
/*
|
|
** Advance to the next WhereTerm that matches according to the criteria
|
|
** established when the pScan object was initialized by whereScanInit().
|
|
@@ -144077,19 +157255,20 @@ static WhereTerm *whereScanNext(WhereScan *pScan){
|
|
iColumn = pScan->aiColumn[pScan->iEquiv-1];
|
|
iCur = pScan->aiCur[pScan->iEquiv-1];
|
|
assert( pWC!=0 );
|
|
+ assert( iCur>=0 );
|
|
do{
|
|
for(pTerm=pWC->a+k; k<pWC->nTerm; k++, pTerm++){
|
|
+ assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 || pTerm->leftCursor<0 );
|
|
if( pTerm->leftCursor==iCur
|
|
- && pTerm->u.leftColumn==iColumn
|
|
+ && pTerm->u.x.leftColumn==iColumn
|
|
&& (iColumn!=XN_EXPR
|
|
|| sqlite3ExprCompareSkip(pTerm->pExpr->pLeft,
|
|
pScan->pIdxExpr,iCur)==0)
|
|
- && (pScan->iEquiv<=1 || !ExprHasProperty(pTerm->pExpr, EP_FromJoin))
|
|
+ && (pScan->iEquiv<=1 || !ExprHasProperty(pTerm->pExpr, EP_OuterON))
|
|
){
|
|
if( (pTerm->eOperator & WO_EQUIV)!=0
|
|
&& pScan->nEquiv<ArraySize(pScan->aiCur)
|
|
- && (pX = sqlite3ExprSkipCollateAndLikely(pTerm->pExpr->pRight))->op
|
|
- ==TK_COLUMN
|
|
+ && (pX = whereRightSubexprIsColumn(pTerm->pExpr))!=0
|
|
){
|
|
int j;
|
|
for(j=0; j<pScan->nEquiv; j++){
|
|
@@ -144121,7 +157300,8 @@ static WhereTerm *whereScanNext(WhereScan *pScan){
|
|
}
|
|
}
|
|
if( (pTerm->eOperator & (WO_EQ|WO_IS))!=0
|
|
- && (pX = pTerm->pExpr->pRight)->op==TK_COLUMN
|
|
+ && (pX = pTerm->pExpr->pRight, ALWAYS(pX!=0))
|
|
+ && pX->op==TK_COLUMN
|
|
&& pX->iTable==pScan->aiCur[0]
|
|
&& pX->iColumn==pScan->aiColumn[0]
|
|
){
|
|
@@ -144130,6 +157310,18 @@ static WhereTerm *whereScanNext(WhereScan *pScan){
|
|
}
|
|
pScan->pWC = pWC;
|
|
pScan->k = k+1;
|
|
+#ifdef WHERETRACE_ENABLED
|
|
+ if( sqlite3WhereTrace & 0x20000 ){
|
|
+ int ii;
|
|
+ sqlite3DebugPrintf("SCAN-TERM %p: nEquiv=%d",
|
|
+ pTerm, pScan->nEquiv);
|
|
+ for(ii=0; ii<pScan->nEquiv; ii++){
|
|
+ sqlite3DebugPrintf(" {%d:%d}",
|
|
+ pScan->aiCur[ii], pScan->aiColumn[ii]);
|
|
+ }
|
|
+ sqlite3DebugPrintf("\n");
|
|
+ }
|
|
+#endif
|
|
return pTerm;
|
|
}
|
|
}
|
|
@@ -144196,16 +157388,16 @@ static WhereTerm *whereScanInit(
|
|
if( pIdx ){
|
|
int j = iColumn;
|
|
iColumn = pIdx->aiColumn[j];
|
|
- if( iColumn==XN_EXPR ){
|
|
- pScan->pIdxExpr = pIdx->aColExpr->a[j].pExpr;
|
|
- pScan->zCollName = pIdx->azColl[j];
|
|
- pScan->aiColumn[0] = XN_EXPR;
|
|
- return whereScanInitIndexExpr(pScan);
|
|
- }else if( iColumn==pIdx->pTable->iPKey ){
|
|
+ if( iColumn==pIdx->pTable->iPKey ){
|
|
iColumn = XN_ROWID;
|
|
}else if( iColumn>=0 ){
|
|
pScan->idxaff = pIdx->pTable->aCol[iColumn].affinity;
|
|
pScan->zCollName = pIdx->azColl[j];
|
|
+ }else if( iColumn==XN_EXPR ){
|
|
+ pScan->pIdxExpr = pIdx->aColExpr->a[j].pExpr;
|
|
+ pScan->zCollName = pIdx->azColl[j];
|
|
+ pScan->aiColumn[0] = XN_EXPR;
|
|
+ return whereScanInitIndexExpr(pScan);
|
|
}
|
|
}else if( iColumn==XN_EXPR ){
|
|
return 0;
|
|
@@ -144220,7 +157412,7 @@ static WhereTerm *whereScanInit(
|
|
** if pIdx!=0 and <op> is one of the WO_xx operator codes specified by
|
|
** the op parameter. Return a pointer to the term. Return 0 if not found.
|
|
**
|
|
-** If pIdx!=0 then it must be one of the indexes of table iCur.
|
|
+** If pIdx!=0 then it must be one of the indexes of table iCur.
|
|
** Search for terms matching the iColumn-th column of pIdx
|
|
** rather than the iColumn-th column of table iCur.
|
|
**
|
|
@@ -144285,7 +157477,8 @@ static int findIndexCol(
|
|
|
|
for(i=0; i<pList->nExpr; i++){
|
|
Expr *p = sqlite3ExprSkipCollateAndLikely(pList->a[i].pExpr);
|
|
- if( p->op==TK_COLUMN
|
|
+ if( ALWAYS(p!=0)
|
|
+ && (p->op==TK_COLUMN || p->op==TK_AGG_COLUMN)
|
|
&& p->iColumn==pIdx->aiColumn[iCol]
|
|
&& p->iTable==iBase
|
|
){
|
|
@@ -144333,23 +157526,25 @@ static int isDistinctRedundant(
|
|
){
|
|
Table *pTab;
|
|
Index *pIdx;
|
|
- int i;
|
|
+ int i;
|
|
int iBase;
|
|
|
|
/* If there is more than one table or sub-select in the FROM clause of
|
|
- ** this query, then it will not be possible to show that the DISTINCT
|
|
+ ** this query, then it will not be possible to show that the DISTINCT
|
|
** clause is redundant. */
|
|
if( pTabList->nSrc!=1 ) return 0;
|
|
iBase = pTabList->a[0].iCursor;
|
|
pTab = pTabList->a[0].pTab;
|
|
|
|
- /* If any of the expressions is an IPK column on table iBase, then return
|
|
+ /* If any of the expressions is an IPK column on table iBase, then return
|
|
** true. Note: The (p->iTable==iBase) part of this test may be false if the
|
|
** current SELECT is a correlated sub-query.
|
|
*/
|
|
for(i=0; i<pDistinct->nExpr; i++){
|
|
Expr *p = sqlite3ExprSkipCollateAndLikely(pDistinct->a[i].pExpr);
|
|
- if( p->op==TK_COLUMN && p->iTable==iBase && p->iColumn<0 ) return 1;
|
|
+ if( NEVER(p==0) ) continue;
|
|
+ if( p->op!=TK_COLUMN && p->op!=TK_AGG_COLUMN ) continue;
|
|
+ if( p->iTable==iBase && p->iColumn<0 ) return 1;
|
|
}
|
|
|
|
/* Loop through all indices on the table, checking each to see if it makes
|
|
@@ -144367,6 +157562,7 @@ static int isDistinctRedundant(
|
|
*/
|
|
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
|
if( !IsUniqueIndex(pIdx) ) continue;
|
|
+ if( pIdx->pPartIdxWhere ) continue;
|
|
for(i=0; i<pIdx->nKeyCol; i++){
|
|
if( 0==sqlite3WhereFindTerm(pWC, iBase, i, ~(Bitmask)0, WO_EQ, pIdx) ){
|
|
if( findIndexCol(pParse, pDistinct, iBase, pIdx, i)<0 ) break;
|
|
@@ -144394,7 +157590,7 @@ static LogEst estLog(LogEst N){
|
|
** Convert OP_Column opcodes to OP_Copy in previously generated code.
|
|
**
|
|
** This routine runs over generated VDBE code and translates OP_Column
|
|
-** opcodes into OP_Copy when the table is being accessed via co-routine
|
|
+** opcodes into OP_Copy when the table is being accessed via co-routine
|
|
** instead of via table lookup.
|
|
**
|
|
** If the iAutoidxCur is not zero, then any OP_Rowid instructions on
|
|
@@ -144420,15 +157616,16 @@ static void translateColumnToCopy(
|
|
pOp->p1 = pOp->p2 + iRegister;
|
|
pOp->p2 = pOp->p3;
|
|
pOp->p3 = 0;
|
|
+ pOp->p5 = 2; /* Cause the MEM_Subtype flag to be cleared */
|
|
}else if( pOp->opcode==OP_Rowid ){
|
|
- if( iAutoidxCur ){
|
|
- pOp->opcode = OP_Sequence;
|
|
- pOp->p1 = iAutoidxCur;
|
|
- }else{
|
|
+ pOp->opcode = OP_Sequence;
|
|
+ pOp->p1 = iAutoidxCur;
|
|
+#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
|
|
+ if( iAutoidxCur==0 ){
|
|
pOp->opcode = OP_Null;
|
|
- pOp->p1 = 0;
|
|
pOp->p3 = 0;
|
|
}
|
|
+#endif
|
|
}
|
|
}
|
|
}
|
|
@@ -144442,14 +157639,16 @@ static void translateColumnToCopy(
|
|
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(WHERETRACE_ENABLED)
|
|
static void whereTraceIndexInfoInputs(sqlite3_index_info *p){
|
|
int i;
|
|
- if( !sqlite3WhereTrace ) return;
|
|
+ if( (sqlite3WhereTrace & 0x10)==0 ) return;
|
|
for(i=0; i<p->nConstraint; i++){
|
|
- sqlite3DebugPrintf(" constraint[%d]: col=%d termid=%d op=%d usabled=%d\n",
|
|
+ sqlite3DebugPrintf(
|
|
+ " constraint[%d]: col=%d termid=%d op=%d usabled=%d collseq=%s\n",
|
|
i,
|
|
p->aConstraint[i].iColumn,
|
|
p->aConstraint[i].iTermOffset,
|
|
p->aConstraint[i].op,
|
|
- p->aConstraint[i].usable);
|
|
+ p->aConstraint[i].usable,
|
|
+ sqlite3_vtab_collation(p,i));
|
|
}
|
|
for(i=0; i<p->nOrderBy; i++){
|
|
sqlite3DebugPrintf(" orderby[%d]: col=%d desc=%d\n",
|
|
@@ -144460,7 +157659,7 @@ static void whereTraceIndexInfoInputs(sqlite3_index_info *p){
|
|
}
|
|
static void whereTraceIndexInfoOutputs(sqlite3_index_info *p){
|
|
int i;
|
|
- if( !sqlite3WhereTrace ) return;
|
|
+ if( (sqlite3WhereTrace & 0x10)==0 ) return;
|
|
for(i=0; i<p->nConstraint; i++){
|
|
sqlite3DebugPrintf(" usage[%d]: argvIdx=%d omit=%d\n",
|
|
i,
|
|
@@ -144478,6 +157677,43 @@ static void whereTraceIndexInfoOutputs(sqlite3_index_info *p){
|
|
#define whereTraceIndexInfoOutputs(A)
|
|
#endif
|
|
|
|
+/*
|
|
+** We know that pSrc is an operand of an outer join. Return true if
|
|
+** pTerm is a constraint that is compatible with that join.
|
|
+**
|
|
+** pTerm must be EP_OuterON if pSrc is the right operand of an
|
|
+** outer join. pTerm can be either EP_OuterON or EP_InnerON if pSrc
|
|
+** is the left operand of a RIGHT join.
|
|
+**
|
|
+** See https://sqlite.org/forum/forumpost/206d99a16dd9212f
|
|
+** for an example of a WHERE clause constraints that may not be used on
|
|
+** the right table of a RIGHT JOIN because the constraint implies a
|
|
+** not-NULL condition on the left table of the RIGHT JOIN.
|
|
+*/
|
|
+static int constraintCompatibleWithOuterJoin(
|
|
+ const WhereTerm *pTerm, /* WHERE clause term to check */
|
|
+ const SrcItem *pSrc /* Table we are trying to access */
|
|
+){
|
|
+ assert( (pSrc->fg.jointype&(JT_LEFT|JT_LTORJ|JT_RIGHT))!=0 ); /* By caller */
|
|
+ testcase( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))==JT_LEFT );
|
|
+ testcase( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))==JT_LTORJ );
|
|
+ testcase( ExprHasProperty(pTerm->pExpr, EP_OuterON) )
|
|
+ testcase( ExprHasProperty(pTerm->pExpr, EP_InnerON) );
|
|
+ if( !ExprHasProperty(pTerm->pExpr, EP_OuterON|EP_InnerON)
|
|
+ || pTerm->pExpr->w.iJoin != pSrc->iCursor
|
|
+ ){
|
|
+ return 0;
|
|
+ }
|
|
+ if( (pSrc->fg.jointype & (JT_LEFT|JT_RIGHT))!=0
|
|
+ && ExprHasProperty(pTerm->pExpr, EP_InnerON)
|
|
+ ){
|
|
+ return 0;
|
|
+ }
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+
|
|
+
|
|
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
|
|
/*
|
|
** Return TRUE if the WHERE clause term pTerm is of a form where it
|
|
@@ -144485,25 +157721,23 @@ static void whereTraceIndexInfoOutputs(sqlite3_index_info *p){
|
|
** index existed.
|
|
*/
|
|
static int termCanDriveIndex(
|
|
- WhereTerm *pTerm, /* WHERE clause term to check */
|
|
- struct SrcList_item *pSrc, /* Table we are trying to access */
|
|
- Bitmask notReady /* Tables in outer loops of the join */
|
|
+ const WhereTerm *pTerm, /* WHERE clause term to check */
|
|
+ const SrcItem *pSrc, /* Table we are trying to access */
|
|
+ const Bitmask notReady /* Tables in outer loops of the join */
|
|
){
|
|
char aff;
|
|
if( pTerm->leftCursor!=pSrc->iCursor ) return 0;
|
|
if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) return 0;
|
|
- if( (pSrc->fg.jointype & JT_LEFT)
|
|
- && !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
|
|
- && (pTerm->eOperator & WO_IS)
|
|
+ assert( (pSrc->fg.jointype & JT_RIGHT)==0 );
|
|
+ if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))!=0
|
|
+ && !constraintCompatibleWithOuterJoin(pTerm,pSrc)
|
|
){
|
|
- /* Cannot use an IS term from the WHERE clause as an index driver for
|
|
- ** the RHS of a LEFT JOIN. Such a term can only be used if it is from
|
|
- ** the ON clause. */
|
|
- return 0;
|
|
+ return 0; /* See https://sqlite.org/forum/forumpost/51e6959f61 */
|
|
}
|
|
if( (pTerm->prereqRight & notReady)!=0 ) return 0;
|
|
- if( pTerm->u.leftColumn<0 ) return 0;
|
|
- aff = pSrc->pTab->aCol[pTerm->u.leftColumn].affinity;
|
|
+ assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 );
|
|
+ if( pTerm->u.x.leftColumn<0 ) return 0;
|
|
+ aff = pSrc->pTab->aCol[pTerm->u.x.leftColumn].affinity;
|
|
if( !sqlite3IndexAffinityOk(pTerm->pExpr, aff) ) return 0;
|
|
testcase( pTerm->pExpr->op==TK_IS );
|
|
return 1;
|
|
@@ -144512,16 +157746,67 @@ static int termCanDriveIndex(
|
|
|
|
|
|
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
|
|
+
|
|
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
|
|
+/*
|
|
+** Argument pIdx represents an automatic index that the current statement
|
|
+** will create and populate. Add an OP_Explain with text of the form:
|
|
+**
|
|
+** CREATE AUTOMATIC INDEX ON <table>(<cols>) [WHERE <expr>]
|
|
+**
|
|
+** This is only required if sqlite3_stmt_scanstatus() is enabled, to
|
|
+** associate an SQLITE_SCANSTAT_NCYCLE and SQLITE_SCANSTAT_NLOOP
|
|
+** values with. In order to avoid breaking legacy code and test cases,
|
|
+** the OP_Explain is not added if this is an EXPLAIN QUERY PLAN command.
|
|
+*/
|
|
+static void explainAutomaticIndex(
|
|
+ Parse *pParse,
|
|
+ Index *pIdx, /* Automatic index to explain */
|
|
+ int bPartial, /* True if pIdx is a partial index */
|
|
+ int *pAddrExplain /* OUT: Address of OP_Explain */
|
|
+){
|
|
+ if( pParse->explain!=2 ){
|
|
+ Table *pTab = pIdx->pTable;
|
|
+ const char *zSep = "";
|
|
+ char *zText = 0;
|
|
+ int ii = 0;
|
|
+ sqlite3_str *pStr = sqlite3_str_new(pParse->db);
|
|
+ sqlite3_str_appendf(pStr,"CREATE AUTOMATIC INDEX ON %s(", pTab->zName);
|
|
+ assert( pIdx->nColumn>1 );
|
|
+ assert( pIdx->aiColumn[pIdx->nColumn-1]==XN_ROWID );
|
|
+ for(ii=0; ii<(pIdx->nColumn-1); ii++){
|
|
+ const char *zName = 0;
|
|
+ int iCol = pIdx->aiColumn[ii];
|
|
+
|
|
+ zName = pTab->aCol[iCol].zCnName;
|
|
+ sqlite3_str_appendf(pStr, "%s%s", zSep, zName);
|
|
+ zSep = ", ";
|
|
+ }
|
|
+ zText = sqlite3_str_finish(pStr);
|
|
+ if( zText==0 ){
|
|
+ sqlite3OomFault(pParse->db);
|
|
+ }else{
|
|
+ *pAddrExplain = sqlite3VdbeExplain(
|
|
+ pParse, 0, "%s)%s", zText, (bPartial ? " WHERE <expr>" : "")
|
|
+ );
|
|
+ sqlite3_free(zText);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+#else
|
|
+# define explainAutomaticIndex(a,b,c,d)
|
|
+#endif
|
|
+
|
|
/*
|
|
** Generate code to construct the Index object for an automatic index
|
|
** and to set up the WhereLevel object pLevel so that the code generator
|
|
** makes use of the automatic index.
|
|
*/
|
|
-static void constructAutomaticIndex(
|
|
+static SQLITE_NOINLINE void constructAutomaticIndex(
|
|
Parse *pParse, /* The parsing context */
|
|
- WhereClause *pWC, /* The WHERE clause */
|
|
- struct SrcList_item *pSrc, /* The FROM clause term to get the next index */
|
|
- Bitmask notReady, /* Mask of cursors that are not available */
|
|
+ const WhereClause *pWC, /* The WHERE clause */
|
|
+ const SrcItem *pSrc, /* The FROM clause term to get the next index */
|
|
+ const Bitmask notReady, /* Mask of cursors that are not available */
|
|
WhereLevel *pLevel /* Write new index here */
|
|
){
|
|
int nKeyCol; /* Number of columns in the constructed index */
|
|
@@ -144544,9 +157829,12 @@ static void constructAutomaticIndex(
|
|
u8 sentWarning = 0; /* True if a warnning has been issued */
|
|
Expr *pPartial = 0; /* Partial Index Expression */
|
|
int iContinue = 0; /* Jump here to skip excluded rows */
|
|
- struct SrcList_item *pTabItem; /* FROM clause term being indexed */
|
|
+ SrcItem *pTabItem; /* FROM clause term being indexed */
|
|
int addrCounter = 0; /* Address where integer counter is initialized */
|
|
int regBase; /* Array of registers where record is assembled */
|
|
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
|
|
+ int addrExp = 0; /* Address of OP_Explain */
|
|
+#endif
|
|
|
|
/* Generate code to skip over the creation and initialization of the
|
|
** transient index on 2nd and subsequent iterations of the loop. */
|
|
@@ -144563,25 +157851,27 @@ static void constructAutomaticIndex(
|
|
idxCols = 0;
|
|
for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){
|
|
Expr *pExpr = pTerm->pExpr;
|
|
- assert( !ExprHasProperty(pExpr, EP_FromJoin) /* prereq always non-zero */
|
|
- || pExpr->iRightJoinTable!=pSrc->iCursor /* for the right-hand */
|
|
- || pLoop->prereq!=0 ); /* table of a LEFT JOIN */
|
|
- if( pLoop->prereq==0
|
|
- && (pTerm->wtFlags & TERM_VIRTUAL)==0
|
|
- && !ExprHasProperty(pExpr, EP_FromJoin)
|
|
- && sqlite3ExprIsTableConstant(pExpr, pSrc->iCursor) ){
|
|
+ /* Make the automatic index a partial index if there are terms in the
|
|
+ ** 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)
|
|
+ ){
|
|
pPartial = sqlite3ExprAnd(pParse, pPartial,
|
|
sqlite3ExprDup(pParse->db, pExpr, 0));
|
|
}
|
|
if( termCanDriveIndex(pTerm, pSrc, notReady) ){
|
|
- int iCol = pTerm->u.leftColumn;
|
|
- Bitmask cMask = iCol>=BMS ? MASKBIT(BMS-1) : MASKBIT(iCol);
|
|
+ int iCol;
|
|
+ Bitmask cMask;
|
|
+ assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 );
|
|
+ iCol = pTerm->u.x.leftColumn;
|
|
+ cMask = iCol>=BMS ? MASKBIT(BMS-1) : MASKBIT(iCol);
|
|
testcase( iCol==BMS );
|
|
testcase( iCol==BMS-1 );
|
|
if( !sentWarning ){
|
|
sqlite3_log(SQLITE_WARNING_AUTOINDEX,
|
|
"automatic index on %s(%s)", pTable->zName,
|
|
- pTable->aCol[iCol].zName);
|
|
+ pTable->aCol[iCol].zCnName);
|
|
sentWarning = 1;
|
|
}
|
|
if( (idxCols & cMask)==0 ){
|
|
@@ -144593,7 +157883,7 @@ static void constructAutomaticIndex(
|
|
}
|
|
}
|
|
}
|
|
- assert( nKeyCol>0 );
|
|
+ assert( nKeyCol>0 || pParse->db->mallocFailed );
|
|
pLoop->u.btree.nEq = pLoop->nLTerm = nKeyCol;
|
|
pLoop->wsFlags = WHERE_COLUMN_EQ | WHERE_IDX_ONLY | WHERE_INDEXED
|
|
| WHERE_AUTO_INDEX;
|
|
@@ -144627,14 +157917,17 @@ static void constructAutomaticIndex(
|
|
idxCols = 0;
|
|
for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){
|
|
if( termCanDriveIndex(pTerm, pSrc, notReady) ){
|
|
- int iCol = pTerm->u.leftColumn;
|
|
- Bitmask cMask = iCol>=BMS ? MASKBIT(BMS-1) : MASKBIT(iCol);
|
|
+ int iCol;
|
|
+ Bitmask cMask;
|
|
+ assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 );
|
|
+ iCol = pTerm->u.x.leftColumn;
|
|
+ cMask = iCol>=BMS ? MASKBIT(BMS-1) : MASKBIT(iCol);
|
|
testcase( iCol==BMS-1 );
|
|
testcase( iCol==BMS );
|
|
if( (idxCols & cMask)==0 ){
|
|
Expr *pX = pTerm->pExpr;
|
|
idxCols |= cMask;
|
|
- pIdx->aiColumn[n] = pTerm->u.leftColumn;
|
|
+ pIdx->aiColumn[n] = pTerm->u.x.leftColumn;
|
|
pColl = sqlite3ExprCompareCollSeq(pParse, pX);
|
|
assert( pColl!=0 || pParse->nErr>0 ); /* TH3 collate01.800 */
|
|
pIdx->azColl[n] = pColl ? pColl->zName : sqlite3StrBINARY;
|
|
@@ -144665,11 +157958,16 @@ static void constructAutomaticIndex(
|
|
pIdx->azColl[n] = sqlite3StrBINARY;
|
|
|
|
/* Create the automatic index */
|
|
+ explainAutomaticIndex(pParse, pIdx, pPartial!=0, &addrExp);
|
|
assert( pLevel->iIdxCur>=0 );
|
|
pLevel->iIdxCur = pParse->nTab++;
|
|
sqlite3VdbeAddOp2(v, OP_OpenAutoindex, pLevel->iIdxCur, nKeyCol+1);
|
|
sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
|
|
VdbeComment((v, "for %s", pTable->zName));
|
|
+ if( OptimizationEnabled(pParse->db, SQLITE_BloomFilter) ){
|
|
+ pLevel->regFilter = ++pParse->nMem;
|
|
+ sqlite3VdbeAddOp2(v, OP_Blob, 10000, pLevel->regFilter);
|
|
+ }
|
|
|
|
/* Fill the automatic index with content */
|
|
pTabItem = &pWC->pWInfo->pTabList->a[pLevel->iFrom];
|
|
@@ -144692,6 +157990,11 @@ static void constructAutomaticIndex(
|
|
regBase = sqlite3GenerateIndexKey(
|
|
pParse, pIdx, pLevel->iTabCur, regRecord, 0, 0, 0, 0
|
|
);
|
|
+ if( pLevel->regFilter ){
|
|
+ sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pLevel->regFilter, 0,
|
|
+ regBase, pLoop->u.btree.nEq);
|
|
+ }
|
|
+ sqlite3VdbeScanStatusCounters(v, addrExp, addrExp, sqlite3VdbeCurrentAddr(v));
|
|
sqlite3VdbeAddOp2(v, OP_IdxInsert, pLevel->iIdxCur, regRecord);
|
|
sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
|
|
if( pPartial ) sqlite3VdbeResolveLabel(v, iContinue);
|
|
@@ -144709,31 +158012,163 @@ static void constructAutomaticIndex(
|
|
}
|
|
sqlite3VdbeJumpHere(v, addrTop);
|
|
sqlite3ReleaseTempReg(pParse, regRecord);
|
|
-
|
|
+
|
|
/* Jump here when skipping the initialization */
|
|
sqlite3VdbeJumpHere(v, addrInit);
|
|
+ sqlite3VdbeScanStatusRange(v, addrExp, addrExp, -1);
|
|
|
|
end_auto_index_create:
|
|
sqlite3ExprDelete(pParse->db, pPartial);
|
|
}
|
|
#endif /* SQLITE_OMIT_AUTOMATIC_INDEX */
|
|
|
|
+/*
|
|
+** Generate bytecode that will initialize a Bloom filter that is appropriate
|
|
+** for pLevel.
|
|
+**
|
|
+** If there are inner loops within pLevel that have the WHERE_BLOOMFILTER
|
|
+** flag set, initialize a Bloomfilter for them as well. Except don't do
|
|
+** this recursive initialization if the SQLITE_BloomPulldown optimization has
|
|
+** been turned off.
|
|
+**
|
|
+** When the Bloom filter is initialized, the WHERE_BLOOMFILTER flag is cleared
|
|
+** from the loop, but the regFilter value is set to a register that implements
|
|
+** the Bloom filter. When regFilter is positive, the
|
|
+** sqlite3WhereCodeOneLoopStart() will generate code to test the Bloom filter
|
|
+** and skip the subsequence B-Tree seek if the Bloom filter indicates that
|
|
+** no matching rows exist.
|
|
+**
|
|
+** This routine may only be called if it has previously been determined that
|
|
+** the loop would benefit from a Bloom filter, and the WHERE_BLOOMFILTER bit
|
|
+** is set.
|
|
+*/
|
|
+static SQLITE_NOINLINE void sqlite3ConstructBloomFilter(
|
|
+ WhereInfo *pWInfo, /* The WHERE clause */
|
|
+ int iLevel, /* Index in pWInfo->a[] that is pLevel */
|
|
+ WhereLevel *pLevel, /* Make a Bloom filter for this FROM term */
|
|
+ Bitmask notReady /* Loops that are not ready */
|
|
+){
|
|
+ int addrOnce; /* Address of opening OP_Once */
|
|
+ int addrTop; /* Address of OP_Rewind */
|
|
+ int addrCont; /* Jump here to skip a row */
|
|
+ const WhereTerm *pTerm; /* For looping over WHERE clause terms */
|
|
+ const WhereTerm *pWCEnd; /* Last WHERE clause term */
|
|
+ Parse *pParse = pWInfo->pParse; /* Parsing context */
|
|
+ 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 */
|
|
+
|
|
+ saved_pIdxEpr = pParse->pIdxEpr;
|
|
+ pParse->pIdxEpr = 0;
|
|
+
|
|
+ assert( pLoop!=0 );
|
|
+ assert( v!=0 );
|
|
+ assert( pLoop->wsFlags & WHERE_BLOOMFILTER );
|
|
+
|
|
+ addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
|
|
+ do{
|
|
+ const SrcItem *pItem;
|
|
+ const Table *pTab;
|
|
+ u64 sz;
|
|
+ sqlite3WhereExplainBloomFilter(pParse, pWInfo, pLevel);
|
|
+ addrCont = sqlite3VdbeMakeLabel(pParse);
|
|
+ iCur = pLevel->iTabCur;
|
|
+ pLevel->regFilter = ++pParse->nMem;
|
|
+
|
|
+ /* The Bloom filter is a Blob held in a register. Initialize it
|
|
+ ** to zero-filled blob of at least 80K bits, but maybe more if the
|
|
+ ** estimated size of the table is larger. We could actually
|
|
+ ** measure the size of the table at run-time using OP_Count with
|
|
+ ** P3==1 and use that value to initialize the blob. But that makes
|
|
+ ** 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];
|
|
+ assert( pItem!=0 );
|
|
+ pTab = pItem->pTab;
|
|
+ assert( pTab!=0 );
|
|
+ sz = sqlite3LogEstToInt(pTab->nRowLogEst);
|
|
+ if( sz<10000 ){
|
|
+ sz = 10000;
|
|
+ }else if( sz>10000000 ){
|
|
+ sz = 10000000;
|
|
+ }
|
|
+ sqlite3VdbeAddOp2(v, OP_Blob, (int)sz, pLevel->regFilter);
|
|
+
|
|
+ addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, iCur); VdbeCoverage(v);
|
|
+ pWCEnd = &pWInfo->sWC.a[pWInfo->sWC.nTerm];
|
|
+ for(pTerm=pWInfo->sWC.a; pTerm<pWCEnd; pTerm++){
|
|
+ Expr *pExpr = pTerm->pExpr;
|
|
+ if( (pTerm->wtFlags & TERM_VIRTUAL)==0
|
|
+ && sqlite3ExprIsTableConstraint(pExpr, pItem)
|
|
+ ){
|
|
+ sqlite3ExprIfFalse(pParse, pTerm->pExpr, addrCont, SQLITE_JUMPIFNULL);
|
|
+ }
|
|
+ }
|
|
+ if( pLoop->wsFlags & WHERE_IPK ){
|
|
+ int r1 = sqlite3GetTempReg(pParse);
|
|
+ sqlite3VdbeAddOp2(v, OP_Rowid, iCur, r1);
|
|
+ sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pLevel->regFilter, 0, r1, 1);
|
|
+ sqlite3ReleaseTempReg(pParse, r1);
|
|
+ }else{
|
|
+ Index *pIdx = pLoop->u.btree.pIndex;
|
|
+ int n = pLoop->u.btree.nEq;
|
|
+ int r1 = sqlite3GetTempRange(pParse, n);
|
|
+ int jj;
|
|
+ for(jj=0; jj<n; jj++){
|
|
+ assert( pIdx->pTable==pItem->pTab );
|
|
+ sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iCur, jj, r1+jj);
|
|
+ }
|
|
+ sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pLevel->regFilter, 0, r1, n);
|
|
+ sqlite3ReleaseTempRange(pParse, r1, n);
|
|
+ }
|
|
+ sqlite3VdbeResolveLabel(v, addrCont);
|
|
+ sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1);
|
|
+ VdbeCoverage(v);
|
|
+ sqlite3VdbeJumpHere(v, addrTop);
|
|
+ pLoop->wsFlags &= ~WHERE_BLOOMFILTER;
|
|
+ if( OptimizationDisabled(pParse->db, SQLITE_BloomPulldown) ) break;
|
|
+ while( ++iLevel < pWInfo->nLevel ){
|
|
+ const SrcItem *pTabItem;
|
|
+ pLevel = &pWInfo->a[iLevel];
|
|
+ pTabItem = &pWInfo->pTabList->a[pLevel->iFrom];
|
|
+ if( pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ) ) continue;
|
|
+ pLoop = pLevel->pWLoop;
|
|
+ if( NEVER(pLoop==0) ) continue;
|
|
+ if( pLoop->prereq & notReady ) continue;
|
|
+ if( (pLoop->wsFlags & (WHERE_BLOOMFILTER|WHERE_COLUMN_IN))
|
|
+ ==WHERE_BLOOMFILTER
|
|
+ ){
|
|
+ /* This is a candidate for bloom-filter pull-down (early evaluation).
|
|
+ ** The test that WHERE_COLUMN_IN is omitted is important, as we are
|
|
+ ** not able to do early evaluation of bloom filters that make use of
|
|
+ ** the IN operator */
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }while( iLevel < pWInfo->nLevel );
|
|
+ sqlite3VdbeJumpHere(v, addrOnce);
|
|
+ pParse->pIdxEpr = saved_pIdxEpr;
|
|
+}
|
|
+
|
|
+
|
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
|
/*
|
|
-** Allocate and populate an sqlite3_index_info structure. It is the
|
|
+** Allocate and populate an sqlite3_index_info structure. It is the
|
|
** responsibility of the caller to eventually release the structure
|
|
-** by passing the pointer returned by this function to sqlite3_free().
|
|
+** by passing the pointer returned by this function to freeIndexInfo().
|
|
*/
|
|
static sqlite3_index_info *allocateIndexInfo(
|
|
- Parse *pParse, /* The parsing context */
|
|
+ WhereInfo *pWInfo, /* The WHERE clause */
|
|
WhereClause *pWC, /* The WHERE clause being analyzed */
|
|
Bitmask mUnusable, /* Ignore terms with these prereqs */
|
|
- struct SrcList_item *pSrc, /* The FROM clause term that is the vtab */
|
|
- ExprList *pOrderBy, /* The ORDER BY clause */
|
|
+ SrcItem *pSrc, /* The FROM clause term that is the vtab */
|
|
u16 *pmNoOmit /* Mask of terms not to omit */
|
|
){
|
|
int i, j;
|
|
int nTerm;
|
|
+ Parse *pParse = pWInfo->pParse;
|
|
struct sqlite3_index_constraint *pIdxCons;
|
|
struct sqlite3_index_orderby *pIdxOrderBy;
|
|
struct sqlite3_index_constraint_usage *pUsage;
|
|
@@ -144742,10 +158177,21 @@ static sqlite3_index_info *allocateIndexInfo(
|
|
int nOrderBy;
|
|
sqlite3_index_info *pIdxInfo;
|
|
u16 mNoOmit = 0;
|
|
+ const Table *pTab;
|
|
+ int eDistinct = 0;
|
|
+ ExprList *pOrderBy = pWInfo->pOrderBy;
|
|
+
|
|
+ assert( pSrc!=0 );
|
|
+ pTab = pSrc->pTab;
|
|
+ assert( pTab!=0 );
|
|
+ assert( IsVirtual(pTab) );
|
|
|
|
- /* Count the number of possible WHERE clause constraints referring
|
|
- ** to this virtual table */
|
|
+ /* Find all WHERE clause constraints referring to this virtual table.
|
|
+ ** Mark each term with the TERM_OK flag. Set nTerm to the number of
|
|
+ ** terms found.
|
|
+ */
|
|
for(i=nTerm=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
|
|
+ pTerm->wtFlags &= ~TERM_OK;
|
|
if( pTerm->leftCursor != pSrc->iCursor ) continue;
|
|
if( pTerm->prereqRight & mUnusable ) continue;
|
|
assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) );
|
|
@@ -144755,11 +158201,20 @@ static sqlite3_index_info *allocateIndexInfo(
|
|
testcase( pTerm->eOperator & WO_ALL );
|
|
if( (pTerm->eOperator & ~(WO_EQUIV))==0 ) continue;
|
|
if( pTerm->wtFlags & TERM_VNULL ) continue;
|
|
- assert( pTerm->u.leftColumn>=(-1) );
|
|
+
|
|
+ assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 );
|
|
+ assert( pTerm->u.x.leftColumn>=XN_ROWID );
|
|
+ assert( pTerm->u.x.leftColumn<pTab->nCol );
|
|
+ if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))!=0
|
|
+ && !constraintCompatibleWithOuterJoin(pTerm,pSrc)
|
|
+ ){
|
|
+ continue;
|
|
+ }
|
|
nTerm++;
|
|
+ pTerm->wtFlags |= TERM_OK;
|
|
}
|
|
|
|
- /* If the ORDER BY clause contains only columns in the current
|
|
+ /* If the ORDER BY clause contains only columns in the current
|
|
** virtual table then allocate space for the aOrderBy part of
|
|
** the sqlite3_index_info structure.
|
|
*/
|
|
@@ -144768,11 +158223,49 @@ static sqlite3_index_info *allocateIndexInfo(
|
|
int n = pOrderBy->nExpr;
|
|
for(i=0; i<n; i++){
|
|
Expr *pExpr = pOrderBy->a[i].pExpr;
|
|
- if( pExpr->op!=TK_COLUMN || pExpr->iTable!=pSrc->iCursor ) break;
|
|
- if( pOrderBy->a[i].sortFlags & KEYINFO_ORDER_BIGNULL ) break;
|
|
+ Expr *pE2;
|
|
+
|
|
+ /* Skip over constant terms in the ORDER BY clause */
|
|
+ if( sqlite3ExprIsConstant(pExpr) ){
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ /* Virtual tables are unable to deal with NULLS FIRST */
|
|
+ if( pOrderBy->a[i].fg.sortFlags & KEYINFO_ORDER_BIGNULL ) break;
|
|
+
|
|
+ /* First case - a direct column references without a COLLATE operator */
|
|
+ if( pExpr->op==TK_COLUMN && pExpr->iTable==pSrc->iCursor ){
|
|
+ assert( pExpr->iColumn>=XN_ROWID && pExpr->iColumn<pTab->nCol );
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ /* 2nd case - a column reference with a COLLATE operator. Only match
|
|
+ ** of the COLLATE operator matches the collation of the column. */
|
|
+ if( pExpr->op==TK_COLLATE
|
|
+ && (pE2 = pExpr->pLeft)->op==TK_COLUMN
|
|
+ && pE2->iTable==pSrc->iCursor
|
|
+ ){
|
|
+ const char *zColl; /* The collating sequence name */
|
|
+ assert( !ExprHasProperty(pExpr, EP_IntValue) );
|
|
+ assert( pExpr->u.zToken!=0 );
|
|
+ assert( pE2->iColumn>=XN_ROWID && pE2->iColumn<pTab->nCol );
|
|
+ pExpr->iColumn = pE2->iColumn;
|
|
+ if( pE2->iColumn<0 ) continue; /* Collseq does not matter for rowid */
|
|
+ zColl = sqlite3ColumnColl(&pTab->aCol[pE2->iColumn]);
|
|
+ if( zColl==0 ) zColl = sqlite3StrBINARY;
|
|
+ if( sqlite3_stricmp(pExpr->u.zToken, zColl)==0 ) continue;
|
|
+ }
|
|
+
|
|
+ /* No matches cause a break out of the loop */
|
|
+ break;
|
|
}
|
|
- if( i==n){
|
|
+ if( i==n ){
|
|
nOrderBy = n;
|
|
+ if( (pWInfo->wctrlFlags & WHERE_DISTINCTBY) ){
|
|
+ eDistinct = 2 + ((pWInfo->wctrlFlags & WHERE_SORTBYGROUP)!=0);
|
|
+ }else if( pWInfo->wctrlFlags & WHERE_GROUPBY ){
|
|
+ eDistinct = 1;
|
|
+ }
|
|
}
|
|
}
|
|
|
|
@@ -144780,46 +158273,35 @@ static sqlite3_index_info *allocateIndexInfo(
|
|
*/
|
|
pIdxInfo = sqlite3DbMallocZero(pParse->db, sizeof(*pIdxInfo)
|
|
+ (sizeof(*pIdxCons) + sizeof(*pUsage))*nTerm
|
|
- + sizeof(*pIdxOrderBy)*nOrderBy + sizeof(*pHidden) );
|
|
+ + sizeof(*pIdxOrderBy)*nOrderBy + sizeof(*pHidden)
|
|
+ + sizeof(sqlite3_value*)*nTerm );
|
|
if( pIdxInfo==0 ){
|
|
sqlite3ErrorMsg(pParse, "out of memory");
|
|
return 0;
|
|
}
|
|
pHidden = (struct HiddenIndexInfo*)&pIdxInfo[1];
|
|
- pIdxCons = (struct sqlite3_index_constraint*)&pHidden[1];
|
|
+ pIdxCons = (struct sqlite3_index_constraint*)&pHidden->aRhs[nTerm];
|
|
pIdxOrderBy = (struct sqlite3_index_orderby*)&pIdxCons[nTerm];
|
|
pUsage = (struct sqlite3_index_constraint_usage*)&pIdxOrderBy[nOrderBy];
|
|
- pIdxInfo->nOrderBy = nOrderBy;
|
|
pIdxInfo->aConstraint = pIdxCons;
|
|
pIdxInfo->aOrderBy = pIdxOrderBy;
|
|
pIdxInfo->aConstraintUsage = pUsage;
|
|
pHidden->pWC = pWC;
|
|
pHidden->pParse = pParse;
|
|
+ pHidden->eDistinct = eDistinct;
|
|
+ pHidden->mIn = 0;
|
|
for(i=j=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
|
|
u16 op;
|
|
- if( pTerm->leftCursor != pSrc->iCursor ) continue;
|
|
- if( pTerm->prereqRight & mUnusable ) continue;
|
|
- assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) );
|
|
- testcase( pTerm->eOperator & WO_IN );
|
|
- testcase( pTerm->eOperator & WO_IS );
|
|
- testcase( pTerm->eOperator & WO_ISNULL );
|
|
- testcase( pTerm->eOperator & WO_ALL );
|
|
- if( (pTerm->eOperator & ~(WO_EQUIV))==0 ) continue;
|
|
- if( pTerm->wtFlags & TERM_VNULL ) continue;
|
|
-
|
|
- /* tag-20191211-002: WHERE-clause constraints are not useful to the
|
|
- ** right-hand table of a LEFT JOIN. See tag-20191211-001 for the
|
|
- ** equivalent restriction for ordinary tables. */
|
|
- if( (pSrc->fg.jointype & JT_LEFT)!=0
|
|
- && !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
|
|
- ){
|
|
- continue;
|
|
- }
|
|
- assert( pTerm->u.leftColumn>=(-1) );
|
|
- pIdxCons[j].iColumn = pTerm->u.leftColumn;
|
|
+ if( (pTerm->wtFlags & TERM_OK)==0 ) continue;
|
|
+ pIdxCons[j].iColumn = pTerm->u.x.leftColumn;
|
|
pIdxCons[j].iTermOffset = i;
|
|
op = pTerm->eOperator & WO_ALL;
|
|
- if( op==WO_IN ) op = WO_EQ;
|
|
+ if( op==WO_IN ){
|
|
+ if( (pTerm->wtFlags & TERM_SLICE)==0 ){
|
|
+ pHidden->mIn |= SMASKBIT32(j);
|
|
+ }
|
|
+ op = WO_EQ;
|
|
+ }
|
|
if( op==WO_AUX ){
|
|
pIdxCons[j].op = pTerm->eMatchOp;
|
|
}else if( op & (WO_ISNULL|WO_IS) ){
|
|
@@ -144841,7 +158323,7 @@ static sqlite3_index_info *allocateIndexInfo(
|
|
assert( pTerm->eOperator&(WO_IN|WO_EQ|WO_LT|WO_LE|WO_GT|WO_GE|WO_AUX) );
|
|
|
|
if( op & (WO_LT|WO_LE|WO_GT|WO_GE)
|
|
- && sqlite3ExprIsVector(pTerm->pExpr->pRight)
|
|
+ && sqlite3ExprIsVector(pTerm->pExpr->pRight)
|
|
){
|
|
testcase( j!=i );
|
|
if( j<16 ) mNoOmit |= (1 << j);
|
|
@@ -144852,17 +158334,42 @@ static sqlite3_index_info *allocateIndexInfo(
|
|
|
|
j++;
|
|
}
|
|
+ assert( j==nTerm );
|
|
pIdxInfo->nConstraint = j;
|
|
- for(i=0; i<nOrderBy; i++){
|
|
+ for(i=j=0; i<nOrderBy; i++){
|
|
Expr *pExpr = pOrderBy->a[i].pExpr;
|
|
- pIdxOrderBy[i].iColumn = pExpr->iColumn;
|
|
- pIdxOrderBy[i].desc = pOrderBy->a[i].sortFlags & KEYINFO_ORDER_DESC;
|
|
+ if( sqlite3ExprIsConstant(pExpr) ) continue;
|
|
+ assert( pExpr->op==TK_COLUMN
|
|
+ || (pExpr->op==TK_COLLATE && pExpr->pLeft->op==TK_COLUMN
|
|
+ && pExpr->iColumn==pExpr->pLeft->iColumn) );
|
|
+ pIdxOrderBy[j].iColumn = pExpr->iColumn;
|
|
+ pIdxOrderBy[j].desc = pOrderBy->a[i].fg.sortFlags & KEYINFO_ORDER_DESC;
|
|
+ j++;
|
|
}
|
|
+ pIdxInfo->nOrderBy = j;
|
|
|
|
*pmNoOmit = mNoOmit;
|
|
return pIdxInfo;
|
|
}
|
|
|
|
+/*
|
|
+** Free an sqlite3_index_info structure allocated by allocateIndexInfo()
|
|
+** and possibly modified by xBestIndex methods.
|
|
+*/
|
|
+static void freeIndexInfo(sqlite3 *db, sqlite3_index_info *pIdxInfo){
|
|
+ HiddenIndexInfo *pHidden;
|
|
+ int i;
|
|
+ assert( pIdxInfo!=0 );
|
|
+ pHidden = (HiddenIndexInfo*)&pIdxInfo[1];
|
|
+ assert( pHidden->pParse!=0 );
|
|
+ assert( pHidden->pParse->db==db );
|
|
+ for(i=0; i<pIdxInfo->nConstraint; i++){
|
|
+ sqlite3ValueFree(pHidden->aRhs[i]); /* IMP: R-14553-25174 */
|
|
+ pHidden->aRhs[i] = 0;
|
|
+ }
|
|
+ sqlite3DbFree(db, pIdxInfo);
|
|
+}
|
|
+
|
|
/*
|
|
** The table object reference passed as the second argument to this function
|
|
** must represent a virtual table. This function invokes the xBestIndex()
|
|
@@ -144884,7 +158391,9 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
|
|
int rc;
|
|
|
|
whereTraceIndexInfoInputs(p);
|
|
+ pParse->db->nSchemaLock++;
|
|
rc = pVtab->pModule->xBestIndex(pVtab, p);
|
|
+ pParse->db->nSchemaLock--;
|
|
whereTraceIndexInfoOutputs(p);
|
|
|
|
if( rc!=SQLITE_OK && rc!=SQLITE_CONSTRAINT ){
|
|
@@ -144913,8 +158422,8 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
|
|
** Return the index of the sample that is the smallest sample that
|
|
** is greater than or equal to pRec. Note that this index is not an index
|
|
** into the aSample[] array - it is an index into a virtual set of samples
|
|
-** based on the contents of aSample[] and the number of fields in record
|
|
-** pRec.
|
|
+** based on the contents of aSample[] and the number of fields in record
|
|
+** pRec.
|
|
*/
|
|
static int whereKeyStats(
|
|
Parse *pParse, /* Database connection */
|
|
@@ -144938,7 +158447,8 @@ static int whereKeyStats(
|
|
#endif
|
|
assert( pRec!=0 );
|
|
assert( pIdx->nSample>0 );
|
|
- assert( pRec->nField>0 && pRec->nField<=pIdx->nSampleCol );
|
|
+ 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
|
|
@@ -144950,41 +158460,46 @@ static int whereKeyStats(
|
|
** consider prefixes of those samples. For example, if the set of samples
|
|
** in aSample is:
|
|
**
|
|
- ** aSample[0] = (a, 5)
|
|
- ** aSample[1] = (a, 10)
|
|
- ** aSample[2] = (b, 5)
|
|
- ** aSample[3] = (c, 100)
|
|
+ ** aSample[0] = (a, 5)
|
|
+ ** aSample[1] = (a, 10)
|
|
+ ** aSample[2] = (b, 5)
|
|
+ ** aSample[3] = (c, 100)
|
|
** aSample[4] = (c, 105)
|
|
**
|
|
- ** Then the search space should ideally be the samples above and the
|
|
- ** unique prefixes [a], [b] and [c]. But since that is hard to organize,
|
|
+ ** Then the search space should ideally be the samples above and the
|
|
+ ** unique prefixes [a], [b] and [c]. But since that is hard to organize,
|
|
** the code actually searches this set:
|
|
**
|
|
- ** 0: (a)
|
|
- ** 1: (a, 5)
|
|
- ** 2: (a, 10)
|
|
- ** 3: (a, 10)
|
|
- ** 4: (b)
|
|
- ** 5: (b, 5)
|
|
- ** 6: (c)
|
|
- ** 7: (c, 100)
|
|
+ ** 0: (a)
|
|
+ ** 1: (a, 5)
|
|
+ ** 2: (a, 10)
|
|
+ ** 3: (a, 10)
|
|
+ ** 4: (b)
|
|
+ ** 5: (b, 5)
|
|
+ ** 6: (c)
|
|
+ ** 7: (c, 100)
|
|
** 8: (c, 105)
|
|
** 9: (c, 105)
|
|
**
|
|
** For each sample in the aSample[] array, N samples are present in the
|
|
- ** effective sample array. In the above, samples 0 and 1 are based on
|
|
+ ** effective sample array. In the above, samples 0 and 1 are based on
|
|
** sample aSample[0]. Samples 2 and 3 on aSample[1] etc.
|
|
**
|
|
** Often, sample i of each block of N effective samples has (i+1) fields.
|
|
** Except, each sample may be extended to ensure that it is greater than or
|
|
- ** equal to the previous sample in the array. For example, in the above,
|
|
- ** sample 2 is the first sample of a block of N samples, so at first it
|
|
- ** appears that it should be 1 field in size. However, that would make it
|
|
- ** smaller than sample 1, so the binary search would not work. As a result,
|
|
- ** it is extended to two fields. The duplicates that this creates do not
|
|
+ ** equal to the previous sample in the array. For example, in the above,
|
|
+ ** sample 2 is the first sample of a block of N samples, so at first it
|
|
+ ** appears that it should be 1 field in size. However, that would make it
|
|
+ ** smaller than sample 1, so the binary search would not work. As a result,
|
|
+ ** it is extended to two fields. The duplicates that this creates do not
|
|
** cause any problems.
|
|
*/
|
|
- nField = pRec->nField;
|
|
+ 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{
|
|
@@ -144995,7 +158510,7 @@ static int whereKeyStats(
|
|
iSamp = iTest / nField;
|
|
if( iSamp>0 ){
|
|
/* The proposed effective sample is a prefix of sample aSample[iSamp].
|
|
- ** Specifically, the shortest prefix of at least (1 + iTest%nField)
|
|
+ ** Specifically, the shortest prefix of at least (1 + iTest%nField)
|
|
** fields that is greater than the previous effective sample. */
|
|
for(n=(iTest % nField) + 1; n<nField; n++){
|
|
if( aSample[iSamp-1].anLt[n-1]!=aSample[iSamp].anLt[n-1] ) break;
|
|
@@ -145030,8 +158545,8 @@ static int whereKeyStats(
|
|
assert( i<pIdx->nSample );
|
|
assert( iCol==nField-1 );
|
|
pRec->nField = nField;
|
|
- assert( 0==sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec)
|
|
- || pParse->db->mallocFailed
|
|
+ assert( 0==sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec)
|
|
+ || pParse->db->mallocFailed
|
|
);
|
|
}else{
|
|
/* Unless i==pIdx->nSample, indicating that pRec is larger than
|
|
@@ -145039,7 +158554,7 @@ static int whereKeyStats(
|
|
** (iCol+1) field prefix of sample i. */
|
|
assert( i<=pIdx->nSample && i>=0 );
|
|
pRec->nField = iCol+1;
|
|
- assert( i==pIdx->nSample
|
|
+ assert( i==pIdx->nSample
|
|
|| sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec)>0
|
|
|| pParse->db->mallocFailed );
|
|
|
|
@@ -145050,12 +158565,12 @@ static int whereKeyStats(
|
|
if( iCol>0 ){
|
|
pRec->nField = iCol;
|
|
assert( sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec)<=0
|
|
- || pParse->db->mallocFailed );
|
|
+ || pParse->db->mallocFailed || CORRUPT_DB );
|
|
}
|
|
if( i>0 ){
|
|
pRec->nField = nField;
|
|
assert( sqlite3VdbeRecordCompare(aSample[i-1].n, aSample[i-1].p, pRec)<0
|
|
- || pParse->db->mallocFailed );
|
|
+ || pParse->db->mallocFailed || CORRUPT_DB );
|
|
}
|
|
}
|
|
}
|
|
@@ -145067,12 +158582,12 @@ static int whereKeyStats(
|
|
aStat[0] = aSample[i].anLt[iCol];
|
|
aStat[1] = aSample[i].anEq[iCol];
|
|
}else{
|
|
- /* At this point, the (iCol+1) field prefix of aSample[i] is the first
|
|
+ /* At this point, the (iCol+1) field prefix of aSample[i] is the first
|
|
** sample that is greater than pRec. Or, if i==pIdx->nSample then pRec
|
|
** is larger than all samples in the array. */
|
|
tRowcnt iUpper, iGap;
|
|
if( i>=pIdx->nSample ){
|
|
- iUpper = sqlite3LogEstToInt(pIdx->aiRowLogEst[0]);
|
|
+ iUpper = pIdx->nRowEst0;
|
|
}else{
|
|
iUpper = aSample[i].anLt[iCol];
|
|
}
|
|
@@ -145099,7 +158614,7 @@ static int whereKeyStats(
|
|
|
|
/*
|
|
** If it is not NULL, pTerm is a term that provides an upper or lower
|
|
-** bound on a range scan. Without considering pTerm, it is estimated
|
|
+** bound on a range scan. Without considering pTerm, it is estimated
|
|
** that the scan will visit nNew rows. This function returns the number
|
|
** estimated to be visited after taking pTerm into account.
|
|
**
|
|
@@ -145137,18 +158652,18 @@ SQLITE_PRIVATE char sqlite3IndexColumnAffinity(sqlite3 *db, Index *pIdx, int iCo
|
|
|
|
|
|
#ifdef SQLITE_ENABLE_STAT4
|
|
-/*
|
|
+/*
|
|
** This function is called to estimate the number of rows visited by a
|
|
** range-scan on a skip-scan index. For example:
|
|
**
|
|
** CREATE INDEX i1 ON t1(a, b, c);
|
|
** SELECT * FROM t1 WHERE a=? AND c BETWEEN ? AND ?;
|
|
**
|
|
-** Value pLoop->nOut is currently set to the estimated number of rows
|
|
-** visited for scanning (a=? AND b=?). This function reduces that estimate
|
|
+** 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
|
|
-** times (once for each (a,b) combination that matches a=?) is dealt with
|
|
+** on the stat4 data for the index. this scan will be peformed multiple
|
|
+** times (once for each (a,b) combination that matches a=?) is dealt with
|
|
** by the caller.
|
|
**
|
|
** It does this by scanning through all stat4 samples, comparing values
|
|
@@ -145169,7 +158684,7 @@ SQLITE_PRIVATE char sqlite3IndexColumnAffinity(sqlite3 *db, Index *pIdx, int iCo
|
|
** estimate of the number of rows delivered remains unchanged), *pbDone
|
|
** is left as is.
|
|
**
|
|
-** If an error occurs, an SQLite error code is returned. Otherwise,
|
|
+** If an error occurs, an SQLite error code is returned. Otherwise,
|
|
** SQLITE_OK.
|
|
*/
|
|
static int whereRangeSkipScanEst(
|
|
@@ -145187,7 +158702,7 @@ static int whereRangeSkipScanEst(
|
|
int rc = SQLITE_OK;
|
|
u8 aff = sqlite3IndexColumnAffinity(db, p, nEq);
|
|
CollSeq *pColl;
|
|
-
|
|
+
|
|
sqlite3_value *p1 = 0; /* Value extracted from pLower */
|
|
sqlite3_value *p2 = 0; /* Value extracted from pUpper */
|
|
sqlite3_value *pVal = 0; /* Value extracted from record */
|
|
@@ -145219,7 +158734,7 @@ static int whereRangeSkipScanEst(
|
|
nDiff = (nUpper - nLower);
|
|
if( nDiff<=0 ) nDiff = 1;
|
|
|
|
- /* If there is both an upper and lower bound specified, and the
|
|
+ /* If there is both an upper and lower bound specified, and the
|
|
** comparisons indicate that they are close together, use the fallback
|
|
** method (assume that the scan visits 1/64 of the rows) for estimating
|
|
** the number of rows visited. Otherwise, estimate the number of rows
|
|
@@ -145228,7 +158743,7 @@ static int whereRangeSkipScanEst(
|
|
int nAdjust = (sqlite3LogEst(p->nSample) - sqlite3LogEst(nDiff));
|
|
pLoop->nOut -= nAdjust;
|
|
*pbDone = 1;
|
|
- WHERETRACE(0x10, ("range skip-scan regions: %u..%u adjust=%d est=%d\n",
|
|
+ WHERETRACE(0x20, ("range skip-scan regions: %u..%u adjust=%d est=%d\n",
|
|
nLower, nUpper, nAdjust*-1, pLoop->nOut));
|
|
}
|
|
|
|
@@ -145266,7 +158781,7 @@ static int whereRangeSkipScanEst(
|
|
**
|
|
** ... FROM t1 WHERE a = ? AND b > ? AND b < ? ...
|
|
**
|
|
-** then nEq is set to 1 (as the range restricted column, b, is the second
|
|
+** then nEq is set to 1 (as the range restricted column, b, is the second
|
|
** left-most column of the index). Or, if the query is:
|
|
**
|
|
** ... FROM t1 WHERE a > ? AND a < ? ...
|
|
@@ -145274,13 +158789,13 @@ static int whereRangeSkipScanEst(
|
|
** then nEq is set to 0.
|
|
**
|
|
** When this function is called, *pnOut is set to the sqlite3LogEst() of the
|
|
-** number of rows that the index scan is expected to visit without
|
|
-** considering the range constraints. If nEq is 0, then *pnOut is the number of
|
|
+** number of rows that the index scan is expected to visit without
|
|
+** considering the range constraints. If nEq is 0, then *pnOut is the number of
|
|
** rows in the index. Assuming no error occurs, *pnOut is adjusted (reduced)
|
|
** to account for the range constraints pLower and pUpper.
|
|
-**
|
|
+**
|
|
** In the absence of sqlite_stat4 ANALYZE data, or if such data cannot be
|
|
-** used, a single range inequality reduces the search space by a factor of 4.
|
|
+** used, a single range inequality reduces the search space by a factor of 4.
|
|
** and a pair of constraints (x>? AND x<?) reduces the expected number of
|
|
** rows visited by a factor of 64.
|
|
*/
|
|
@@ -145308,7 +158823,7 @@ static int whereRangeScanEst(
|
|
int nBtm = pLoop->u.btree.nBtm;
|
|
int nTop = pLoop->u.btree.nTop;
|
|
|
|
- /* Variable iLower will be set to the estimate of the number of rows in
|
|
+ /* Variable iLower will be set to the estimate of the number of rows in
|
|
** the index that are less than the lower bound of the range query. The
|
|
** lower bound being the concatenation of $P and $L, where $P is the
|
|
** key-prefix formed by the nEq values matched against the nEq left-most
|
|
@@ -145317,7 +158832,7 @@ static int whereRangeScanEst(
|
|
** Or, if pLower is NULL or $L cannot be extracted from it (because it
|
|
** is not a simple variable or literal value), the lower bound of the
|
|
** range is $P. Due to a quirk in the way whereKeyStats() works, even
|
|
- ** if $L is available, whereKeyStats() is called for both ($P) and
|
|
+ ** if $L is available, whereKeyStats() is called for both ($P) and
|
|
** ($P:$L) and the larger of the two returned values is used.
|
|
**
|
|
** Similarly, iUpper is to be set to the estimate of the number of rows
|
|
@@ -145341,7 +158856,7 @@ static int whereRangeScanEst(
|
|
iLower = 0;
|
|
iUpper = p->nRowEst0;
|
|
}else{
|
|
- /* Note: this call could be optimized away - since the same values must
|
|
+ /* Note: this call could be optimized away - since the same values must
|
|
** have been requested when testing key $P in whereEqualScanEst(). */
|
|
whereKeyStats(pParse, p, pRec, 0, a);
|
|
iLower = a[0];
|
|
@@ -145406,7 +158921,7 @@ static int whereRangeScanEst(
|
|
if( nNew<nOut ){
|
|
nOut = nNew;
|
|
}
|
|
- WHERETRACE(0x10, ("STAT4 range scan: %u..%u est=%d\n",
|
|
+ WHERETRACE(0x20, ("STAT4 range scan: %u..%u est=%d\n",
|
|
(u32)iLower, (u32)iUpper, nOut));
|
|
}
|
|
}else{
|
|
@@ -145429,7 +158944,7 @@ static int whereRangeScanEst(
|
|
** reduced by an additional 75%. This means that, by default, an open-ended
|
|
** range query (e.g. col > ?) is assumed to match 1/4 of the rows in the
|
|
** index. While a closed range (e.g. col BETWEEN ? AND ?) is estimated to
|
|
- ** match 1/64 of the index. */
|
|
+ ** match 1/64 of the index. */
|
|
if( pLower && pLower->truthProb>0 && pUpper && pUpper->truthProb>0 ){
|
|
nNew -= 20;
|
|
}
|
|
@@ -145439,7 +158954,7 @@ static int whereRangeScanEst(
|
|
if( nNew<nOut ) nOut = nNew;
|
|
#if defined(WHERETRACE_ENABLED)
|
|
if( pLoop->nOut>nOut ){
|
|
- WHERETRACE(0x10,("Range scan lowers nOut from %d to %d\n",
|
|
+ WHERETRACE(0x20,("Range scan lowers nOut from %d to %d\n",
|
|
pLoop->nOut, nOut));
|
|
}
|
|
#endif
|
|
@@ -145456,7 +158971,7 @@ static int whereRangeScanEst(
|
|
** for that index. When pExpr==NULL that means the constraint is
|
|
** "x IS NULL" instead of "x=VALUE".
|
|
**
|
|
-** Write the estimated row count into *pnRow and return SQLITE_OK.
|
|
+** Write the estimated row count into *pnRow and return SQLITE_OK.
|
|
** If unable to make an estimate, leave *pnRow unchanged and return
|
|
** non-zero.
|
|
**
|
|
@@ -145504,10 +159019,10 @@ static int whereEqualScanEst(
|
|
pBuilder->nRecValid = nEq;
|
|
|
|
whereKeyStats(pParse, p, pRec, 0, a);
|
|
- WHERETRACE(0x10,("equality scan regions %s(%d): %d\n",
|
|
+ WHERETRACE(0x20,("equality scan regions %s(%d): %d\n",
|
|
p->zName, nEq-1, (int)a[1]));
|
|
*pnRow = a[1];
|
|
-
|
|
+
|
|
return rc;
|
|
}
|
|
#endif /* SQLITE_ENABLE_STAT4 */
|
|
@@ -145520,7 +159035,7 @@ static int whereEqualScanEst(
|
|
**
|
|
** WHERE x IN (1,2,3,4)
|
|
**
|
|
-** Write the estimated row count into *pnRow and return SQLITE_OK.
|
|
+** Write the estimated row count into *pnRow and return SQLITE_OK.
|
|
** If unable to make an estimate, leave *pnRow unchanged and return
|
|
** non-zero.
|
|
**
|
|
@@ -145552,9 +159067,9 @@ static int whereInScanEst(
|
|
}
|
|
|
|
if( rc==SQLITE_OK ){
|
|
- if( nRowEst > nRow0 ) nRowEst = nRow0;
|
|
+ if( nRowEst > (tRowcnt)nRow0 ) nRowEst = nRow0;
|
|
*pnRow = nRowEst;
|
|
- WHERETRACE(0x10,("IN row estimate: est=%d\n", nRowEst));
|
|
+ WHERETRACE(0x20,("IN row estimate: est=%d\n", nRowEst));
|
|
}
|
|
assert( pBuilder->nRecValid==nRecValid );
|
|
return rc;
|
|
@@ -145575,13 +159090,14 @@ SQLITE_PRIVATE void sqlite3WhereTermPrint(WhereTerm *pTerm, int iTerm){
|
|
memcpy(zType, "....", 5);
|
|
if( pTerm->wtFlags & TERM_VIRTUAL ) zType[0] = 'V';
|
|
if( pTerm->eOperator & WO_EQUIV ) zType[1] = 'E';
|
|
- if( ExprHasProperty(pTerm->pExpr, EP_FromJoin) ) zType[2] = 'L';
|
|
+ if( ExprHasProperty(pTerm->pExpr, EP_OuterON) ) zType[2] = 'L';
|
|
if( pTerm->wtFlags & TERM_CODED ) zType[3] = 'C';
|
|
if( pTerm->eOperator & WO_SINGLE ){
|
|
+ assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 );
|
|
sqlite3_snprintf(sizeof(zLeft),zLeft,"left={%d:%d}",
|
|
- pTerm->leftCursor, pTerm->u.leftColumn);
|
|
+ pTerm->leftCursor, pTerm->u.x.leftColumn);
|
|
}else if( (pTerm->eOperator & WO_OR)!=0 && pTerm->u.pOrInfo!=0 ){
|
|
- sqlite3_snprintf(sizeof(zLeft),zLeft,"indexable=0x%lld",
|
|
+ sqlite3_snprintf(sizeof(zLeft),zLeft,"indexable=0x%llx",
|
|
pTerm->u.pOrInfo->indexable);
|
|
}else{
|
|
sqlite3_snprintf(sizeof(zLeft),zLeft,"left=%d", pTerm->leftCursor);
|
|
@@ -145595,8 +159111,8 @@ SQLITE_PRIVATE void sqlite3WhereTermPrint(WhereTerm *pTerm, int iTerm){
|
|
sqlite3DebugPrintf(" prob=%-3d prereq=%llx,%llx",
|
|
pTerm->truthProb, (u64)pTerm->prereqAll, (u64)pTerm->prereqRight);
|
|
}
|
|
- if( pTerm->iField ){
|
|
- sqlite3DebugPrintf(" iField=%d", pTerm->iField);
|
|
+ if( (pTerm->eOperator & (WO_OR|WO_AND))==0 && pTerm->u.x.iField ){
|
|
+ sqlite3DebugPrintf(" iField=%d", pTerm->u.x.iField);
|
|
}
|
|
if( pTerm->iParent>=0 ){
|
|
sqlite3DebugPrintf(" iParent=%d", pTerm->iParent);
|
|
@@ -145626,7 +159142,7 @@ SQLITE_PRIVATE void sqlite3WhereClausePrint(WhereClause *pWC){
|
|
SQLITE_PRIVATE void sqlite3WhereLoopPrint(WhereLoop *p, WhereClause *pWC){
|
|
WhereInfo *pWInfo = pWC->pWInfo;
|
|
int nb = 1+(pWInfo->pTabList->nSrc+3)/4;
|
|
- struct SrcList_item *pItem = pWInfo->pTabList->a + p->iTab;
|
|
+ SrcItem *pItem = pWInfo->pTabList->a + p->iTab;
|
|
Table *pTab = pItem->pTab;
|
|
Bitmask mAll = (((Bitmask)1)<<(nb*4)) - 1;
|
|
sqlite3DebugPrintf("%c%2d.%0*llx.%0*llx", p->cId,
|
|
@@ -145657,12 +159173,12 @@ SQLITE_PRIVATE void sqlite3WhereLoopPrint(WhereLoop *p, WhereClause *pWC){
|
|
sqlite3_free(z);
|
|
}
|
|
if( p->wsFlags & WHERE_SKIPSCAN ){
|
|
- sqlite3DebugPrintf(" f %05x %d-%d", p->wsFlags, p->nLTerm,p->nSkip);
|
|
+ sqlite3DebugPrintf(" f %06x %d-%d", p->wsFlags, p->nLTerm,p->nSkip);
|
|
}else{
|
|
- sqlite3DebugPrintf(" f %05x N %d", p->wsFlags, p->nLTerm);
|
|
+ sqlite3DebugPrintf(" f %06x N %d", p->wsFlags, p->nLTerm);
|
|
}
|
|
sqlite3DebugPrintf(" cost %d,%d,%d\n", p->rSetup, p->rRun, p->nOut);
|
|
- if( p->nLTerm && (sqlite3WhereTrace & 0x100)!=0 ){
|
|
+ if( p->nLTerm && (sqlite3WhereTrace & 0x4000)!=0 ){
|
|
int i;
|
|
for(i=0; i<p->nLTerm; i++){
|
|
sqlite3WhereTermPrint(p->aLTerm[i], i);
|
|
@@ -145700,12 +159216,18 @@ static void whereLoopClearUnion(sqlite3 *db, WhereLoop *p){
|
|
}
|
|
|
|
/*
|
|
-** Deallocate internal memory used by a WhereLoop object
|
|
+** Deallocate internal memory used by a WhereLoop object. Leave the
|
|
+** object in an initialized state, as if it had been newly allocated.
|
|
*/
|
|
static void whereLoopClear(sqlite3 *db, WhereLoop *p){
|
|
- if( p->aLTerm!=p->aLTermSpace ) sqlite3DbFreeNN(db, p->aLTerm);
|
|
+ if( p->aLTerm!=p->aLTermSpace ){
|
|
+ sqlite3DbFreeNN(db, p->aLTerm);
|
|
+ p->aLTerm = p->aLTermSpace;
|
|
+ p->nLSlot = ArraySize(p->aLTermSpace);
|
|
+ }
|
|
whereLoopClearUnion(db, p);
|
|
- whereLoopInit(p);
|
|
+ p->nLTerm = 0;
|
|
+ p->wsFlags = 0;
|
|
}
|
|
|
|
/*
|
|
@@ -145729,8 +159251,10 @@ static int whereLoopResize(sqlite3 *db, WhereLoop *p, int n){
|
|
*/
|
|
static int whereLoopXfer(sqlite3 *db, WhereLoop *pTo, WhereLoop *pFrom){
|
|
whereLoopClearUnion(db, pTo);
|
|
- if( whereLoopResize(db, pTo, pFrom->nLTerm) ){
|
|
- memset(&pTo->u, 0, sizeof(pTo->u));
|
|
+ if( pFrom->nLTerm > pTo->nLSlot
|
|
+ && whereLoopResize(db, pTo, pFrom->nLTerm)
|
|
+ ){
|
|
+ memset(pTo, 0, WHERE_LOOP_XFER_SZ);
|
|
return SQLITE_NOMEM_BKPT;
|
|
}
|
|
memcpy(pTo, pFrom, WHERE_LOOP_XFER_SZ);
|
|
@@ -145747,36 +159271,36 @@ static int whereLoopXfer(sqlite3 *db, WhereLoop *pTo, WhereLoop *pFrom){
|
|
** Delete a WhereLoop object
|
|
*/
|
|
static void whereLoopDelete(sqlite3 *db, WhereLoop *p){
|
|
+ assert( db!=0 );
|
|
whereLoopClear(db, p);
|
|
- sqlite3DbFreeNN(db, p);
|
|
+ sqlite3DbNNFreeNN(db, p);
|
|
}
|
|
|
|
/*
|
|
** Free a WhereInfo structure
|
|
*/
|
|
static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
|
|
- int i;
|
|
assert( pWInfo!=0 );
|
|
- for(i=0; i<pWInfo->nLevel; i++){
|
|
- WhereLevel *pLevel = &pWInfo->a[i];
|
|
- if( pLevel->pWLoop && (pLevel->pWLoop->wsFlags & WHERE_IN_ABLE) ){
|
|
- sqlite3DbFree(db, pLevel->u.in.aInLoop);
|
|
- }
|
|
- }
|
|
+ assert( db!=0 );
|
|
sqlite3WhereClauseClear(&pWInfo->sWC);
|
|
while( pWInfo->pLoops ){
|
|
WhereLoop *p = pWInfo->pLoops;
|
|
pWInfo->pLoops = p->pNextLoop;
|
|
whereLoopDelete(db, p);
|
|
}
|
|
- assert( pWInfo->pExprMods==0 );
|
|
- sqlite3DbFreeNN(db, pWInfo);
|
|
+ while( pWInfo->pMemToFree ){
|
|
+ WhereMemBlock *pNext = pWInfo->pMemToFree->pNext;
|
|
+ sqlite3DbNNFreeNN(db, pWInfo->pMemToFree);
|
|
+ pWInfo->pMemToFree = pNext;
|
|
+ }
|
|
+ sqlite3DbNNFreeNN(db, pWInfo);
|
|
}
|
|
|
|
/*
|
|
** Return TRUE if all of the following are true:
|
|
**
|
|
-** (1) X has the same or lower cost that Y
|
|
+** (1) X has the same or lower cost, or returns the same or fewer rows,
|
|
+** than Y.
|
|
** (2) X uses fewer WHERE clause terms than Y
|
|
** (3) Every WHERE clause term used by X is also used by Y
|
|
** (4) X skips at least as many columns as Y
|
|
@@ -145784,7 +159308,7 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
|
|
**
|
|
** Conditions (2) and (3) mean that X is a "proper subset" of Y.
|
|
** If X is a proper subset of Y then Y is a better choice and ought
|
|
-** to have a lower cost. This routine returns TRUE when that cost
|
|
+** to have a lower cost. This routine returns TRUE when that cost
|
|
** relationship is inverted and needs to be adjusted. Constraint (4)
|
|
** was added because if X uses skip-scan less than Y it still might
|
|
** deserve a lower cost even if it is a proper subset of Y. Constraint (5)
|
|
@@ -145799,11 +159323,8 @@ static int whereLoopCheaperProperSubset(
|
|
if( pX->nLTerm-pX->nSkip >= pY->nLTerm-pY->nSkip ){
|
|
return 0; /* X is not a subset of Y */
|
|
}
|
|
+ if( pX->rRun>pY->rRun && pX->nOut>pY->nOut ) return 0;
|
|
if( pY->nSkip > pX->nSkip ) return 0;
|
|
- if( pX->rRun >= pY->rRun ){
|
|
- if( pX->rRun > pY->rRun ) return 0; /* X costs more than Y */
|
|
- if( pX->nOut > pY->nOut ) return 0; /* X costs more than Y */
|
|
- }
|
|
for(i=pX->nLTerm-1; i>=0; i--){
|
|
if( pX->aLTerm[i]==0 ) continue;
|
|
for(j=pY->nLTerm-1; j>=0; j--){
|
|
@@ -145811,7 +159332,7 @@ static int whereLoopCheaperProperSubset(
|
|
}
|
|
if( j<0 ) return 0; /* X not a subset of Y since term X[i] not used by Y */
|
|
}
|
|
- if( (pX->wsFlags&WHERE_IDX_ONLY)!=0
|
|
+ if( (pX->wsFlags&WHERE_IDX_ONLY)!=0
|
|
&& (pY->wsFlags&WHERE_IDX_ONLY)==0 ){
|
|
return 0; /* Constraint (5) */
|
|
}
|
|
@@ -145819,8 +159340,8 @@ static int whereLoopCheaperProperSubset(
|
|
}
|
|
|
|
/*
|
|
-** Try to adjust the cost of WhereLoop pTemplate upwards or downwards so
|
|
-** that:
|
|
+** Try to adjust the cost and number of output rows of WhereLoop pTemplate
|
|
+** upwards or downwards so that:
|
|
**
|
|
** (1) pTemplate costs less than any other WhereLoops that are a proper
|
|
** subset of pTemplate
|
|
@@ -145838,19 +159359,23 @@ static void whereLoopAdjustCost(const WhereLoop *p, WhereLoop *pTemplate){
|
|
if( p->iTab!=pTemplate->iTab ) continue;
|
|
if( (p->wsFlags & WHERE_INDEXED)==0 ) continue;
|
|
if( whereLoopCheaperProperSubset(p, pTemplate) ){
|
|
- /* Adjust pTemplate cost downward so that it is cheaper than its
|
|
+ /* Adjust pTemplate cost downward so that it is cheaper than its
|
|
** subset p. */
|
|
WHERETRACE(0x80,("subset cost adjustment %d,%d to %d,%d\n",
|
|
- pTemplate->rRun, pTemplate->nOut, p->rRun, p->nOut-1));
|
|
- pTemplate->rRun = p->rRun;
|
|
- pTemplate->nOut = p->nOut - 1;
|
|
+ pTemplate->rRun, pTemplate->nOut,
|
|
+ MIN(p->rRun, pTemplate->rRun),
|
|
+ MIN(p->nOut - 1, pTemplate->nOut)));
|
|
+ pTemplate->rRun = MIN(p->rRun, pTemplate->rRun);
|
|
+ pTemplate->nOut = MIN(p->nOut - 1, pTemplate->nOut);
|
|
}else if( whereLoopCheaperProperSubset(pTemplate, p) ){
|
|
/* Adjust pTemplate cost upward so that it is costlier than p since
|
|
** pTemplate is a proper subset of p */
|
|
WHERETRACE(0x80,("subset cost adjustment %d,%d to %d,%d\n",
|
|
- pTemplate->rRun, pTemplate->nOut, p->rRun, p->nOut+1));
|
|
- pTemplate->rRun = p->rRun;
|
|
- pTemplate->nOut = p->nOut + 1;
|
|
+ pTemplate->rRun, pTemplate->nOut,
|
|
+ MAX(p->rRun, pTemplate->rRun),
|
|
+ MAX(p->nOut + 1, pTemplate->nOut)));
|
|
+ pTemplate->rRun = MAX(p->rRun, pTemplate->rRun);
|
|
+ pTemplate->nOut = MAX(p->nOut + 1, pTemplate->nOut);
|
|
}
|
|
}
|
|
}
|
|
@@ -145884,7 +159409,7 @@ static WhereLoop **whereLoopFindLesser(
|
|
/* In the current implementation, the rSetup value is either zero
|
|
** or the cost of building an automatic index (NlogN) and the NlogN
|
|
** is the same for compatible WhereLoops. */
|
|
- assert( p->rSetup==0 || pTemplate->rSetup==0
|
|
+ assert( p->rSetup==0 || pTemplate->rSetup==0
|
|
|| p->rSetup==pTemplate->rSetup );
|
|
|
|
/* whereLoopAddBtree() always generates and inserts the automatic index
|
|
@@ -145949,7 +159474,7 @@ static WhereLoop **whereLoopFindLesser(
|
|
**
|
|
** When accumulating multiple loops (when pBuilder->pOrSet is NULL) we
|
|
** still might overwrite similar loops with the new template if the
|
|
-** new template is better. Loops may be overwritten if the following
|
|
+** new template is better. Loops may be overwritten if the following
|
|
** conditions are met:
|
|
**
|
|
** (1) They have the same iTab.
|
|
@@ -146007,7 +159532,7 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
|
|
sqlite3WhereLoopPrint(pTemplate, pBuilder->pWC);
|
|
}
|
|
#endif
|
|
- return SQLITE_OK;
|
|
+ return SQLITE_OK;
|
|
}else{
|
|
p = *ppPrev;
|
|
}
|
|
@@ -146105,11 +159630,11 @@ static void whereLoopOutputAdjust(
|
|
LogEst iReduce = 0; /* pLoop->nOut should not exceed nRow-iReduce */
|
|
|
|
assert( (pLoop->wsFlags & WHERE_AUTO_INDEX)==0 );
|
|
- for(i=pWC->nTerm, pTerm=pWC->a; i>0; i--, pTerm++){
|
|
+ for(i=pWC->nBase, pTerm=pWC->a; i>0; i--, pTerm++){
|
|
assert( pTerm!=0 );
|
|
- if( (pTerm->wtFlags & TERM_VIRTUAL)!=0 ) break;
|
|
- if( (pTerm->prereqAll & pLoop->maskSelf)==0 ) continue;
|
|
if( (pTerm->prereqAll & notAllowed)!=0 ) continue;
|
|
+ if( (pTerm->prereqAll & pLoop->maskSelf)==0 ) continue;
|
|
+ if( (pTerm->wtFlags & TERM_VIRTUAL)!=0 ) continue;
|
|
for(j=pLoop->nLTerm-1; j>=0; j--){
|
|
pX = pLoop->aLTerm[j];
|
|
if( pX==0 ) continue;
|
|
@@ -146117,6 +159642,24 @@ static void whereLoopOutputAdjust(
|
|
if( pX->iParent>=0 && (&pWC->a[pX->iParent])==pTerm ) break;
|
|
}
|
|
if( j<0 ){
|
|
+ sqlite3ProgressCheck(pWC->pWInfo->pParse);
|
|
+ if( pLoop->maskSelf==pTerm->prereqAll ){
|
|
+ /* If there are extra terms in the WHERE clause not used by an index
|
|
+ ** that depend only on the table being scanned, and that will tend to
|
|
+ ** cause many rows to be omitted, then mark that table as
|
|
+ ** "self-culling".
|
|
+ **
|
|
+ ** 2022-03-24: Self-culling only applies if either the extra terms
|
|
+ ** are straight comparison operators that are non-true with NULL
|
|
+ ** operand, or if the loop is not an OUTER JOIN.
|
|
+ */
|
|
+ if( (pTerm->eOperator & 0x3f)!=0
|
|
+ || (pWC->pWInfo->pTabList->a[pLoop->iTab].fg.jointype
|
|
+ & (JT_LEFT|JT_LTORJ))==0
|
|
+ ){
|
|
+ pLoop->wsFlags |= WHERE_SELFCULL;
|
|
+ }
|
|
+ }
|
|
if( pTerm->truthProb<=0 ){
|
|
/* If a truth probability is specified using the likelihood() hints,
|
|
** then use the probability provided by the application. */
|
|
@@ -146125,7 +159668,9 @@ static void whereLoopOutputAdjust(
|
|
/* In the absence of explicit truth probabilities, use heuristics to
|
|
** guess a reasonable truth probability. */
|
|
pLoop->nOut--;
|
|
- if( pTerm->eOperator&(WO_EQ|WO_IS) ){
|
|
+ if( (pTerm->eOperator&(WO_EQ|WO_IS))!=0
|
|
+ && (pTerm->wtFlags & TERM_HIGHTRUTH)==0 /* tag-20200224-1 */
|
|
+ ){
|
|
Expr *pRight = pTerm->pExpr->pRight;
|
|
int k = 0;
|
|
testcase( pTerm->pExpr->op==TK_IS );
|
|
@@ -146134,15 +159679,20 @@ static void whereLoopOutputAdjust(
|
|
}else{
|
|
k = 20;
|
|
}
|
|
- if( iReduce<k ) iReduce = k;
|
|
+ if( iReduce<k ){
|
|
+ pTerm->wtFlags |= TERM_HEURTRUTH;
|
|
+ iReduce = k;
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- if( pLoop->nOut > nRow-iReduce ) pLoop->nOut = nRow - iReduce;
|
|
+ if( pLoop->nOut > nRow-iReduce ){
|
|
+ pLoop->nOut = nRow - iReduce;
|
|
+ }
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** Term pTerm is a vector range comparison operation. The first comparison
|
|
** in the vector can be optimized using column nEq of the index. This
|
|
** function returns the total number of vector elements that can be used
|
|
@@ -146171,14 +159721,17 @@ static int whereRangeVectorLen(
|
|
|
|
nCmp = MIN(nCmp, (pIdx->nColumn - nEq));
|
|
for(i=1; i<nCmp; i++){
|
|
- /* Test if comparison i of pTerm is compatible with column (i+nEq)
|
|
+ /* Test if comparison i of pTerm is compatible with column (i+nEq)
|
|
** of the index. If not, exit the loop. */
|
|
char aff; /* Comparison affinity */
|
|
char idxaff = 0; /* Indexed columns affinity */
|
|
CollSeq *pColl; /* Comparison collation sequence */
|
|
- Expr *pLhs = pTerm->pExpr->pLeft->x.pList->a[i].pExpr;
|
|
- Expr *pRhs = pTerm->pExpr->pRight;
|
|
- if( pRhs->flags & EP_xIsSelect ){
|
|
+ Expr *pLhs, *pRhs;
|
|
+
|
|
+ assert( ExprUseXList(pTerm->pExpr->pLeft) );
|
|
+ pLhs = pTerm->pExpr->pLeft->x.pList->a[i].pExpr;
|
|
+ pRhs = pTerm->pExpr->pRight;
|
|
+ if( ExprUseXSelect(pRhs) ){
|
|
pRhs = pRhs->x.pSelect->pEList->a[i].pExpr;
|
|
}else{
|
|
pRhs = pRhs->x.pList->a[i].pExpr;
|
|
@@ -146188,9 +159741,9 @@ static int whereRangeVectorLen(
|
|
** the right column of the right source table. And that the sort
|
|
** order of the index column is the same as the sort order of the
|
|
** leftmost index column. */
|
|
- if( pLhs->op!=TK_COLUMN
|
|
- || pLhs->iTable!=iCur
|
|
- || pLhs->iColumn!=pIdx->aiColumn[i+nEq]
|
|
+ if( pLhs->op!=TK_COLUMN
|
|
+ || pLhs->iTable!=iCur
|
|
+ || pLhs->iColumn!=pIdx->aiColumn[i+nEq]
|
|
|| pIdx->aSortOrder[i+nEq]!=pIdx->aSortOrder[nEq]
|
|
){
|
|
break;
|
|
@@ -146219,20 +159772,20 @@ static int whereRangeVectorLen(
|
|
#endif
|
|
|
|
/*
|
|
-** We have so far matched pBuilder->pNew->u.btree.nEq terms of the
|
|
+** We have so far matched pBuilder->pNew->u.btree.nEq terms of the
|
|
** index pIndex. Try to match one more.
|
|
**
|
|
-** When this function is called, pBuilder->pNew->nOut contains the
|
|
-** number of rows expected to be visited by filtering using the nEq
|
|
-** terms only. If it is modified, this value is restored before this
|
|
+** When this function is called, pBuilder->pNew->nOut contains the
|
|
+** number of rows expected to be visited by filtering using the nEq
|
|
+** terms only. If it is modified, this value is restored before this
|
|
** function returns.
|
|
**
|
|
-** If pProbe->idxType==SQLITE_IDXTYPE_IPK, that means pIndex is
|
|
+** If pProbe->idxType==SQLITE_IDXTYPE_IPK, that means pIndex is
|
|
** a fake index used for the INTEGER PRIMARY KEY.
|
|
*/
|
|
static int whereLoopAddBtreeIndex(
|
|
WhereLoopBuilder *pBuilder, /* The WhereLoop factory */
|
|
- struct SrcList_item *pSrc, /* FROM clause term being analyzed */
|
|
+ SrcItem *pSrc, /* FROM clause term being analyzed */
|
|
Index *pProbe, /* An index on pSrc */
|
|
LogEst nInMul /* log(Number of iterations due to IN) */
|
|
){
|
|
@@ -146257,10 +159810,13 @@ static int whereLoopAddBtreeIndex(
|
|
WhereTerm *pTop = 0, *pBtm = 0; /* Top and bottom range constraints */
|
|
|
|
pNew = pBuilder->pNew;
|
|
- if( db->mallocFailed ) return SQLITE_NOMEM_BKPT;
|
|
- WHERETRACE(0x800, ("BEGIN %s.addBtreeIdx(%s), nEq=%d, nSkip=%d\n",
|
|
+ assert( db->mallocFailed==0 || pParse->nErr>0 );
|
|
+ if( pParse->nErr ){
|
|
+ return pParse->rc;
|
|
+ }
|
|
+ WHERETRACE(0x800, ("BEGIN %s.addBtreeIdx(%s), nEq=%d, nSkip=%d, rRun=%d\n",
|
|
pProbe->pTable->zName,pProbe->zName,
|
|
- pNew->u.btree.nEq, pNew->nSkip));
|
|
+ pNew->u.btree.nEq, pNew->nSkip, pNew->rRun));
|
|
|
|
assert( (pNew->wsFlags & WHERE_VIRTUALTABLE)==0 );
|
|
assert( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 );
|
|
@@ -146273,6 +159829,8 @@ static int whereLoopAddBtreeIndex(
|
|
if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE);
|
|
|
|
assert( pNew->u.btree.nEq<pProbe->nColumn );
|
|
+ assert( pNew->u.btree.nEq<pProbe->nKeyCol
|
|
+ || pProbe->idxType!=SQLITE_IDXTYPE_PRIMARYKEY );
|
|
|
|
saved_nEq = pNew->u.btree.nEq;
|
|
saved_nBtm = pNew->u.btree.nBtm;
|
|
@@ -146306,38 +159864,38 @@ static int whereLoopAddBtreeIndex(
|
|
** to mix with a lower range bound from some other source */
|
|
if( pTerm->wtFlags & TERM_LIKEOPT && pTerm->eOperator==WO_LT ) continue;
|
|
|
|
- /* tag-20191211-001: Do not allow constraints from the WHERE clause to
|
|
- ** be used by the right table of a LEFT JOIN. Only constraints in the
|
|
- ** ON clause are allowed. See tag-20191211-002 for the vtab equivalent. */
|
|
- if( (pSrc->fg.jointype & JT_LEFT)!=0
|
|
- && !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
|
|
+ if( (pSrc->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))!=0
|
|
+ && !constraintCompatibleWithOuterJoin(pTerm,pSrc)
|
|
){
|
|
continue;
|
|
}
|
|
-
|
|
if( IsUniqueIndex(pProbe) && saved_nEq==pProbe->nKeyCol-1 ){
|
|
- pBuilder->bldFlags |= SQLITE_BLDF_UNIQUE;
|
|
+ pBuilder->bldFlags1 |= SQLITE_BLDF1_UNIQUE;
|
|
}else{
|
|
- pBuilder->bldFlags |= SQLITE_BLDF_INDEXED;
|
|
+ pBuilder->bldFlags1 |= SQLITE_BLDF1_INDEXED;
|
|
}
|
|
pNew->wsFlags = saved_wsFlags;
|
|
pNew->u.btree.nEq = saved_nEq;
|
|
pNew->u.btree.nBtm = saved_nBtm;
|
|
pNew->u.btree.nTop = saved_nTop;
|
|
pNew->nLTerm = saved_nLTerm;
|
|
- if( whereLoopResize(db, pNew, pNew->nLTerm+1) ) break; /* OOM */
|
|
+ if( pNew->nLTerm>=pNew->nLSlot
|
|
+ && whereLoopResize(db, pNew, pNew->nLTerm+1)
|
|
+ ){
|
|
+ break; /* OOM while trying to enlarge the pNew->aLTerm array */
|
|
+ }
|
|
pNew->aLTerm[pNew->nLTerm++] = pTerm;
|
|
pNew->prereq = (saved_prereq | pTerm->prereqRight) & ~pNew->maskSelf;
|
|
|
|
assert( nInMul==0
|
|
- || (pNew->wsFlags & WHERE_COLUMN_NULL)!=0
|
|
- || (pNew->wsFlags & WHERE_COLUMN_IN)!=0
|
|
- || (pNew->wsFlags & WHERE_SKIPSCAN)!=0
|
|
+ || (pNew->wsFlags & WHERE_COLUMN_NULL)!=0
|
|
+ || (pNew->wsFlags & WHERE_COLUMN_IN)!=0
|
|
+ || (pNew->wsFlags & WHERE_SKIPSCAN)!=0
|
|
);
|
|
|
|
if( eOp & WO_IN ){
|
|
Expr *pExpr = pTerm->pExpr;
|
|
- if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
|
+ if( ExprUseXSelect(pExpr) ){
|
|
/* "x IN (SELECT ...)": TUNING: the SELECT returns 25 rows */
|
|
int i;
|
|
nIn = 46; assert( 46==sqlite3LogEst(25) );
|
|
@@ -146354,12 +159912,12 @@ static int whereLoopAddBtreeIndex(
|
|
/* "x IN (value, value, ...)" */
|
|
nIn = sqlite3LogEst(pExpr->x.pList->nExpr);
|
|
}
|
|
- if( pProbe->hasStat1 ){
|
|
- LogEst M, logK, safetyMargin;
|
|
+ if( pProbe->hasStat1 && rLogSize>=10 ){
|
|
+ LogEst M, logK, x;
|
|
/* Let:
|
|
** N = the total number of rows in the table
|
|
** K = the number of entries on the RHS of the IN operator
|
|
- ** M = the number of rows in the table that match terms to the
|
|
+ ** M = the number of rows in the table that match terms to the
|
|
** to the left in the same index. If the IN operator is on
|
|
** the left-most index column, M==N.
|
|
**
|
|
@@ -146373,20 +159931,30 @@ static int whereLoopAddBtreeIndex(
|
|
** a safety margin of 2 (LogEst: 10) that favors using the IN operator
|
|
** with the index, as using an index has better worst-case behavior.
|
|
** If we do not have real sqlite_stat1 data, always prefer to use
|
|
- ** the index.
|
|
+ ** the index. Do not bother with this optimization on very small
|
|
+ ** tables (less than 2 rows) as it is pointless in that case.
|
|
*/
|
|
M = pProbe->aiRowLogEst[saved_nEq];
|
|
logK = estLog(nIn);
|
|
- safetyMargin = 10; /* TUNING: extra weight for indexed IN */
|
|
- if( M + logK + safetyMargin < nIn + rLogSize ){
|
|
+ /* TUNING v----- 10 to bias toward indexed IN */
|
|
+ x = M + logK + 10 - (nIn + rLogSize);
|
|
+ if( x>=0 ){
|
|
WHERETRACE(0x40,
|
|
- ("Scan preferred over IN operator on column %d of \"%s\" (%d<%d)\n",
|
|
- saved_nEq, pProbe->zName, M+logK+10, nIn+rLogSize));
|
|
- continue;
|
|
+ ("IN operator (N=%d M=%d logK=%d nIn=%d rLogSize=%d x=%d) "
|
|
+ "prefers indexed lookup\n",
|
|
+ saved_nEq, M, logK, nIn, rLogSize, x));
|
|
+ }else if( nInMul<2 && OptimizationEnabled(db, SQLITE_SeekScan) ){
|
|
+ WHERETRACE(0x40,
|
|
+ ("IN operator (N=%d M=%d logK=%d nIn=%d rLogSize=%d x=%d"
|
|
+ " nInMul=%d) prefers skip-scan\n",
|
|
+ saved_nEq, M, logK, nIn, rLogSize, x, nInMul));
|
|
+ pNew->wsFlags |= WHERE_IN_SEEKSCAN;
|
|
}else{
|
|
WHERETRACE(0x40,
|
|
- ("IN operator preferred on column %d of \"%s\" (%d>=%d)\n",
|
|
- saved_nEq, pProbe->zName, M+logK+10, nIn+rLogSize));
|
|
+ ("IN operator (N=%d M=%d logK=%d nIn=%d rLogSize=%d x=%d"
|
|
+ " nInMul=%d) prefers normal scan\n",
|
|
+ saved_nEq, M, logK, nIn, rLogSize, x, nInMul));
|
|
+ continue;
|
|
}
|
|
}
|
|
pNew->wsFlags |= WHERE_COLUMN_IN;
|
|
@@ -146394,56 +159962,58 @@ static int whereLoopAddBtreeIndex(
|
|
int iCol = pProbe->aiColumn[saved_nEq];
|
|
pNew->wsFlags |= WHERE_COLUMN_EQ;
|
|
assert( saved_nEq==pNew->u.btree.nEq );
|
|
- if( iCol==XN_ROWID
|
|
+ if( iCol==XN_ROWID
|
|
|| (iCol>=0 && nInMul==0 && saved_nEq==pProbe->nKeyCol-1)
|
|
){
|
|
- if( iCol==XN_ROWID || pProbe->uniqNotNull
|
|
- || (pProbe->nKeyCol==1 && pProbe->onError && eOp==WO_EQ)
|
|
+ if( iCol==XN_ROWID || pProbe->uniqNotNull
|
|
+ || (pProbe->nKeyCol==1 && pProbe->onError && eOp==WO_EQ)
|
|
){
|
|
pNew->wsFlags |= WHERE_ONEROW;
|
|
}else{
|
|
pNew->wsFlags |= WHERE_UNQ_WANTED;
|
|
}
|
|
}
|
|
+ if( scan.iEquiv>1 ) pNew->wsFlags |= WHERE_TRANSCONS;
|
|
}else if( eOp & WO_ISNULL ){
|
|
pNew->wsFlags |= WHERE_COLUMN_NULL;
|
|
- }else if( eOp & (WO_GT|WO_GE) ){
|
|
- testcase( eOp & WO_GT );
|
|
- testcase( eOp & WO_GE );
|
|
- pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_BTM_LIMIT;
|
|
- pNew->u.btree.nBtm = whereRangeVectorLen(
|
|
- pParse, pSrc->iCursor, pProbe, saved_nEq, pTerm
|
|
- );
|
|
- pBtm = pTerm;
|
|
- pTop = 0;
|
|
- if( pTerm->wtFlags & TERM_LIKEOPT ){
|
|
- /* Range contraints that come from the LIKE optimization are
|
|
- ** always used in pairs. */
|
|
- pTop = &pTerm[1];
|
|
- assert( (pTop-(pTerm->pWC->a))<pTerm->pWC->nTerm );
|
|
- assert( pTop->wtFlags & TERM_LIKEOPT );
|
|
- assert( pTop->eOperator==WO_LT );
|
|
- if( whereLoopResize(db, pNew, pNew->nLTerm+1) ) break; /* OOM */
|
|
- pNew->aLTerm[pNew->nLTerm++] = pTop;
|
|
- pNew->wsFlags |= WHERE_TOP_LIMIT;
|
|
- pNew->u.btree.nTop = 1;
|
|
- }
|
|
- }else{
|
|
- assert( eOp & (WO_LT|WO_LE) );
|
|
- testcase( eOp & WO_LT );
|
|
- testcase( eOp & WO_LE );
|
|
- pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_TOP_LIMIT;
|
|
- pNew->u.btree.nTop = whereRangeVectorLen(
|
|
+ }else{
|
|
+ int nVecLen = whereRangeVectorLen(
|
|
pParse, pSrc->iCursor, pProbe, saved_nEq, pTerm
|
|
);
|
|
- pTop = pTerm;
|
|
- pBtm = (pNew->wsFlags & WHERE_BTM_LIMIT)!=0 ?
|
|
- pNew->aLTerm[pNew->nLTerm-2] : 0;
|
|
+ if( eOp & (WO_GT|WO_GE) ){
|
|
+ testcase( eOp & WO_GT );
|
|
+ testcase( eOp & WO_GE );
|
|
+ pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_BTM_LIMIT;
|
|
+ pNew->u.btree.nBtm = nVecLen;
|
|
+ pBtm = pTerm;
|
|
+ pTop = 0;
|
|
+ if( pTerm->wtFlags & TERM_LIKEOPT ){
|
|
+ /* Range constraints that come from the LIKE optimization are
|
|
+ ** always used in pairs. */
|
|
+ pTop = &pTerm[1];
|
|
+ assert( (pTop-(pTerm->pWC->a))<pTerm->pWC->nTerm );
|
|
+ assert( pTop->wtFlags & TERM_LIKEOPT );
|
|
+ assert( pTop->eOperator==WO_LT );
|
|
+ if( whereLoopResize(db, pNew, pNew->nLTerm+1) ) break; /* OOM */
|
|
+ pNew->aLTerm[pNew->nLTerm++] = pTop;
|
|
+ pNew->wsFlags |= WHERE_TOP_LIMIT;
|
|
+ pNew->u.btree.nTop = 1;
|
|
+ }
|
|
+ }else{
|
|
+ assert( eOp & (WO_LT|WO_LE) );
|
|
+ testcase( eOp & WO_LT );
|
|
+ testcase( eOp & WO_LE );
|
|
+ pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_TOP_LIMIT;
|
|
+ pNew->u.btree.nTop = nVecLen;
|
|
+ pTop = pTerm;
|
|
+ pBtm = (pNew->wsFlags & WHERE_BTM_LIMIT)!=0 ?
|
|
+ pNew->aLTerm[pNew->nLTerm-2] : 0;
|
|
+ }
|
|
}
|
|
|
|
/* At this point pNew->nOut is set to the number of rows expected to
|
|
** be visited by the index scan before considering term pTerm, or the
|
|
- ** values of nIn and nInMul. In other words, assuming that all
|
|
+ ** values of nIn and nInMul. In other words, assuming that all
|
|
** "x IN(...)" terms are replaced with "x = ?". This block updates
|
|
** the value of pNew->nOut to account for pTerm (but not nIn/nInMul). */
|
|
assert( pNew->nOut==saved_nOut );
|
|
@@ -146464,10 +160034,10 @@ static int whereLoopAddBtreeIndex(
|
|
}else{
|
|
#ifdef SQLITE_ENABLE_STAT4
|
|
tRowcnt nOut = 0;
|
|
- if( nInMul==0
|
|
- && pProbe->nSample
|
|
- && pNew->u.btree.nEq<=pProbe->nSampleCol
|
|
- && ((eOp & WO_IN)==0 || !ExprHasProperty(pTerm->pExpr, EP_xIsSelect))
|
|
+ if( nInMul==0
|
|
+ && pProbe->nSample
|
|
+ && ALWAYS(pNew->u.btree.nEq<=pProbe->nSampleCol)
|
|
+ && ((eOp & WO_IN)==0 || ExprUseXList(pTerm->pExpr))
|
|
&& OptimizationEnabled(db, SQLITE_Stat4)
|
|
){
|
|
Expr *pExpr = pTerm->pExpr;
|
|
@@ -146483,6 +160053,27 @@ static int whereLoopAddBtreeIndex(
|
|
if( rc!=SQLITE_OK ) break; /* Jump out of the pTerm loop */
|
|
if( nOut ){
|
|
pNew->nOut = sqlite3LogEst(nOut);
|
|
+ if( nEq==1
|
|
+ /* TUNING: Mark terms as "low selectivity" if they seem likely
|
|
+ ** to be true for half or more of the rows in the table.
|
|
+ ** See tag-202002240-1 */
|
|
+ && pNew->nOut+10 > pProbe->aiRowLogEst[0]
|
|
+ ){
|
|
+#if WHERETRACE_ENABLED /* 0x01 */
|
|
+ if( sqlite3WhereTrace & 0x20 ){
|
|
+ sqlite3DebugPrintf(
|
|
+ "STAT4 determines term has low selectivity:\n");
|
|
+ sqlite3WhereTermPrint(pTerm, 999);
|
|
+ }
|
|
+#endif
|
|
+ pTerm->wtFlags |= TERM_HIGHTRUTH;
|
|
+ if( pTerm->wtFlags & TERM_HEURTRUTH ){
|
|
+ /* If the term has previously been used with an assumption of
|
|
+ ** higher selectivity, then set the flag to rerun the
|
|
+ ** loop computations. */
|
|
+ pBuilder->bldFlags2 |= SQLITE_BLDF2_2NDPASS;
|
|
+ }
|
|
+ }
|
|
if( pNew->nOut>saved_nOut ) pNew->nOut = saved_nOut;
|
|
pNew->nOut -= nIn;
|
|
}
|
|
@@ -146492,8 +160083,8 @@ static int whereLoopAddBtreeIndex(
|
|
{
|
|
pNew->nOut += (pProbe->aiRowLogEst[nEq] - pProbe->aiRowLogEst[nEq-1]);
|
|
if( eOp & WO_ISNULL ){
|
|
- /* TUNING: If there is no likelihood() value, assume that a
|
|
- ** "col IS NULL" expression matches twice as many rows
|
|
+ /* TUNING: If there is no likelihood() value, assume that a
|
|
+ ** "col IS NULL" expression matches twice as many rows
|
|
** as (col=?). */
|
|
pNew->nOut += 10;
|
|
}
|
|
@@ -146506,9 +160097,17 @@ static int whereLoopAddBtreeIndex(
|
|
** seek only. Then, if this is a non-covering index, add the cost of
|
|
** visiting the rows in the main table. */
|
|
assert( pSrc->pTab->szTabRow>0 );
|
|
- rCostIdx = pNew->nOut + 1 + (15*pProbe->szIdxRow)/pSrc->pTab->szTabRow;
|
|
+ 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.
|
|
+ ** But the leaf pages are full-size, so pProbe->szIdxRow would badly
|
|
+ ** under-estimate the scanning cost. */
|
|
+ rCostIdx = pNew->nOut + 16;
|
|
+ }else{
|
|
+ rCostIdx = pNew->nOut + 1 + (15*pProbe->szIdxRow)/pSrc->pTab->szTabRow;
|
|
+ }
|
|
pNew->rRun = sqlite3LogEstAdd(rLogSize, rCostIdx);
|
|
- if( (pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK))==0 ){
|
|
+ if( (pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK|WHERE_EXPRIDX))==0 ){
|
|
pNew->rRun = sqlite3LogEstAdd(pNew->rRun, pNew->nOut + 16);
|
|
}
|
|
ApplyCostMultiplier(pNew->rRun, pProbe->pTable->costMult);
|
|
@@ -146527,7 +160126,12 @@ static int whereLoopAddBtreeIndex(
|
|
|
|
if( (pNew->wsFlags & WHERE_TOP_LIMIT)==0
|
|
&& pNew->u.btree.nEq<pProbe->nColumn
|
|
+ && (pNew->u.btree.nEq<pProbe->nKeyCol ||
|
|
+ pProbe->idxType!=SQLITE_IDXTYPE_PRIMARYKEY)
|
|
){
|
|
+ if( pNew->u.btree.nEq>3 ){
|
|
+ sqlite3ProgressCheck(pParse);
|
|
+ }
|
|
whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nInMul+nIn);
|
|
}
|
|
pNew->nOut = saved_nOut;
|
|
@@ -146546,12 +160150,12 @@ static int whereLoopAddBtreeIndex(
|
|
|
|
/* Consider using a skip-scan if there are no WHERE clause constraints
|
|
** available for the left-most terms of the index, and if the average
|
|
- ** number of repeats in the left-most terms is at least 18.
|
|
+ ** number of repeats in the left-most terms is at least 18.
|
|
**
|
|
** The magic number 18 is selected on the basis that scanning 17 rows
|
|
** is almost always quicker than an index seek (even though if the index
|
|
** contains fewer than 2^17 rows we assume otherwise in other parts of
|
|
- ** the code). And, even if it is not, it should not be too much slower.
|
|
+ ** the code). And, even if it is not, it should not be too much slower.
|
|
** On the other hand, the extra seeks could end up being significantly
|
|
** more expensive. */
|
|
assert( 42==sqlite3LogEst(18) );
|
|
@@ -146559,6 +160163,7 @@ static int whereLoopAddBtreeIndex(
|
|
&& saved_nEq+1<pProbe->nKeyCol
|
|
&& saved_nEq==pNew->nLTerm
|
|
&& pProbe->noSkipScan==0
|
|
+ && pProbe->hasStat1!=0
|
|
&& OptimizationEnabled(db, SQLITE_SkipScan)
|
|
&& pProbe->aiRowLogEst[saved_nEq+1]>=42 /* TUNING: Minimum for skip-scan */
|
|
&& (rc = whereLoopResize(db, pNew, pNew->nLTerm+1))==SQLITE_OK
|
|
@@ -146606,6 +160211,7 @@ static int indexMightHelpWithOrderBy(
|
|
if( (pOB = pBuilder->pWInfo->pOrderBy)==0 ) return 0;
|
|
for(ii=0; ii<pOB->nExpr; ii++){
|
|
Expr *pExpr = sqlite3ExprSkipCollateAndLikely(pOB->a[ii].pExpr);
|
|
+ if( NEVER(pExpr==0) ) continue;
|
|
if( pExpr->op==TK_COLUMN && pExpr->iTable==iCursor ){
|
|
if( pExpr->iColumn<0 ) return 1;
|
|
for(jj=0; jj<pIndex->nKeyCol; jj++){
|
|
@@ -146628,24 +160234,48 @@ static int indexMightHelpWithOrderBy(
|
|
*/
|
|
static int whereUsablePartialIndex(
|
|
int iTab, /* The table for which we want an index */
|
|
- int isLeft, /* True if iTab is the right table of a LEFT JOIN */
|
|
+ u8 jointype, /* The JT_* flags on the join */
|
|
WhereClause *pWC, /* The WHERE clause of the query */
|
|
Expr *pWhere /* The WHERE clause from the partial index */
|
|
){
|
|
int i;
|
|
WhereTerm *pTerm;
|
|
- Parse *pParse = pWC->pWInfo->pParse;
|
|
+ Parse *pParse;
|
|
+
|
|
+ if( jointype & JT_LTORJ ) return 0;
|
|
+ pParse = pWC->pWInfo->pParse;
|
|
while( pWhere->op==TK_AND ){
|
|
- if( !whereUsablePartialIndex(iTab,isLeft,pWC,pWhere->pLeft) ) return 0;
|
|
+ if( !whereUsablePartialIndex(iTab,jointype,pWC,pWhere->pLeft) ) return 0;
|
|
pWhere = pWhere->pRight;
|
|
}
|
|
if( pParse->db->flags & SQLITE_EnableQPSG ) pParse = 0;
|
|
for(i=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
|
|
Expr *pExpr;
|
|
pExpr = pTerm->pExpr;
|
|
- if( (!ExprHasProperty(pExpr, EP_FromJoin) || pExpr->iRightJoinTable==iTab)
|
|
- && (isLeft==0 || ExprHasProperty(pExpr, EP_FromJoin))
|
|
- && sqlite3ExprImpliesExpr(pParse, pExpr, pWhere, iTab)
|
|
+ if( (!ExprHasProperty(pExpr, EP_OuterON) || pExpr->w.iJoin==iTab)
|
|
+ && ((jointype & JT_OUTER)==0 || ExprHasProperty(pExpr, EP_OuterON))
|
|
+ && sqlite3ExprImpliesExpr(pParse, pExpr, pWhere, iTab)
|
|
+ && (pTerm->wtFlags & TERM_VNULL)==0
|
|
+ ){
|
|
+ return 1;
|
|
+ }
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*
|
|
+** pIdx is an index containing expressions. Check it see if any of the
|
|
+** expressions in the index match the pExpr expression.
|
|
+*/
|
|
+static int exprIsCoveredByIndex(
|
|
+ const Expr *pExpr,
|
|
+ const Index *pIdx,
|
|
+ int iTabCur
|
|
+){
|
|
+ int i;
|
|
+ for(i=0; i<pIdx->nColumn; i++){
|
|
+ if( pIdx->aiColumn[i]==XN_EXPR
|
|
+ && sqlite3ExprCompare(0, pExpr, pIdx->aColExpr->a[i].pExpr, iTabCur)==0
|
|
){
|
|
return 1;
|
|
}
|
|
@@ -146653,6 +160283,129 @@ static int whereUsablePartialIndex(
|
|
return 0;
|
|
}
|
|
|
|
+/*
|
|
+** Structure passed to the whereIsCoveringIndex Walker callback.
|
|
+*/
|
|
+typedef struct CoveringIndexCheck CoveringIndexCheck;
|
|
+struct CoveringIndexCheck {
|
|
+ Index *pIdx; /* The index */
|
|
+ int iTabCur; /* Cursor number for the corresponding table */
|
|
+ u8 bExpr; /* Uses an indexed expression */
|
|
+ u8 bUnidx; /* Uses an unindexed column not within an indexed expr */
|
|
+};
|
|
+
|
|
+/*
|
|
+** Information passed in is pWalk->u.pCovIdxCk. Call it pCk.
|
|
+**
|
|
+** If the Expr node references the table with cursor pCk->iTabCur, then
|
|
+** make sure that column is covered by the index pCk->pIdx. We know that
|
|
+** all columns less than 63 (really BMS-1) are covered, so we don't need
|
|
+** to check them. But we do need to check any column at 63 or greater.
|
|
+**
|
|
+** If the index does not cover the column, then set pWalk->eCode to
|
|
+** non-zero and return WRC_Abort to stop the search.
|
|
+**
|
|
+** If this node does not disprove that the index can be a covering index,
|
|
+** then just return WRC_Continue, to continue the search.
|
|
+**
|
|
+** If pCk->pIdx contains indexed expressions and one of those expressions
|
|
+** matches pExpr, then prune the search.
|
|
+*/
|
|
+static int whereIsCoveringIndexWalkCallback(Walker *pWalk, Expr *pExpr){
|
|
+ int i; /* Loop counter */
|
|
+ const Index *pIdx; /* The index of interest */
|
|
+ const i16 *aiColumn; /* Columns contained in the index */
|
|
+ u16 nColumn; /* Number of columns in the index */
|
|
+ CoveringIndexCheck *pCk; /* Info about this search */
|
|
+
|
|
+ pCk = pWalk->u.pCovIdxCk;
|
|
+ pIdx = pCk->pIdx;
|
|
+ if( (pExpr->op==TK_COLUMN || pExpr->op==TK_AGG_COLUMN) ){
|
|
+ /* if( pExpr->iColumn<(BMS-1) && pIdx->bHasExpr==0 ) return WRC_Continue;*/
|
|
+ if( pExpr->iTable!=pCk->iTabCur ) return WRC_Continue;
|
|
+ pIdx = pWalk->u.pCovIdxCk->pIdx;
|
|
+ aiColumn = pIdx->aiColumn;
|
|
+ nColumn = pIdx->nColumn;
|
|
+ for(i=0; i<nColumn; i++){
|
|
+ if( aiColumn[i]==pExpr->iColumn ) return WRC_Continue;
|
|
+ }
|
|
+ pCk->bUnidx = 1;
|
|
+ return WRC_Abort;
|
|
+ }else if( pIdx->bHasExpr
|
|
+ && exprIsCoveredByIndex(pExpr, pIdx, pWalk->u.pCovIdxCk->iTabCur) ){
|
|
+ pCk->bExpr = 1;
|
|
+ return WRC_Prune;
|
|
+ }
|
|
+ return WRC_Continue;
|
|
+}
|
|
+
|
|
+
|
|
+/*
|
|
+** pIdx is an index that covers all of the low-number columns used by
|
|
+** pWInfo->pSelect (columns from 0 through 62) or an index that has
|
|
+** expressions terms. Hence, we cannot determine whether or not it is
|
|
+** a covering index by using the colUsed bitmasks. We have to do a search
|
|
+** to see if the index is covering. This routine does that search.
|
|
+**
|
|
+** The return value is one of these:
|
|
+**
|
|
+** 0 The index is definitely not a covering index
|
|
+**
|
|
+** WHERE_IDX_ONLY The index is definitely a covering index
|
|
+**
|
|
+** WHERE_EXPRIDX The index is likely a covering index, but it is
|
|
+** difficult to determine precisely because of the
|
|
+** expressions that are indexed. Score it as a
|
|
+** covering index, but still keep the main table open
|
|
+** just in case we need it.
|
|
+**
|
|
+** This routine is an optimization. It is always safe to return zero.
|
|
+** But returning one of the other two values when zero should have been
|
|
+** returned can lead to incorrect bytecode and assertion faults.
|
|
+*/
|
|
+static SQLITE_NOINLINE u32 whereIsCoveringIndex(
|
|
+ WhereInfo *pWInfo, /* The WHERE clause context */
|
|
+ Index *pIdx, /* Index that is being tested */
|
|
+ int iTabCur /* Cursor for the table being indexed */
|
|
+){
|
|
+ int i, rc;
|
|
+ struct CoveringIndexCheck ck;
|
|
+ Walker w;
|
|
+ if( pWInfo->pSelect==0 ){
|
|
+ /* We don't have access to the full query, so we cannot check to see
|
|
+ ** if pIdx is covering. Assume it is not. */
|
|
+ return 0;
|
|
+ }
|
|
+ if( pIdx->bHasExpr==0 ){
|
|
+ for(i=0; i<pIdx->nColumn; i++){
|
|
+ if( pIdx->aiColumn[i]>=BMS-1 ) break;
|
|
+ }
|
|
+ if( i>=pIdx->nColumn ){
|
|
+ /* pIdx does not index any columns greater than 62, but we know from
|
|
+ ** colMask that columns greater than 62 are used, so this is not a
|
|
+ ** covering index */
|
|
+ return 0;
|
|
+ }
|
|
+ }
|
|
+ ck.pIdx = pIdx;
|
|
+ ck.iTabCur = iTabCur;
|
|
+ ck.bExpr = 0;
|
|
+ ck.bUnidx = 0;
|
|
+ memset(&w, 0, sizeof(w));
|
|
+ w.xExprCallback = whereIsCoveringIndexWalkCallback;
|
|
+ w.xSelectCallback = sqlite3SelectWalkNoop;
|
|
+ w.u.pCovIdxCk = &ck;
|
|
+ sqlite3WalkSelect(&w, pWInfo->pSelect);
|
|
+ if( ck.bUnidx ){
|
|
+ rc = 0;
|
|
+ }else if( ck.bExpr ){
|
|
+ rc = WHERE_EXPRIDX;
|
|
+ }else{
|
|
+ rc = WHERE_IDX_ONLY;
|
|
+ }
|
|
+ return rc;
|
|
+}
|
|
+
|
|
/*
|
|
** 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
|
|
@@ -146667,18 +160420,18 @@ static int whereUsablePartialIndex(
|
|
** cost = nRow * K // scan of covering index
|
|
** cost = nRow * (K+3.0) // scan of non-covering index
|
|
**
|
|
-** where K is a value between 1.1 and 3.0 set based on the relative
|
|
+** where K is a value between 1.1 and 3.0 set based on the relative
|
|
** estimated average size of the index and table records.
|
|
**
|
|
** For an index scan, where nVisit is the number of index rows visited
|
|
-** by the scan, and nSeek is the number of seek operations required on
|
|
+** by the scan, and nSeek is the number of seek operations required on
|
|
** the index b-tree:
|
|
**
|
|
** cost = nSeek * (log(nRow) + K * nVisit) // covering index
|
|
** cost = nSeek * (log(nRow) + (K+3.0) * nVisit) // non-covering index
|
|
**
|
|
-** Normally, nSeek is 1. nSeek values greater than 1 come about if the
|
|
-** WHERE clause includes "x IN (....)" terms used in place of "x=?". Or when
|
|
+** Normally, nSeek is 1. nSeek values greater than 1 come about if the
|
|
+** WHERE clause includes "x IN (....)" terms used in place of "x=?". Or when
|
|
** implicit "x IN (SELECT x FROM tbl)" terms are added for skip-scans.
|
|
**
|
|
** The estimated values (nRow, nVisit, nSeek) often contain a large amount
|
|
@@ -146699,16 +160452,15 @@ static int whereLoopAddBtree(
|
|
LogEst aiRowEstPk[2]; /* The aiRowLogEst[] value for the sPk index */
|
|
i16 aiColumnPk = -1; /* The aColumn[] value for the sPk index */
|
|
SrcList *pTabList; /* The FROM clause */
|
|
- struct SrcList_item *pSrc; /* The FROM clause btree term to add */
|
|
+ SrcItem *pSrc; /* The FROM clause btree term to add */
|
|
WhereLoop *pNew; /* Template WhereLoop object */
|
|
int rc = SQLITE_OK; /* Return code */
|
|
int iSortIdx = 1; /* Index number */
|
|
int b; /* A boolean value */
|
|
LogEst rSize; /* number of rows in the table */
|
|
- LogEst rLogSize; /* Logarithm of the number of rows in the table */
|
|
WhereClause *pWC; /* The parsed WHERE clause */
|
|
Table *pTab; /* Table being queried */
|
|
-
|
|
+
|
|
pNew = pBuilder->pNew;
|
|
pWInfo = pBuilder->pWInfo;
|
|
pTabList = pWInfo->pTabList;
|
|
@@ -146717,9 +160469,10 @@ static int whereLoopAddBtree(
|
|
pWC = pBuilder->pWC;
|
|
assert( !IsVirtual(pSrc->pTab) );
|
|
|
|
- if( pSrc->pIBIndex ){
|
|
+ if( pSrc->fg.isIndexedBy ){
|
|
+ assert( pSrc->fg.isCte==0 );
|
|
/* An INDEXED BY clause specifies a particular index to use */
|
|
- pProbe = pSrc->pIBIndex;
|
|
+ pProbe = pSrc->u2.pIBIndex;
|
|
}else if( !HasRowid(pTab) ){
|
|
pProbe = pTab->pIndex;
|
|
}else{
|
|
@@ -146735,7 +160488,7 @@ static int whereLoopAddBtree(
|
|
sPk.aiRowLogEst = aiRowEstPk;
|
|
sPk.onError = OE_Replace;
|
|
sPk.pTable = pTab;
|
|
- sPk.szIdxRow = pTab->szTabRow;
|
|
+ sPk.szIdxRow = 3; /* TUNING: Interior rows of IPK table are very small */
|
|
sPk.idxType = SQLITE_IDXTYPE_IPK;
|
|
aiRowEstPk[0] = pTab->nRowLogEst;
|
|
aiRowEstPk[1] = 0;
|
|
@@ -146748,22 +160501,24 @@ static int whereLoopAddBtree(
|
|
pProbe = &sPk;
|
|
}
|
|
rSize = pTab->nRowLogEst;
|
|
- rLogSize = estLog(rSize);
|
|
|
|
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
|
|
/* Automatic indexes */
|
|
if( !pBuilder->pOrSet /* Not part of an OR optimization */
|
|
- && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0
|
|
+ && (pWInfo->wctrlFlags & (WHERE_RIGHT_JOIN|WHERE_OR_SUBCLAUSE))==0
|
|
&& (pWInfo->pParse->db->flags & SQLITE_AutoIndex)!=0
|
|
- && pSrc->pIBIndex==0 /* Has no INDEXED BY clause */
|
|
+ && !pSrc->fg.isIndexedBy /* Has no INDEXED BY clause */
|
|
&& !pSrc->fg.notIndexed /* Has no NOT INDEXED clause */
|
|
&& HasRowid(pTab) /* Not WITHOUT ROWID table. (FIXME: Why not?) */
|
|
&& !pSrc->fg.isCorrelated /* Not a correlated subquery */
|
|
&& !pSrc->fg.isRecursive /* Not a recursive common table expression. */
|
|
+ && (pSrc->fg.jointype & JT_RIGHT)==0 /* Not the right tab of a RIGHT JOIN */
|
|
){
|
|
/* Generate auto-index WhereLoops */
|
|
+ LogEst rLogSize; /* Logarithm of the number of rows in the table */
|
|
WhereTerm *pTerm;
|
|
WhereTerm *pWCEnd = pWC->a + pWC->nTerm;
|
|
+ rLogSize = estLog(rSize);
|
|
for(pTerm=pWC->a; rc==SQLITE_OK && pTerm<pWCEnd; pTerm++){
|
|
if( pTerm->prereqRight & pNew->maskSelf ) continue;
|
|
if( termCanDriveIndex(pTerm, pSrc, 0) ){
|
|
@@ -146781,10 +160536,11 @@ static int whereLoopAddBtree(
|
|
** those objects, since there is no opportunity to add schema
|
|
** indexes on subqueries and views. */
|
|
pNew->rSetup = rLogSize + rSize;
|
|
- if( pTab->pSelect==0 && (pTab->tabFlags & TF_Ephemeral)==0 ){
|
|
+ if( !IsView(pTab) && (pTab->tabFlags & TF_Ephemeral)==0 ){
|
|
pNew->rSetup += 28;
|
|
}else{
|
|
- pNew->rSetup -= 10;
|
|
+ pNew->rSetup -= 25; /* Greatly reduced setup cost for auto indexes
|
|
+ ** on ephemeral materializations of views */
|
|
}
|
|
ApplyCostMultiplier(pNew->rSetup, pTab->costMult);
|
|
if( pNew->rSetup<0 ) pNew->rSetup = 0;
|
|
@@ -146802,14 +160558,13 @@ static int whereLoopAddBtree(
|
|
}
|
|
#endif /* SQLITE_OMIT_AUTOMATIC_INDEX */
|
|
|
|
- /* Loop over all indices. If there was an INDEXED BY clause, then only
|
|
+ /* Loop over all indices. If there was an INDEXED BY clause, then only
|
|
** consider index pProbe. */
|
|
- for(; rc==SQLITE_OK && pProbe;
|
|
- pProbe=(pSrc->pIBIndex ? 0 : pProbe->pNext), iSortIdx++
|
|
+ for(; rc==SQLITE_OK && pProbe;
|
|
+ pProbe=(pSrc->fg.isIndexedBy ? 0 : pProbe->pNext), iSortIdx++
|
|
){
|
|
- int isLeft = (pSrc->fg.jointype & JT_OUTER)!=0;
|
|
if( pProbe->pPartIdxWhere!=0
|
|
- && !whereUsablePartialIndex(pSrc->iCursor, isLeft, pWC,
|
|
+ && !whereUsablePartialIndex(pSrc->iCursor, pSrc->fg.jointype, pWC,
|
|
pProbe->pPartIdxWhere)
|
|
){
|
|
testcase( pNew->iTab!=pSrc->iCursor ); /* See ticket [98d973b8f5] */
|
|
@@ -146828,6 +160583,7 @@ static int whereLoopAddBtree(
|
|
pNew->nOut = rSize;
|
|
pNew->u.btree.pIndex = pProbe;
|
|
b = indexMightHelpWithOrderBy(pBuilder, pProbe, pSrc->iCursor);
|
|
+
|
|
/* The ONEPASS_DESIRED flags never occurs together with ORDER BY */
|
|
assert( (pWInfo->wctrlFlags & WHERE_ONEPASS_DESIRED)==0 || b==0 );
|
|
if( pProbe->idxType==SQLITE_IDXTYPE_IPK ){
|
|
@@ -146836,8 +160592,26 @@ static int whereLoopAddBtree(
|
|
|
|
/* Full table scan */
|
|
pNew->iSortIdx = b ? iSortIdx : 0;
|
|
- /* TUNING: Cost of full table scan is (N*3.0). */
|
|
+ /* TUNING: Cost of full table scan is 3.0*N. The 3.0 factor is an
|
|
+ ** extra cost designed to discourage the use of full table scans,
|
|
+ ** since index lookups have better worst-case performance if our
|
|
+ ** stat guesses are wrong. Reduce the 3.0 penalty slightly
|
|
+ ** (to 2.75) if we have valid STAT4 information for the table.
|
|
+ ** At 2.75, a full table scan is preferred over using an index on
|
|
+ ** a column with just two distinct values where each value has about
|
|
+ ** an equal number of appearances. Without STAT4 data, we still want
|
|
+ ** to use an index in that case, since the constraint might be for
|
|
+ ** the scarcer of the two values, and in that case an index lookup is
|
|
+ ** better.
|
|
+ */
|
|
+#ifdef SQLITE_ENABLE_STAT4
|
|
+ pNew->rRun = rSize + 16 - 2*((pTab->tabFlags & TF_HasStat4)!=0);
|
|
+#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);
|
|
@@ -146846,17 +160620,45 @@ static int whereLoopAddBtree(
|
|
}else{
|
|
Bitmask m;
|
|
if( pProbe->isCovering ){
|
|
- pNew->wsFlags = WHERE_IDX_ONLY | WHERE_INDEXED;
|
|
m = 0;
|
|
+ pNew->wsFlags = WHERE_IDX_ONLY | WHERE_INDEXED;
|
|
}else{
|
|
m = pSrc->colUsed & pProbe->colNotIdxed;
|
|
- pNew->wsFlags = (m==0) ? (WHERE_IDX_ONLY|WHERE_INDEXED) : WHERE_INDEXED;
|
|
+ pNew->wsFlags = WHERE_INDEXED;
|
|
+ if( m==TOPBIT || (pProbe->bHasExpr && !pProbe->bHasVCol && m!=0) ){
|
|
+ u32 isCov = whereIsCoveringIndex(pWInfo, pProbe, pSrc->iCursor);
|
|
+ if( isCov==0 ){
|
|
+ WHERETRACE(0x200,
|
|
+ ("-> %s is not a covering index"
|
|
+ " according to whereIsCoveringIndex()\n", pProbe->zName));
|
|
+ assert( m!=0 );
|
|
+ }else{
|
|
+ m = 0;
|
|
+ pNew->wsFlags |= isCov;
|
|
+ if( isCov & WHERE_IDX_ONLY ){
|
|
+ WHERETRACE(0x200,
|
|
+ ("-> %s is a covering expression index"
|
|
+ " according to whereIsCoveringIndex()\n", pProbe->zName));
|
|
+ }else{
|
|
+ assert( isCov==WHERE_EXPRIDX );
|
|
+ WHERETRACE(0x200,
|
|
+ ("-> %s might be a covering expression index"
|
|
+ " according to whereIsCoveringIndex()\n", pProbe->zName));
|
|
+ }
|
|
+ }
|
|
+ }else if( m==0 ){
|
|
+ WHERETRACE(0x200,
|
|
+ ("-> %s a covering index according to bitmasks\n",
|
|
+ pProbe->zName, m==0 ? "is" : "is not"));
|
|
+ pNew->wsFlags = WHERE_IDX_ONLY | WHERE_INDEXED;
|
|
+ }
|
|
}
|
|
|
|
/* Full scan via index */
|
|
if( b
|
|
|| !HasRowid(pTab)
|
|
|| pProbe->pPartIdxWhere!=0
|
|
+ || pSrc->fg.isIndexedBy
|
|
|| ( m==0
|
|
&& pProbe->bUnordered==0
|
|
&& (pProbe->szIdxRow<pTab->szTabRow)
|
|
@@ -146895,20 +160697,27 @@ static int whereLoopAddBtree(
|
|
if( pTerm->eOperator & (WO_EQ|WO_IS) ) nLookup -= 19;
|
|
}
|
|
}
|
|
-
|
|
+
|
|
pNew->rRun = sqlite3LogEstAdd(pNew->rRun, nLookup);
|
|
}
|
|
ApplyCostMultiplier(pNew->rRun, pTab->costMult);
|
|
whereLoopOutputAdjust(pWC, pNew, rSize);
|
|
- rc = whereLoopInsert(pBuilder, pNew);
|
|
+ if( (pSrc->fg.jointype & JT_RIGHT)!=0 && pProbe->aColExpr ){
|
|
+ /* Do not do an SCAN of a index-on-expression in a RIGHT JOIN
|
|
+ ** because the cursor used to access the index might not be
|
|
+ ** positioned to the correct row during the right-join no-match
|
|
+ ** loop. */
|
|
+ }else{
|
|
+ rc = whereLoopInsert(pBuilder, pNew);
|
|
+ }
|
|
pNew->nOut = rSize;
|
|
if( rc ) break;
|
|
}
|
|
}
|
|
|
|
- pBuilder->bldFlags = 0;
|
|
+ pBuilder->bldFlags1 = 0;
|
|
rc = whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, 0);
|
|
- if( pBuilder->bldFlags==SQLITE_BLDF_INDEXED ){
|
|
+ if( pBuilder->bldFlags1==SQLITE_BLDF1_INDEXED ){
|
|
/* If a non-unique index is used, or if a prefix of the key for
|
|
** unique index is used (making the index functionally non-unique)
|
|
** then the sqlite_stat1 data becomes important for scoring the
|
|
@@ -146926,6 +160735,15 @@ static int whereLoopAddBtree(
|
|
|
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
|
|
|
+/*
|
|
+** Return true if pTerm is a virtual table LIMIT or OFFSET term.
|
|
+*/
|
|
+static int isLimitTerm(WhereTerm *pTerm){
|
|
+ assert( pTerm->eOperator==WO_AUX || pTerm->eMatchOp==0 );
|
|
+ return pTerm->eMatchOp>=SQLITE_INDEX_CONSTRAINT_LIMIT
|
|
+ && pTerm->eMatchOp<=SQLITE_INDEX_CONSTRAINT_OFFSET;
|
|
+}
|
|
+
|
|
/*
|
|
** Argument pIdxInfo is already populated with all constraints that may
|
|
** be used by the virtual table identified by pBuilder->pNew->iTab. This
|
|
@@ -146953,9 +160771,11 @@ static int whereLoopAddVirtualOne(
|
|
u16 mExclude, /* Exclude terms using these operators */
|
|
sqlite3_index_info *pIdxInfo, /* Populated object for xBestIndex */
|
|
u16 mNoOmit, /* Do not omit these constraints */
|
|
- int *pbIn /* OUT: True if plan uses an IN(...) op */
|
|
+ int *pbIn, /* OUT: True if plan uses an IN(...) op */
|
|
+ int *pbRetryLimit /* OUT: Retry without LIMIT/OFFSET */
|
|
){
|
|
WhereClause *pWC = pBuilder->pWC;
|
|
+ HiddenIndexInfo *pHidden = (HiddenIndexInfo*)&pIdxInfo[1];
|
|
struct sqlite3_index_constraint *pIdxCons;
|
|
struct sqlite3_index_constraint_usage *pUsage = pIdxInfo->aConstraintUsage;
|
|
int i;
|
|
@@ -146963,21 +160783,22 @@ static int whereLoopAddVirtualOne(
|
|
int rc = SQLITE_OK;
|
|
WhereLoop *pNew = pBuilder->pNew;
|
|
Parse *pParse = pBuilder->pWInfo->pParse;
|
|
- struct SrcList_item *pSrc = &pBuilder->pWInfo->pTabList->a[pNew->iTab];
|
|
+ SrcItem *pSrc = &pBuilder->pWInfo->pTabList->a[pNew->iTab];
|
|
int nConstraint = pIdxInfo->nConstraint;
|
|
|
|
assert( (mUsable & mPrereq)==mPrereq );
|
|
*pbIn = 0;
|
|
pNew->prereq = mPrereq;
|
|
|
|
- /* Set the usable flag on the subset of constraints identified by
|
|
+ /* Set the usable flag on the subset of constraints identified by
|
|
** arguments mUsable and mExclude. */
|
|
pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint;
|
|
for(i=0; i<nConstraint; i++, pIdxCons++){
|
|
WhereTerm *pTerm = &pWC->a[pIdxCons->iTermOffset];
|
|
pIdxCons->usable = 0;
|
|
- if( (pTerm->prereqRight & mUsable)==pTerm->prereqRight
|
|
+ if( (pTerm->prereqRight & mUsable)==pTerm->prereqRight
|
|
&& (pTerm->eOperator & mExclude)==0
|
|
+ && (pbRetryLimit || !isLimitTerm(pTerm))
|
|
){
|
|
pIdxCons->usable = 1;
|
|
}
|
|
@@ -146993,6 +160814,7 @@ static int whereLoopAddVirtualOne(
|
|
pIdxInfo->estimatedRows = 25;
|
|
pIdxInfo->idxFlags = 0;
|
|
pIdxInfo->colUsed = (sqlite3_int64)pSrc->colUsed;
|
|
+ pHidden->mHandleIn = 0;
|
|
|
|
/* Invoke the virtual table xBestIndex() method */
|
|
rc = vtabBestIndex(pParse, pSrc->pTab, pIdxInfo);
|
|
@@ -147002,7 +160824,7 @@ static int whereLoopAddVirtualOne(
|
|
** that the particular combination of parameters provided is unusable.
|
|
** Make no entries in the loop table.
|
|
*/
|
|
- WHERETRACE(0xffff, (" ^^^^--- non-viable plan rejected!\n"));
|
|
+ WHERETRACE(0xffffffff, (" ^^^^--- non-viable plan rejected!\n"));
|
|
return SQLITE_OK;
|
|
}
|
|
return rc;
|
|
@@ -147010,8 +160832,8 @@ static int whereLoopAddVirtualOne(
|
|
|
|
mxTerm = -1;
|
|
assert( pNew->nLSlot>=nConstraint );
|
|
- for(i=0; i<nConstraint; i++) pNew->aLTerm[i] = 0;
|
|
- pNew->u.vtab.omitMask = 0;
|
|
+ memset(pNew->aLTerm, 0, sizeof(pNew->aLTerm[0])*nConstraint );
|
|
+ memset(&pNew->u.vtab, 0, sizeof(pNew->u.vtab));
|
|
pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint;
|
|
for(i=0; i<nConstraint; i++, pIdxCons++){
|
|
int iTerm;
|
|
@@ -147045,8 +160867,13 @@ static int whereLoopAddVirtualOne(
|
|
}else{
|
|
testcase( i!=iTerm );
|
|
}
|
|
+ if( pTerm->eMatchOp==SQLITE_INDEX_CONSTRAINT_OFFSET ){
|
|
+ pNew->u.vtab.bOmitOffset = 1;
|
|
+ }
|
|
}
|
|
- if( (pTerm->eOperator & WO_IN)!=0 ){
|
|
+ if( SMASKBIT32(i) & pHidden->mHandleIn ){
|
|
+ pNew->u.vtab.mHandleIn |= MASKBIT32(iTerm);
|
|
+ }else if( (pTerm->eOperator & WO_IN)!=0 ){
|
|
/* A virtual table that is constrained by an IN clause may not
|
|
** consume the ORDER BY clause because (1) the order of IN terms
|
|
** is not necessarily related to the order of output terms and
|
|
@@ -147056,6 +160883,22 @@ static int whereLoopAddVirtualOne(
|
|
pIdxInfo->idxFlags &= ~SQLITE_INDEX_SCAN_UNIQUE;
|
|
*pbIn = 1; assert( (mExclude & WO_IN)==0 );
|
|
}
|
|
+
|
|
+ assert( pbRetryLimit || !isLimitTerm(pTerm) );
|
|
+ if( isLimitTerm(pTerm) && *pbIn ){
|
|
+ /* If there is an IN(...) term handled as an == (separate call to
|
|
+ ** xFilter for each value on the RHS of the IN) and a LIMIT or
|
|
+ ** OFFSET term handled as well, the plan is unusable. Set output
|
|
+ ** variable *pbRetryLimit to true to tell the caller to retry with
|
|
+ ** LIMIT and OFFSET disabled. */
|
|
+ if( pIdxInfo->needToFreeIdxStr ){
|
|
+ sqlite3_free(pIdxInfo->idxStr);
|
|
+ pIdxInfo->idxStr = 0;
|
|
+ pIdxInfo->needToFreeIdxStr = 0;
|
|
+ }
|
|
+ *pbRetryLimit = 1;
|
|
+ return SQLITE_OK;
|
|
+ }
|
|
}
|
|
}
|
|
|
|
@@ -147092,7 +160935,7 @@ static int whereLoopAddVirtualOne(
|
|
sqlite3_free(pNew->u.vtab.idxStr);
|
|
pNew->u.vtab.needFree = 0;
|
|
}
|
|
- WHERETRACE(0xffff, (" bIn=%d prereqIn=%04llx prereqOut=%04llx\n",
|
|
+ WHERETRACE(0xffffffff, (" bIn=%d prereqIn=%04llx prereqOut=%04llx\n",
|
|
*pbIn, (sqlite3_uint64)mPrereq,
|
|
(sqlite3_uint64)(pNew->prereq & ~mPrereq)));
|
|
|
|
@@ -147100,11 +160943,19 @@ static int whereLoopAddVirtualOne(
|
|
}
|
|
|
|
/*
|
|
-** If this function is invoked from within an xBestIndex() callback, it
|
|
-** returns a pointer to a buffer containing the name of the collation
|
|
-** sequence associated with element iCons of the sqlite3_index_info.aConstraint
|
|
-** array. Or, if iCons is out of range or there is no active xBestIndex
|
|
-** call, return NULL.
|
|
+** Return the collating sequence for a constraint passed into xBestIndex.
|
|
+**
|
|
+** pIdxInfo must be an sqlite3_index_info structure passed into xBestIndex.
|
|
+** This routine depends on there being a HiddenIndexInfo structure immediately
|
|
+** following the sqlite3_index_info structure.
|
|
+**
|
|
+** Return a pointer to the collation name:
|
|
+**
|
|
+** 1. If there is an explicit COLLATE operator on the constaint, return it.
|
|
+**
|
|
+** 2. Else, if the column has an alternative collation, return that.
|
|
+**
|
|
+** 3. Otherwise, return "BINARY".
|
|
*/
|
|
SQLITE_API const char *sqlite3_vtab_collation(sqlite3_index_info *pIdxInfo, int iCons){
|
|
HiddenIndexInfo *pHidden = (HiddenIndexInfo*)&pIdxInfo[1];
|
|
@@ -147121,6 +160972,97 @@ SQLITE_API const char *sqlite3_vtab_collation(sqlite3_index_info *pIdxInfo, int
|
|
return zRet;
|
|
}
|
|
|
|
+/*
|
|
+** Return true if constraint iCons is really an IN(...) constraint, or
|
|
+** false otherwise. If iCons is an IN(...) constraint, set (if bHandle!=0)
|
|
+** or clear (if bHandle==0) the flag to handle it using an iterator.
|
|
+*/
|
|
+SQLITE_API int sqlite3_vtab_in(sqlite3_index_info *pIdxInfo, int iCons, int bHandle){
|
|
+ HiddenIndexInfo *pHidden = (HiddenIndexInfo*)&pIdxInfo[1];
|
|
+ u32 m = SMASKBIT32(iCons);
|
|
+ if( m & pHidden->mIn ){
|
|
+ if( bHandle==0 ){
|
|
+ pHidden->mHandleIn &= ~m;
|
|
+ }else if( bHandle>0 ){
|
|
+ pHidden->mHandleIn |= m;
|
|
+ }
|
|
+ return 1;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*
|
|
+** This interface is callable from within the xBestIndex callback only.
|
|
+**
|
|
+** If possible, set (*ppVal) to point to an object containing the value
|
|
+** on the right-hand-side of constraint iCons.
|
|
+*/
|
|
+SQLITE_API int sqlite3_vtab_rhs_value(
|
|
+ sqlite3_index_info *pIdxInfo, /* Copy of first argument to xBestIndex */
|
|
+ int iCons, /* Constraint for which RHS is wanted */
|
|
+ sqlite3_value **ppVal /* Write value extracted here */
|
|
+){
|
|
+ HiddenIndexInfo *pH = (HiddenIndexInfo*)&pIdxInfo[1];
|
|
+ sqlite3_value *pVal = 0;
|
|
+ int rc = SQLITE_OK;
|
|
+ if( iCons<0 || iCons>=pIdxInfo->nConstraint ){
|
|
+ rc = SQLITE_MISUSE; /* EV: R-30545-25046 */
|
|
+ }else{
|
|
+ if( pH->aRhs[iCons]==0 ){
|
|
+ WhereTerm *pTerm = &pH->pWC->a[pIdxInfo->aConstraint[iCons].iTermOffset];
|
|
+ rc = sqlite3ValueFromExpr(
|
|
+ pH->pParse->db, pTerm->pExpr->pRight, ENC(pH->pParse->db),
|
|
+ SQLITE_AFF_BLOB, &pH->aRhs[iCons]
|
|
+ );
|
|
+ testcase( rc!=SQLITE_OK );
|
|
+ }
|
|
+ pVal = pH->aRhs[iCons];
|
|
+ }
|
|
+ *ppVal = pVal;
|
|
+
|
|
+ if( rc==SQLITE_OK && pVal==0 ){ /* IMP: R-19933-32160 */
|
|
+ rc = SQLITE_NOTFOUND; /* IMP: R-36424-56542 */
|
|
+ }
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Return true if ORDER BY clause may be handled as DISTINCT.
|
|
+*/
|
|
+SQLITE_API int sqlite3_vtab_distinct(sqlite3_index_info *pIdxInfo){
|
|
+ HiddenIndexInfo *pHidden = (HiddenIndexInfo*)&pIdxInfo[1];
|
|
+ assert( pHidden->eDistinct>=0 && pHidden->eDistinct<=3 );
|
|
+ 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
|
|
+** prepared is read-only, then just start read transactions on all
|
|
+** schemas. But if this is a write operation, start writes on all
|
|
+** schemas.
|
|
+**
|
|
+** This is used by the (built-in) sqlite_dbpage virtual table.
|
|
+*/
|
|
+SQLITE_PRIVATE void sqlite3VtabUsesAllSchemas(sqlite3_index_info *pIdxInfo){
|
|
+ HiddenIndexInfo *pHidden = (HiddenIndexInfo*)&pIdxInfo[1];
|
|
+ Parse *pParse = pHidden->pParse;
|
|
+ int nDb = pParse->db->nDb;
|
|
+ int i;
|
|
+ for(i=0; i<nDb; i++){
|
|
+ sqlite3CodeVerifySchema(pParse, i);
|
|
+ }
|
|
+ if( DbMaskNonZero(pParse->writeMask) ){
|
|
+ for(i=0; i<nDb; i++){
|
|
+ sqlite3BeginWriteOperation(pParse, 0, i);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+#endif
|
|
+
|
|
/*
|
|
** Add all WhereLoop objects for a table of the join identified by
|
|
** pBuilder->pNew->iTab. That table is guaranteed to be a virtual table.
|
|
@@ -147130,8 +161072,8 @@ SQLITE_API const char *sqlite3_vtab_collation(sqlite3_index_info *pIdxInfo, int
|
|
** entries that occur before the virtual table in the FROM clause and are
|
|
** separated from it by at least one LEFT or CROSS JOIN. Similarly, the
|
|
** mUnusable mask contains all FROM clause entries that occur after the
|
|
-** virtual table and are separated from it by at least one LEFT or
|
|
-** CROSS JOIN.
|
|
+** virtual table and are separated from it by at least one LEFT or
|
|
+** CROSS JOIN.
|
|
**
|
|
** For example, if the query were:
|
|
**
|
|
@@ -147139,9 +161081,9 @@ SQLITE_API const char *sqlite3_vtab_collation(sqlite3_index_info *pIdxInfo, int
|
|
**
|
|
** then mPrereq corresponds to (t1, t2) and mUnusable to (t5, t6).
|
|
**
|
|
-** All the tables in mPrereq must be scanned before the current virtual
|
|
-** table. So any terms for which all prerequisites are satisfied by
|
|
-** mPrereq may be specified as "usable" in all calls to xBestIndex.
|
|
+** All the tables in mPrereq must be scanned before the current virtual
|
|
+** table. So any terms for which all prerequisites are satisfied by
|
|
+** mPrereq may be specified as "usable" in all calls to xBestIndex.
|
|
** Conversely, all tables in mUnusable must be scanned after the current
|
|
** virtual table, so any terms for which the prerequisites overlap with
|
|
** mUnusable should always be configured as "not-usable" for xBestIndex.
|
|
@@ -147155,13 +161097,14 @@ static int whereLoopAddVirtual(
|
|
WhereInfo *pWInfo; /* WHERE analysis context */
|
|
Parse *pParse; /* The parsing context */
|
|
WhereClause *pWC; /* The WHERE clause */
|
|
- struct SrcList_item *pSrc; /* The FROM clause term to search */
|
|
+ SrcItem *pSrc; /* The FROM clause term to search */
|
|
sqlite3_index_info *p; /* Object to pass to xBestIndex() */
|
|
int nConstraint; /* Number of constraints in p */
|
|
int bIn; /* True if plan uses IN(...) operator */
|
|
WhereLoop *pNew;
|
|
Bitmask mBest; /* Tables used by best possible plan */
|
|
u16 mNoOmit;
|
|
+ int bRetry = 0; /* True to retry with LIMIT/OFFSET disabled */
|
|
|
|
assert( (mPrereq & mUnusable)==0 );
|
|
pWInfo = pBuilder->pWInfo;
|
|
@@ -147170,8 +161113,7 @@ static int whereLoopAddVirtual(
|
|
pNew = pBuilder->pNew;
|
|
pSrc = &pWInfo->pTabList->a[pNew->iTab];
|
|
assert( IsVirtual(pSrc->pTab) );
|
|
- p = allocateIndexInfo(pParse, pWC, mUnusable, pSrc, pBuilder->pOrderBy,
|
|
- &mNoOmit);
|
|
+ p = allocateIndexInfo(pWInfo, pWC, mUnusable, pSrc, &mNoOmit);
|
|
if( p==0 ) return SQLITE_NOMEM_BKPT;
|
|
pNew->rSetup = 0;
|
|
pNew->wsFlags = WHERE_VIRTUALTABLE;
|
|
@@ -147179,18 +161121,26 @@ static int whereLoopAddVirtual(
|
|
pNew->u.vtab.needFree = 0;
|
|
nConstraint = p->nConstraint;
|
|
if( whereLoopResize(pParse->db, pNew, nConstraint) ){
|
|
- sqlite3DbFree(pParse->db, p);
|
|
+ freeIndexInfo(pParse->db, p);
|
|
return SQLITE_NOMEM_BKPT;
|
|
}
|
|
|
|
/* First call xBestIndex() with all constraints usable. */
|
|
WHERETRACE(0x800, ("BEGIN %s.addVirtual()\n", pSrc->pTab->zName));
|
|
- WHERETRACE(0x40, (" VirtualOne: all usable\n"));
|
|
- rc = whereLoopAddVirtualOne(pBuilder, mPrereq, ALLBITS, 0, p, mNoOmit, &bIn);
|
|
+ WHERETRACE(0x800, (" VirtualOne: all usable\n"));
|
|
+ rc = whereLoopAddVirtualOne(
|
|
+ pBuilder, mPrereq, ALLBITS, 0, p, mNoOmit, &bIn, &bRetry
|
|
+ );
|
|
+ if( bRetry ){
|
|
+ assert( rc==SQLITE_OK );
|
|
+ rc = whereLoopAddVirtualOne(
|
|
+ pBuilder, mPrereq, ALLBITS, 0, p, mNoOmit, &bIn, 0
|
|
+ );
|
|
+ }
|
|
|
|
/* If the call to xBestIndex() with all terms enabled produced a plan
|
|
** that does not require any source tables (IOW: a plan with mBest==0)
|
|
- ** and does not use an IN(...) operator, then there is no point in making
|
|
+ ** and does not use an IN(...) operator, then there is no point in making
|
|
** any further calls to xBestIndex() since they will all return the same
|
|
** result (if the xBestIndex() implementation is sane). */
|
|
if( rc==SQLITE_OK && ((mBest = (pNew->prereq & ~mPrereq))!=0 || bIn) ){
|
|
@@ -147202,9 +161152,9 @@ static int whereLoopAddVirtual(
|
|
/* If the plan produced by the earlier call uses an IN(...) term, call
|
|
** xBestIndex again, this time with IN(...) terms disabled. */
|
|
if( bIn ){
|
|
- WHERETRACE(0x40, (" VirtualOne: all usable w/o IN\n"));
|
|
+ WHERETRACE(0x800, (" VirtualOne: all usable w/o IN\n"));
|
|
rc = whereLoopAddVirtualOne(
|
|
- pBuilder, mPrereq, ALLBITS, WO_IN, p, mNoOmit, &bIn);
|
|
+ pBuilder, mPrereq, ALLBITS, WO_IN, p, mNoOmit, &bIn, 0);
|
|
assert( bIn==0 );
|
|
mBestNoIn = pNew->prereq & ~mPrereq;
|
|
if( mBestNoIn==0 ){
|
|
@@ -147213,7 +161163,7 @@ static int whereLoopAddVirtual(
|
|
}
|
|
}
|
|
|
|
- /* Call xBestIndex once for each distinct value of (prereqRight & ~mPrereq)
|
|
+ /* Call xBestIndex once for each distinct value of (prereqRight & ~mPrereq)
|
|
** in the set of terms that apply to the current virtual table. */
|
|
while( rc==SQLITE_OK ){
|
|
int i;
|
|
@@ -147228,10 +161178,10 @@ static int whereLoopAddVirtual(
|
|
mPrev = mNext;
|
|
if( mNext==ALLBITS ) break;
|
|
if( mNext==mBest || mNext==mBestNoIn ) continue;
|
|
- WHERETRACE(0x40, (" VirtualOne: mPrev=%04llx mNext=%04llx\n",
|
|
+ WHERETRACE(0x800, (" VirtualOne: mPrev=%04llx mNext=%04llx\n",
|
|
(sqlite3_uint64)mPrev, (sqlite3_uint64)mNext));
|
|
rc = whereLoopAddVirtualOne(
|
|
- pBuilder, mPrereq, mNext|mPrereq, 0, p, mNoOmit, &bIn);
|
|
+ pBuilder, mPrereq, mNext|mPrereq, 0, p, mNoOmit, &bIn, 0);
|
|
if( pNew->prereq==mPrereq ){
|
|
seenZero = 1;
|
|
if( bIn==0 ) seenZeroNoIN = 1;
|
|
@@ -147242,9 +161192,9 @@ static int whereLoopAddVirtual(
|
|
** that requires no source tables at all (i.e. one guaranteed to be
|
|
** usable), make a call here with all source tables disabled */
|
|
if( rc==SQLITE_OK && seenZero==0 ){
|
|
- WHERETRACE(0x40, (" VirtualOne: all disabled\n"));
|
|
+ WHERETRACE(0x800, (" VirtualOne: all disabled\n"));
|
|
rc = whereLoopAddVirtualOne(
|
|
- pBuilder, mPrereq, mPrereq, 0, p, mNoOmit, &bIn);
|
|
+ pBuilder, mPrereq, mPrereq, 0, p, mNoOmit, &bIn, 0);
|
|
if( bIn==0 ) seenZeroNoIN = 1;
|
|
}
|
|
|
|
@@ -147252,14 +161202,14 @@ static int whereLoopAddVirtual(
|
|
** that requires no source tables at all and does not use an IN(...)
|
|
** operator, make a final call to obtain one here. */
|
|
if( rc==SQLITE_OK && seenZeroNoIN==0 ){
|
|
- WHERETRACE(0x40, (" VirtualOne: all disabled and w/o IN\n"));
|
|
+ WHERETRACE(0x800, (" VirtualOne: all disabled and w/o IN\n"));
|
|
rc = whereLoopAddVirtualOne(
|
|
- pBuilder, mPrereq, mPrereq, WO_IN, p, mNoOmit, &bIn);
|
|
+ pBuilder, mPrereq, mPrereq, WO_IN, p, mNoOmit, &bIn, 0);
|
|
}
|
|
}
|
|
|
|
if( p->needToFreeIdxStr ) sqlite3_free(p->idxStr);
|
|
- sqlite3DbFreeNN(pParse->db, p);
|
|
+ freeIndexInfo(pParse->db, p);
|
|
WHERETRACE(0x800, ("END %s.addVirtual(), rc=%d\n", pSrc->pTab->zName, rc));
|
|
return rc;
|
|
}
|
|
@@ -147270,8 +161220,8 @@ static int whereLoopAddVirtual(
|
|
** btrees or virtual tables.
|
|
*/
|
|
static int whereLoopAddOr(
|
|
- WhereLoopBuilder *pBuilder,
|
|
- Bitmask mPrereq,
|
|
+ WhereLoopBuilder *pBuilder,
|
|
+ Bitmask mPrereq,
|
|
Bitmask mUnusable
|
|
){
|
|
WhereInfo *pWInfo = pBuilder->pWInfo;
|
|
@@ -147283,8 +161233,8 @@ static int whereLoopAddOr(
|
|
WhereClause tempWC;
|
|
WhereLoopBuilder sSubBuild;
|
|
WhereOrSet sSum, sCur;
|
|
- struct SrcList_item *pItem;
|
|
-
|
|
+ SrcItem *pItem;
|
|
+
|
|
pWC = pBuilder->pWC;
|
|
pWCEnd = pWC->a + pWC->nTerm;
|
|
pNew = pBuilder->pNew;
|
|
@@ -147292,21 +161242,23 @@ static int whereLoopAddOr(
|
|
pItem = pWInfo->pTabList->a + pNew->iTab;
|
|
iCur = pItem->iCursor;
|
|
|
|
+ /* The multi-index OR optimization does not work for RIGHT and FULL JOIN */
|
|
+ if( pItem->fg.jointype & JT_RIGHT ) return SQLITE_OK;
|
|
+
|
|
for(pTerm=pWC->a; pTerm<pWCEnd && rc==SQLITE_OK; pTerm++){
|
|
if( (pTerm->eOperator & WO_OR)!=0
|
|
- && (pTerm->u.pOrInfo->indexable & pNew->maskSelf)!=0
|
|
+ && (pTerm->u.pOrInfo->indexable & pNew->maskSelf)!=0
|
|
){
|
|
WhereClause * const pOrWC = &pTerm->u.pOrInfo->wc;
|
|
WhereTerm * const pOrWCEnd = &pOrWC->a[pOrWC->nTerm];
|
|
WhereTerm *pOrTerm;
|
|
int once = 1;
|
|
int i, j;
|
|
-
|
|
+
|
|
sSubBuild = *pBuilder;
|
|
- sSubBuild.pOrderBy = 0;
|
|
sSubBuild.pOrSet = &sCur;
|
|
|
|
- WHERETRACE(0x200, ("Begin processing OR-clause %p\n", pTerm));
|
|
+ WHERETRACE(0x400, ("Begin processing OR-clause %p\n", pTerm));
|
|
for(pOrTerm=pOrWC->a; pOrTerm<pOrWCEnd; pOrTerm++){
|
|
if( (pOrTerm->eOperator & WO_AND)!=0 ){
|
|
sSubBuild.pWC = &pOrTerm->u.pAndInfo->wc;
|
|
@@ -147315,6 +161267,7 @@ static int whereLoopAddOr(
|
|
tempWC.pOuter = pWC;
|
|
tempWC.op = TK_AND;
|
|
tempWC.nTerm = 1;
|
|
+ tempWC.nBase = 1;
|
|
tempWC.a = pOrTerm;
|
|
sSubBuild.pWC = &tempWC;
|
|
}else{
|
|
@@ -147322,9 +161275,9 @@ static int whereLoopAddOr(
|
|
}
|
|
sCur.n = 0;
|
|
#ifdef WHERETRACE_ENABLED
|
|
- WHERETRACE(0x200, ("OR-term %d of %p has %d subterms:\n",
|
|
+ WHERETRACE(0x400, ("OR-term %d of %p has %d subterms:\n",
|
|
(int)(pOrTerm-pOrWC->a), pTerm, sSubBuild.pWC->nTerm));
|
|
- if( sqlite3WhereTrace & 0x400 ){
|
|
+ if( sqlite3WhereTrace & 0x20000 ){
|
|
sqlite3WhereClausePrint(sSubBuild.pWC);
|
|
}
|
|
#endif
|
|
@@ -147339,7 +161292,7 @@ static int whereLoopAddOr(
|
|
if( rc==SQLITE_OK ){
|
|
rc = whereLoopAddOr(&sSubBuild, mPrereq, mUnusable);
|
|
}
|
|
- assert( rc==SQLITE_OK || rc==SQLITE_DONE || sCur.n==0 );
|
|
+ testcase( rc==SQLITE_NOMEM && sCur.n>0 );
|
|
testcase( rc==SQLITE_DONE );
|
|
if( sCur.n==0 ){
|
|
sSum.n = 0;
|
|
@@ -147370,8 +161323,8 @@ static int whereLoopAddOr(
|
|
/* TUNING: Currently sSum.a[i].rRun is set to the sum of the costs
|
|
** of all sub-scans required by the OR-scan. However, due to rounding
|
|
** errors, it may be that the cost of the OR-scan is equal to its
|
|
- ** most expensive sub-scan. Add the smallest possible penalty
|
|
- ** (equivalent to multiplying the cost by 1.07) to ensure that
|
|
+ ** most expensive sub-scan. Add the smallest possible penalty
|
|
+ ** (equivalent to multiplying the cost by 1.07) to ensure that
|
|
** this does not happen. Otherwise, for WHERE clauses such as the
|
|
** following where there is an index on "y":
|
|
**
|
|
@@ -147384,14 +161337,14 @@ static int whereLoopAddOr(
|
|
pNew->prereq = sSum.a[i].prereq;
|
|
rc = whereLoopInsert(pBuilder, pNew);
|
|
}
|
|
- WHERETRACE(0x200, ("End processing OR-clause %p\n", pTerm));
|
|
+ WHERETRACE(0x400, ("End processing OR-clause %p\n", pTerm));
|
|
}
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
-** Add all WhereLoop objects for all tables
|
|
+** Add all WhereLoop objects for all tables
|
|
*/
|
|
static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
|
|
WhereInfo *pWInfo = pBuilder->pWInfo;
|
|
@@ -147399,33 +161352,54 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
|
|
Bitmask mPrior = 0;
|
|
int iTab;
|
|
SrcList *pTabList = pWInfo->pTabList;
|
|
- struct SrcList_item *pItem;
|
|
- struct SrcList_item *pEnd = &pTabList->a[pWInfo->nLevel];
|
|
+ SrcItem *pItem;
|
|
+ SrcItem *pEnd = &pTabList->a[pWInfo->nLevel];
|
|
sqlite3 *db = pWInfo->pParse->db;
|
|
int rc = SQLITE_OK;
|
|
+ int bFirstPastRJ = 0;
|
|
+ int hasRightJoin = 0;
|
|
WhereLoop *pNew;
|
|
- u8 priorJointype = 0;
|
|
+
|
|
|
|
/* Loop over the tables in the join, from left to right */
|
|
pNew = pBuilder->pNew;
|
|
- whereLoopInit(pNew);
|
|
+
|
|
+ /* Verify that pNew has already been initialized */
|
|
+ assert( pNew->nLTerm==0 );
|
|
+ assert( pNew->wsFlags==0 );
|
|
+ assert( pNew->nLSlot>=ArraySize(pNew->aLTermSpace) );
|
|
+ assert( pNew->aLTerm!=0 );
|
|
+
|
|
pBuilder->iPlanLimit = SQLITE_QUERY_PLANNER_LIMIT;
|
|
for(iTab=0, pItem=pTabList->a; pItem<pEnd; iTab++, pItem++){
|
|
Bitmask mUnusable = 0;
|
|
pNew->iTab = iTab;
|
|
pBuilder->iPlanLimit += SQLITE_QUERY_PLANNER_LIMIT_INCR;
|
|
pNew->maskSelf = sqlite3WhereGetMask(&pWInfo->sMaskSet, pItem->iCursor);
|
|
- if( ((pItem->fg.jointype|priorJointype) & (JT_LEFT|JT_CROSS))!=0 ){
|
|
- /* This condition is true when pItem is the FROM clause term on the
|
|
- ** right-hand-side of a LEFT or CROSS JOIN. */
|
|
- mPrereq = mPrior;
|
|
+ if( bFirstPastRJ
|
|
+ || (pItem->fg.jointype & (JT_OUTER|JT_CROSS|JT_LTORJ))!=0
|
|
+ ){
|
|
+ /* Add prerequisites to prevent reordering of FROM clause terms
|
|
+ ** across CROSS joins and outer joins. The bFirstPastRJ boolean
|
|
+ ** prevents the right operand of a RIGHT JOIN from being swapped with
|
|
+ ** other elements even further to the right.
|
|
+ **
|
|
+ ** The JT_LTORJ case and the hasRightJoin flag work together to
|
|
+ ** prevent FROM-clause terms from moving from the right side of
|
|
+ ** a LEFT JOIN over to the left side of that join if the LEFT JOIN
|
|
+ ** is itself on the left side of a RIGHT JOIN.
|
|
+ */
|
|
+ if( pItem->fg.jointype & JT_LTORJ ) hasRightJoin = 1;
|
|
+ mPrereq |= mPrior;
|
|
+ bFirstPastRJ = (pItem->fg.jointype & JT_RIGHT)!=0;
|
|
+ }else if( !hasRightJoin ){
|
|
+ mPrereq = 0;
|
|
}
|
|
- priorJointype = pItem->fg.jointype;
|
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
|
if( IsVirtual(pItem->pTab) ){
|
|
- struct SrcList_item *p;
|
|
+ SrcItem *p;
|
|
for(p=&pItem[1]; p<pEnd; p++){
|
|
- if( mUnusable || (p->fg.jointype & (JT_LEFT|JT_CROSS)) ){
|
|
+ if( mUnusable || (p->fg.jointype & (JT_OUTER|JT_CROSS)) ){
|
|
mUnusable |= sqlite3WhereGetMask(&pWInfo->sMaskSet, p->iCursor);
|
|
}
|
|
}
|
|
@@ -147458,17 +161432,17 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
|
|
** Examine a WherePath (with the addition of the extra WhereLoop of the 6th
|
|
** parameters) to see if it outputs rows in the requested ORDER BY
|
|
** (or GROUP BY) without requiring a separate sort operation. Return N:
|
|
-**
|
|
+**
|
|
** N>0: N terms of the ORDER BY clause are satisfied
|
|
** N==0: No terms of the ORDER BY clause are satisfied
|
|
-** N<0: Unknown yet how many terms of ORDER BY might be satisfied.
|
|
+** N<0: Unknown yet how many terms of ORDER BY might be satisfied.
|
|
**
|
|
** Note that processing for WHERE_GROUPBY and WHERE_DISTINCTBY is not as
|
|
** strict. With GROUP BY and DISTINCT the only requirement is that
|
|
** equivalent rows appear immediately adjacent to one another. GROUP BY
|
|
** and DISTINCT do not require rows to appear in any particular order as long
|
|
** as equivalent rows are grouped together. Thus for GROUP BY and DISTINCT
|
|
-** the pOrderBy terms can be matched in any order. With ORDER BY, the
|
|
+** the pOrderBy terms can be matched in any order. With ORDER BY, the
|
|
** pOrderBy terms must be matched in strict left-to-right order.
|
|
*/
|
|
static i8 wherePathSatisfiesOrderBy(
|
|
@@ -147518,7 +161492,7 @@ static i8 wherePathSatisfiesOrderBy(
|
|
** row of the WhereLoop. Every one-row WhereLoop is automatically
|
|
** order-distinct. A WhereLoop that has no columns in the ORDER BY clause
|
|
** is not order-distinct. To be order-distinct is not quite the same as being
|
|
- ** UNIQUE since a UNIQUE column or index can have multiple rows that
|
|
+ ** UNIQUE since a UNIQUE column or index can have multiple rows that
|
|
** are NULL and NULL values are equivalent for the purpose of order-distinct.
|
|
** To be order-distinct, the columns must be UNIQUE and NOT NULL.
|
|
**
|
|
@@ -147538,7 +161512,9 @@ static i8 wherePathSatisfiesOrderBy(
|
|
orderDistinctMask = 0;
|
|
ready = 0;
|
|
eqOpMask = WO_EQ | WO_IS | WO_ISNULL;
|
|
- if( wctrlFlags & WHERE_ORDERBY_LIMIT ) eqOpMask |= WO_IN;
|
|
+ if( wctrlFlags & (WHERE_ORDERBY_LIMIT|WHERE_ORDERBY_MAX|WHERE_ORDERBY_MIN) ){
|
|
+ eqOpMask |= WO_IN;
|
|
+ }
|
|
for(iLoop=0; isOrderDistinct && obSat<obDone && iLoop<=nLoop; iLoop++){
|
|
if( iLoop>0 ) ready |= pLoop->maskSelf;
|
|
if( iLoop<nLoop ){
|
|
@@ -147548,7 +161524,9 @@ static i8 wherePathSatisfiesOrderBy(
|
|
pLoop = pLast;
|
|
}
|
|
if( pLoop->wsFlags & WHERE_VIRTUALTABLE ){
|
|
- if( pLoop->u.vtab.isOrdered && (wctrlFlags & WHERE_DISTINCTBY)==0 ){
|
|
+ if( pLoop->u.vtab.isOrdered
|
|
+ && ((wctrlFlags&(WHERE_DISTINCTBY|WHERE_SORTBYGROUP))!=WHERE_DISTINCTBY)
|
|
+ ){
|
|
obSat = obDone;
|
|
}
|
|
break;
|
|
@@ -147565,22 +161543,27 @@ static i8 wherePathSatisfiesOrderBy(
|
|
for(i=0; i<nOrderBy; i++){
|
|
if( MASKBIT(i) & obSat ) continue;
|
|
pOBExpr = sqlite3ExprSkipCollateAndLikely(pOrderBy->a[i].pExpr);
|
|
- if( pOBExpr->op!=TK_COLUMN ) continue;
|
|
+ if( NEVER(pOBExpr==0) ) continue;
|
|
+ if( pOBExpr->op!=TK_COLUMN && pOBExpr->op!=TK_AGG_COLUMN ) continue;
|
|
if( pOBExpr->iTable!=iCur ) continue;
|
|
pTerm = sqlite3WhereFindTerm(&pWInfo->sWC, iCur, pOBExpr->iColumn,
|
|
~ready, eqOpMask, 0);
|
|
if( pTerm==0 ) continue;
|
|
if( pTerm->eOperator==WO_IN ){
|
|
- /* IN terms are only valid for sorting in the ORDER BY LIMIT
|
|
+ /* IN terms are only valid for sorting in the ORDER BY LIMIT
|
|
** optimization, and then only if they are actually used
|
|
** by the query plan */
|
|
- assert( wctrlFlags & WHERE_ORDERBY_LIMIT );
|
|
+ assert( wctrlFlags &
|
|
+ (WHERE_ORDERBY_LIMIT|WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX) );
|
|
for(j=0; j<pLoop->nLTerm && pTerm!=pLoop->aLTerm[j]; j++){}
|
|
if( j>=pLoop->nLTerm ) continue;
|
|
}
|
|
if( (pTerm->eOperator&(WO_EQ|WO_IS))!=0 && pOBExpr->iColumn>=0 ){
|
|
- if( sqlite3ExprCollSeqMatch(pWInfo->pParse,
|
|
- pOrderBy->a[i].pExpr, pTerm->pExpr)==0 ){
|
|
+ Parse *pParse = pWInfo->pParse;
|
|
+ CollSeq *pColl1 = sqlite3ExprNNCollSeq(pParse, pOrderBy->a[i].pExpr);
|
|
+ CollSeq *pColl2 = sqlite3ExprCompareCollSeq(pParse, pTerm->pExpr);
|
|
+ assert( pColl1 );
|
|
+ if( pColl2==0 || sqlite3StrICmp(pColl1->zName, pColl2->zName) ){
|
|
continue;
|
|
}
|
|
testcase( pTerm->pExpr->op==TK_IS );
|
|
@@ -147601,6 +161584,10 @@ static i8 wherePathSatisfiesOrderBy(
|
|
assert( nColumn==nKeyCol+1 || !HasRowid(pIndex->pTable) );
|
|
assert( pIndex->aiColumn[nColumn-1]==XN_ROWID
|
|
|| !HasRowid(pIndex->pTable));
|
|
+ /* All relevant terms of the index must also be non-NULL in order
|
|
+ ** for isOrderDistinct to be true. So the isOrderDistint value
|
|
+ ** computed here might be a false positive. Corrections will be
|
|
+ ** made at tag-20210426-1 below */
|
|
isOrderDistinct = IsUniqueIndex(pIndex)
|
|
&& (pLoop->wsFlags & WHERE_SKIPSCAN)==0;
|
|
}
|
|
@@ -147613,7 +161600,7 @@ static i8 wherePathSatisfiesOrderBy(
|
|
for(j=0; j<nColumn; j++){
|
|
u8 bOnce = 1; /* True to run the ORDER BY search loop */
|
|
|
|
- assert( j>=pLoop->u.btree.nEq
|
|
+ assert( j>=pLoop->u.btree.nEq
|
|
|| (pLoop->aLTerm[j]==0)==(j<pLoop->nSkip)
|
|
);
|
|
if( j<pLoop->u.btree.nEq && j>=pLoop->nSkip ){
|
|
@@ -147625,7 +161612,7 @@ static i8 wherePathSatisfiesOrderBy(
|
|
** the loop need to be marked as not order-distinct because it can
|
|
** have repeated NULL rows.
|
|
**
|
|
- ** If the current term is a column of an ((?,?) IN (SELECT...))
|
|
+ ** If the current term is a column of an ((?,?) IN (SELECT...))
|
|
** expression for which the SELECT returns more than one column,
|
|
** check that it is the only column used by this loop. Otherwise,
|
|
** if it is one of two or more, none of the columns can be
|
|
@@ -147638,7 +161625,7 @@ static i8 wherePathSatisfiesOrderBy(
|
|
testcase( isOrderDistinct );
|
|
isOrderDistinct = 0;
|
|
}
|
|
- continue;
|
|
+ continue;
|
|
}else if( ALWAYS(eOp & WO_IN) ){
|
|
/* ALWAYS() justification: eOp is an equality operator due to the
|
|
** j<pLoop->u.btree.nEq constraint above. Any equality other
|
|
@@ -147668,18 +161655,22 @@ static i8 wherePathSatisfiesOrderBy(
|
|
}
|
|
|
|
/* An unconstrained column that might be NULL means that this
|
|
- ** WhereLoop is not well-ordered
|
|
+ ** WhereLoop is not well-ordered. tag-20210426-1
|
|
*/
|
|
- if( isOrderDistinct
|
|
- && iColumn>=0
|
|
- && j>=pLoop->u.btree.nEq
|
|
- && pIndex->pTable->aCol[iColumn].notNull==0
|
|
- ){
|
|
- isOrderDistinct = 0;
|
|
+ if( isOrderDistinct ){
|
|
+ if( iColumn>=0
|
|
+ && j>=pLoop->u.btree.nEq
|
|
+ && pIndex->pTable->aCol[iColumn].notNull==0
|
|
+ ){
|
|
+ isOrderDistinct = 0;
|
|
+ }
|
|
+ if( iColumn==XN_EXPR ){
|
|
+ isOrderDistinct = 0;
|
|
+ }
|
|
}
|
|
|
|
/* Find the ORDER BY term that corresponds to the j-th column
|
|
- ** of the index and mark that ORDER BY term off
|
|
+ ** of the index and mark that ORDER BY term off
|
|
*/
|
|
isMatch = 0;
|
|
for(i=0; bOnce && i<nOrderBy; i++){
|
|
@@ -147687,14 +161678,15 @@ static i8 wherePathSatisfiesOrderBy(
|
|
pOBExpr = sqlite3ExprSkipCollateAndLikely(pOrderBy->a[i].pExpr);
|
|
testcase( wctrlFlags & WHERE_GROUPBY );
|
|
testcase( wctrlFlags & WHERE_DISTINCTBY );
|
|
+ if( NEVER(pOBExpr==0) ) continue;
|
|
if( (wctrlFlags & (WHERE_GROUPBY|WHERE_DISTINCTBY))==0 ) bOnce = 0;
|
|
if( iColumn>=XN_ROWID ){
|
|
- if( pOBExpr->op!=TK_COLUMN ) continue;
|
|
+ if( pOBExpr->op!=TK_COLUMN && pOBExpr->op!=TK_AGG_COLUMN ) continue;
|
|
if( pOBExpr->iTable!=iCur ) continue;
|
|
if( pOBExpr->iColumn!=iColumn ) continue;
|
|
}else{
|
|
- Expr *pIdxExpr = pIndex->aColExpr->a[j].pExpr;
|
|
- if( sqlite3ExprCompareSkip(pOBExpr, pIdxExpr, iCur) ){
|
|
+ Expr *pIxExpr = pIndex->aColExpr->a[j].pExpr;
|
|
+ if( sqlite3ExprCompareSkip(pOBExpr, pIxExpr, iCur) ){
|
|
continue;
|
|
}
|
|
}
|
|
@@ -147712,16 +161704,18 @@ static i8 wherePathSatisfiesOrderBy(
|
|
/* Make sure the sort order is compatible in an ORDER BY clause.
|
|
** Sort order is irrelevant for a GROUP BY clause. */
|
|
if( revSet ){
|
|
- if( (rev ^ revIdx)!=(pOrderBy->a[i].sortFlags&KEYINFO_ORDER_DESC) ){
|
|
+ if( (rev ^ revIdx)
|
|
+ != (pOrderBy->a[i].fg.sortFlags&KEYINFO_ORDER_DESC)
|
|
+ ){
|
|
isMatch = 0;
|
|
}
|
|
}else{
|
|
- rev = revIdx ^ (pOrderBy->a[i].sortFlags & KEYINFO_ORDER_DESC);
|
|
+ rev = revIdx ^ (pOrderBy->a[i].fg.sortFlags & KEYINFO_ORDER_DESC);
|
|
if( rev ) *pRevMask |= MASKBIT(iLoop);
|
|
revSet = 1;
|
|
}
|
|
}
|
|
- if( isMatch && (pOrderBy->a[i].sortFlags & KEYINFO_ORDER_BIGNULL) ){
|
|
+ if( isMatch && (pOrderBy->a[i].fg.sortFlags & KEYINFO_ORDER_BIGNULL) ){
|
|
if( j==pLoop->u.btree.nEq ){
|
|
pLoop->wsFlags |= WHERE_BIGNULL_SORT;
|
|
}else{
|
|
@@ -147768,7 +161762,7 @@ static i8 wherePathSatisfiesOrderBy(
|
|
if( obSat==obDone ) return (i8)nOrderBy;
|
|
if( !isOrderDistinct ){
|
|
for(i=nOrderBy-1; i>0; i--){
|
|
- Bitmask m = MASKBIT(i) - 1;
|
|
+ Bitmask m = ALWAYS(i<BMS) ? MASKBIT(i) - 1 : 0;
|
|
if( (obSat&m)==m ) return i;
|
|
}
|
|
return 0;
|
|
@@ -147801,7 +161795,7 @@ static i8 wherePathSatisfiesOrderBy(
|
|
** SELECT * FROM t1 GROUP BY y,x ORDER BY y,x; -- IsSorted()==0
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3WhereIsSorted(WhereInfo *pWInfo){
|
|
- assert( pWInfo->wctrlFlags & WHERE_GROUPBY );
|
|
+ assert( pWInfo->wctrlFlags & (WHERE_GROUPBY|WHERE_DISTINCTBY) );
|
|
assert( pWInfo->wctrlFlags & WHERE_SORTBYGROUP );
|
|
return pWInfo->sorted;
|
|
}
|
|
@@ -147819,38 +161813,65 @@ static const char *wherePathName(WherePath *pPath, int nLoop, WhereLoop *pLast){
|
|
#endif
|
|
|
|
/*
|
|
-** Return the cost of sorting nRow rows, assuming that the keys have
|
|
+** Return the cost of sorting nRow rows, assuming that the keys have
|
|
** nOrderby columns and that the first nSorted columns are already in
|
|
** order.
|
|
*/
|
|
static LogEst whereSortingCost(
|
|
- WhereInfo *pWInfo,
|
|
- LogEst nRow,
|
|
- int nOrderBy,
|
|
- int nSorted
|
|
+ WhereInfo *pWInfo, /* Query planning context */
|
|
+ LogEst nRow, /* Estimated number of rows to sort */
|
|
+ int nOrderBy, /* Number of ORDER BY clause terms */
|
|
+ int nSorted /* Number of initial ORDER BY terms naturally in order */
|
|
){
|
|
- /* TUNING: Estimated cost of a full external sort, where N is
|
|
+ /* Estimated cost of a full external sort, where N is
|
|
** the number of rows to sort is:
|
|
**
|
|
- ** cost = (3.0 * N * log(N)).
|
|
- **
|
|
- ** Or, if the order-by clause has X terms but only the last Y
|
|
- ** terms are out of order, then block-sorting will reduce the
|
|
+ ** cost = (K * N * log(N)).
|
|
+ **
|
|
+ ** Or, if the order-by clause has X terms but only the last Y
|
|
+ ** terms are out of order, then block-sorting will reduce the
|
|
** sorting cost to:
|
|
**
|
|
- ** cost = (3.0 * N * log(N)) * (Y/X)
|
|
+ ** cost = (K * N * log(N)) * (Y/X)
|
|
+ **
|
|
+ ** The constant K is at least 2.0 but will be larger if there are a
|
|
+ ** large number of columns to be sorted, as the sorting time is
|
|
+ ** proportional to the amount of content to be sorted. The algorithm
|
|
+ ** does not currently distinguish between fat columns (BLOBs and TEXTs)
|
|
+ ** and skinny columns (INTs). It just uses the number of columns as
|
|
+ ** an approximation for the row width.
|
|
**
|
|
- ** The (Y/X) term is implemented using stack variable rScale
|
|
- ** below. */
|
|
- LogEst rScale, rSortCost;
|
|
- assert( nOrderBy>0 && 66==sqlite3LogEst(100) );
|
|
- rScale = sqlite3LogEst((nOrderBy-nSorted)*100/nOrderBy) - 66;
|
|
- rSortCost = nRow + rScale + 16;
|
|
+ ** And extra factor of 2.0 or 3.0 is added to the sorting cost if the sort
|
|
+ ** is built using OP_IdxInsert and OP_Sort rather than with OP_SorterInsert.
|
|
+ */
|
|
+ LogEst rSortCost, nCol;
|
|
+ assert( pWInfo->pSelect!=0 );
|
|
+ assert( pWInfo->pSelect->pEList!=0 );
|
|
+ /* TUNING: sorting cost proportional to the number of output columns: */
|
|
+ nCol = sqlite3LogEst((pWInfo->pSelect->pEList->nExpr+59)/30);
|
|
+ rSortCost = nRow + nCol;
|
|
+ if( nSorted>0 ){
|
|
+ /* Scale the result by (Y/X) */
|
|
+ rSortCost += sqlite3LogEst((nOrderBy-nSorted)*100/nOrderBy) - 66;
|
|
+ }
|
|
|
|
/* Multiple by log(M) where M is the number of output rows.
|
|
- ** Use the LIMIT for M if it is smaller */
|
|
- if( (pWInfo->wctrlFlags & WHERE_USE_LIMIT)!=0 && pWInfo->iLimit<nRow ){
|
|
- nRow = pWInfo->iLimit;
|
|
+ ** Use the LIMIT for M if it is smaller. Or if this sort is for
|
|
+ ** a DISTINCT operator, M will be the number of distinct output
|
|
+ ** rows, so fudge it downwards a bit.
|
|
+ */
|
|
+ if( (pWInfo->wctrlFlags & WHERE_USE_LIMIT)!=0 ){
|
|
+ rSortCost += 10; /* TUNING: Extra 2.0x if using LIMIT */
|
|
+ if( nSorted!=0 ){
|
|
+ rSortCost += 6; /* TUNING: Extra 1.5x if also using partial sort */
|
|
+ }
|
|
+ if( pWInfo->iLimit<nRow ){
|
|
+ nRow = pWInfo->iLimit;
|
|
+ }
|
|
+ }else if( (pWInfo->wctrlFlags & WHERE_WANT_DISTINCT) ){
|
|
+ /* TUNING: In the sort for a DISTINCT operator, assume that the DISTINCT
|
|
+ ** reduces the number of output rows by a factor of 2 */
|
|
+ if( nRow>10 ){ nRow -= 10; assert( 10==sqlite3LogEst(2) ); }
|
|
}
|
|
rSortCost += estLog(nRow);
|
|
return rSortCost;
|
|
@@ -147872,7 +161893,6 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
|
|
int mxChoice; /* Maximum number of simultaneous paths tracked */
|
|
int nLoop; /* Number of terms in the join */
|
|
Parse *pParse; /* Parsing context */
|
|
- sqlite3 *db; /* The database connection */
|
|
int iLoop; /* Loop counter over the terms of the join */
|
|
int ii, jj; /* Loop counters */
|
|
int mxI = 0; /* Index of next entry to replace */
|
|
@@ -147891,7 +161911,6 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
|
|
int nSpace; /* Bytes of space allocated at pSpace */
|
|
|
|
pParse = pWInfo->pParse;
|
|
- db = pParse->db;
|
|
nLoop = pWInfo->nLevel;
|
|
/* TUNING: For simple queries, only the best path is tracked.
|
|
** For 2-way joins, the 5 best paths are followed.
|
|
@@ -147914,7 +161933,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
|
|
/* Allocate and initialize space for aTo, aFrom and aSortCost[] */
|
|
nSpace = (sizeof(WherePath)+sizeof(WhereLoop*)*nLoop)*mxChoice*2;
|
|
nSpace += sizeof(LogEst) * nOrderBy;
|
|
- pSpace = sqlite3DbMallocRawNN(db, nSpace);
|
|
+ pSpace = sqlite3StackAllocRawNN(pParse->db, nSpace);
|
|
if( pSpace==0 ) return SQLITE_NOMEM_BKPT;
|
|
aTo = (WherePath*)pSpace;
|
|
aFrom = aTo+mxChoice;
|
|
@@ -147928,7 +161947,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
|
|
** space for the aSortCost[] array. Each element of the aSortCost array
|
|
** is either zero - meaning it has not yet been initialized - or the
|
|
** cost of sorting nRowEst rows of data where the first X terms of
|
|
- ** the ORDER BY clause are already in order, where X is the array
|
|
+ ** the ORDER BY clause are already in order, where X is the array
|
|
** index. */
|
|
aSortCost = (LogEst*)pX;
|
|
memset(aSortCost, 0, sizeof(LogEst) * nOrderBy);
|
|
@@ -147949,7 +161968,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
|
|
** in this case the query may return a maximum of one row, the results
|
|
** are already in the requested order. Set isOrdered to nOrderBy to
|
|
** indicate this. Or, if nLoop is greater than zero, set isOrdered to
|
|
- ** -1, indicating that the result set may or may not be ordered,
|
|
+ ** -1, indicating that the result set may or may not be ordered,
|
|
** depending on the loops added to the current plan. */
|
|
aFrom[0].isOrdered = nLoop>0 ? -1 : nOrderBy;
|
|
}
|
|
@@ -147964,9 +161983,9 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
|
|
LogEst nOut; /* Rows visited by (pFrom+pWLoop) */
|
|
LogEst rCost; /* Cost of path (pFrom+pWLoop) */
|
|
LogEst rUnsorted; /* Unsorted cost of (pFrom+pWLoop) */
|
|
- i8 isOrdered = pFrom->isOrdered; /* isOrdered for (pFrom+pWLoop) */
|
|
+ i8 isOrdered; /* isOrdered for (pFrom+pWLoop) */
|
|
Bitmask maskNew; /* Mask of src visited by (..) */
|
|
- Bitmask revMask = 0; /* Mask of rev-order loops for (..) */
|
|
+ Bitmask revMask; /* Mask of rev-order loops for (..) */
|
|
|
|
if( (pWLoop->prereq & ~pFrom->maskLoop)!=0 ) continue;
|
|
if( (pWLoop->maskSelf & pFrom->maskLoop)!=0 ) continue;
|
|
@@ -147979,13 +161998,15 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
|
|
continue;
|
|
}
|
|
|
|
- /* At this point, pWLoop is a candidate to be the next loop.
|
|
+ /* At this point, pWLoop is a candidate to be the next loop.
|
|
** Compute its cost */
|
|
rUnsorted = sqlite3LogEstAdd(pWLoop->rSetup,pWLoop->rRun + pFrom->nRow);
|
|
rUnsorted = sqlite3LogEstAdd(rUnsorted, pFrom->rUnsorted);
|
|
nOut = pFrom->nRow + pWLoop->nOut;
|
|
maskNew = pFrom->maskLoop | pWLoop->maskSelf;
|
|
+ isOrdered = pFrom->isOrdered;
|
|
if( isOrdered<0 ){
|
|
+ revMask = 0;
|
|
isOrdered = wherePathSatisfiesOrderBy(pWInfo,
|
|
pWInfo->pOrderBy, pFrom, pWInfo->wctrlFlags,
|
|
iLoop, pWLoop, &revMask);
|
|
@@ -147998,21 +162019,28 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
|
|
pWInfo, nRowEst, nOrderBy, isOrdered
|
|
);
|
|
}
|
|
- /* TUNING: Add a small extra penalty (5) to sorting as an
|
|
+ /* TUNING: Add a small extra penalty (3) to sorting as an
|
|
** extra encouragment to the query planner to select a plan
|
|
** where the rows emerge in the correct order without any sorting
|
|
** required. */
|
|
- rCost = sqlite3LogEstAdd(rUnsorted, aSortCost[isOrdered]) + 5;
|
|
+ rCost = sqlite3LogEstAdd(rUnsorted, aSortCost[isOrdered]) + 3;
|
|
|
|
WHERETRACE(0x002,
|
|
("---- sort cost=%-3d (%d/%d) increases cost %3d to %-3d\n",
|
|
- aSortCost[isOrdered], (nOrderBy-isOrdered), nOrderBy,
|
|
+ aSortCost[isOrdered], (nOrderBy-isOrdered), nOrderBy,
|
|
rUnsorted, rCost));
|
|
}else{
|
|
rCost = rUnsorted;
|
|
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.
|
|
**
|
|
@@ -148071,11 +162099,11 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
|
|
** same set of loops and has the same isOrdered setting as the
|
|
** candidate path. Check to see if the candidate should replace
|
|
** pTo or if the candidate should be skipped.
|
|
- **
|
|
+ **
|
|
** The conditional is an expanded vector comparison equivalent to:
|
|
** (pTo->rCost,pTo->nRow,pTo->rUnsorted) <= (rCost,nOut,rUnsorted)
|
|
*/
|
|
- if( pTo->rCost<rCost
|
|
+ if( pTo->rCost<rCost
|
|
|| (pTo->rCost==rCost
|
|
&& (pTo->nRow<nOut
|
|
|| (pTo->nRow==nOut && pTo->rUnsorted<=rUnsorted)
|
|
@@ -148126,8 +162154,8 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
|
|
mxCost = aTo[0].rCost;
|
|
mxUnsorted = aTo[0].nRow;
|
|
for(jj=1, pTo=&aTo[1]; jj<mxChoice; jj++, pTo++){
|
|
- if( pTo->rCost>mxCost
|
|
- || (pTo->rCost==mxCost && pTo->rUnsorted>mxUnsorted)
|
|
+ if( pTo->rCost>mxCost
|
|
+ || (pTo->rCost==mxCost && pTo->rUnsorted>mxUnsorted)
|
|
){
|
|
mxCost = pTo->rCost;
|
|
mxUnsorted = pTo->rUnsorted;
|
|
@@ -148163,10 +162191,10 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
|
|
|
|
if( nFrom==0 ){
|
|
sqlite3ErrorMsg(pParse, "no query solution");
|
|
- sqlite3DbFreeNN(db, pSpace);
|
|
+ sqlite3StackFreeNN(pParse->db, pSpace);
|
|
return SQLITE_ERROR;
|
|
}
|
|
-
|
|
+
|
|
/* Find the lowest cost path. pFrom will be left pointing to that path */
|
|
pFrom = aFrom;
|
|
for(ii=1; ii<nFrom; ii++){
|
|
@@ -148194,18 +162222,22 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
|
|
}
|
|
pWInfo->bOrderedInnerLoop = 0;
|
|
if( pWInfo->pOrderBy ){
|
|
+ pWInfo->nOBSat = pFrom->isOrdered;
|
|
if( pWInfo->wctrlFlags & WHERE_DISTINCTBY ){
|
|
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->nOBSat = pFrom->isOrdered;
|
|
pWInfo->revMask = pFrom->revLoop;
|
|
if( pWInfo->nOBSat<=0 ){
|
|
pWInfo->nOBSat = 0;
|
|
if( nLoop>0 ){
|
|
u32 wsFlags = pFrom->aLoop[nLoop-1]->wsFlags;
|
|
- if( (wsFlags & WHERE_ONEROW)==0
|
|
+ if( (wsFlags & WHERE_ONEROW)==0
|
|
&& (wsFlags&(WHERE_IPK|WHERE_COLUMN_IN))!=(WHERE_IPK|WHERE_COLUMN_IN)
|
|
){
|
|
Bitmask m = 0;
|
|
@@ -148219,13 +162251,18 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
|
|
}
|
|
}
|
|
}
|
|
+ }else if( nLoop
|
|
+ && pWInfo->nOBSat==1
|
|
+ && (pWInfo->wctrlFlags & (WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX))!=0
|
|
+ ){
|
|
+ pWInfo->bOrderedInnerLoop = 1;
|
|
}
|
|
}
|
|
if( (pWInfo->wctrlFlags & WHERE_SORTBYGROUP)
|
|
&& pWInfo->nOBSat==pWInfo->pOrderBy->nExpr && nLoop>0
|
|
){
|
|
Bitmask revMask = 0;
|
|
- int nOrder = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pOrderBy,
|
|
+ int nOrder = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pOrderBy,
|
|
pFrom, 0, nLoop-1, pFrom->aLoop[nLoop-1], &revMask
|
|
);
|
|
assert( pWInfo->sorted==0 );
|
|
@@ -148240,7 +162277,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
|
|
pWInfo->nRowOut = pFrom->nRow;
|
|
|
|
/* Free temporary memory and return success */
|
|
- sqlite3DbFreeNN(db, pSpace);
|
|
+ sqlite3StackFreeNN(pParse->db, pSpace);
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
@@ -148252,12 +162289,12 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
|
|
** times for the common case.
|
|
**
|
|
** Return non-zero on success, if this query can be handled by this
|
|
-** no-frills query planner. Return zero if this query needs the
|
|
+** no-frills query planner. Return zero if this query needs the
|
|
** general-purpose query planner.
|
|
*/
|
|
static int whereShortCut(WhereLoopBuilder *pBuilder){
|
|
WhereInfo *pWInfo;
|
|
- struct SrcList_item *pItem;
|
|
+ SrcItem *pItem;
|
|
WhereClause *pWC;
|
|
WhereTerm *pTerm;
|
|
WhereLoop *pLoop;
|
|
@@ -148265,6 +162302,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
|
|
int j;
|
|
Table *pTab;
|
|
Index *pIdx;
|
|
+ WhereScan scan;
|
|
|
|
pWInfo = pBuilder->pWInfo;
|
|
if( pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE ) return 0;
|
|
@@ -148272,13 +162310,18 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
|
|
pItem = pWInfo->pTabList->a;
|
|
pTab = pItem->pTab;
|
|
if( IsVirtual(pTab) ) return 0;
|
|
- if( pItem->fg.isIndexedBy ) return 0;
|
|
+ if( pItem->fg.isIndexedBy || pItem->fg.notIndexed ){
|
|
+ testcase( pItem->fg.isIndexedBy );
|
|
+ testcase( pItem->fg.notIndexed );
|
|
+ return 0;
|
|
+ }
|
|
iCur = pItem->iCursor;
|
|
pWC = &pWInfo->sWC;
|
|
pLoop = pBuilder->pNew;
|
|
pLoop->wsFlags = 0;
|
|
pLoop->nSkip = 0;
|
|
- pTerm = sqlite3WhereFindTerm(pWC, iCur, -1, 0, WO_EQ|WO_IS, 0);
|
|
+ pTerm = whereScanInit(&scan, pWC, iCur, -1, WO_EQ|WO_IS, 0);
|
|
+ while( pTerm && pTerm->prereqRight ) pTerm = whereScanNext(&scan);
|
|
if( pTerm ){
|
|
testcase( pTerm->eOperator & WO_IS );
|
|
pLoop->wsFlags = WHERE_COLUMN_EQ|WHERE_IPK|WHERE_ONEROW;
|
|
@@ -148292,12 +162335,13 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
|
|
int opMask;
|
|
assert( pLoop->aLTermSpace==pLoop->aLTerm );
|
|
if( !IsUniqueIndex(pIdx)
|
|
- || pIdx->pPartIdxWhere!=0
|
|
- || pIdx->nKeyCol>ArraySize(pLoop->aLTermSpace)
|
|
+ || pIdx->pPartIdxWhere!=0
|
|
+ || pIdx->nKeyCol>ArraySize(pLoop->aLTermSpace)
|
|
) continue;
|
|
opMask = pIdx->uniqNotNull ? (WO_EQ|WO_IS) : WO_EQ;
|
|
for(j=0; j<pIdx->nKeyCol; j++){
|
|
- pTerm = sqlite3WhereFindTerm(pWC, iCur, j, 0, opMask, pIdx);
|
|
+ pTerm = whereScanInit(&scan, pWC, iCur, j, opMask, pIdx);
|
|
+ while( pTerm && pTerm->prereqRight ) pTerm = whereScanNext(&scan);
|
|
if( pTerm==0 ) break;
|
|
testcase( pTerm->eOperator & WO_IS );
|
|
pLoop->aLTerm[j] = pTerm;
|
|
@@ -148326,8 +162370,14 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
|
|
if( pWInfo->wctrlFlags & WHERE_WANT_DISTINCT ){
|
|
pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE;
|
|
}
|
|
+ if( scan.iEquiv>1 ) pLoop->wsFlags |= WHERE_TRANSCONS;
|
|
#ifdef SQLITE_DEBUG
|
|
pLoop->cId = '0';
|
|
+#endif
|
|
+#ifdef WHERETRACE_ENABLED
|
|
+ if( sqlite3WhereTrace & 0x02 ){
|
|
+ sqlite3DebugPrintf("whereShortCut() used to compute solution\n");
|
|
+ }
|
|
#endif
|
|
return 1;
|
|
}
|
|
@@ -148346,8 +162396,8 @@ static int exprNodeIsDeterministic(Walker *pWalker, Expr *pExpr){
|
|
}
|
|
|
|
/*
|
|
-** Return true if the expression contains no non-deterministic SQL
|
|
-** functions. Do not consider non-deterministic SQL functions that are
|
|
+** Return true if the expression contains no non-deterministic SQL
|
|
+** functions. Do not consider non-deterministic SQL functions that are
|
|
** part of sub-select statements.
|
|
*/
|
|
static int exprIsDeterministic(Expr *p){
|
|
@@ -148360,6 +162410,251 @@ static int exprIsDeterministic(Expr *p){
|
|
return w.eCode;
|
|
}
|
|
|
|
+
|
|
+#ifdef WHERETRACE_ENABLED
|
|
+/*
|
|
+** Display all WhereLoops in pWInfo
|
|
+*/
|
|
+static void showAllWhereLoops(WhereInfo *pWInfo, WhereClause *pWC){
|
|
+ if( sqlite3WhereTrace ){ /* Display all of the WhereLoop objects */
|
|
+ WhereLoop *p;
|
|
+ int i;
|
|
+ static const char zLabel[] = "0123456789abcdefghijklmnopqrstuvwyxz"
|
|
+ "ABCDEFGHIJKLMNOPQRSTUVWYXZ";
|
|
+ for(p=pWInfo->pLoops, i=0; p; p=p->pNextLoop, i++){
|
|
+ p->cId = zLabel[i%(sizeof(zLabel)-1)];
|
|
+ sqlite3WhereLoopPrint(p, pWC);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+# define WHERETRACE_ALL_LOOPS(W,C) showAllWhereLoops(W,C)
|
|
+#else
|
|
+# define WHERETRACE_ALL_LOOPS(W,C)
|
|
+#endif
|
|
+
|
|
+/* Attempt to omit tables from a join that do not affect the result.
|
|
+** For a table to not affect the result, the following must be true:
|
|
+**
|
|
+** 1) The query must not be an aggregate.
|
|
+** 2) The table must be the RHS of a LEFT JOIN.
|
|
+** 3) Either the query must be DISTINCT, or else the ON or USING clause
|
|
+** must contain a constraint that limits the scan of the table to
|
|
+** 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.
|
|
+**
|
|
+** For example, given:
|
|
+**
|
|
+** CREATE TABLE t1(ipk INTEGER PRIMARY KEY, v1);
|
|
+** CREATE TABLE t2(ipk INTEGER PRIMARY KEY, v2);
|
|
+** CREATE TABLE t3(ipk INTEGER PRIMARY KEY, v3);
|
|
+**
|
|
+** then table t2 can be omitted from the following:
|
|
+**
|
|
+** SELECT v1, v3 FROM t1
|
|
+** LEFT JOIN t2 ON (t1.ipk=t2.ipk)
|
|
+** LEFT JOIN t3 ON (t1.ipk=t3.ipk)
|
|
+**
|
|
+** or from:
|
|
+**
|
|
+** SELECT DISTINCT v1, v3 FROM t1
|
|
+** LEFT JOIN t2
|
|
+** LEFT JOIN t3 ON (t1.ipk=t3.ipk)
|
|
+*/
|
|
+static SQLITE_NOINLINE Bitmask whereOmitNoopJoin(
|
|
+ WhereInfo *pWInfo,
|
|
+ Bitmask notReady
|
|
+){
|
|
+ int i;
|
|
+ Bitmask tabUsed;
|
|
+
|
|
+ /* Preconditions checked by the caller */
|
|
+ assert( pWInfo->nLevel>=2 );
|
|
+ assert( OptimizationEnabled(pWInfo->pParse->db, SQLITE_OmitNoopJoin) );
|
|
+
|
|
+ /* These two preconditions checked by the caller combine to guarantee
|
|
+ ** condition (1) of the header comment */
|
|
+ assert( pWInfo->pResultSet!=0 );
|
|
+ assert( 0==(pWInfo->wctrlFlags & WHERE_AGG_DISTINCT) );
|
|
+
|
|
+ tabUsed = sqlite3WhereExprListUsage(&pWInfo->sMaskSet, pWInfo->pResultSet);
|
|
+ if( pWInfo->pOrderBy ){
|
|
+ tabUsed |= sqlite3WhereExprListUsage(&pWInfo->sMaskSet, pWInfo->pOrderBy);
|
|
+ }
|
|
+ for(i=pWInfo->nLevel-1; i>=1; i--){
|
|
+ WhereTerm *pTerm, *pEnd;
|
|
+ SrcItem *pItem;
|
|
+ WhereLoop *pLoop;
|
|
+ pLoop = pWInfo->a[i].pWLoop;
|
|
+ pItem = &pWInfo->pTabList->a[pLoop->iTab];
|
|
+ if( (pItem->fg.jointype & (JT_LEFT|JT_RIGHT))!=JT_LEFT ) continue;
|
|
+ if( (pWInfo->wctrlFlags & WHERE_WANT_DISTINCT)==0
|
|
+ && (pLoop->wsFlags & WHERE_ONEROW)==0
|
|
+ ){
|
|
+ continue;
|
|
+ }
|
|
+ if( (tabUsed & pLoop->maskSelf)!=0 ) continue;
|
|
+ pEnd = pWInfo->sWC.a + pWInfo->sWC.nTerm;
|
|
+ for(pTerm=pWInfo->sWC.a; pTerm<pEnd; pTerm++){
|
|
+ if( (pTerm->prereqAll & pLoop->maskSelf)!=0 ){
|
|
+ if( !ExprHasProperty(pTerm->pExpr, EP_OuterON)
|
|
+ || pTerm->pExpr->w.iJoin!=pItem->iCursor
|
|
+ ){
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ if( pTerm<pEnd ) continue;
|
|
+ WHERETRACE(0xffffffff, ("-> drop loop %c not used\n", pLoop->cId));
|
|
+ notReady &= ~pLoop->maskSelf;
|
|
+ for(pTerm=pWInfo->sWC.a; pTerm<pEnd; pTerm++){
|
|
+ if( (pTerm->prereqAll & pLoop->maskSelf)!=0 ){
|
|
+ pTerm->wtFlags |= TERM_CODED;
|
|
+ }
|
|
+ }
|
|
+ if( i!=pWInfo->nLevel-1 ){
|
|
+ int nByte = (pWInfo->nLevel-1-i) * sizeof(WhereLevel);
|
|
+ memmove(&pWInfo->a[i], &pWInfo->a[i+1], nByte);
|
|
+ }
|
|
+ pWInfo->nLevel--;
|
|
+ assert( pWInfo->nLevel>0 );
|
|
+ }
|
|
+ return notReady;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Check to see if there are any SEARCH loops that might benefit from
|
|
+** using a Bloom filter. Consider a Bloom filter if:
|
|
+**
|
|
+** (1) The SEARCH happens more than N times where N is the number
|
|
+** of rows in the table that is being considered for the Bloom
|
|
+** filter.
|
|
+** (2) Some searches are expected to find zero rows. (This is determined
|
|
+** by the WHERE_SELFCULL flag on the term.)
|
|
+** (3) Bloom-filter processing is not disabled. (Checked by the
|
|
+** caller.)
|
|
+** (4) The size of the table being searched is known by ANALYZE.
|
|
+**
|
|
+** This block of code merely checks to see if a Bloom filter would be
|
|
+** appropriate, and if so sets the WHERE_BLOOMFILTER flag on the
|
|
+** WhereLoop. The implementation of the Bloom filter comes further
|
|
+** down where the code for each WhereLoop is generated.
|
|
+*/
|
|
+static SQLITE_NOINLINE void whereCheckIfBloomFilterIsUseful(
|
|
+ const WhereInfo *pWInfo
|
|
+){
|
|
+ int i;
|
|
+ LogEst nSearch = 0;
|
|
+
|
|
+ assert( pWInfo->nLevel>=2 );
|
|
+ assert( OptimizationEnabled(pWInfo->pParse->db, SQLITE_BloomFilter) );
|
|
+ for(i=0; i<pWInfo->nLevel; i++){
|
|
+ WhereLoop *pLoop = pWInfo->a[i].pWLoop;
|
|
+ const unsigned int reqFlags = (WHERE_SELFCULL|WHERE_COLUMN_EQ);
|
|
+ SrcItem *pItem = &pWInfo->pTabList->a[pLoop->iTab];
|
|
+ Table *pTab = pItem->pTab;
|
|
+ if( (pTab->tabFlags & TF_HasStat1)==0 ) break;
|
|
+ pTab->tabFlags |= TF_StatsUsed;
|
|
+ if( i>=1
|
|
+ && (pLoop->wsFlags & reqFlags)==reqFlags
|
|
+ /* vvvvvv--- Always the case if WHERE_COLUMN_EQ is defined */
|
|
+ && ALWAYS((pLoop->wsFlags & (WHERE_IPK|WHERE_INDEXED))!=0)
|
|
+ ){
|
|
+ if( nSearch > pTab->nRowLogEst ){
|
|
+ testcase( pItem->fg.jointype & JT_LEFT );
|
|
+ pLoop->wsFlags |= WHERE_BLOOMFILTER;
|
|
+ pLoop->wsFlags &= ~WHERE_IDX_ONLY;
|
|
+ WHERETRACE(0xffffffff, (
|
|
+ "-> use Bloom-filter on loop %c because there are ~%.1e "
|
|
+ "lookups into %s which has only ~%.1e rows\n",
|
|
+ pLoop->cId, (double)sqlite3LogEstToInt(nSearch), pTab->zName,
|
|
+ (double)sqlite3LogEstToInt(pTab->nRowLogEst)));
|
|
+ }
|
|
+ }
|
|
+ nSearch += pLoop->nOut;
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+** 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
|
|
+** number for the index and iDataCur is the cursor number for the corresponding
|
|
+** table.
|
|
+**
|
|
+** This routine adds IndexedExpr entries to the Parse->pIdxEpr field for
|
|
+** each of the expressions in the index so that the expression code generator
|
|
+** will know to replace occurrences of the indexed expression with
|
|
+** references to the corresponding column of the index.
|
|
+*/
|
|
+static SQLITE_NOINLINE void whereAddIndexedExpr(
|
|
+ Parse *pParse, /* Add IndexedExpr entries to pParse->pIdxEpr */
|
|
+ Index *pIdx, /* The index-on-expression that contains the expressions */
|
|
+ int iIdxCur, /* Cursor number for pIdx */
|
|
+ SrcItem *pTabItem /* The FROM clause entry for the table */
|
|
+){
|
|
+ int i;
|
|
+ IndexedExpr *p;
|
|
+ Table *pTab;
|
|
+ assert( pIdx->bHasExpr );
|
|
+ pTab = pIdx->pTable;
|
|
+ for(i=0; i<pIdx->nColumn; i++){
|
|
+ Expr *pExpr;
|
|
+ int j = pIdx->aiColumn[i];
|
|
+ int bMaybeNullRow;
|
|
+ if( j==XN_EXPR ){
|
|
+ pExpr = pIdx->aColExpr->a[i].pExpr;
|
|
+ testcase( pTabItem->fg.jointype & JT_LEFT );
|
|
+ testcase( pTabItem->fg.jointype & JT_RIGHT );
|
|
+ testcase( pTabItem->fg.jointype & JT_LTORJ );
|
|
+ bMaybeNullRow = (pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))!=0;
|
|
+ }else if( j>=0 && (pTab->aCol[j].colFlags & COLFLAG_VIRTUAL)!=0 ){
|
|
+ pExpr = sqlite3ColumnExpr(pTab, &pTab->aCol[j]);
|
|
+ bMaybeNullRow = 0;
|
|
+ }else{
|
|
+ continue;
|
|
+ }
|
|
+ if( sqlite3ExprIsConstant(pExpr) ) continue;
|
|
+ p = sqlite3DbMallocRaw(pParse->db, sizeof(IndexedExpr));
|
|
+ if( p==0 ) break;
|
|
+ p->pIENext = pParse->pIdxEpr;
|
|
+#ifdef WHERETRACE_ENABLED
|
|
+ if( sqlite3WhereTrace & 0x200 ){
|
|
+ sqlite3DebugPrintf("New pParse->pIdxEpr term {%d,%d}\n", iIdxCur, i);
|
|
+ if( sqlite3WhereTrace & 0x5000 ) sqlite3ShowExpr(pExpr);
|
|
+ }
|
|
+#endif
|
|
+ p->pExpr = sqlite3ExprDup(pParse->db, pExpr, 0);
|
|
+ p->iDataCur = pTabItem->iCursor;
|
|
+ p->iIdxCur = iIdxCur;
|
|
+ p->iIdxCol = i;
|
|
+ p->bMaybeNullRow = bMaybeNullRow;
|
|
+ if( sqlite3IndexAffinityStr(pParse->db, pIdx) ){
|
|
+ p->aff = pIdx->zColAff[i];
|
|
+ }
|
|
+#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
|
|
+ p->zIdxName = pIdx->zName;
|
|
+#endif
|
|
+ pParse->pIdxEpr = p;
|
|
+ if( p->pIENext==0 ){
|
|
+ sqlite3ParserAddCleanup(pParse, whereIndexedExprCleanup, pParse);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
/*
|
|
** Generate the beginning of the loop used for WHERE clause processing.
|
|
** The return value is a pointer to an opaque structure that contains
|
|
@@ -148440,7 +162735,7 @@ static int exprIsDeterministic(Expr *p){
|
|
** if there is one. If there is no ORDER BY clause or if this routine
|
|
** is called from an UPDATE or DELETE statement, then pOrderBy is NULL.
|
|
**
|
|
-** The iIdxCur parameter is the cursor number of an index. If
|
|
+** The iIdxCur parameter is the cursor number of an index. If
|
|
** WHERE_OR_SUBCLAUSE is set, iIdxCur is the cursor number of an index
|
|
** to use for OR clause processing. The WHERE clause should use this
|
|
** specific cursor. If WHERE_ONEPASS_DESIRED is set, then iIdxCur is
|
|
@@ -148454,6 +162749,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
|
|
Expr *pWhere, /* The WHERE clause */
|
|
ExprList *pOrderBy, /* An ORDER BY (or GROUP BY) clause, or NULL */
|
|
ExprList *pResultSet, /* Query result set. Req'd for DISTINCT */
|
|
+ Select *pSelect, /* The entire SELECT statement */
|
|
u16 wctrlFlags, /* The WHERE_* flags defined in sqliteInt.h */
|
|
int iAuxArg /* If WHERE_OR_SUBCLAUSE is set, index cursor number
|
|
** If WHERE_USE_LIMIT, then the limit amount */
|
|
@@ -148473,8 +162769,8 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
|
|
u8 bFordelete = 0; /* OPFLAG_FORDELETE or zero, as appropriate */
|
|
|
|
assert( (wctrlFlags & WHERE_ONEPASS_MULTIROW)==0 || (
|
|
- (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0
|
|
- && (wctrlFlags & WHERE_OR_SUBCLAUSE)==0
|
|
+ (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0
|
|
+ && (wctrlFlags & WHERE_OR_SUBCLAUSE)==0
|
|
));
|
|
|
|
/* Only one of WHERE_OR_SUBCLAUSE or WHERE_USE_LIMIT */
|
|
@@ -148488,16 +162784,9 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
|
|
/* An ORDER/GROUP BY clause of more than 63 terms cannot be optimized */
|
|
testcase( pOrderBy && pOrderBy->nExpr==BMS-1 );
|
|
if( pOrderBy && pOrderBy->nExpr>=BMS ) pOrderBy = 0;
|
|
- sWLB.pOrderBy = pOrderBy;
|
|
-
|
|
- /* Disable the DISTINCT optimization if SQLITE_DistinctOpt is set via
|
|
- ** sqlite3_test_ctrl(SQLITE_TESTCTRL_OPTIMIZATIONS,...) */
|
|
- if( OptimizationDisabled(db, SQLITE_DistinctOpt) ){
|
|
- wctrlFlags &= ~WHERE_WANT_DISTINCT;
|
|
- }
|
|
|
|
/* The number of tables in the FROM clause is limited by the number of
|
|
- ** bits in a Bitmask
|
|
+ ** bits in a Bitmask
|
|
*/
|
|
testcase( pTabList->nSrc==BMS );
|
|
if( pTabList->nSrc>BMS ){
|
|
@@ -148505,7 +162794,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
|
|
return 0;
|
|
}
|
|
|
|
- /* This function normally generates a nested loop for all tables in
|
|
+ /* This function normally generates a nested loop for all tables in
|
|
** pTabList. But if the WHERE_OR_SUBCLAUSE flag is set, then we should
|
|
** only generate code for the first table in pTabList and assume that
|
|
** any cursors associated with subsequent tables are uninitialized.
|
|
@@ -148519,7 +162808,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
|
|
** field (type Bitmask) it must be aligned on an 8-byte boundary on
|
|
** some architectures. Hence the ROUND8() below.
|
|
*/
|
|
- nByteWInfo = ROUND8(sizeof(WhereInfo)+(nTabList-1)*sizeof(WhereLevel));
|
|
+ nByteWInfo = ROUND8P(sizeof(WhereInfo)+(nTabList-1)*sizeof(WhereLevel));
|
|
pWInfo = sqlite3DbMallocRawNN(db, nByteWInfo + sizeof(WhereLoop));
|
|
if( db->mallocFailed ){
|
|
sqlite3DbFree(db, pWInfo);
|
|
@@ -148529,7 +162818,9 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
|
|
pWInfo->pParse = pParse;
|
|
pWInfo->pTabList = pTabList;
|
|
pWInfo->pOrderBy = pOrderBy;
|
|
+#if WHERETRACE_ENABLED
|
|
pWInfo->pWhere = pWhere;
|
|
+#endif
|
|
pWInfo->pResultSet = pResultSet;
|
|
pWInfo->aiCurOnePass[0] = pWInfo->aiCurOnePass[1] = -1;
|
|
pWInfo->nLevel = nTabList;
|
|
@@ -148537,11 +162828,16 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
|
|
pWInfo->wctrlFlags = wctrlFlags;
|
|
pWInfo->iLimit = iAuxArg;
|
|
pWInfo->savedNQueryLoop = pParse->nQueryLoop;
|
|
- memset(&pWInfo->nOBSat, 0,
|
|
+ pWInfo->pSelect = pSelect;
|
|
+ memset(&pWInfo->nOBSat, 0,
|
|
offsetof(WhereInfo,sWC) - offsetof(WhereInfo,nOBSat));
|
|
memset(&pWInfo->a[0], 0, sizeof(WhereLoop)+nTabList*sizeof(WhereLevel));
|
|
assert( pWInfo->eOnePass==ONEPASS_OFF ); /* ONEPASS defaults to OFF */
|
|
pMaskSet = &pWInfo->sMaskSet;
|
|
+ pMaskSet->n = 0;
|
|
+ pMaskSet->ix[0] = -99; /* Initialize ix[0] to a value that can never be
|
|
+ ** a valid cursor number, to avoid an initial
|
|
+ ** test for pMaskSet->n==0 in sqlite3WhereGetMask() */
|
|
sWLB.pWInfo = pWInfo;
|
|
sWLB.pWC = &pWInfo->sWC;
|
|
sWLB.pNew = (WhereLoop*)(((char*)pWInfo)+nByteWInfo);
|
|
@@ -148554,15 +162850,16 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
|
|
/* Split the WHERE clause into separate subexpressions where each
|
|
** subexpression is separated by an AND operator.
|
|
*/
|
|
- initMaskSet(pMaskSet);
|
|
sqlite3WhereClauseInit(&pWInfo->sWC, pWInfo);
|
|
sqlite3WhereSplit(&pWInfo->sWC, pWhere, TK_AND);
|
|
-
|
|
+
|
|
/* Special case: No FROM clause
|
|
*/
|
|
if( nTabList==0 ){
|
|
if( pOrderBy ) pWInfo->nOBSat = pOrderBy->nExpr;
|
|
- if( wctrlFlags & WHERE_WANT_DISTINCT ){
|
|
+ if( (wctrlFlags & WHERE_WANT_DISTINCT)!=0
|
|
+ && OptimizationEnabled(db, SQLITE_DistinctOpt)
|
|
+ ){
|
|
pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE;
|
|
}
|
|
ExplainQueryPlan((pParse, 0, "SCAN CONSTANT ROW"));
|
|
@@ -148597,14 +162894,17 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
|
|
}
|
|
#endif
|
|
}
|
|
-
|
|
+
|
|
/* Analyze all of the subexpressions. */
|
|
sqlite3WhereExprAnalyze(pTabList, &pWInfo->sWC);
|
|
- if( db->mallocFailed ) goto whereBeginError;
|
|
+ if( pSelect && pSelect->pLimit ){
|
|
+ sqlite3WhereAddLimit(&pWInfo->sWC, pSelect);
|
|
+ }
|
|
+ if( pParse->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.
|
|
+ ** generated code if the result is not true.
|
|
**
|
|
** Do not do this if the expression contains non-deterministic functions
|
|
** that are not within a sub-select. This is not strictly required, but
|
|
@@ -148613,7 +162913,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
|
|
** FROM ... WHERE random()>0; -- eval random() once per row
|
|
** FROM ... WHERE (SELECT random())>0; -- eval random() once overall
|
|
*/
|
|
- for(ii=0; ii<sWLB.pWC->nTerm; ii++){
|
|
+ for(ii=0; ii<sWLB.pWC->nBase; ii++){
|
|
WhereTerm *pT = &sWLB.pWC->a[ii];
|
|
if( pT->wtFlags & TERM_VIRTUAL ) continue;
|
|
if( pT->prereqAll==0 && (nTabList==0 || exprIsDeterministic(pT->pExpr)) ){
|
|
@@ -148623,7 +162923,12 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
|
|
}
|
|
|
|
if( wctrlFlags & WHERE_WANT_DISTINCT ){
|
|
- if( isDistinctRedundant(pParse, pTabList, &pWInfo->sWC, pResultSet) ){
|
|
+ if( OptimizationDisabled(db, SQLITE_DistinctOpt) ){
|
|
+ /* Disable the DISTINCT optimization if SQLITE_DistinctOpt is set via
|
|
+ ** sqlite3_test_ctrl(SQLITE_TESTCTRL_OPTIMIZATIONS,...) */
|
|
+ wctrlFlags &= ~WHERE_WANT_DISTINCT;
|
|
+ pWInfo->wctrlFlags &= ~WHERE_WANT_DISTINCT;
|
|
+ }else if( isDistinctRedundant(pParse, pTabList, &pWInfo->sWC, pResultSet) ){
|
|
/* The DISTINCT marking is pointless. Ignore it. */
|
|
pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE;
|
|
}else if( pOrderBy==0 ){
|
|
@@ -148635,13 +162940,13 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
|
|
|
|
/* Construct the WhereLoop objects */
|
|
#if defined(WHERETRACE_ENABLED)
|
|
- if( sqlite3WhereTrace & 0xffff ){
|
|
+ if( sqlite3WhereTrace & 0xffffffff ){
|
|
sqlite3DebugPrintf("*** Optimizer Start *** (wctrlFlags: 0x%x",wctrlFlags);
|
|
if( wctrlFlags & WHERE_USE_LIMIT ){
|
|
sqlite3DebugPrintf(", limit: %d", iAuxArg);
|
|
}
|
|
sqlite3DebugPrintf(")\n");
|
|
- if( sqlite3WhereTrace & 0x100 ){
|
|
+ if( sqlite3WhereTrace & 0x8000 ){
|
|
Select sSelect;
|
|
memset(&sSelect, 0, sizeof(sSelect));
|
|
sSelect.selFlags = SF_WhereBegin;
|
|
@@ -148651,30 +162956,39 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
|
|
sSelect.pEList = pResultSet;
|
|
sqlite3TreeViewSelect(0, &sSelect, 0);
|
|
}
|
|
- }
|
|
- if( sqlite3WhereTrace & 0x100 ){ /* Display all terms of the WHERE clause */
|
|
- sqlite3DebugPrintf("---- WHERE clause at start of analysis:\n");
|
|
- sqlite3WhereClausePrint(sWLB.pWC);
|
|
+ if( sqlite3WhereTrace & 0x4000 ){ /* Display all WHERE clause terms */
|
|
+ sqlite3DebugPrintf("---- WHERE clause at start of analysis:\n");
|
|
+ sqlite3WhereClausePrint(sWLB.pWC);
|
|
+ }
|
|
}
|
|
#endif
|
|
|
|
if( nTabList!=1 || whereShortCut(&sWLB)==0 ){
|
|
rc = whereLoopAddAll(&sWLB);
|
|
if( rc ) goto whereBeginError;
|
|
-
|
|
-#ifdef WHERETRACE_ENABLED
|
|
- if( sqlite3WhereTrace ){ /* Display all of the WhereLoop objects */
|
|
- WhereLoop *p;
|
|
- int i;
|
|
- static const char zLabel[] = "0123456789abcdefghijklmnopqrstuvwyxz"
|
|
- "ABCDEFGHIJKLMNOPQRSTUVWYXZ";
|
|
- for(p=pWInfo->pLoops, i=0; p; p=p->pNextLoop, i++){
|
|
- p->cId = zLabel[i%(sizeof(zLabel)-1)];
|
|
- sqlite3WhereLoopPrint(p, sWLB.pWC);
|
|
- }
|
|
- }
|
|
-#endif
|
|
-
|
|
+
|
|
+#ifdef SQLITE_ENABLE_STAT4
|
|
+ /* If one or more WhereTerm.truthProb values were used in estimating
|
|
+ ** loop parameters, but then those truthProb values were subsequently
|
|
+ ** changed based on STAT4 information while computing subsequent loops,
|
|
+ ** then we need to rerun the whole loop building process so that all
|
|
+ ** loops will be built using the revised truthProb values. */
|
|
+ if( sWLB.bldFlags2 & SQLITE_BLDF2_2NDPASS ){
|
|
+ WHERETRACE_ALL_LOOPS(pWInfo, sWLB.pWC);
|
|
+ WHERETRACE(0xffffffff,
|
|
+ ("**** Redo all loop computations due to"
|
|
+ " TERM_HIGHTRUTH changes ****\n"));
|
|
+ while( pWInfo->pLoops ){
|
|
+ WhereLoop *p = pWInfo->pLoops;
|
|
+ pWInfo->pLoops = p->pNextLoop;
|
|
+ whereLoopDelete(db, p);
|
|
+ }
|
|
+ rc = whereLoopAddAll(&sWLB);
|
|
+ if( rc ) goto whereBeginError;
|
|
+ }
|
|
+#endif
|
|
+ WHERETRACE_ALL_LOOPS(pWInfo, sWLB.pWC);
|
|
+
|
|
wherePathSolver(pWInfo, 0);
|
|
if( db->mallocFailed ) goto whereBeginError;
|
|
if( pWInfo->pOrderBy ){
|
|
@@ -148685,9 +162999,10 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
|
|
if( pWInfo->pOrderBy==0 && (db->flags & SQLITE_ReverseOrder)!=0 ){
|
|
pWInfo->revMask = ALLBITS;
|
|
}
|
|
- if( pParse->nErr || NEVER(db->mallocFailed) ){
|
|
+ if( pParse->nErr ){
|
|
goto whereBeginError;
|
|
}
|
|
+ assert( db->mallocFailed==0 );
|
|
#ifdef WHERETRACE_ENABLED
|
|
if( sqlite3WhereTrace ){
|
|
sqlite3DebugPrintf("---- Solution nRow=%d", pWInfo->nRowOut);
|
|
@@ -148715,89 +163030,42 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
|
|
}
|
|
#endif
|
|
|
|
- /* Attempt to omit tables from the join that do not affect the result.
|
|
- ** For a table to not affect the result, the following must be true:
|
|
- **
|
|
- ** 1) The query must not be an aggregate.
|
|
- ** 2) The table must be the RHS of a LEFT JOIN.
|
|
- ** 3) Either the query must be DISTINCT, or else the ON or USING clause
|
|
- ** must contain a constraint that limits the scan of the table to
|
|
- ** 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.
|
|
- **
|
|
- ** For example, given:
|
|
- **
|
|
- ** CREATE TABLE t1(ipk INTEGER PRIMARY KEY, v1);
|
|
- ** CREATE TABLE t2(ipk INTEGER PRIMARY KEY, v2);
|
|
- ** CREATE TABLE t3(ipk INTEGER PRIMARY KEY, v3);
|
|
+ /* Attempt to omit tables from a join that do not affect the result.
|
|
+ ** See the comment on whereOmitNoopJoin() for further information.
|
|
**
|
|
- ** then table t2 can be omitted from the following:
|
|
- **
|
|
- ** SELECT v1, v3 FROM t1
|
|
- ** LEFT JOIN t2 ON (t1.ipk=t2.ipk)
|
|
- ** LEFT JOIN t3 ON (t1.ipk=t3.ipk)
|
|
- **
|
|
- ** or from:
|
|
- **
|
|
- ** SELECT DISTINCT v1, v3 FROM t1
|
|
- ** LEFT JOIN t2
|
|
- ** LEFT JOIN t3 ON (t1.ipk=t3.ipk)
|
|
+ ** This query optimization is factored out into a separate "no-inline"
|
|
+ ** procedure to keep the sqlite3WhereBegin() procedure from becoming
|
|
+ ** too large. If sqlite3WhereBegin() becomes too large, that prevents
|
|
+ ** some C-compiler optimizers from in-lining the
|
|
+ ** sqlite3WhereCodeOneLoopStart() procedure, and it is important to
|
|
+ ** in-line sqlite3WhereCodeOneLoopStart() for performance reasons.
|
|
*/
|
|
notReady = ~(Bitmask)0;
|
|
if( pWInfo->nLevel>=2
|
|
- && pResultSet!=0 /* guarantees condition (1) above */
|
|
+ && pResultSet!=0 /* these two combine to guarantee */
|
|
+ && 0==(wctrlFlags & WHERE_AGG_DISTINCT) /* condition (1) above */
|
|
&& OptimizationEnabled(db, SQLITE_OmitNoopJoin)
|
|
){
|
|
- int i;
|
|
- Bitmask tabUsed = sqlite3WhereExprListUsage(pMaskSet, pResultSet);
|
|
- if( sWLB.pOrderBy ){
|
|
- tabUsed |= sqlite3WhereExprListUsage(pMaskSet, sWLB.pOrderBy);
|
|
- }
|
|
- for(i=pWInfo->nLevel-1; i>=1; i--){
|
|
- WhereTerm *pTerm, *pEnd;
|
|
- struct SrcList_item *pItem;
|
|
- pLoop = pWInfo->a[i].pWLoop;
|
|
- pItem = &pWInfo->pTabList->a[pLoop->iTab];
|
|
- if( (pItem->fg.jointype & JT_LEFT)==0 ) continue;
|
|
- if( (wctrlFlags & WHERE_WANT_DISTINCT)==0
|
|
- && (pLoop->wsFlags & WHERE_ONEROW)==0
|
|
- ){
|
|
- continue;
|
|
- }
|
|
- if( (tabUsed & pLoop->maskSelf)!=0 ) continue;
|
|
- pEnd = sWLB.pWC->a + sWLB.pWC->nTerm;
|
|
- for(pTerm=sWLB.pWC->a; pTerm<pEnd; pTerm++){
|
|
- if( (pTerm->prereqAll & pLoop->maskSelf)!=0 ){
|
|
- if( !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
|
|
- || pTerm->pExpr->iRightJoinTable!=pItem->iCursor
|
|
- ){
|
|
- break;
|
|
- }
|
|
- }
|
|
- }
|
|
- if( pTerm<pEnd ) continue;
|
|
- WHERETRACE(0xffff, ("-> drop loop %c not used\n", pLoop->cId));
|
|
- notReady &= ~pLoop->maskSelf;
|
|
- for(pTerm=sWLB.pWC->a; pTerm<pEnd; pTerm++){
|
|
- if( (pTerm->prereqAll & pLoop->maskSelf)!=0 ){
|
|
- pTerm->wtFlags |= TERM_CODED;
|
|
- }
|
|
- }
|
|
- if( i!=pWInfo->nLevel-1 ){
|
|
- int nByte = (pWInfo->nLevel-1-i) * sizeof(WhereLevel);
|
|
- memmove(&pWInfo->a[i], &pWInfo->a[i+1], nByte);
|
|
- }
|
|
- pWInfo->nLevel--;
|
|
- nTabList--;
|
|
- }
|
|
+ notReady = whereOmitNoopJoin(pWInfo, notReady);
|
|
+ nTabList = pWInfo->nLevel;
|
|
+ assert( nTabList>0 );
|
|
}
|
|
+
|
|
+ /* Check to see if there are any SEARCH loops that might benefit from
|
|
+ ** using a Bloom filter.
|
|
+ */
|
|
+ if( pWInfo->nLevel>=2
|
|
+ && OptimizationEnabled(db, SQLITE_BloomFilter)
|
|
+ ){
|
|
+ whereCheckIfBloomFilterIsUseful(pWInfo);
|
|
+ }
|
|
+
|
|
#if defined(WHERETRACE_ENABLED)
|
|
- if( sqlite3WhereTrace & 0x100 ){ /* Display all terms of the WHERE clause */
|
|
+ if( sqlite3WhereTrace & 0x4000 ){ /* Display all terms of the WHERE clause */
|
|
sqlite3DebugPrintf("---- WHERE clause at end of analysis:\n");
|
|
sqlite3WhereClausePrint(sWLB.pWC);
|
|
}
|
|
- WHERETRACE(0xffff,("*** Optimizer Finished ***\n"));
|
|
+ WHERETRACE(0xffffffff,("*** Optimizer Finished ***\n"));
|
|
#endif
|
|
pWInfo->pParse->nQueryLoop += pWInfo->nRowOut;
|
|
|
|
@@ -148846,13 +163114,13 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
|
|
for(ii=0, pLevel=pWInfo->a; ii<nTabList; ii++, pLevel++){
|
|
Table *pTab; /* Table to open */
|
|
int iDb; /* Index of database containing table/index */
|
|
- struct SrcList_item *pTabItem;
|
|
+ SrcItem *pTabItem;
|
|
|
|
pTabItem = &pTabList->a[pLevel->iFrom];
|
|
pTab = pTabItem->pTab;
|
|
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
|
pLoop = pLevel->pWLoop;
|
|
- if( (pTab->tabFlags & TF_Ephemeral)!=0 || pTab->pSelect ){
|
|
+ if( (pTab->tabFlags & TF_Ephemeral)!=0 || IsView(pTab) ){
|
|
/* Do nothing */
|
|
}else
|
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
|
@@ -148864,8 +163132,10 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
|
|
/* noop */
|
|
}else
|
|
#endif
|
|
- if( (pLoop->wsFlags & WHERE_IDX_ONLY)==0
|
|
- && (wctrlFlags & WHERE_OR_SUBCLAUSE)==0 ){
|
|
+ if( ((pLoop->wsFlags & WHERE_IDX_ONLY)==0
|
|
+ && (wctrlFlags & WHERE_OR_SUBCLAUSE)==0)
|
|
+ || (pTabItem->fg.jointype & (JT_LTORJ|JT_RIGHT))!=0
|
|
+ ){
|
|
int op = OP_OpenRead;
|
|
if( pWInfo->eOnePass!=ONEPASS_OFF ){
|
|
op = OP_OpenWrite;
|
|
@@ -148875,9 +163145,10 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
|
|
assert( pTabItem->iCursor==pLevel->iTabCur );
|
|
testcase( pWInfo->eOnePass==ONEPASS_OFF && pTab->nCol==BMS-1 );
|
|
testcase( pWInfo->eOnePass==ONEPASS_OFF && pTab->nCol==BMS );
|
|
- if( pWInfo->eOnePass==ONEPASS_OFF
|
|
+ if( pWInfo->eOnePass==ONEPASS_OFF
|
|
&& pTab->nCol<BMS
|
|
&& (pTab->tabFlags & (TF_HasGenerated|TF_WithoutRowid))==0
|
|
+ && (pLoop->wsFlags & (WHERE_AUTO_INDEX|WHERE_BLOOMFILTER))==0
|
|
){
|
|
/* If we know that only a prefix of the record will be used,
|
|
** it is advantageous to reduce the "column count" field in
|
|
@@ -148931,8 +163202,12 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
|
|
op = OP_ReopenIdx;
|
|
}else{
|
|
iIndexCur = pParse->nTab++;
|
|
+ if( pIx->bHasExpr && OptimizationEnabled(db, SQLITE_IndexedExpr) ){
|
|
+ whereAddIndexedExpr(pParse, pIx, iIndexCur, pTabItem);
|
|
+ }
|
|
}
|
|
pLevel->iIdxCur = iIndexCur;
|
|
+ assert( pIx!=0 );
|
|
assert( pIx->pSchema==pTab->pSchema );
|
|
assert( iIndexCur>=0 );
|
|
if( op ){
|
|
@@ -148941,10 +163216,11 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
|
|
if( (pLoop->wsFlags & WHERE_CONSTRAINT)!=0
|
|
&& (pLoop->wsFlags & (WHERE_COLUMN_RANGE|WHERE_SKIPSCAN))==0
|
|
&& (pLoop->wsFlags & WHERE_BIGNULL_SORT)==0
|
|
+ && (pLoop->wsFlags & WHERE_IN_SEEKSCAN)==0
|
|
&& (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)==0
|
|
&& pWInfo->eDistinct!=WHERE_DISTINCT_ORDERED
|
|
){
|
|
- sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ); /* Hint to COMDB2 */
|
|
+ sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ);
|
|
}
|
|
VdbeComment((v, "%s", pIx->zName));
|
|
#ifdef SQLITE_ENABLE_COLUMN_USED_MASK
|
|
@@ -148965,6 +163241,37 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
|
|
}
|
|
}
|
|
if( iDb>=0 ) sqlite3CodeVerifySchema(pParse, iDb);
|
|
+ if( (pTabItem->fg.jointype & JT_RIGHT)!=0
|
|
+ && (pLevel->pRJ = sqlite3WhereMalloc(pWInfo, sizeof(WhereRightJoin)))!=0
|
|
+ ){
|
|
+ WhereRightJoin *pRJ = pLevel->pRJ;
|
|
+ pRJ->iMatch = pParse->nTab++;
|
|
+ pRJ->regBloom = ++pParse->nMem;
|
|
+ sqlite3VdbeAddOp2(v, OP_Blob, 65536, pRJ->regBloom);
|
|
+ pRJ->regReturn = ++pParse->nMem;
|
|
+ sqlite3VdbeAddOp2(v, OP_Null, 0, pRJ->regReturn);
|
|
+ assert( pTab==pTabItem->pTab );
|
|
+ if( HasRowid(pTab) ){
|
|
+ KeyInfo *pInfo;
|
|
+ sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRJ->iMatch, 1);
|
|
+ pInfo = sqlite3KeyInfoAlloc(pParse->db, 1, 0);
|
|
+ if( pInfo ){
|
|
+ pInfo->aColl[0] = 0;
|
|
+ pInfo->aSortFlags[0] = 0;
|
|
+ sqlite3VdbeAppendP4(v, pInfo, P4_KEYINFO);
|
|
+ }
|
|
+ }else{
|
|
+ Index *pPk = sqlite3PrimaryKeyIndex(pTab);
|
|
+ sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRJ->iMatch, pPk->nKeyCol);
|
|
+ sqlite3VdbeSetP4KeyInfo(pParse, pPk);
|
|
+ }
|
|
+ pLoop->wsFlags &= ~WHERE_IDX_ONLY;
|
|
+ /* The nature of RIGHT JOIN processing is such that it messes up
|
|
+ ** the output order. So omit any ORDER BY/GROUP BY elimination
|
|
+ ** optimizations. We need to do an actual sort for RIGHT JOIN. */
|
|
+ pWInfo->nOBSat = 0;
|
|
+ pWInfo->eDistinct = WHERE_DISTINCT_UNORDERED;
|
|
+ }
|
|
}
|
|
pWInfo->iTop = sqlite3VdbeCurrentAddr(v);
|
|
if( db->mallocFailed ) goto whereBeginError;
|
|
@@ -148976,15 +163283,31 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
|
|
for(ii=0; ii<nTabList; ii++){
|
|
int addrExplain;
|
|
int wsFlags;
|
|
+ SrcItem *pSrc;
|
|
+ if( pParse->nErr ) goto whereBeginError;
|
|
pLevel = &pWInfo->a[ii];
|
|
wsFlags = pLevel->pWLoop->wsFlags;
|
|
+ pSrc = &pTabList->a[pLevel->iFrom];
|
|
+ if( pSrc->fg.isMaterialized ){
|
|
+ if( pSrc->fg.isCorrelated ){
|
|
+ sqlite3VdbeAddOp2(v, OP_Gosub, pSrc->regReturn, pSrc->addrFillSub);
|
|
+ }else{
|
|
+ int iOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
|
|
+ sqlite3VdbeAddOp2(v, OP_Gosub, pSrc->regReturn, pSrc->addrFillSub);
|
|
+ sqlite3VdbeJumpHere(v, iOnce);
|
|
+ }
|
|
+ }
|
|
+ if( (wsFlags & (WHERE_AUTO_INDEX|WHERE_BLOOMFILTER))!=0 ){
|
|
+ if( (wsFlags & WHERE_AUTO_INDEX)!=0 ){
|
|
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
|
|
- if( (pLevel->pWLoop->wsFlags & WHERE_AUTO_INDEX)!=0 ){
|
|
- constructAutomaticIndex(pParse, &pWInfo->sWC,
|
|
- &pTabList->a[pLevel->iFrom], notReady, pLevel);
|
|
+ constructAutomaticIndex(pParse, &pWInfo->sWC,
|
|
+ &pTabList->a[pLevel->iFrom], notReady, pLevel);
|
|
+#endif
|
|
+ }else{
|
|
+ sqlite3ConstructBloomFilter(pWInfo, ii, pLevel, notReady);
|
|
+ }
|
|
if( db->mallocFailed ) goto whereBeginError;
|
|
}
|
|
-#endif
|
|
addrExplain = sqlite3WhereExplainOneScan(
|
|
pParse, pTabList, pLevel, wctrlFlags
|
|
);
|
|
@@ -148998,6 +163321,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
|
|
|
|
/* Done. */
|
|
VdbeModuleComment((v, "Begin WHERE-core"));
|
|
+ pWInfo->iEndWhere = sqlite3VdbeCurrentAddr(v);
|
|
return pWInfo;
|
|
|
|
/* Jump here if malloc fails */
|
|
@@ -149029,8 +163353,28 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
|
|
}
|
|
#endif
|
|
|
|
+#ifdef SQLITE_DEBUG
|
|
/*
|
|
-** Generate the end of the WHERE loop. See comments on
|
|
+** Return true if cursor iCur is opened by instruction k of the
|
|
+** bytecode. Used inside of assert() only.
|
|
+*/
|
|
+static int cursorIsOpen(Vdbe *v, int iCur, int k){
|
|
+ while( k>=0 ){
|
|
+ VdbeOp *pOp = sqlite3VdbeGetOp(v,k--);
|
|
+ if( pOp->p1!=iCur ) continue;
|
|
+ if( pOp->opcode==OP_Close ) return 0;
|
|
+ if( pOp->opcode==OP_OpenRead ) return 1;
|
|
+ if( pOp->opcode==OP_OpenWrite ) return 1;
|
|
+ if( pOp->opcode==OP_OpenDup ) return 1;
|
|
+ if( pOp->opcode==OP_OpenAutoindex ) return 1;
|
|
+ if( pOp->opcode==OP_OpenEphemeral ) return 1;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+#endif /* SQLITE_DEBUG */
|
|
+
|
|
+/*
|
|
+** Generate the end of the WHERE loop. See comments on
|
|
** sqlite3WhereBegin() for additional information.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
|
|
@@ -149041,6 +163385,8 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
|
|
WhereLoop *pLoop;
|
|
SrcList *pTabList = pWInfo->pTabList;
|
|
sqlite3 *db = pParse->db;
|
|
+ int iEnd = sqlite3VdbeCurrentAddr(v);
|
|
+ int nRJ = 0;
|
|
|
|
/* Generate loop termination code.
|
|
*/
|
|
@@ -149048,6 +163394,17 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
|
|
for(i=pWInfo->nLevel-1; i>=0; i--){
|
|
int addr;
|
|
pLevel = &pWInfo->a[i];
|
|
+ if( pLevel->pRJ ){
|
|
+ /* Terminate the subroutine that forms the interior of the loop of
|
|
+ ** the RIGHT JOIN table */
|
|
+ WhereRightJoin *pRJ = pLevel->pRJ;
|
|
+ sqlite3VdbeResolveLabel(v, pLevel->addrCont);
|
|
+ pLevel->addrCont = 0;
|
|
+ pRJ->endSubrtn = sqlite3VdbeCurrentAddr(v);
|
|
+ sqlite3VdbeAddOp3(v, OP_Return, pRJ->regReturn, pRJ->addrSubrtn, 1);
|
|
+ VdbeCoverage(v);
|
|
+ nRJ++;
|
|
+ }
|
|
pLoop = pLevel->pWLoop;
|
|
if( pLevel->op!=OP_Noop ){
|
|
#ifndef SQLITE_DISABLE_SKIPAHEAD_DISTINCT
|
|
@@ -149075,7 +163432,7 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
|
|
}
|
|
#endif /* SQLITE_DISABLE_SKIPAHEAD_DISTINCT */
|
|
/* The common case: Advance to the next row */
|
|
- sqlite3VdbeResolveLabel(v, pLevel->addrCont);
|
|
+ if( pLevel->addrCont ) sqlite3VdbeResolveLabel(v, pLevel->addrCont);
|
|
sqlite3VdbeAddOp3(v, pLevel->op, pLevel->p1, pLevel->p2, pLevel->p3);
|
|
sqlite3VdbeChangeP5(v, pLevel->p5);
|
|
VdbeCoverage(v);
|
|
@@ -149090,24 +163447,22 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
|
|
#ifndef SQLITE_DISABLE_SKIPAHEAD_DISTINCT
|
|
if( addrSeek ) sqlite3VdbeJumpHere(v, addrSeek);
|
|
#endif
|
|
- }else{
|
|
+ }else if( pLevel->addrCont ){
|
|
sqlite3VdbeResolveLabel(v, pLevel->addrCont);
|
|
}
|
|
- if( pLoop->wsFlags & WHERE_IN_ABLE && pLevel->u.in.nIn>0 ){
|
|
+ if( (pLoop->wsFlags & WHERE_IN_ABLE)!=0 && pLevel->u.in.nIn>0 ){
|
|
struct InLoop *pIn;
|
|
int j;
|
|
sqlite3VdbeResolveLabel(v, pLevel->addrNxt);
|
|
for(j=pLevel->u.in.nIn, pIn=&pLevel->u.in.aInLoop[j-1]; j>0; j--, pIn--){
|
|
+ assert( sqlite3VdbeGetOp(v, pIn->addrInTop+1)->opcode==OP_IsNull
|
|
+ || pParse->db->mallocFailed );
|
|
sqlite3VdbeJumpHere(v, pIn->addrInTop+1);
|
|
if( pIn->eEndLoopOp!=OP_Noop ){
|
|
if( pIn->nPrefix ){
|
|
- assert( pLoop->wsFlags & WHERE_IN_EARLYOUT );
|
|
- if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 ){
|
|
- sqlite3VdbeAddOp4Int(v, OP_IfNoHope, pLevel->iIdxCur,
|
|
- sqlite3VdbeCurrentAddr(v)+2+(pLevel->iLeftJoin!=0),
|
|
- pIn->iBase, pIn->nPrefix);
|
|
- VdbeCoverage(v);
|
|
- }
|
|
+ int bEarlyOut =
|
|
+ (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0
|
|
+ && (pLoop->wsFlags & WHERE_IN_EARLYOUT)!=0;
|
|
if( pLevel->iLeftJoin ){
|
|
/* For LEFT JOIN queries, cursor pIn->iCur may not have been
|
|
** opened yet. This occurs for WHERE clauses such as
|
|
@@ -149117,10 +163472,20 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
|
|
** return the null-row. So, if the cursor is not open yet,
|
|
** jump over the OP_Next or OP_Prev instruction about to
|
|
** be coded. */
|
|
- sqlite3VdbeAddOp2(v, OP_IfNotOpen, pIn->iCur,
|
|
- sqlite3VdbeCurrentAddr(v) + 2
|
|
- );
|
|
+ sqlite3VdbeAddOp2(v, OP_IfNotOpen, pIn->iCur,
|
|
+ sqlite3VdbeCurrentAddr(v) + 2 + bEarlyOut);
|
|
+ VdbeCoverage(v);
|
|
+ }
|
|
+ if( bEarlyOut ){
|
|
+ sqlite3VdbeAddOp4Int(v, OP_IfNoHope, pLevel->iIdxCur,
|
|
+ sqlite3VdbeCurrentAddr(v)+2,
|
|
+ pIn->iBase, pIn->nPrefix);
|
|
VdbeCoverage(v);
|
|
+ /* Retarget the OP_IsNull against the left operand of IN so
|
|
+ ** it jumps past the OP_IfNoHope. This is because the
|
|
+ ** OP_IsNull also bypasses the OP_Affinity opcode that is
|
|
+ ** required by OP_IfNoHope. */
|
|
+ sqlite3VdbeJumpHere(v, pIn->addrInTop+1);
|
|
}
|
|
}
|
|
sqlite3VdbeAddOp2(v, pIn->eEndLoopOp, pIn->iCur, pIn->addrInTop);
|
|
@@ -149132,6 +163497,10 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
|
|
}
|
|
}
|
|
sqlite3VdbeResolveLabel(v, pLevel->addrBrk);
|
|
+ if( pLevel->pRJ ){
|
|
+ sqlite3VdbeAddOp3(v, OP_Return, pLevel->pRJ->regReturn, 0, 1);
|
|
+ VdbeCoverage(v);
|
|
+ }
|
|
if( pLevel->addrSkip ){
|
|
sqlite3VdbeGoto(v, pLevel->addrSkip);
|
|
VdbeComment((v, "next skip-scan on %s", pLoop->u.btree.pIndex->zName));
|
|
@@ -149153,9 +163522,15 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
|
|
assert( pLevel->iTabCur==pTabList->a[pLevel->iFrom].iCursor );
|
|
sqlite3VdbeAddOp1(v, OP_NullRow, pLevel->iTabCur);
|
|
}
|
|
- if( (ws & WHERE_INDEXED)
|
|
- || ((ws & WHERE_MULTI_OR) && pLevel->u.pCovidx)
|
|
+ if( (ws & WHERE_INDEXED)
|
|
+ || ((ws & WHERE_MULTI_OR) && pLevel->u.pCoveringIdx)
|
|
){
|
|
+ if( ws & WHERE_MULTI_OR ){
|
|
+ Index *pIx = pLevel->u.pCoveringIdx;
|
|
+ int iDb = sqlite3SchemaToIndex(db, pIx->pSchema);
|
|
+ sqlite3VdbeAddOp3(v, OP_ReopenIdx, pLevel->iIdxCur, pIx->tnum, iDb);
|
|
+ sqlite3VdbeSetP4KeyInfo(pParse, pIx);
|
|
+ }
|
|
sqlite3VdbeAddOp1(v, OP_NullRow, pLevel->iIdxCur);
|
|
}
|
|
if( pLevel->op==OP_Return ){
|
|
@@ -149169,21 +163544,25 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
|
|
pWInfo->pTabList->a[pLevel->iFrom].pTab->zName));
|
|
}
|
|
|
|
- /* The "break" point is here, just past the end of the outer loop.
|
|
- ** Set it.
|
|
- */
|
|
- sqlite3VdbeResolveLabel(v, pWInfo->iBreak);
|
|
-
|
|
assert( pWInfo->nLevel<=pTabList->nSrc );
|
|
for(i=0, pLevel=pWInfo->a; i<pWInfo->nLevel; i++, pLevel++){
|
|
int k, last;
|
|
- VdbeOp *pOp;
|
|
+ VdbeOp *pOp, *pLastOp;
|
|
Index *pIdx = 0;
|
|
- struct SrcList_item *pTabItem = &pTabList->a[pLevel->iFrom];
|
|
+ SrcItem *pTabItem = &pTabList->a[pLevel->iFrom];
|
|
Table *pTab = pTabItem->pTab;
|
|
assert( pTab!=0 );
|
|
pLoop = pLevel->pWLoop;
|
|
|
|
+ /* Do RIGHT JOIN processing. Generate code that will output the
|
|
+ ** unmatched rows of the right operand of the RIGHT JOIN with
|
|
+ ** all of the columns of the left operand set to NULL.
|
|
+ */
|
|
+ if( pLevel->pRJ ){
|
|
+ sqlite3WhereRightJoinLoop(pWInfo, i, pLevel);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
/* For a co-routine, change all OP_Column references to the table of
|
|
** the co-routine into OP_Copy of result contained in a register.
|
|
** OP_Rowid becomes OP_Null.
|
|
@@ -149195,34 +163574,11 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
|
|
continue;
|
|
}
|
|
|
|
-#ifdef SQLITE_ENABLE_EARLY_CURSOR_CLOSE
|
|
- /* Close all of the cursors that were opened by sqlite3WhereBegin.
|
|
- ** Except, do not close cursors that will be reused by the OR optimization
|
|
- ** (WHERE_OR_SUBCLAUSE). And do not close the OP_OpenWrite cursors
|
|
- ** created for the ONEPASS optimization.
|
|
- */
|
|
- if( (pTab->tabFlags & TF_Ephemeral)==0
|
|
- && pTab->pSelect==0
|
|
- && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE)==0
|
|
- ){
|
|
- int ws = pLoop->wsFlags;
|
|
- if( pWInfo->eOnePass==ONEPASS_OFF && (ws & WHERE_IDX_ONLY)==0 ){
|
|
- sqlite3VdbeAddOp1(v, OP_Close, pTabItem->iCursor);
|
|
- }
|
|
- if( (ws & WHERE_INDEXED)!=0
|
|
- && (ws & (WHERE_IPK|WHERE_AUTO_INDEX))==0
|
|
- && pLevel->iIdxCur!=pWInfo->aiCurOnePass[1]
|
|
- ){
|
|
- sqlite3VdbeAddOp1(v, OP_Close, pLevel->iIdxCur);
|
|
- }
|
|
- }
|
|
-#endif
|
|
-
|
|
/* If this scan uses an index, make VDBE code substitutions to read data
|
|
** from the index instead of from the table where possible. In some cases
|
|
** this optimization prevents the table from ever being read, which can
|
|
** yield a significant performance boost.
|
|
- **
|
|
+ **
|
|
** Calls to the code generator in between sqlite3WhereBegin and
|
|
** sqlite3WhereEnd will have created code that references the table
|
|
** directly. This loop scans all that code looking for opcodes
|
|
@@ -149232,29 +163588,62 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
|
|
if( pLoop->wsFlags & (WHERE_INDEXED|WHERE_IDX_ONLY) ){
|
|
pIdx = pLoop->u.btree.pIndex;
|
|
}else if( pLoop->wsFlags & WHERE_MULTI_OR ){
|
|
- pIdx = pLevel->u.pCovidx;
|
|
+ pIdx = pLevel->u.pCoveringIdx;
|
|
}
|
|
if( pIdx
|
|
- && (pWInfo->eOnePass==ONEPASS_OFF || !HasRowid(pIdx->pTable))
|
|
&& !db->mallocFailed
|
|
){
|
|
- last = sqlite3VdbeCurrentAddr(v);
|
|
- k = pLevel->addrBody;
|
|
+ if( pWInfo->eOnePass==ONEPASS_OFF || !HasRowid(pIdx->pTable) ){
|
|
+ last = iEnd;
|
|
+ }else{
|
|
+ last = pWInfo->iEndWhere;
|
|
+ }
|
|
+ if( pIdx->bHasExpr ){
|
|
+ IndexedExpr *p = pParse->pIdxEpr;
|
|
+ while( p ){
|
|
+ if( p->iIdxCur==pLevel->iIdxCur ){
|
|
+#ifdef WHERETRACE_ENABLED
|
|
+ if( sqlite3WhereTrace & 0x200 ){
|
|
+ sqlite3DebugPrintf("Disable pParse->pIdxEpr term {%d,%d}\n",
|
|
+ p->iIdxCur, p->iIdxCol);
|
|
+ if( sqlite3WhereTrace & 0x5000 ) sqlite3ShowExpr(p->pExpr);
|
|
+ }
|
|
+#endif
|
|
+ p->iDataCur = -1;
|
|
+ p->iIdxCur = -1;
|
|
+ }
|
|
+ p = p->pIENext;
|
|
+ }
|
|
+ }
|
|
+ k = pLevel->addrBody + 1;
|
|
#ifdef SQLITE_DEBUG
|
|
if( db->flags & SQLITE_VdbeAddopTrace ){
|
|
printf("TRANSLATE opcodes in range %d..%d\n", k, last-1);
|
|
}
|
|
+ /* Proof that the "+1" on the k value above is safe */
|
|
+ pOp = sqlite3VdbeGetOp(v, k - 1);
|
|
+ assert( pOp->opcode!=OP_Column || pOp->p1!=pLevel->iTabCur );
|
|
+ assert( pOp->opcode!=OP_Rowid || pOp->p1!=pLevel->iTabCur );
|
|
+ assert( pOp->opcode!=OP_IfNullRow || pOp->p1!=pLevel->iTabCur );
|
|
#endif
|
|
pOp = sqlite3VdbeGetOp(v, k);
|
|
- for(; k<last; k++, pOp++){
|
|
- if( pOp->p1!=pLevel->iTabCur ) continue;
|
|
- if( pOp->opcode==OP_Column
|
|
+ pLastOp = pOp + (last - k);
|
|
+ assert( pOp<=pLastOp );
|
|
+ do{
|
|
+ if( pOp->p1!=pLevel->iTabCur ){
|
|
+ /* no-op */
|
|
+ }else if( pOp->opcode==OP_Column
|
|
#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
|
|
|| pOp->opcode==OP_Offset
|
|
#endif
|
|
){
|
|
int x = pOp->p2;
|
|
assert( pIdx->pTable==pTab );
|
|
+#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
|
|
+ if( pOp->opcode==OP_Offset ){
|
|
+ /* Do not need to translate the column number */
|
|
+ }else
|
|
+#endif
|
|
if( !HasRowid(pTab) ){
|
|
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
|
|
x = pPk->aiColumn[x];
|
|
@@ -149268,9 +163657,22 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
|
|
pOp->p2 = x;
|
|
pOp->p1 = pLevel->iIdxCur;
|
|
OpcodeRewriteTrace(db, k, pOp);
|
|
+ }else{
|
|
+ /* Unable to translate the table reference into an index
|
|
+ ** reference. Verify that this is harmless - that the
|
|
+ ** table being referenced really is open.
|
|
+ */
|
|
+#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
|
|
+ assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0
|
|
+ || cursorIsOpen(v,pOp->p1,k)
|
|
+ || pOp->opcode==OP_Offset
|
|
+ );
|
|
+#else
|
|
+ assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0
|
|
+ || cursorIsOpen(v,pOp->p1,k)
|
|
+ );
|
|
+#endif
|
|
}
|
|
- assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 || x>=0
|
|
- || pWInfo->eOnePass );
|
|
}else if( pOp->opcode==OP_Rowid ){
|
|
pOp->p1 = pLevel->iIdxCur;
|
|
pOp->opcode = OP_IdxRowid;
|
|
@@ -149279,25 +163681,26 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
|
|
pOp->p1 = pLevel->iIdxCur;
|
|
OpcodeRewriteTrace(db, k, pOp);
|
|
}
|
|
- }
|
|
+#ifdef SQLITE_DEBUG
|
|
+ k++;
|
|
+#endif
|
|
+ }while( (++pOp)<pLastOp );
|
|
#ifdef SQLITE_DEBUG
|
|
if( db->flags & SQLITE_VdbeAddopTrace ) printf("TRANSLATE complete\n");
|
|
#endif
|
|
}
|
|
}
|
|
|
|
- /* Undo all Expr node modifications */
|
|
- while( pWInfo->pExprMods ){
|
|
- WhereExprMod *p = pWInfo->pExprMods;
|
|
- pWInfo->pExprMods = p->pNext;
|
|
- memcpy(p->pExpr, &p->orig, sizeof(p->orig));
|
|
- sqlite3DbFree(db, p);
|
|
- }
|
|
+ /* The "break" point is here, just past the end of the outer loop.
|
|
+ ** Set it.
|
|
+ */
|
|
+ sqlite3VdbeResolveLabel(v, pWInfo->iBreak);
|
|
|
|
/* Final cleanup
|
|
*/
|
|
pParse->nQueryLoop = pWInfo->savedNQueryLoop;
|
|
whereInfoFree(db, pWInfo);
|
|
+ pParse->withinRJSubrtn -= nRJ;
|
|
return;
|
|
}
|
|
|
|
@@ -149345,12 +163748,12 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
|
|
** (in this case max()) to process rows sorted in order of (c, d), which
|
|
** makes things easier for obvious reasons. More generally:
|
|
**
|
|
-** * FROM, WHERE, GROUP BY and HAVING clauses are all moved to
|
|
+** * FROM, WHERE, GROUP BY and HAVING clauses are all moved to
|
|
** the sub-query.
|
|
**
|
|
** * ORDER BY, LIMIT and OFFSET remain part of the parent query.
|
|
**
|
|
-** * Terminals from each of the expression trees that make up the
|
|
+** * Terminals from each of the expression trees that make up the
|
|
** select-list and ORDER BY expressions in the parent query are
|
|
** selected by the sub-query. For the purposes of the transformation,
|
|
** terminals are column references and aggregate functions.
|
|
@@ -149359,14 +163762,14 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
|
|
** the same window declaration (the OVER bit), then a single scan may
|
|
** be used to process more than one window function. For example:
|
|
**
|
|
-** SELECT max(b) OVER (PARTITION BY c ORDER BY d),
|
|
-** min(e) OVER (PARTITION BY c ORDER BY d)
|
|
+** SELECT max(b) OVER (PARTITION BY c ORDER BY d),
|
|
+** min(e) OVER (PARTITION BY c ORDER BY d)
|
|
** FROM t1;
|
|
**
|
|
** is transformed in the same way as the example above. However:
|
|
**
|
|
-** SELECT max(b) OVER (PARTITION BY c ORDER BY d),
|
|
-** min(e) OVER (PARTITION BY a ORDER BY b)
|
|
+** SELECT max(b) OVER (PARTITION BY c ORDER BY d),
|
|
+** min(e) OVER (PARTITION BY a ORDER BY b)
|
|
** FROM t1;
|
|
**
|
|
** Must be transformed to:
|
|
@@ -149419,15 +163822,15 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
|
|
** first_value(expr)
|
|
** last_value(expr)
|
|
** nth_value(expr, N)
|
|
-**
|
|
-** These are the same built-in window functions supported by Postgres.
|
|
+**
|
|
+** 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
|
|
** be implemented using an API, built-in window functions are much more
|
|
-** esoteric. Additionally, some window functions (e.g. nth_value())
|
|
+** esoteric. Additionally, some window functions (e.g. nth_value())
|
|
** may only be implemented by caching the entire partition in memory.
|
|
** As such, some built-in window functions use the same API as aggregate
|
|
-** window functions and some are implemented directly using VDBE
|
|
+** window functions and some are implemented directly using VDBE
|
|
** instructions. Additionally, for those functions that use the API, the
|
|
** window frame is sometimes modified before the SELECT statement is
|
|
** rewritten. For example, regardless of the specified window frame, the
|
|
@@ -149439,7 +163842,7 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
|
|
**
|
|
** As well as some of the built-in window functions, aggregate window
|
|
** functions min() and max() are implemented using VDBE instructions if
|
|
-** the start of the window frame is declared as anything other than
|
|
+** the start of the window frame is declared as anything other than
|
|
** UNBOUNDED PRECEDING.
|
|
*/
|
|
|
|
@@ -149450,7 +163853,7 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
|
|
** ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
|
|
*/
|
|
static void row_numberStepFunc(
|
|
- sqlite3_context *pCtx,
|
|
+ sqlite3_context *pCtx,
|
|
int nArg,
|
|
sqlite3_value **apArg
|
|
){
|
|
@@ -149478,10 +163881,10 @@ struct CallCount {
|
|
** Implementation of built-in window function dense_rank(). Assumes that
|
|
** the window frame has been set to:
|
|
**
|
|
-** RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
|
|
+** RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
|
|
*/
|
|
static void dense_rankStepFunc(
|
|
- sqlite3_context *pCtx,
|
|
+ sqlite3_context *pCtx,
|
|
int nArg,
|
|
sqlite3_value **apArg
|
|
){
|
|
@@ -149513,7 +163916,7 @@ struct NthValueCtx {
|
|
sqlite3_value *pValue;
|
|
};
|
|
static void nth_valueStepFunc(
|
|
- sqlite3_context *pCtx,
|
|
+ sqlite3_context *pCtx,
|
|
int nArg,
|
|
sqlite3_value **apArg
|
|
){
|
|
@@ -149566,7 +163969,7 @@ static void nth_valueFinalizeFunc(sqlite3_context *pCtx){
|
|
#define nth_valueValueFunc noopValueFunc
|
|
|
|
static void first_valueStepFunc(
|
|
- sqlite3_context *pCtx,
|
|
+ sqlite3_context *pCtx,
|
|
int nArg,
|
|
sqlite3_value **apArg
|
|
){
|
|
@@ -149597,10 +164000,10 @@ static void first_valueFinalizeFunc(sqlite3_context *pCtx){
|
|
** Implementation of built-in window function rank(). Assumes that
|
|
** the window frame has been set to:
|
|
**
|
|
-** RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
|
|
+** RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
|
|
*/
|
|
static void rankStepFunc(
|
|
- sqlite3_context *pCtx,
|
|
+ sqlite3_context *pCtx,
|
|
int nArg,
|
|
sqlite3_value **apArg
|
|
){
|
|
@@ -149631,7 +164034,7 @@ static void rankValueFunc(sqlite3_context *pCtx){
|
|
** GROUPS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING
|
|
*/
|
|
static void percent_rankStepFunc(
|
|
- sqlite3_context *pCtx,
|
|
+ sqlite3_context *pCtx,
|
|
int nArg,
|
|
sqlite3_value **apArg
|
|
){
|
|
@@ -149644,7 +164047,7 @@ static void percent_rankStepFunc(
|
|
}
|
|
}
|
|
static void percent_rankInvFunc(
|
|
- sqlite3_context *pCtx,
|
|
+ sqlite3_context *pCtx,
|
|
int nArg,
|
|
sqlite3_value **apArg
|
|
){
|
|
@@ -149676,7 +164079,7 @@ static void percent_rankValueFunc(sqlite3_context *pCtx){
|
|
** GROUPS BETWEEN 1 FOLLOWING AND UNBOUNDED FOLLOWING
|
|
*/
|
|
static void cume_distStepFunc(
|
|
- sqlite3_context *pCtx,
|
|
+ sqlite3_context *pCtx,
|
|
int nArg,
|
|
sqlite3_value **apArg
|
|
){
|
|
@@ -149689,7 +164092,7 @@ static void cume_distStepFunc(
|
|
}
|
|
}
|
|
static void cume_distInvFunc(
|
|
- sqlite3_context *pCtx,
|
|
+ sqlite3_context *pCtx,
|
|
int nArg,
|
|
sqlite3_value **apArg
|
|
){
|
|
@@ -149725,7 +164128,7 @@ struct NtileCtx {
|
|
** ROWS CURRENT ROW AND UNBOUNDED FOLLOWING
|
|
*/
|
|
static void ntileStepFunc(
|
|
- sqlite3_context *pCtx,
|
|
+ sqlite3_context *pCtx,
|
|
int nArg,
|
|
sqlite3_value **apArg
|
|
){
|
|
@@ -149745,7 +164148,7 @@ static void ntileStepFunc(
|
|
}
|
|
}
|
|
static void ntileInvFunc(
|
|
- sqlite3_context *pCtx,
|
|
+ sqlite3_context *pCtx,
|
|
int nArg,
|
|
sqlite3_value **apArg
|
|
){
|
|
@@ -149791,7 +164194,7 @@ struct LastValueCtx {
|
|
** Implementation of last_value().
|
|
*/
|
|
static void last_valueStepFunc(
|
|
- sqlite3_context *pCtx,
|
|
+ sqlite3_context *pCtx,
|
|
int nArg,
|
|
sqlite3_value **apArg
|
|
){
|
|
@@ -149809,7 +164212,7 @@ static void last_valueStepFunc(
|
|
}
|
|
}
|
|
static void last_valueInvFunc(
|
|
- sqlite3_context *pCtx,
|
|
+ sqlite3_context *pCtx,
|
|
int nArg,
|
|
sqlite3_value **apArg
|
|
){
|
|
@@ -149886,7 +164289,7 @@ static void noopValueFunc(sqlite3_context *p){ UNUSED_PARAMETER(p); /*no-op*/ }
|
|
/* Window functions that use all window interfaces: xStep, xFinal,
|
|
** xValue, and xInverse */
|
|
#define WINDOWFUNCALL(name,nArg,extra) { \
|
|
- nArg, (SQLITE_UTF8|SQLITE_FUNC_WINDOW|extra), 0, 0, \
|
|
+ nArg, (SQLITE_FUNC_BUILTIN|SQLITE_UTF8|SQLITE_FUNC_WINDOW|extra), 0, 0, \
|
|
name ## StepFunc, name ## FinalizeFunc, name ## ValueFunc, \
|
|
name ## InvFunc, name ## Name, {0} \
|
|
}
|
|
@@ -149894,7 +164297,7 @@ static void noopValueFunc(sqlite3_context *p){ UNUSED_PARAMETER(p); /*no-op*/ }
|
|
/* Window functions that are implemented using bytecode and thus have
|
|
** no-op routines for their methods */
|
|
#define WINDOWFUNCNOOP(name,nArg,extra) { \
|
|
- nArg, (SQLITE_UTF8|SQLITE_FUNC_WINDOW|extra), 0, 0, \
|
|
+ nArg, (SQLITE_FUNC_BUILTIN|SQLITE_UTF8|SQLITE_FUNC_WINDOW|extra), 0, 0, \
|
|
noopStepFunc, noopValueFunc, noopValueFunc, \
|
|
noopStepFunc, name ## Name, {0} \
|
|
}
|
|
@@ -149903,7 +164306,7 @@ static void noopValueFunc(sqlite3_context *p){ UNUSED_PARAMETER(p); /*no-op*/ }
|
|
** same routine for xFinalize and xValue and which never call
|
|
** xInverse. */
|
|
#define WINDOWFUNCX(name,nArg,extra) { \
|
|
- nArg, (SQLITE_UTF8|SQLITE_FUNC_WINDOW|extra), 0, 0, \
|
|
+ nArg, (SQLITE_FUNC_BUILTIN|SQLITE_UTF8|SQLITE_FUNC_WINDOW|extra), 0, 0, \
|
|
name ## StepFunc, name ## ValueFunc, name ## ValueFunc, \
|
|
noopStepFunc, name ## Name, {0} \
|
|
}
|
|
@@ -149962,7 +164365,7 @@ static Window *windowFind(Parse *pParse, Window *pList, const char *zName){
|
|
** of this file), pWin is updated here.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3WindowUpdate(
|
|
- Parse *pParse,
|
|
+ Parse *pParse,
|
|
Window *pList, /* List of named windows for this SELECT */
|
|
Window *pWin, /* Window frame to update */
|
|
FuncDef *pFunc /* Window function definition */
|
|
@@ -149982,17 +164385,17 @@ SQLITE_PRIVATE void sqlite3WindowUpdate(
|
|
sqlite3WindowChain(pParse, pWin, pList);
|
|
}
|
|
if( (pWin->eFrmType==TK_RANGE)
|
|
- && (pWin->pStart || pWin->pEnd)
|
|
+ && (pWin->pStart || pWin->pEnd)
|
|
&& (pWin->pOrderBy==0 || pWin->pOrderBy->nExpr!=1)
|
|
){
|
|
- sqlite3ErrorMsg(pParse,
|
|
+ sqlite3ErrorMsg(pParse,
|
|
"RANGE with offset PRECEDING/FOLLOWING requires one ORDER BY expression"
|
|
);
|
|
}else
|
|
if( pFunc->funcFlags & SQLITE_FUNC_WINDOW ){
|
|
sqlite3 *db = pParse->db;
|
|
if( pWin->pFilter ){
|
|
- sqlite3ErrorMsg(pParse,
|
|
+ sqlite3ErrorMsg(pParse,
|
|
"FILTER clause may only be used with aggregate window functions"
|
|
);
|
|
}else{
|
|
@@ -150002,14 +164405,14 @@ SQLITE_PRIVATE void sqlite3WindowUpdate(
|
|
int eStart;
|
|
int eEnd;
|
|
} aUp[] = {
|
|
- { row_numberName, TK_ROWS, TK_UNBOUNDED, TK_CURRENT },
|
|
- { dense_rankName, TK_RANGE, TK_UNBOUNDED, TK_CURRENT },
|
|
- { rankName, TK_RANGE, TK_UNBOUNDED, TK_CURRENT },
|
|
- { percent_rankName, TK_GROUPS, TK_CURRENT, TK_UNBOUNDED },
|
|
- { cume_distName, TK_GROUPS, TK_FOLLOWING, TK_UNBOUNDED },
|
|
- { ntileName, TK_ROWS, TK_CURRENT, TK_UNBOUNDED },
|
|
- { leadName, TK_ROWS, TK_UNBOUNDED, TK_UNBOUNDED },
|
|
- { lagName, TK_ROWS, TK_UNBOUNDED, TK_CURRENT },
|
|
+ { row_numberName, TK_ROWS, TK_UNBOUNDED, TK_CURRENT },
|
|
+ { dense_rankName, TK_RANGE, TK_UNBOUNDED, TK_CURRENT },
|
|
+ { rankName, TK_RANGE, TK_UNBOUNDED, TK_CURRENT },
|
|
+ { percent_rankName, TK_GROUPS, TK_CURRENT, TK_UNBOUNDED },
|
|
+ { cume_distName, TK_GROUPS, TK_FOLLOWING, TK_UNBOUNDED },
|
|
+ { ntileName, TK_ROWS, TK_CURRENT, TK_UNBOUNDED },
|
|
+ { leadName, TK_ROWS, TK_UNBOUNDED, TK_UNBOUNDED },
|
|
+ { lagName, TK_ROWS, TK_UNBOUNDED, TK_CURRENT },
|
|
};
|
|
int i;
|
|
for(i=0; i<ArraySize(aUp); i++){
|
|
@@ -150029,7 +164432,7 @@ SQLITE_PRIVATE void sqlite3WindowUpdate(
|
|
}
|
|
}
|
|
}
|
|
- pWin->pFunc = pFunc;
|
|
+ pWin->pWFunc = pFunc;
|
|
}
|
|
|
|
/*
|
|
@@ -150047,7 +164450,7 @@ struct WindowRewrite {
|
|
|
|
/*
|
|
** Callback function used by selectWindowRewriteEList(). If necessary,
|
|
-** this function appends to the output expression-list and updates
|
|
+** this function appends to the output expression-list and updates
|
|
** expression (*ppExpr) in place.
|
|
*/
|
|
static int selectWindowRewriteExprCb(Walker *pWalker, Expr *pExpr){
|
|
@@ -150088,11 +164491,12 @@ static int selectWindowRewriteExprCb(Walker *pWalker, Expr *pExpr){
|
|
}
|
|
}
|
|
}
|
|
- /* Fall through. */
|
|
+ /* no break */ deliberate_fall_through
|
|
|
|
case TK_AGG_FUNCTION:
|
|
case TK_COLUMN: {
|
|
int iCol = -1;
|
|
+ if( pParse->db->mallocFailed ) return WRC_Abort;
|
|
if( p->pSub ){
|
|
int i;
|
|
for(i=0; i<p->pSub->nExpr; i++){
|
|
@@ -150108,6 +164512,7 @@ static int selectWindowRewriteExprCb(Walker *pWalker, Expr *pExpr){
|
|
p->pSub = sqlite3ExprListAppend(pParse, p->pSub, pDup);
|
|
}
|
|
if( p->pSub ){
|
|
+ int f = pExpr->flags & EP_Collate;
|
|
assert( ExprHasProperty(pExpr, EP_Static)==0 );
|
|
ExprSetProperty(pExpr, EP_Static);
|
|
sqlite3ExprDelete(pParse->db, pExpr);
|
|
@@ -150118,6 +164523,7 @@ static int selectWindowRewriteExprCb(Walker *pWalker, Expr *pExpr){
|
|
pExpr->iColumn = (iCol<0 ? p->pSub->nExpr-1: iCol);
|
|
pExpr->iTable = p->pWin->iEphCsr;
|
|
pExpr->y.pTab = p->pTab;
|
|
+ pExpr->flags = f;
|
|
}
|
|
if( pParse->db->mallocFailed ) return WRC_Abort;
|
|
break;
|
|
@@ -150148,16 +164554,16 @@ static int selectWindowRewriteSelectCb(Walker *pWalker, Select *pSelect){
|
|
**
|
|
** * TK_COLUMN,
|
|
** * aggregate function, or
|
|
-** * window function with a Window object that is not a member of the
|
|
+** * window function with a Window object that is not a member of the
|
|
** Window list passed as the second argument (pWin).
|
|
**
|
|
** Append the node to output expression-list (*ppSub). And replace it
|
|
-** with a TK_COLUMN that reads the (N-1)th element of table
|
|
+** with a TK_COLUMN that reads the (N-1)th element of table
|
|
** pWin->iEphCsr, where N is the number of elements in (*ppSub) after
|
|
** appending the new one.
|
|
*/
|
|
static void selectWindowRewriteEList(
|
|
- Parse *pParse,
|
|
+ Parse *pParse,
|
|
Window *pWin,
|
|
SrcList *pSrc,
|
|
ExprList *pEList, /* Rewrite expressions in this list */
|
|
@@ -150200,31 +164606,69 @@ static ExprList *exprListAppendList(
|
|
int i;
|
|
int nInit = pList ? pList->nExpr : 0;
|
|
for(i=0; i<pAppend->nExpr; i++){
|
|
- int iDummy;
|
|
- Expr *pDup = sqlite3ExprDup(pParse->db, pAppend->a[i].pExpr, 0);
|
|
- assert( pDup==0 || !ExprHasProperty(pDup, EP_MemToken) );
|
|
- if( bIntToNull && pDup && sqlite3ExprIsInteger(pDup, &iDummy) ){
|
|
- pDup->op = TK_NULL;
|
|
- pDup->flags &= ~(EP_IntValue|EP_IsTrue|EP_IsFalse);
|
|
- pDup->u.zToken = 0;
|
|
+ sqlite3 *db = pParse->db;
|
|
+ Expr *pDup = sqlite3ExprDup(db, pAppend->a[i].pExpr, 0);
|
|
+ if( db->mallocFailed ){
|
|
+ sqlite3ExprDelete(db, pDup);
|
|
+ break;
|
|
+ }
|
|
+ if( bIntToNull ){
|
|
+ int iDummy;
|
|
+ Expr *pSub;
|
|
+ pSub = sqlite3ExprSkipCollateAndLikely(pDup);
|
|
+ if( sqlite3ExprIsInteger(pSub, &iDummy) ){
|
|
+ pSub->op = TK_NULL;
|
|
+ pSub->flags &= ~(EP_IntValue|EP_IsTrue|EP_IsFalse);
|
|
+ pSub->u.zToken = 0;
|
|
+ }
|
|
}
|
|
pList = sqlite3ExprListAppend(pParse, pList, pDup);
|
|
- if( pList ) pList->a[nInit+i].sortFlags = pAppend->a[i].sortFlags;
|
|
+ if( pList ) pList->a[nInit+i].fg.sortFlags = pAppend->a[i].fg.sortFlags;
|
|
}
|
|
}
|
|
return pList;
|
|
}
|
|
|
|
+/*
|
|
+** When rewriting a query, if the new subquery in the FROM clause
|
|
+** contains TK_AGG_FUNCTION nodes that refer to an outer query,
|
|
+** then we have to increase the Expr->op2 values of those nodes
|
|
+** due to the extra subquery layer that was added.
|
|
+**
|
|
+** See also the incrAggDepth() routine in resolve.c
|
|
+*/
|
|
+static int sqlite3WindowExtraAggFuncDepth(Walker *pWalker, Expr *pExpr){
|
|
+ if( pExpr->op==TK_AGG_FUNCTION
|
|
+ && pExpr->op2>=pWalker->walkerDepth
|
|
+ ){
|
|
+ pExpr->op2++;
|
|
+ }
|
|
+ return WRC_Continue;
|
|
+}
|
|
+
|
|
+static int disallowAggregatesInOrderByCb(Walker *pWalker, Expr *pExpr){
|
|
+ if( pExpr->op==TK_AGG_FUNCTION && pExpr->pAggInfo==0 ){
|
|
+ assert( !ExprHasProperty(pExpr, EP_IntValue) );
|
|
+ sqlite3ErrorMsg(pWalker->pParse,
|
|
+ "misuse of aggregate: %s()", pExpr->u.zToken);
|
|
+ }
|
|
+ return WRC_Continue;
|
|
+}
|
|
+
|
|
/*
|
|
** If the SELECT statement passed as the second argument does not invoke
|
|
-** any SQL window functions, this function is a no-op. Otherwise, it
|
|
+** any SQL window functions, this function is a no-op. Otherwise, it
|
|
** rewrites the SELECT statement so that window function xStep functions
|
|
** are invoked in the correct order as described under "SELECT REWRITING"
|
|
** at the top of this file.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3WindowRewrite(Parse *pParse, Select *p){
|
|
int rc = SQLITE_OK;
|
|
- if( p->pWin && p->pPrior==0 && (p->selFlags & SF_WinRewrite)==0 ){
|
|
+ if( p->pWin
|
|
+ && p->pPrior==0
|
|
+ && ALWAYS((p->selFlags & SF_WinRewrite)==0)
|
|
+ && ALWAYS(!IN_RENAME_OBJECT)
|
|
+ ){
|
|
Vdbe *v = sqlite3GetVdbe(pParse);
|
|
sqlite3 *db = pParse->db;
|
|
Select *pSub = 0; /* The subquery */
|
|
@@ -150235,14 +164679,24 @@ SQLITE_PRIVATE int sqlite3WindowRewrite(Parse *pParse, Select *p){
|
|
ExprList *pSort = 0;
|
|
|
|
ExprList *pSublist = 0; /* Expression list for sub-query */
|
|
- Window *pMWin = p->pWin; /* Master window object */
|
|
+ Window *pMWin = p->pWin; /* Main window object */
|
|
Window *pWin; /* Window object iterator */
|
|
Table *pTab;
|
|
+ Walker w;
|
|
+
|
|
+ u32 selFlags = p->selFlags;
|
|
|
|
pTab = sqlite3DbMallocZero(db, sizeof(Table));
|
|
if( pTab==0 ){
|
|
return sqlite3ErrorToParser(db, SQLITE_NOMEM);
|
|
}
|
|
+ sqlite3AggInfoPersistWalkerInit(&w, pParse);
|
|
+ sqlite3WalkSelect(&w, p);
|
|
+ if( (p->selFlags & SF_Aggregate)==0 ){
|
|
+ w.xExprCallback = disallowAggregatesInOrderByCb;
|
|
+ w.xSelectCallback = 0;
|
|
+ sqlite3WalkExprList(&w, p->pOrderBy);
|
|
+ }
|
|
|
|
p->pSrc = 0;
|
|
p->pWhere = 0;
|
|
@@ -150276,8 +164730,8 @@ SQLITE_PRIVATE int sqlite3WindowRewrite(Parse *pParse, Select *p){
|
|
selectWindowRewriteEList(pParse, pMWin, pSrc, p->pOrderBy, pTab, &pSublist);
|
|
pMWin->nBufferCol = (pSublist ? pSublist->nExpr : 0);
|
|
|
|
- /* Append the PARTITION BY and ORDER BY expressions to the to the
|
|
- ** sub-select expression list. They are required to figure out where
|
|
+ /* Append the PARTITION BY and ORDER BY expressions to the to the
|
|
+ ** sub-select expression list. They are required to figure out where
|
|
** boundaries for partitions and sets of peer rows lie. */
|
|
pSublist = exprListAppendList(pParse, pSublist, pMWin->pPartition, 0);
|
|
pSublist = exprListAppendList(pParse, pSublist, pMWin->pOrderBy, 0);
|
|
@@ -150287,8 +164741,11 @@ SQLITE_PRIVATE int sqlite3WindowRewrite(Parse *pParse, Select *p){
|
|
** window function - one for the accumulator, another for interim
|
|
** results. */
|
|
for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
|
|
- ExprList *pArgs = pWin->pOwner->x.pList;
|
|
- if( pWin->pFunc->funcFlags & SQLITE_FUNC_SUBTYPE ){
|
|
+ ExprList *pArgs;
|
|
+ assert( ExprUseXList(pWin->pOwner) );
|
|
+ assert( pWin->pWFunc!=0 );
|
|
+ pArgs = pWin->pOwner->x.pList;
|
|
+ if( pWin->pWFunc->funcFlags & SQLITE_FUNC_SUBTYPE ){
|
|
selectWindowRewriteEList(pParse, pMWin, pSrc, pArgs, pTab, &pSublist);
|
|
pWin->iArgCol = (pSublist ? pSublist->nExpr : 0);
|
|
pWin->bExprArgs = 1;
|
|
@@ -150308,11 +164765,11 @@ SQLITE_PRIVATE int sqlite3WindowRewrite(Parse *pParse, Select *p){
|
|
/* If there is no ORDER BY or PARTITION BY clause, and the window
|
|
** function accepts zero arguments, and there are no other columns
|
|
** selected (e.g. "SELECT row_number() OVER () FROM t1"), it is possible
|
|
- ** that pSublist is still NULL here. Add a constant expression here to
|
|
- ** keep everything legal in this case.
|
|
+ ** that pSublist is still NULL here. Add a constant expression here to
|
|
+ ** keep everything legal in this case.
|
|
*/
|
|
if( pSublist==0 ){
|
|
- pSublist = sqlite3ExprListAppend(pParse, 0,
|
|
+ pSublist = sqlite3ExprListAppend(pParse, 0,
|
|
sqlite3Expr(db, TK_INTEGER, "0")
|
|
);
|
|
}
|
|
@@ -150320,13 +164777,21 @@ SQLITE_PRIVATE int sqlite3WindowRewrite(Parse *pParse, Select *p){
|
|
pSub = sqlite3SelectNew(
|
|
pParse, pSublist, pSrc, pWhere, pGroupBy, pHaving, pSort, 0, 0
|
|
);
|
|
+ TREETRACE(0x40,pParse,pSub,
|
|
+ ("New window-function subquery in FROM clause of (%u/%p)\n",
|
|
+ p->selId, p));
|
|
p->pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
|
|
+ assert( pSub!=0 || p->pSrc==0 ); /* Due to db->mallocFailed test inside
|
|
+ ** of sqlite3DbMallocRawNN() called from
|
|
+ ** sqlite3SrcListAppend() */
|
|
if( p->pSrc ){
|
|
Table *pTab2;
|
|
p->pSrc->a[0].pSelect = pSub;
|
|
+ p->pSrc->a[0].fg.isCorrelated = 1;
|
|
sqlite3SrcListAssignCursors(pParse, p->pSrc);
|
|
- pSub->selFlags |= SF_Expanded;
|
|
+ pSub->selFlags |= SF_Expanded|SF_OrderByReqd;
|
|
pTab2 = sqlite3ResultSetOfSelect(pParse, pSub, SQLITE_AFF_NONE);
|
|
+ pSub->selFlags |= (selFlags & SF_Aggregate);
|
|
if( pTab2==0 ){
|
|
/* Might actually be some other kind of error, but in that case
|
|
** pParse->nErr will be set, so if SQLITE_NOMEM is set, we will get
|
|
@@ -150337,21 +164802,24 @@ SQLITE_PRIVATE int sqlite3WindowRewrite(Parse *pParse, Select *p){
|
|
pTab->tabFlags |= TF_Ephemeral;
|
|
p->pSrc->a[0].pTab = pTab;
|
|
pTab = pTab2;
|
|
+ memset(&w, 0, sizeof(w));
|
|
+ w.xExprCallback = sqlite3WindowExtraAggFuncDepth;
|
|
+ w.xSelectCallback = sqlite3WalkerDepthIncrease;
|
|
+ w.xSelectCallback2 = sqlite3WalkerDepthDecrease;
|
|
+ sqlite3WalkSelect(&w, pSub);
|
|
}
|
|
}else{
|
|
sqlite3SelectDelete(db, pSub);
|
|
}
|
|
if( db->mallocFailed ) rc = SQLITE_NOMEM;
|
|
- sqlite3DbFree(db, pTab);
|
|
- }
|
|
|
|
- if( rc ){
|
|
- if( pParse->nErr==0 ){
|
|
- assert( pParse->db->mallocFailed );
|
|
- sqlite3ErrorToParser(pParse->db, SQLITE_NOMEM);
|
|
- }
|
|
- sqlite3SelectReset(pParse, p);
|
|
+ /* Defer deleting the temporary table pTab because if an error occurred,
|
|
+ ** there could still be references to that table embedded in the
|
|
+ ** result-set or ORDER BY clause of the SELECT statement p. */
|
|
+ sqlite3ParserAddCleanup(pParse, sqlite3DbFree, pTab);
|
|
}
|
|
+
|
|
+ assert( rc==SQLITE_OK || pParse->nErr!=0 );
|
|
return rc;
|
|
}
|
|
|
|
@@ -150487,10 +164955,10 @@ SQLITE_PRIVATE Window *sqlite3WindowAlloc(
|
|
** equivalent nul-terminated string.
|
|
*/
|
|
SQLITE_PRIVATE Window *sqlite3WindowAssemble(
|
|
- Parse *pParse,
|
|
- Window *pWin,
|
|
- ExprList *pPartition,
|
|
- ExprList *pOrderBy,
|
|
+ Parse *pParse,
|
|
+ Window *pWin,
|
|
+ ExprList *pPartition,
|
|
+ ExprList *pOrderBy,
|
|
Token *pBase
|
|
){
|
|
if( pWin ){
|
|
@@ -150528,7 +164996,7 @@ SQLITE_PRIVATE void sqlite3WindowChain(Parse *pParse, Window *pWin, Window *pLis
|
|
zErr = "frame specification";
|
|
}
|
|
if( zErr ){
|
|
- sqlite3ErrorMsg(pParse,
|
|
+ sqlite3ErrorMsg(pParse,
|
|
"cannot override %s of window: %s", zErr, pWin->zBase
|
|
);
|
|
}else{
|
|
@@ -150571,15 +165039,19 @@ SQLITE_PRIVATE void sqlite3WindowAttach(Parse *pParse, Expr *p, Window *pWin){
|
|
** SELECT, or (b) the windows already linked use a compatible window frame.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3WindowLink(Select *pSel, Window *pWin){
|
|
- if( pSel!=0
|
|
- && (0==pSel->pWin || 0==sqlite3WindowCompare(0, pSel->pWin, pWin, 0))
|
|
- ){
|
|
- pWin->pNextWin = pSel->pWin;
|
|
- if( pSel->pWin ){
|
|
- pSel->pWin->ppThis = &pWin->pNextWin;
|
|
+ if( pSel ){
|
|
+ if( 0==pSel->pWin || 0==sqlite3WindowCompare(0, pSel->pWin, pWin, 0) ){
|
|
+ pWin->pNextWin = pSel->pWin;
|
|
+ if( pSel->pWin ){
|
|
+ pSel->pWin->ppThis = &pWin->pNextWin;
|
|
+ }
|
|
+ pSel->pWin = pWin;
|
|
+ pWin->ppThis = &pSel->pWin;
|
|
+ }else{
|
|
+ if( sqlite3ExprListCompare(pWin->pPartition, pSel->pWin->pPartition,-1) ){
|
|
+ pSel->selFlags |= SF_MultiPart;
|
|
+ }
|
|
}
|
|
- pSel->pWin = pWin;
|
|
- pWin->ppThis = &pSel->pWin;
|
|
}
|
|
}
|
|
|
|
@@ -150588,7 +165060,12 @@ SQLITE_PRIVATE void sqlite3WindowLink(Select *pSel, Window *pWin){
|
|
** different, or 2 if it cannot be determined if the objects are identical
|
|
** or not. Identical window objects can be processed in a single scan.
|
|
*/
|
|
-SQLITE_PRIVATE int sqlite3WindowCompare(Parse *pParse, Window *p1, Window *p2, int bFilter){
|
|
+SQLITE_PRIVATE int sqlite3WindowCompare(
|
|
+ const Parse *pParse,
|
|
+ const Window *p1,
|
|
+ const Window *p2,
|
|
+ int bFilter
|
|
+){
|
|
int res;
|
|
if( NEVER(p1==0) || NEVER(p2==0) ) return 1;
|
|
if( p1->eFrmType!=p2->eFrmType ) return 1;
|
|
@@ -150651,7 +165128,7 @@ SQLITE_PRIVATE void sqlite3WindowCodeInit(Parse *pParse, Select *pSelect){
|
|
}
|
|
|
|
for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
|
|
- FuncDef *p = pWin->pFunc;
|
|
+ FuncDef *p = pWin->pWFunc;
|
|
if( (p->funcFlags & SQLITE_FUNC_MINMAX) && pWin->eStart!=TK_UNBOUNDED ){
|
|
/* The inline versions of min() and max() require a single ephemeral
|
|
** table and 3 registers. The registers are used as follows:
|
|
@@ -150660,12 +165137,15 @@ SQLITE_PRIVATE void sqlite3WindowCodeInit(Parse *pParse, Select *pSelect){
|
|
** regApp+1: integer value used to ensure keys are unique
|
|
** regApp+2: output of MakeRecord
|
|
*/
|
|
- ExprList *pList = pWin->pOwner->x.pList;
|
|
- KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pList, 0, 0);
|
|
+ ExprList *pList;
|
|
+ KeyInfo *pKeyInfo;
|
|
+ assert( ExprUseXList(pWin->pOwner) );
|
|
+ pList = pWin->pOwner->x.pList;
|
|
+ pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pList, 0, 0);
|
|
pWin->csrApp = pParse->nTab++;
|
|
pWin->regApp = pParse->nMem+1;
|
|
pParse->nMem += 3;
|
|
- if( pKeyInfo && pWin->pFunc->zName[1]=='i' ){
|
|
+ if( pKeyInfo && pWin->pWFunc->zName[1]=='i' ){
|
|
assert( pKeyInfo->aSortFlags[0]==0 );
|
|
pKeyInfo->aSortFlags[0] = KEYINFO_ORDER_DESC;
|
|
}
|
|
@@ -150732,6 +165212,7 @@ static void windowCheckValue(Parse *pParse, int reg, int eCond){
|
|
VdbeCoverageIf(v, eCond==2);
|
|
}
|
|
sqlite3VdbeAddOp3(v, aOp[eCond], regZero, sqlite3VdbeCurrentAddr(v)+2, reg);
|
|
+ sqlite3VdbeChangeP5(v, SQLITE_AFF_NUMERIC);
|
|
VdbeCoverageNeverNullIf(v, eCond==0); /* NULL case captured by */
|
|
VdbeCoverageNeverNullIf(v, eCond==1); /* the OP_MustBeInt */
|
|
VdbeCoverageNeverNullIf(v, eCond==2);
|
|
@@ -150748,7 +165229,9 @@ static void windowCheckValue(Parse *pParse, int reg, int eCond){
|
|
** with the object passed as the only argument to this function.
|
|
*/
|
|
static int windowArgCount(Window *pWin){
|
|
- ExprList *pList = pWin->pOwner->x.pList;
|
|
+ const ExprList *pList;
|
|
+ assert( ExprUseXList(pWin->pOwner) );
|
|
+ pList = pWin->pOwner->x.pList;
|
|
return (pList ? pList->nExpr : 0);
|
|
}
|
|
|
|
@@ -150764,7 +165247,7 @@ struct WindowCsrAndReg {
|
|
};
|
|
|
|
/*
|
|
-** A single instance of this structure is allocated on the stack by
|
|
+** A single instance of this structure is allocated on the stack by
|
|
** sqlite3WindowCodeStep() and a pointer to it passed to the various helper
|
|
** routines. This is to reduce the number of arguments required by each
|
|
** helper function.
|
|
@@ -150811,7 +165294,7 @@ struct WindowCsrAndReg {
|
|
**
|
|
** Each cursor (start, current and end) consists of a VDBE cursor
|
|
** (WindowCsrAndReg.csr) and an array of registers (starting at
|
|
-** WindowCodeArg.reg) that always contains a copy of the peer values
|
|
+** WindowCodeArg.reg) that always contains a copy of the peer values
|
|
** read from the corresponding cursor.
|
|
**
|
|
** Depending on the window-frame in question, all three cursors may not
|
|
@@ -150826,6 +165309,7 @@ struct WindowCodeArg {
|
|
int regGosub; /* Register used with OP_Gosub(addrGosub) */
|
|
int regArg; /* First in array of accumulator registers */
|
|
int eDelete; /* See above */
|
|
+ int regRowid;
|
|
|
|
WindowCsrAndReg start;
|
|
WindowCsrAndReg current;
|
|
@@ -150855,8 +165339,8 @@ static void windowReadPeerValues(
|
|
}
|
|
|
|
/*
|
|
-** Generate VM code to invoke either xStep() (if bInverse is 0) or
|
|
-** xInverse (if bInverse is non-zero) for each window function in the
|
|
+** Generate VM code to invoke either xStep() (if bInverse is 0) or
|
|
+** xInverse (if bInverse is non-zero) for each window function in the
|
|
** linked list starting at pMWin. Or, for built-in window functions
|
|
** that do not use the standard function API, generate the required
|
|
** inline VM code.
|
|
@@ -150884,7 +165368,7 @@ static void windowAggStep(
|
|
Vdbe *v = sqlite3GetVdbe(pParse);
|
|
Window *pWin;
|
|
for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
|
|
- FuncDef *pFunc = pWin->pFunc;
|
|
+ FuncDef *pFunc = pWin->pWFunc;
|
|
int regArg;
|
|
int nArg = pWin->bExprArgs ? 0 : windowArgCount(pWin);
|
|
int i;
|
|
@@ -150905,7 +165389,7 @@ static void windowAggStep(
|
|
regArg = reg;
|
|
|
|
if( pMWin->regStartRowid==0
|
|
- && (pFunc->funcFlags & SQLITE_FUNC_MINMAX)
|
|
+ && (pFunc->funcFlags & SQLITE_FUNC_MINMAX)
|
|
&& (pWin->eStart!=TK_UNBOUNDED)
|
|
){
|
|
int addrIsNull = sqlite3VdbeAddOp1(v, OP_IsNull, regArg);
|
|
@@ -150932,6 +165416,7 @@ static void windowAggStep(
|
|
int addrIf = 0;
|
|
if( pWin->pFilter ){
|
|
int regTmp;
|
|
+ assert( ExprUseXList(pWin->pOwner) );
|
|
assert( pWin->bExprArgs || !nArg ||nArg==pWin->pOwner->x.pList->nExpr );
|
|
assert( pWin->bExprArgs || nArg ||pWin->pOwner->x.pList==0 );
|
|
regTmp = sqlite3GetTempReg(pParse);
|
|
@@ -150940,18 +165425,19 @@ static void windowAggStep(
|
|
VdbeCoverage(v);
|
|
sqlite3ReleaseTempReg(pParse, regTmp);
|
|
}
|
|
-
|
|
+
|
|
if( pWin->bExprArgs ){
|
|
- int iStart = sqlite3VdbeCurrentAddr(v);
|
|
- VdbeOp *pOp, *pEnd;
|
|
+ int iOp = sqlite3VdbeCurrentAddr(v);
|
|
+ int iEnd;
|
|
|
|
+ assert( ExprUseXList(pWin->pOwner) );
|
|
nArg = pWin->pOwner->x.pList->nExpr;
|
|
regArg = sqlite3GetTempRange(pParse, nArg);
|
|
sqlite3ExprCodeExprList(pParse, pWin->pOwner->x.pList, regArg, 0, 0);
|
|
|
|
- pEnd = sqlite3VdbeGetOp(v, -1);
|
|
- for(pOp=sqlite3VdbeGetOp(v, iStart); pOp<=pEnd; pOp++){
|
|
- if( pOp->opcode==OP_Column && pOp->p1==pWin->iEphCsr ){
|
|
+ for(iEnd=sqlite3VdbeCurrentAddr(v); iOp<iEnd; iOp++){
|
|
+ VdbeOp *pOp = sqlite3VdbeGetOp(v, iOp);
|
|
+ if( pOp->opcode==OP_Column && pOp->p1==pMWin->iEphCsr ){
|
|
pOp->p1 = csr;
|
|
}
|
|
}
|
|
@@ -150959,10 +165445,11 @@ static void windowAggStep(
|
|
if( pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){
|
|
CollSeq *pColl;
|
|
assert( nArg>0 );
|
|
+ assert( ExprUseXList(pWin->pOwner) );
|
|
pColl = sqlite3ExprNNCollSeq(pParse, pWin->pOwner->x.pList->a[0].pExpr);
|
|
sqlite3VdbeAddOp4(v, OP_CollSeq, 0,0,0, (const char*)pColl, P4_COLLSEQ);
|
|
}
|
|
- sqlite3VdbeAddOp3(v, bInverse? OP_AggInverse : OP_AggStep,
|
|
+ sqlite3VdbeAddOp3(v, bInverse? OP_AggInverse : OP_AggStep,
|
|
bInverse, regArg, pWin->regAccum);
|
|
sqlite3VdbeAppendP4(v, pFunc, P4_FUNCDEF);
|
|
sqlite3VdbeChangeP5(v, (u8)nArg);
|
|
@@ -150995,7 +165482,7 @@ static void windowAggFinal(WindowCodeArg *p, int bFin){
|
|
|
|
for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
|
|
if( pMWin->regStartRowid==0
|
|
- && (pWin->pFunc->funcFlags & SQLITE_FUNC_MINMAX)
|
|
+ && (pWin->pWFunc->funcFlags & SQLITE_FUNC_MINMAX)
|
|
&& (pWin->eStart!=TK_UNBOUNDED)
|
|
){
|
|
sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regResult);
|
|
@@ -151009,12 +165496,12 @@ static void windowAggFinal(WindowCodeArg *p, int bFin){
|
|
int nArg = windowArgCount(pWin);
|
|
if( bFin ){
|
|
sqlite3VdbeAddOp2(v, OP_AggFinal, pWin->regAccum, nArg);
|
|
- sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF);
|
|
+ sqlite3VdbeAppendP4(v, pWin->pWFunc, P4_FUNCDEF);
|
|
sqlite3VdbeAddOp2(v, OP_Copy, pWin->regAccum, pWin->regResult);
|
|
sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regAccum);
|
|
}else{
|
|
sqlite3VdbeAddOp3(v, OP_AggValue,pWin->regAccum,nArg,pWin->regResult);
|
|
- sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF);
|
|
+ sqlite3VdbeAppendP4(v, pWin->pWFunc, P4_FUNCDEF);
|
|
}
|
|
}
|
|
}
|
|
@@ -151143,7 +165630,8 @@ static void windowReturnOneRow(WindowCodeArg *p){
|
|
Window *pWin;
|
|
|
|
for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
|
|
- FuncDef *pFunc = pWin->pFunc;
|
|
+ FuncDef *pFunc = pWin->pWFunc;
|
|
+ assert( ExprUseXList(pWin->pOwner) );
|
|
if( pFunc->zName==nth_valueName
|
|
|| pFunc->zName==first_valueName
|
|
){
|
|
@@ -151151,7 +165639,7 @@ static void windowReturnOneRow(WindowCodeArg *p){
|
|
int lbl = sqlite3VdbeMakeLabel(pParse);
|
|
int tmpReg = sqlite3GetTempReg(pParse);
|
|
sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regResult);
|
|
-
|
|
+
|
|
if( pFunc->zName==nth_valueName ){
|
|
sqlite3VdbeAddOp3(v, OP_Column,pMWin->iEphCsr,pWin->iArgCol+1,tmpReg);
|
|
windowCheckValue(pParse, tmpReg, 2);
|
|
@@ -151173,7 +165661,7 @@ static void windowReturnOneRow(WindowCodeArg *p){
|
|
int lbl = sqlite3VdbeMakeLabel(pParse);
|
|
int tmpReg = sqlite3GetTempReg(pParse);
|
|
int iEph = pMWin->iEphCsr;
|
|
-
|
|
+
|
|
if( nArg<3 ){
|
|
sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regResult);
|
|
}else{
|
|
@@ -151190,7 +165678,7 @@ static void windowReturnOneRow(WindowCodeArg *p){
|
|
sqlite3VdbeAddOp3(v, op, tmpReg2, tmpReg, tmpReg);
|
|
sqlite3ReleaseTempReg(pParse, tmpReg2);
|
|
}
|
|
-
|
|
+
|
|
sqlite3VdbeAddOp3(v, OP_SeekRowid, csr, lbl, tmpReg);
|
|
VdbeCoverage(v);
|
|
sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol, pWin->regResult);
|
|
@@ -151214,7 +165702,8 @@ static int windowInitAccum(Parse *pParse, Window *pMWin){
|
|
int nArg = 0;
|
|
Window *pWin;
|
|
for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
|
|
- FuncDef *pFunc = pWin->pFunc;
|
|
+ FuncDef *pFunc = pWin->pWFunc;
|
|
+ assert( pWin->regAccum );
|
|
sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regAccum);
|
|
nArg = MAX(nArg, windowArgCount(pWin));
|
|
if( pMWin->regStartRowid==0 ){
|
|
@@ -151235,7 +165724,7 @@ static int windowInitAccum(Parse *pParse, Window *pMWin){
|
|
return regArg;
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** Return true if the current frame should be cached in the ephemeral table,
|
|
** even if there are no xInverse() calls required.
|
|
*/
|
|
@@ -151243,7 +165732,7 @@ static int windowCacheFrame(Window *pMWin){
|
|
Window *pWin;
|
|
if( pMWin->regStartRowid ) return 1;
|
|
for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
|
|
- FuncDef *pFunc = pWin->pFunc;
|
|
+ FuncDef *pFunc = pWin->pWFunc;
|
|
if( (pFunc->zName==nth_valueName)
|
|
|| (pFunc->zName==first_valueName)
|
|
|| (pFunc->zName==leadName)
|
|
@@ -151259,9 +165748,9 @@ static int windowCacheFrame(Window *pMWin){
|
|
** regOld and regNew are each the first register in an array of size
|
|
** pOrderBy->nExpr. This function generates code to compare the two
|
|
** arrays of registers using the collation sequences and other comparison
|
|
-** parameters specified by pOrderBy.
|
|
+** parameters specified by pOrderBy.
|
|
**
|
|
-** If the two arrays are not equal, the contents of regNew is copied to
|
|
+** If the two arrays are not equal, the contents of regNew is copied to
|
|
** regOld and control falls through. Otherwise, if the contents of the arrays
|
|
** are equal, an OP_Goto is executed. The address of the OP_Goto is returned.
|
|
*/
|
|
@@ -151278,7 +165767,7 @@ static void windowIfNewPeer(
|
|
KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pOrderBy, 0, 0);
|
|
sqlite3VdbeAddOp3(v, OP_Compare, regOld, regNew, nVal);
|
|
sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO);
|
|
- sqlite3VdbeAddOp3(v, OP_Jump,
|
|
+ sqlite3VdbeAddOp3(v, OP_Jump,
|
|
sqlite3VdbeCurrentAddr(v)+1, addr, sqlite3VdbeCurrentAddr(v)+1
|
|
);
|
|
VdbeCoverageEqNe(v);
|
|
@@ -151308,11 +165797,11 @@ static void windowIfNewPeer(
|
|
** if( csr1.peerVal - regVal <= csr2.peerVal ) goto lbl;
|
|
**
|
|
** A special type of arithmetic is used such that if csr1.peerVal is not
|
|
-** a numeric type (real or integer), then the result of the addition addition
|
|
+** a numeric type (real or integer), then the result of the addition
|
|
** or subtraction is a a copy of csr1.peerVal.
|
|
*/
|
|
static void windowCodeRangeTest(
|
|
- WindowCodeArg *p,
|
|
+ WindowCodeArg *p,
|
|
int op, /* OP_Ge, OP_Gt, or OP_Le */
|
|
int csr1, /* Cursor number for cursor 1 */
|
|
int regVal, /* Register containing non-negative number */
|
|
@@ -151327,10 +165816,16 @@ static void windowCodeRangeTest(
|
|
int regString = ++pParse->nMem; /* Reg. for constant value '' */
|
|
int arith = OP_Add; /* OP_Add or OP_Subtract */
|
|
int addrGe; /* Jump destination */
|
|
+ int addrDone = sqlite3VdbeMakeLabel(pParse); /* Address past OP_Ge */
|
|
+ CollSeq *pColl;
|
|
+
|
|
+ /* Read the peer-value from each cursor into a register */
|
|
+ windowReadPeerValues(p, csr1, reg1);
|
|
+ windowReadPeerValues(p, csr2, reg2);
|
|
|
|
assert( op==OP_Ge || op==OP_Gt || op==OP_Le );
|
|
assert( pOrderBy && pOrderBy->nExpr==1 );
|
|
- if( pOrderBy->a[0].sortFlags & KEYINFO_ORDER_DESC ){
|
|
+ if( pOrderBy->a[0].fg.sortFlags & KEYINFO_ORDER_DESC ){
|
|
switch( op ){
|
|
case OP_Ge: op = OP_Le; break;
|
|
case OP_Gt: op = OP_Lt; break;
|
|
@@ -151339,36 +165834,13 @@ static void windowCodeRangeTest(
|
|
arith = OP_Subtract;
|
|
}
|
|
|
|
- /* Read the peer-value from each cursor into a register */
|
|
- windowReadPeerValues(p, csr1, reg1);
|
|
- windowReadPeerValues(p, csr2, reg2);
|
|
-
|
|
VdbeModuleComment((v, "CodeRangeTest: if( R%d %s R%d %s R%d ) goto lbl",
|
|
reg1, (arith==OP_Add ? "+" : "-"), regVal,
|
|
((op==OP_Ge) ? ">=" : (op==OP_Le) ? "<=" : (op==OP_Gt) ? ">" : "<"), reg2
|
|
));
|
|
|
|
- /* Register reg1 currently contains csr1.peerVal (the peer-value from csr1).
|
|
- ** This block adds (or subtracts for DESC) the numeric value in regVal
|
|
- ** from it. Or, if reg1 is not numeric (it is a NULL, a text value or a blob),
|
|
- ** then leave reg1 as it is. In pseudo-code, this is implemented as:
|
|
- **
|
|
- ** if( reg1>='' ) goto addrGe;
|
|
- ** reg1 = reg1 +/- regVal
|
|
- ** addrGe:
|
|
- **
|
|
- ** Since all strings and blobs are greater-than-or-equal-to an empty string,
|
|
- ** the add/subtract is skipped for these, as required. If reg1 is a NULL,
|
|
- ** then the arithmetic is performed, but since adding or subtracting from
|
|
- ** NULL is always NULL anyway, this case is handled as required too. */
|
|
- sqlite3VdbeAddOp4(v, OP_String8, 0, regString, 0, "", P4_STATIC);
|
|
- addrGe = sqlite3VdbeAddOp3(v, OP_Ge, regString, 0, reg1);
|
|
- VdbeCoverage(v);
|
|
- sqlite3VdbeAddOp3(v, arith, regVal, reg1, reg1);
|
|
- sqlite3VdbeJumpHere(v, addrGe);
|
|
-
|
|
- /* If the BIGNULL flag is set for the ORDER BY, then it is required to
|
|
- ** consider NULL values to be larger than all other values, instead of
|
|
+ /* If the BIGNULL flag is set for the ORDER BY, then it is required to
|
|
+ ** consider NULL values to be larger than all other values, instead of
|
|
** the usual smaller. The VDBE opcodes OP_Ge and so on do not handle this
|
|
** (and adding that capability causes a performance regression), so
|
|
** instead if the BIGNULL flag is set then cases where either reg1 or
|
|
@@ -151383,41 +165855,65 @@ static void windowCodeRangeTest(
|
|
** if( op==OP_Le ) goto lbl;
|
|
** }
|
|
**
|
|
- ** Additionally, if either reg1 or reg2 are NULL but the jump to lbl is
|
|
+ ** Additionally, if either reg1 or reg2 are NULL but the jump to lbl is
|
|
** not taken, control jumps over the comparison operator coded below this
|
|
** block. */
|
|
- if( pOrderBy->a[0].sortFlags & KEYINFO_ORDER_BIGNULL ){
|
|
+ if( pOrderBy->a[0].fg.sortFlags & KEYINFO_ORDER_BIGNULL ){
|
|
/* This block runs if reg1 contains a NULL. */
|
|
int addr = sqlite3VdbeAddOp1(v, OP_NotNull, reg1); VdbeCoverage(v);
|
|
switch( op ){
|
|
- case OP_Ge:
|
|
- sqlite3VdbeAddOp2(v, OP_Goto, 0, lbl);
|
|
+ case OP_Ge:
|
|
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, lbl);
|
|
break;
|
|
- case OP_Gt:
|
|
- sqlite3VdbeAddOp2(v, OP_NotNull, reg2, lbl);
|
|
- VdbeCoverage(v);
|
|
+ case OP_Gt:
|
|
+ sqlite3VdbeAddOp2(v, OP_NotNull, reg2, lbl);
|
|
+ VdbeCoverage(v);
|
|
break;
|
|
- case OP_Le:
|
|
- sqlite3VdbeAddOp2(v, OP_IsNull, reg2, lbl);
|
|
- VdbeCoverage(v);
|
|
+ case OP_Le:
|
|
+ sqlite3VdbeAddOp2(v, OP_IsNull, reg2, lbl);
|
|
+ VdbeCoverage(v);
|
|
break;
|
|
default: assert( op==OP_Lt ); /* no-op */ break;
|
|
}
|
|
- sqlite3VdbeAddOp2(v, OP_Goto, 0, sqlite3VdbeCurrentAddr(v)+3);
|
|
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, addrDone);
|
|
|
|
/* This block runs if reg1 is not NULL, but reg2 is. */
|
|
sqlite3VdbeJumpHere(v, addr);
|
|
- sqlite3VdbeAddOp2(v, OP_IsNull, reg2, lbl); VdbeCoverage(v);
|
|
- if( op==OP_Gt || op==OP_Ge ){
|
|
- sqlite3VdbeChangeP2(v, -1, sqlite3VdbeCurrentAddr(v)+1);
|
|
- }
|
|
+ sqlite3VdbeAddOp2(v, OP_IsNull, reg2,
|
|
+ (op==OP_Gt || op==OP_Ge) ? addrDone : lbl);
|
|
+ VdbeCoverage(v);
|
|
+ }
|
|
+
|
|
+ /* Register reg1 currently contains csr1.peerVal (the peer-value from csr1).
|
|
+ ** This block adds (or subtracts for DESC) the numeric value in regVal
|
|
+ ** from it. Or, if reg1 is not numeric (it is a NULL, a text value or a blob),
|
|
+ ** then leave reg1 as it is. In pseudo-code, this is implemented as:
|
|
+ **
|
|
+ ** if( reg1>='' ) goto addrGe;
|
|
+ ** reg1 = reg1 +/- regVal
|
|
+ ** addrGe:
|
|
+ **
|
|
+ ** Since all strings and blobs are greater-than-or-equal-to an empty string,
|
|
+ ** the add/subtract is skipped for these, as required. If reg1 is a NULL,
|
|
+ ** then the arithmetic is performed, but since adding or subtracting from
|
|
+ ** NULL is always NULL anyway, this case is handled as required too. */
|
|
+ sqlite3VdbeAddOp4(v, OP_String8, 0, regString, 0, "", P4_STATIC);
|
|
+ addrGe = sqlite3VdbeAddOp3(v, OP_Ge, regString, 0, reg1);
|
|
+ VdbeCoverage(v);
|
|
+ if( (op==OP_Ge && arith==OP_Add) || (op==OP_Le && arith==OP_Subtract) ){
|
|
+ sqlite3VdbeAddOp3(v, op, reg2, lbl, reg1); VdbeCoverage(v);
|
|
}
|
|
+ sqlite3VdbeAddOp3(v, arith, regVal, reg1, reg1);
|
|
+ sqlite3VdbeJumpHere(v, addrGe);
|
|
|
|
/* Compare registers reg2 and reg1, taking the jump if required. Note that
|
|
** control skips over this test if the BIGNULL flag is set and either
|
|
** reg1 or reg2 contain a NULL value. */
|
|
sqlite3VdbeAddOp3(v, op, reg2, lbl, reg1); VdbeCoverage(v);
|
|
+ pColl = sqlite3ExprNNCollSeq(pParse, pOrderBy->a[0].pExpr);
|
|
+ sqlite3VdbeAppendP4(v, (void*)pColl, P4_COLLSEQ);
|
|
sqlite3VdbeChangeP5(v, SQLITE_NULLEQ);
|
|
+ sqlite3VdbeResolveLabel(v, addrDone);
|
|
|
|
assert( op==OP_Ge || op==OP_Gt || op==OP_Lt || op==OP_Le );
|
|
testcase(op==OP_Ge); VdbeCoverageIf(v, op==OP_Ge);
|
|
@@ -151432,7 +165928,7 @@ static void windowCodeRangeTest(
|
|
|
|
/*
|
|
** Helper function for sqlite3WindowCodeStep(). Each call to this function
|
|
-** generates VM code for a single RETURN_ROW, AGGSTEP or AGGINVERSE
|
|
+** generates VM code for a single RETURN_ROW, AGGSTEP or AGGINVERSE
|
|
** operation. Refer to the header comment for sqlite3WindowCodeStep() for
|
|
** details.
|
|
*/
|
|
@@ -151491,18 +165987,26 @@ static int windowCodeOp(
|
|
addrContinue = sqlite3VdbeCurrentAddr(v);
|
|
|
|
/* If this is a (RANGE BETWEEN a FOLLOWING AND b FOLLOWING) or
|
|
- ** (RANGE BETWEEN b PRECEDING AND a PRECEDING) frame, ensure the
|
|
- ** start cursor does not advance past the end cursor within the
|
|
- ** temporary table. It otherwise might, if (a>b). */
|
|
+ ** (RANGE BETWEEN b PRECEDING AND a PRECEDING) frame, ensure the
|
|
+ ** start cursor does not advance past the end cursor within the
|
|
+ ** temporary table. It otherwise might, if (a>b). Also ensure that,
|
|
+ ** if the input cursor is still finding new rows, that the end
|
|
+ ** cursor does not go past it to EOF. */
|
|
if( pMWin->eStart==pMWin->eEnd && regCountdown
|
|
- && pMWin->eFrmType==TK_RANGE && op==WINDOW_AGGINVERSE
|
|
+ && pMWin->eFrmType==TK_RANGE
|
|
){
|
|
int regRowid1 = sqlite3GetTempReg(pParse);
|
|
int regRowid2 = sqlite3GetTempReg(pParse);
|
|
- sqlite3VdbeAddOp2(v, OP_Rowid, p->start.csr, regRowid1);
|
|
- sqlite3VdbeAddOp2(v, OP_Rowid, p->end.csr, regRowid2);
|
|
- sqlite3VdbeAddOp3(v, OP_Ge, regRowid2, lblDone, regRowid1);
|
|
- VdbeCoverage(v);
|
|
+ if( op==WINDOW_AGGINVERSE ){
|
|
+ sqlite3VdbeAddOp2(v, OP_Rowid, p->start.csr, regRowid1);
|
|
+ sqlite3VdbeAddOp2(v, OP_Rowid, p->end.csr, regRowid2);
|
|
+ sqlite3VdbeAddOp3(v, OP_Ge, regRowid2, lblDone, regRowid1);
|
|
+ VdbeCoverage(v);
|
|
+ }else if( p->regRowid ){
|
|
+ sqlite3VdbeAddOp2(v, OP_Rowid, p->end.csr, regRowid1);
|
|
+ sqlite3VdbeAddOp3(v, OP_Ge, p->regRowid, lblDone, regRowid1);
|
|
+ VdbeCoverageNeverNull(v);
|
|
+ }
|
|
sqlite3ReleaseTempReg(pParse, regRowid1);
|
|
sqlite3ReleaseTempReg(pParse, regRowid2);
|
|
assert( pMWin->eStart==TK_PRECEDING || pMWin->eStart==TK_FOLLOWING );
|
|
@@ -151585,7 +166089,7 @@ SQLITE_PRIVATE Window *sqlite3WindowDup(sqlite3 *db, Expr *pOwner, Window *p){
|
|
pNew->zName = sqlite3DbStrDup(db, p->zName);
|
|
pNew->zBase = sqlite3DbStrDup(db, p->zBase);
|
|
pNew->pFilter = sqlite3ExprDup(db, p->pFilter, 0);
|
|
- pNew->pFunc = p->pFunc;
|
|
+ pNew->pWFunc = p->pWFunc;
|
|
pNew->pPartition = sqlite3ExprListDup(db, p->pPartition, 0);
|
|
pNew->pOrderBy = sqlite3ExprListDup(db, p->pOrderBy, 0);
|
|
pNew->eFrmType = p->eFrmType;
|
|
@@ -151593,6 +166097,10 @@ SQLITE_PRIVATE Window *sqlite3WindowDup(sqlite3 *db, Expr *pOwner, Window *p){
|
|
pNew->eStart = p->eStart;
|
|
pNew->eExclude = p->eExclude;
|
|
pNew->regResult = p->regResult;
|
|
+ pNew->regAccum = p->regAccum;
|
|
+ pNew->iArgCol = p->iArgCol;
|
|
+ pNew->iEphCsr = p->iEphCsr;
|
|
+ pNew->bExprArgs = p->bExprArgs;
|
|
pNew->pStart = sqlite3ExprDup(db, p->pStart, 0);
|
|
pNew->pEnd = sqlite3ExprDup(db, p->pEnd, 0);
|
|
pNew->pOwner = pOwner;
|
|
@@ -151621,11 +166129,11 @@ SQLITE_PRIVATE Window *sqlite3WindowListDup(sqlite3 *db, Window *p){
|
|
}
|
|
|
|
/*
|
|
-** Return true if it can be determined at compile time that expression
|
|
-** pExpr evaluates to a value that, when cast to an integer, is greater
|
|
+** Return true if it can be determined at compile time that expression
|
|
+** pExpr evaluates to a value that, when cast to an integer, is greater
|
|
** than zero. False otherwise.
|
|
**
|
|
-** If an OOM error occurs, this function sets the Parse.db.mallocFailed
|
|
+** If an OOM error occurs, this function sets the Parse.db.mallocFailed
|
|
** flag and returns zero.
|
|
*/
|
|
static int windowExprGtZero(Parse *pParse, Expr *pExpr){
|
|
@@ -151641,11 +166149,11 @@ static int windowExprGtZero(Parse *pParse, Expr *pExpr){
|
|
}
|
|
|
|
/*
|
|
-** sqlite3WhereBegin() has already been called for the SELECT statement
|
|
+** sqlite3WhereBegin() has already been called for the SELECT statement
|
|
** passed as the second argument when this function is invoked. It generates
|
|
-** code to populate the Window.regResult register for each window function
|
|
+** code to populate the Window.regResult register for each window function
|
|
** and invoke the sub-routine at instruction addrGosub once for each row.
|
|
-** sqlite3WhereEnd() is always called before returning.
|
|
+** sqlite3WhereEnd() is always called before returning.
|
|
**
|
|
** This function handles several different types of window frames, which
|
|
** require slightly different processing. The following pseudo code is
|
|
@@ -151660,17 +166168,17 @@ static int windowExprGtZero(Parse *pParse, Expr *pExpr){
|
|
** Gosub flush
|
|
** }
|
|
** Insert new row into eph table.
|
|
-**
|
|
+**
|
|
** if( first row of partition ){
|
|
** // Rewind three cursors, all open on the eph table.
|
|
** Rewind(csrEnd);
|
|
** Rewind(csrStart);
|
|
** Rewind(csrCurrent);
|
|
-**
|
|
+**
|
|
** regEnd = <expr2> // FOLLOWING expression
|
|
** regStart = <expr1> // PRECEDING expression
|
|
** }else{
|
|
-** // First time this branch is taken, the eph table contains two
|
|
+** // First time this branch is taken, the eph table contains two
|
|
** // rows. The first row in the partition, which all three cursors
|
|
** // currently point to, and the following row.
|
|
** AGGSTEP
|
|
@@ -151699,17 +166207,17 @@ static int windowExprGtZero(Parse *pParse, Expr *pExpr){
|
|
** with arguments read from the current row of cursor csrEnd, then
|
|
** step cursor csrEnd forward one row (i.e. sqlite3BtreeNext()).
|
|
**
|
|
-** RETURN_ROW: return a row to the caller based on the contents of the
|
|
-** current row of csrCurrent and the current state of all
|
|
+** RETURN_ROW: return a row to the caller based on the contents of the
|
|
+** current row of csrCurrent and the current state of all
|
|
** aggregates. Then step cursor csrCurrent forward one row.
|
|
**
|
|
-** AGGINVERSE: invoke the aggregate xInverse() function for each window
|
|
+** AGGINVERSE: invoke the aggregate xInverse() function for each window
|
|
** functions with arguments read from the current row of cursor
|
|
** csrStart. Then step csrStart forward one row.
|
|
**
|
|
** There are two other ROWS window frames that are handled significantly
|
|
** differently from the above - "BETWEEN <expr> PRECEDING AND <expr> PRECEDING"
|
|
-** and "BETWEEN <expr> FOLLOWING AND <expr> FOLLOWING". These are special
|
|
+** and "BETWEEN <expr> FOLLOWING AND <expr> FOLLOWING". These are special
|
|
** cases because they change the order in which the three cursors (csrStart,
|
|
** csrCurrent and csrEnd) iterate through the ephemeral table. Cases that
|
|
** use UNBOUNDED or CURRENT ROW are much simpler variations on one of these
|
|
@@ -151859,15 +166367,15 @@ static int windowExprGtZero(Parse *pParse, Expr *pExpr){
|
|
** regEnd = <expr2>
|
|
** regStart = <expr1>
|
|
** }else if( new group ){
|
|
-** ...
|
|
+** ...
|
|
** }
|
|
** }
|
|
**
|
|
-** 2. Instead of processing a single row, each RETURN_ROW, AGGSTEP or
|
|
+** 2. Instead of processing a single row, each RETURN_ROW, AGGSTEP or
|
|
** AGGINVERSE step processes the current row of the relevant cursor and
|
|
** all subsequent rows belonging to the same group.
|
|
**
|
|
-** RANGE window frames are a little different again. As for GROUPS, the
|
|
+** RANGE window frames are a little different again. As for GROUPS, the
|
|
** main loop runs once per group only. And RETURN_ROW, AGGSTEP and AGGINVERSE
|
|
** deal in groups instead of rows. As for ROWS and GROUPS, there are three
|
|
** basic cases:
|
|
@@ -151904,7 +166412,7 @@ static int windowExprGtZero(Parse *pParse, Expr *pExpr){
|
|
** }
|
|
** }
|
|
**
|
|
-** In the above notation, "csr.key" means the current value of the ORDER BY
|
|
+** In the above notation, "csr.key" means the current value of the ORDER BY
|
|
** expression (there is only ever 1 for a RANGE that uses an <expr> FOLLOWING
|
|
** or <expr PRECEDING) read from cursor csr.
|
|
**
|
|
@@ -151995,7 +166503,6 @@ SQLITE_PRIVATE void sqlite3WindowCodeStep(
|
|
int addrEmpty; /* Address of OP_Rewind in flush: */
|
|
int regNew; /* Array of registers holding new input row */
|
|
int regRecord; /* regNew array in record form */
|
|
- int regRowid; /* Rowid for regRecord in eph table */
|
|
int regNewPeer = 0; /* Peer values for new row (part of regNew) */
|
|
int regPeer = 0; /* Peer values for current row */
|
|
int regFlushPart = 0; /* Register for "Gosub flush_partition" */
|
|
@@ -152004,11 +166511,11 @@ SQLITE_PRIVATE void sqlite3WindowCodeStep(
|
|
int regStart = 0; /* Value of <expr> PRECEDING */
|
|
int regEnd = 0; /* Value of <expr> FOLLOWING */
|
|
|
|
- assert( pMWin->eStart==TK_PRECEDING || pMWin->eStart==TK_CURRENT
|
|
- || pMWin->eStart==TK_FOLLOWING || pMWin->eStart==TK_UNBOUNDED
|
|
+ assert( pMWin->eStart==TK_PRECEDING || pMWin->eStart==TK_CURRENT
|
|
+ || pMWin->eStart==TK_FOLLOWING || pMWin->eStart==TK_UNBOUNDED
|
|
);
|
|
- assert( pMWin->eEnd==TK_FOLLOWING || pMWin->eEnd==TK_CURRENT
|
|
- || pMWin->eEnd==TK_UNBOUNDED || pMWin->eEnd==TK_PRECEDING
|
|
+ assert( pMWin->eEnd==TK_FOLLOWING || pMWin->eEnd==TK_CURRENT
|
|
+ || pMWin->eEnd==TK_UNBOUNDED || pMWin->eEnd==TK_PRECEDING
|
|
);
|
|
assert( pMWin->eExclude==0 || pMWin->eExclude==TK_CURRENT
|
|
|| pMWin->eExclude==TK_GROUP || pMWin->eExclude==TK_TIES
|
|
@@ -152030,9 +166537,9 @@ SQLITE_PRIVATE void sqlite3WindowCodeStep(
|
|
s.end.csr = s.current.csr+3;
|
|
|
|
/* Figure out when rows may be deleted from the ephemeral table. There
|
|
- ** are four options - they may never be deleted (eDelete==0), they may
|
|
+ ** are four options - they may never be deleted (eDelete==0), they may
|
|
** be deleted as soon as they are no longer part of the window frame
|
|
- ** (eDelete==WINDOW_AGGINVERSE), they may be deleted as after the row
|
|
+ ** (eDelete==WINDOW_AGGINVERSE), they may be deleted as after the row
|
|
** has been returned to the caller (WINDOW_RETURN_ROW), or they may
|
|
** be deleted after they enter the frame (WINDOW_AGGSTEP). */
|
|
switch( pMWin->eStart ){
|
|
@@ -152067,7 +166574,7 @@ SQLITE_PRIVATE void sqlite3WindowCodeStep(
|
|
regNew = pParse->nMem+1;
|
|
pParse->nMem += nInput;
|
|
regRecord = ++pParse->nMem;
|
|
- regRowid = ++pParse->nMem;
|
|
+ s.regRowid = ++pParse->nMem;
|
|
|
|
/* If the window frame contains an "<expr> PRECEDING" or "<expr> FOLLOWING"
|
|
** clause, allocate registers to store the results of evaluating each
|
|
@@ -152080,7 +166587,7 @@ SQLITE_PRIVATE void sqlite3WindowCodeStep(
|
|
}
|
|
|
|
/* If this is not a "ROWS BETWEEN ..." frame, then allocate arrays of
|
|
- ** registers to store copies of the ORDER BY expressions (peer values)
|
|
+ ** registers to store copies of the ORDER BY expressions (peer values)
|
|
** for the main loop, and for each cursor (start, current and end). */
|
|
if( pMWin->eFrmType!=TK_ROWS ){
|
|
int nPeer = (pOrderBy ? pOrderBy->nExpr : 0);
|
|
@@ -152101,7 +166608,7 @@ SQLITE_PRIVATE void sqlite3WindowCodeStep(
|
|
sqlite3VdbeAddOp3(v, OP_MakeRecord, regNew, nInput, regRecord);
|
|
|
|
/* An input row has just been read into an array of registers starting
|
|
- ** at regNew. If the window has a PARTITION clause, this block generates
|
|
+ ** at regNew. If the window has a PARTITION clause, this block generates
|
|
** VM code to check if the input row is the start of a new partition.
|
|
** If so, it does an OP_Gosub to an address to be filled in later. The
|
|
** address of the OP_Gosub is stored in local variable addrGosubFlush. */
|
|
@@ -152123,9 +166630,9 @@ SQLITE_PRIVATE void sqlite3WindowCodeStep(
|
|
}
|
|
|
|
/* Insert the new row into the ephemeral table */
|
|
- sqlite3VdbeAddOp2(v, OP_NewRowid, csrWrite, regRowid);
|
|
- sqlite3VdbeAddOp3(v, OP_Insert, csrWrite, regRecord, regRowid);
|
|
- addrNe = sqlite3VdbeAddOp3(v, OP_Ne, pMWin->regOne, 0, regRowid);
|
|
+ sqlite3VdbeAddOp2(v, OP_NewRowid, csrWrite, s.regRowid);
|
|
+ sqlite3VdbeAddOp3(v, OP_Insert, csrWrite, regRecord, s.regRowid);
|
|
+ addrNe = sqlite3VdbeAddOp3(v, OP_Ne, pMWin->regOne, 0, s.regRowid);
|
|
VdbeCoverageNeverNull(v);
|
|
|
|
/* This block is run for the first row of each partition */
|
|
@@ -152146,8 +166653,7 @@ SQLITE_PRIVATE void sqlite3WindowCodeStep(
|
|
VdbeCoverageNeverNullIf(v, op==OP_Ge); /* NeverNull because bound <expr> */
|
|
VdbeCoverageNeverNullIf(v, op==OP_Le); /* values previously checked */
|
|
windowAggFinal(&s, 0);
|
|
- sqlite3VdbeAddOp2(v, OP_Rewind, s.current.csr, 1);
|
|
- VdbeCoverageNeverTaken(v);
|
|
+ sqlite3VdbeAddOp1(v, OP_Rewind, s.current.csr);
|
|
windowReturnOneRow(&s);
|
|
sqlite3VdbeAddOp1(v, OP_ResetSorter, s.current.csr);
|
|
sqlite3VdbeAddOp2(v, OP_Goto, 0, lblWhereEnd);
|
|
@@ -152159,13 +166665,10 @@ SQLITE_PRIVATE void sqlite3WindowCodeStep(
|
|
}
|
|
|
|
if( pMWin->eStart!=TK_UNBOUNDED ){
|
|
- sqlite3VdbeAddOp2(v, OP_Rewind, s.start.csr, 1);
|
|
- VdbeCoverageNeverTaken(v);
|
|
+ sqlite3VdbeAddOp1(v, OP_Rewind, s.start.csr);
|
|
}
|
|
- sqlite3VdbeAddOp2(v, OP_Rewind, s.current.csr, 1);
|
|
- VdbeCoverageNeverTaken(v);
|
|
- sqlite3VdbeAddOp2(v, OP_Rewind, s.end.csr, 1);
|
|
- VdbeCoverageNeverTaken(v);
|
|
+ sqlite3VdbeAddOp1(v, OP_Rewind, s.current.csr);
|
|
+ sqlite3VdbeAddOp1(v, OP_Rewind, s.end.csr);
|
|
if( regPeer && pOrderBy ){
|
|
sqlite3VdbeAddOp3(v, OP_Copy, regNewPeer, regPeer, pOrderBy->nExpr-1);
|
|
sqlite3VdbeAddOp3(v, OP_Copy, regPeer, s.start.reg, pOrderBy->nExpr-1);
|
|
@@ -152243,6 +166746,7 @@ SQLITE_PRIVATE void sqlite3WindowCodeStep(
|
|
sqlite3VdbeJumpHere(v, addrGosubFlush);
|
|
}
|
|
|
|
+ s.regRowid = 0;
|
|
addrEmpty = sqlite3VdbeAddOp1(v, OP_Rewind, csrWrite);
|
|
VdbeCoverage(v);
|
|
if( pMWin->eEnd==TK_PRECEDING ){
|
|
@@ -152305,8 +166809,10 @@ 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". */
|
|
/*
|
|
-** 2000-05-29
|
|
+** 2001-09-15
|
|
**
|
|
** The author disclaims copyright to this source code. In place of
|
|
** a legal notice, here is a blessing:
|
|
@@ -152316,22 +166822,15 @@ SQLITE_PRIVATE void sqlite3WindowCodeStep(
|
|
** May you share freely, never taking more than you give.
|
|
**
|
|
*************************************************************************
|
|
-** Driver template for the LEMON parser generator.
|
|
-**
|
|
-** The "lemon" program processes an LALR(1) input grammar file, then uses
|
|
-** this template to construct a parser. The "lemon" program inserts text
|
|
-** at each "%%" line. Also, any "P-a-r-s-e" identifer prefix (without the
|
|
-** interstitial "-" characters) contained in this template is changed into
|
|
-** the value of the %name directive from the grammar. Otherwise, the content
|
|
-** of this template is copied straight through into the generate parser
|
|
-** source file.
|
|
+** This file contains SQLite's SQL parser.
|
|
**
|
|
-** The following is the concatenation of all %include directives from the
|
|
-** input grammar file:
|
|
+** 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
|
|
+** this comment as part of the translated C-code. Edits should be made
|
|
+** to the original parse.y sources.
|
|
*/
|
|
-/* #include <stdio.h> */
|
|
-/* #include <assert.h> */
|
|
-/************ Begin %include sections from the grammar ************************/
|
|
|
|
/* #include "sqliteInt.h" */
|
|
|
|
@@ -152394,6 +166893,27 @@ static void disableLookaside(Parse *pParse){
|
|
DisableLookaside;
|
|
}
|
|
|
|
+#if !defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) \
|
|
+ && defined(SQLITE_UDL_CAPABLE_PARSER)
|
|
+/*
|
|
+** Issue an error message if an ORDER BY or LIMIT clause occurs on an
|
|
+** UPDATE or DELETE statement.
|
|
+*/
|
|
+static void updateDeleteLimitError(
|
|
+ Parse *pParse,
|
|
+ ExprList *pOrderBy,
|
|
+ Expr *pLimit
|
|
+){
|
|
+ if( pOrderBy ){
|
|
+ sqlite3ErrorMsg(pParse, "syntax error near \"ORDER BY\"");
|
|
+ }else{
|
|
+ sqlite3ErrorMsg(pParse, "syntax error near \"LIMIT\"");
|
|
+ }
|
|
+ sqlite3ExprListDelete(pParse->db, pOrderBy);
|
|
+ sqlite3ExprDelete(pParse->db, pLimit);
|
|
+}
|
|
+#endif /* SQLITE_ENABLE_UPDATE_DELETE_LIMIT */
|
|
+
|
|
|
|
/*
|
|
** For a compound SELECT statement, make sure p->pPrior->pNext==p for
|
|
@@ -152403,13 +166923,23 @@ static void disableLookaside(Parse *pParse){
|
|
static void parserDoubleLinkSelect(Parse *pParse, Select *p){
|
|
assert( p!=0 );
|
|
if( p->pPrior ){
|
|
- Select *pNext = 0, *pLoop;
|
|
- int mxSelect, cnt = 0;
|
|
- for(pLoop=p; pLoop; pNext=pLoop, pLoop=pLoop->pPrior, cnt++){
|
|
+ Select *pNext = 0, *pLoop = p;
|
|
+ int mxSelect, cnt = 1;
|
|
+ while(1){
|
|
pLoop->pNext = pNext;
|
|
pLoop->selFlags |= SF_Compound;
|
|
+ pNext = pLoop;
|
|
+ pLoop = pLoop->pPrior;
|
|
+ if( pLoop==0 ) break;
|
|
+ cnt++;
|
|
+ if( pLoop->pOrderBy || pLoop->pLimit ){
|
|
+ sqlite3ErrorMsg(pParse,"%s clause should come after %s not before",
|
|
+ pLoop->pOrderBy!=0 ? "ORDER BY" : "LIMIT",
|
|
+ sqlite3SelectOpName(pNext->op));
|
|
+ break;
|
|
+ }
|
|
}
|
|
- if( (p->selFlags & SF_MultiValue)==0 &&
|
|
+ if( (p->selFlags & SF_MultiValue)==0 &&
|
|
(mxSelect = pParse->db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT])>0 &&
|
|
cnt>mxSelect
|
|
){
|
|
@@ -152418,11 +166948,21 @@ static void disableLookaside(Parse *pParse){
|
|
}
|
|
}
|
|
|
|
-
|
|
- /* Construct a new Expr object from a single identifier. Use the
|
|
- ** new Expr to populate pOut. Set the span of pOut to be the identifier
|
|
- ** that created the expression.
|
|
+ /* Attach a With object describing the WITH clause to a Select
|
|
+ ** object describing the query for which the WITH clause is a prefix.
|
|
*/
|
|
+ static Select *attachWithToSelect(Parse *pParse, Select *pSelect, With *pWith){
|
|
+ if( pSelect ){
|
|
+ pSelect->pWith = pWith;
|
|
+ parserDoubleLinkSelect(pParse, pSelect);
|
|
+ }else{
|
|
+ sqlite3WithDelete(pParse->db, pWith);
|
|
+ }
|
|
+ return pSelect;
|
|
+ }
|
|
+
|
|
+
|
|
+ /* Construct a new Expr object from a single token */
|
|
static Expr *tokenExpr(Parse *pParse, int op, Token t){
|
|
Expr *p = sqlite3DbMallocRawNN(pParse->db, sizeof(Expr)+t.n+1);
|
|
if( p ){
|
|
@@ -152430,23 +166970,25 @@ static void disableLookaside(Parse *pParse){
|
|
p->op = (u8)op;
|
|
p->affExpr = 0;
|
|
p->flags = EP_Leaf;
|
|
- p->iAgg = -1;
|
|
+ ExprClearVVAProperties(p);
|
|
+ /* p->iAgg = -1; // Not required */
|
|
p->pLeft = p->pRight = 0;
|
|
- p->x.pList = 0;
|
|
p->pAggInfo = 0;
|
|
- p->y.pTab = 0;
|
|
+ memset(&p->x, 0, sizeof(p->x));
|
|
+ memset(&p->y, 0, sizeof(p->y));
|
|
p->op2 = 0;
|
|
p->iTable = 0;
|
|
p->iColumn = 0;
|
|
p->u.zToken = (char*)&p[1];
|
|
memcpy(p->u.zToken, t.z, t.n);
|
|
p->u.zToken[t.n] = 0;
|
|
+ p->w.iOfst = (int)(t.z - pParse->zTail);
|
|
if( sqlite3Isquote(p->u.zToken[0]) ){
|
|
sqlite3DequoteExpr(p);
|
|
}
|
|
#if SQLITE_MAX_EXPR_DEPTH>0
|
|
p->nHeight = 1;
|
|
-#endif
|
|
+#endif
|
|
if( IN_RENAME_OBJECT ){
|
|
return (Expr*)sqlite3RenameTokenMap(pParse, (void*)p, &t);
|
|
}
|
|
@@ -152493,11 +167035,195 @@ static void disableLookaside(Parse *pParse){
|
|
# error too many tokens in the grammar
|
|
#endif
|
|
/**************** End of %include directives **********************************/
|
|
-/* These constants specify the various numeric values for terminal symbols
|
|
-** in a format understandable to "makeheaders". This section is blank unless
|
|
-** "lemon" is run with the "-m" command-line option.
|
|
-***************** Begin makeheaders token definitions *************************/
|
|
-/**************** End makeheaders token definitions ***************************/
|
|
+/* These constants specify the various numeric values for terminal symbols.
|
|
+***************** Begin token definitions *************************************/
|
|
+#ifndef TK_SEMI
|
|
+#define TK_SEMI 1
|
|
+#define TK_EXPLAIN 2
|
|
+#define TK_QUERY 3
|
|
+#define TK_PLAN 4
|
|
+#define TK_BEGIN 5
|
|
+#define TK_TRANSACTION 6
|
|
+#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_ABORT 27
|
|
+#define TK_ACTION 28
|
|
+#define TK_AFTER 29
|
|
+#define TK_ANALYZE 30
|
|
+#define TK_ASC 31
|
|
+#define TK_ATTACH 32
|
|
+#define TK_BEFORE 33
|
|
+#define TK_BY 34
|
|
+#define TK_CASCADE 35
|
|
+#define TK_CAST 36
|
|
+#define TK_CONFLICT 37
|
|
+#define TK_DATABASE 38
|
|
+#define TK_DESC 39
|
|
+#define TK_DETACH 40
|
|
+#define TK_EACH 41
|
|
+#define TK_FAIL 42
|
|
+#define TK_OR 43
|
|
+#define TK_AND 44
|
|
+#define TK_IS 45
|
|
+#define TK_MATCH 46
|
|
+#define TK_LIKE_KW 47
|
|
+#define TK_BETWEEN 48
|
|
+#define TK_IN 49
|
|
+#define TK_ISNULL 50
|
|
+#define TK_NOTNULL 51
|
|
+#define TK_NE 52
|
|
+#define TK_EQ 53
|
|
+#define TK_GT 54
|
|
+#define TK_LE 55
|
|
+#define TK_LT 56
|
|
+#define TK_GE 57
|
|
+#define TK_ESCAPE 58
|
|
+#define TK_ID 59
|
|
+#define TK_COLUMNKW 60
|
|
+#define TK_DO 61
|
|
+#define TK_FOR 62
|
|
+#define TK_IGNORE 63
|
|
+#define TK_INITIALLY 64
|
|
+#define TK_INSTEAD 65
|
|
+#define TK_NO 66
|
|
+#define TK_KEY 67
|
|
+#define TK_OF 68
|
|
+#define TK_OFFSET 69
|
|
+#define TK_PRAGMA 70
|
|
+#define TK_RAISE 71
|
|
+#define TK_RECURSIVE 72
|
|
+#define TK_REPLACE 73
|
|
+#define TK_RESTRICT 74
|
|
+#define TK_ROW 75
|
|
+#define TK_ROWS 76
|
|
+#define TK_TRIGGER 77
|
|
+#define TK_VACUUM 78
|
|
+#define TK_VIEW 79
|
|
+#define TK_VIRTUAL 80
|
|
+#define TK_WITH 81
|
|
+#define TK_NULLS 82
|
|
+#define TK_FIRST 83
|
|
+#define TK_LAST 84
|
|
+#define TK_CURRENT 85
|
|
+#define TK_FOLLOWING 86
|
|
+#define TK_PARTITION 87
|
|
+#define TK_PRECEDING 88
|
|
+#define TK_RANGE 89
|
|
+#define TK_UNBOUNDED 90
|
|
+#define TK_EXCLUDE 91
|
|
+#define TK_GROUPS 92
|
|
+#define TK_OTHERS 93
|
|
+#define TK_TIES 94
|
|
+#define TK_GENERATED 95
|
|
+#define TK_ALWAYS 96
|
|
+#define TK_MATERIALIZED 97
|
|
+#define TK_REINDEX 98
|
|
+#define TK_RENAME 99
|
|
+#define TK_CTIME_KW 100
|
|
+#define TK_ANY 101
|
|
+#define TK_BITAND 102
|
|
+#define TK_BITOR 103
|
|
+#define TK_LSHIFT 104
|
|
+#define TK_RSHIFT 105
|
|
+#define TK_PLUS 106
|
|
+#define TK_MINUS 107
|
|
+#define TK_STAR 108
|
|
+#define TK_SLASH 109
|
|
+#define TK_REM 110
|
|
+#define TK_CONCAT 111
|
|
+#define TK_PTR 112
|
|
+#define TK_COLLATE 113
|
|
+#define TK_BITNOT 114
|
|
+#define TK_ON 115
|
|
+#define TK_INDEXED 116
|
|
+#define TK_STRING 117
|
|
+#define TK_JOIN_KW 118
|
|
+#define TK_CONSTRAINT 119
|
|
+#define TK_DEFAULT 120
|
|
+#define TK_NULL 121
|
|
+#define TK_PRIMARY 122
|
|
+#define TK_UNIQUE 123
|
|
+#define TK_CHECK 124
|
|
+#define TK_REFERENCES 125
|
|
+#define TK_AUTOINCR 126
|
|
+#define TK_INSERT 127
|
|
+#define TK_DELETE 128
|
|
+#define TK_UPDATE 129
|
|
+#define TK_SET 130
|
|
+#define TK_DEFERRABLE 131
|
|
+#define TK_FOREIGN 132
|
|
+#define TK_DROP 133
|
|
+#define TK_UNION 134
|
|
+#define TK_ALL 135
|
|
+#define TK_EXCEPT 136
|
|
+#define TK_INTERSECT 137
|
|
+#define TK_SELECT 138
|
|
+#define TK_VALUES 139
|
|
+#define TK_DISTINCT 140
|
|
+#define TK_DOT 141
|
|
+#define TK_FROM 142
|
|
+#define TK_JOIN 143
|
|
+#define TK_USING 144
|
|
+#define TK_ORDER 145
|
|
+#define TK_GROUP 146
|
|
+#define TK_HAVING 147
|
|
+#define TK_LIMIT 148
|
|
+#define TK_WHERE 149
|
|
+#define TK_RETURNING 150
|
|
+#define TK_INTO 151
|
|
+#define TK_NOTHING 152
|
|
+#define TK_FLOAT 153
|
|
+#define TK_BLOB 154
|
|
+#define TK_INTEGER 155
|
|
+#define TK_VARIABLE 156
|
|
+#define TK_CASE 157
|
|
+#define TK_WHEN 158
|
|
+#define TK_THEN 159
|
|
+#define TK_ELSE 160
|
|
+#define TK_INDEX 161
|
|
+#define TK_ALTER 162
|
|
+#define TK_ADD 163
|
|
+#define TK_WINDOW 164
|
|
+#define TK_OVER 165
|
|
+#define TK_FILTER 166
|
|
+#define TK_COLUMN 167
|
|
+#define TK_AGG_FUNCTION 168
|
|
+#define TK_AGG_COLUMN 169
|
|
+#define TK_TRUEFALSE 170
|
|
+#define TK_ISNOT 171
|
|
+#define TK_FUNCTION 172
|
|
+#define TK_UMINUS 173
|
|
+#define TK_UPLUS 174
|
|
+#define TK_TRUTH 175
|
|
+#define TK_REGISTER 176
|
|
+#define TK_VECTOR 177
|
|
+#define TK_SELECT_COLUMN 178
|
|
+#define TK_IF_NULL_ROW 179
|
|
+#define TK_ASTERISK 180
|
|
+#define TK_SPAN 181
|
|
+#define TK_ERROR 182
|
|
+#define TK_SPACE 183
|
|
+#define TK_ILLEGAL 184
|
|
+#endif
|
|
+/**************** End token definitions ***************************************/
|
|
|
|
/* The next sections is a series of control #defines.
|
|
** various aspects of the generated parser.
|
|
@@ -152522,7 +167248,7 @@ static void disableLookaside(Parse *pParse){
|
|
** the minor type might be the name of the identifier.
|
|
** Each non-terminal can have a different minor type.
|
|
** Terminal symbols all have the same minor type, though.
|
|
-** This macros defines the minor type for terminal
|
|
+** This macros defines the minor type for terminal
|
|
** symbols.
|
|
** YYMINORTYPE is the data type used for all minor types.
|
|
** This is typically a union of many types, one of
|
|
@@ -152555,28 +167281,31 @@ static void disableLookaside(Parse *pParse){
|
|
#endif
|
|
/************* Begin control #defines *****************************************/
|
|
#define YYCODETYPE unsigned short int
|
|
-#define YYNOCODE 310
|
|
+#define YYNOCODE 319
|
|
#define YYACTIONTYPE unsigned short int
|
|
-#define YYWILDCARD 100
|
|
+#define YYWILDCARD 101
|
|
#define sqlite3ParserTOKENTYPE Token
|
|
typedef union {
|
|
int yyinit;
|
|
sqlite3ParserTOKENTYPE yy0;
|
|
- SrcList* yy47;
|
|
- u8 yy58;
|
|
- struct FrameBound yy77;
|
|
- With* yy131;
|
|
- int yy192;
|
|
- Expr* yy202;
|
|
- struct {int value; int mask;} yy207;
|
|
- struct TrigEvent yy230;
|
|
- ExprList* yy242;
|
|
- Window* yy303;
|
|
- Upsert* yy318;
|
|
- const char* yy436;
|
|
- TriggerStep* yy447;
|
|
- Select* yy539;
|
|
- IdList* yy600;
|
|
+ TriggerStep* yy33;
|
|
+ Window* yy41;
|
|
+ Select* yy47;
|
|
+ SrcList* yy131;
|
|
+ struct TrigEvent yy180;
|
|
+ struct {int value; int mask;} yy231;
|
|
+ IdList* yy254;
|
|
+ u32 yy285;
|
|
+ ExprList* yy322;
|
|
+ Cte* yy385;
|
|
+ int yy394;
|
|
+ Upsert* yy444;
|
|
+ u8 yy516;
|
|
+ With* yy521;
|
|
+ const char* yy522;
|
|
+ Expr* yy528;
|
|
+ OnOrUsing yy561;
|
|
+ struct FrameBound yy595;
|
|
} YYMINORTYPE;
|
|
#ifndef YYSTACKDEPTH
|
|
#define YYSTACKDEPTH 100
|
|
@@ -152592,18 +167321,18 @@ typedef union {
|
|
#define sqlite3ParserCTX_FETCH Parse *pParse=yypParser->pParse;
|
|
#define sqlite3ParserCTX_STORE yypParser->pParse=pParse;
|
|
#define YYFALLBACK 1
|
|
-#define YYNSTATE 551
|
|
-#define YYNRULE 385
|
|
-#define YYNRULE_WITH_ACTION 325
|
|
-#define YYNTOKEN 181
|
|
-#define YY_MAX_SHIFT 550
|
|
-#define YY_MIN_SHIFTREDUCE 801
|
|
-#define YY_MAX_SHIFTREDUCE 1185
|
|
-#define YY_ERROR_ACTION 1186
|
|
-#define YY_ACCEPT_ACTION 1187
|
|
-#define YY_NO_ACTION 1188
|
|
-#define YY_MIN_REDUCE 1189
|
|
-#define YY_MAX_REDUCE 1573
|
|
+#define YYNSTATE 576
|
|
+#define YYNRULE 405
|
|
+#define YYNRULE_WITH_ACTION 342
|
|
+#define YYNTOKEN 185
|
|
+#define YY_MAX_SHIFT 575
|
|
+#define YY_MIN_SHIFTREDUCE 835
|
|
+#define YY_MAX_SHIFTREDUCE 1239
|
|
+#define YY_ERROR_ACTION 1240
|
|
+#define YY_ACCEPT_ACTION 1241
|
|
+#define YY_NO_ACTION 1242
|
|
+#define YY_MIN_REDUCE 1243
|
|
+#define YY_MAX_REDUCE 1647
|
|
/************* End control #defines *******************************************/
|
|
#define YY_NLOOKAHEAD ((int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0])))
|
|
|
|
@@ -152623,7 +167352,7 @@ typedef union {
|
|
/* Next are the tables used to determine what action to take based on the
|
|
** current state and lookahead token. These tables are used to implement
|
|
** functions that take a state number and lookahead value and return an
|
|
-** action integer.
|
|
+** action integer.
|
|
**
|
|
** Suppose the action integer is N. Then the action is determined as
|
|
** follows
|
|
@@ -152670,589 +167399,624 @@ typedef union {
|
|
** yy_default[] Default action for each state.
|
|
**
|
|
*********** Begin parsing tables **********************************************/
|
|
-#define YY_ACTTAB_COUNT (1958)
|
|
+#define YY_ACTTAB_COUNT (2098)
|
|
static const YYACTIONTYPE yy_action[] = {
|
|
- /* 0 */ 544, 1220, 544, 449, 1258, 544, 1237, 544, 114, 111,
|
|
- /* 10 */ 211, 544, 1535, 544, 1258, 521, 114, 111, 211, 390,
|
|
- /* 20 */ 1230, 342, 42, 42, 42, 42, 1223, 42, 42, 71,
|
|
- /* 30 */ 71, 935, 1222, 71, 71, 71, 71, 1460, 1491, 936,
|
|
- /* 40 */ 818, 451, 6, 121, 122, 112, 1163, 1163, 1004, 1007,
|
|
- /* 50 */ 997, 997, 119, 119, 120, 120, 120, 120, 1541, 390,
|
|
- /* 60 */ 1356, 1515, 550, 2, 1191, 194, 526, 434, 143, 291,
|
|
- /* 70 */ 526, 136, 526, 369, 261, 502, 272, 383, 1271, 525,
|
|
- /* 80 */ 501, 491, 164, 121, 122, 112, 1163, 1163, 1004, 1007,
|
|
- /* 90 */ 997, 997, 119, 119, 120, 120, 120, 120, 1356, 440,
|
|
- /* 100 */ 1512, 118, 118, 118, 118, 117, 117, 116, 116, 116,
|
|
- /* 110 */ 115, 422, 266, 266, 266, 266, 1496, 356, 1498, 433,
|
|
- /* 120 */ 355, 1496, 515, 522, 1483, 541, 1112, 541, 1112, 390,
|
|
- /* 130 */ 403, 241, 208, 114, 111, 211, 98, 290, 535, 221,
|
|
- /* 140 */ 1027, 118, 118, 118, 118, 117, 117, 116, 116, 116,
|
|
- /* 150 */ 115, 422, 1140, 121, 122, 112, 1163, 1163, 1004, 1007,
|
|
- /* 160 */ 997, 997, 119, 119, 120, 120, 120, 120, 404, 426,
|
|
- /* 170 */ 117, 117, 116, 116, 116, 115, 422, 1416, 466, 123,
|
|
- /* 180 */ 118, 118, 118, 118, 117, 117, 116, 116, 116, 115,
|
|
- /* 190 */ 422, 116, 116, 116, 115, 422, 538, 538, 538, 390,
|
|
- /* 200 */ 503, 120, 120, 120, 120, 113, 1049, 1140, 1141, 1142,
|
|
- /* 210 */ 1049, 118, 118, 118, 118, 117, 117, 116, 116, 116,
|
|
- /* 220 */ 115, 422, 1459, 121, 122, 112, 1163, 1163, 1004, 1007,
|
|
- /* 230 */ 997, 997, 119, 119, 120, 120, 120, 120, 390, 442,
|
|
- /* 240 */ 314, 83, 461, 81, 357, 380, 1140, 80, 118, 118,
|
|
- /* 250 */ 118, 118, 117, 117, 116, 116, 116, 115, 422, 179,
|
|
- /* 260 */ 432, 422, 121, 122, 112, 1163, 1163, 1004, 1007, 997,
|
|
- /* 270 */ 997, 119, 119, 120, 120, 120, 120, 432, 431, 266,
|
|
- /* 280 */ 266, 118, 118, 118, 118, 117, 117, 116, 116, 116,
|
|
- /* 290 */ 115, 422, 541, 1107, 901, 504, 1140, 114, 111, 211,
|
|
- /* 300 */ 1429, 1140, 1141, 1142, 206, 489, 1107, 390, 447, 1107,
|
|
- /* 310 */ 543, 328, 120, 120, 120, 120, 298, 1429, 1431, 17,
|
|
- /* 320 */ 118, 118, 118, 118, 117, 117, 116, 116, 116, 115,
|
|
- /* 330 */ 422, 121, 122, 112, 1163, 1163, 1004, 1007, 997, 997,
|
|
- /* 340 */ 119, 119, 120, 120, 120, 120, 390, 1356, 432, 1140,
|
|
- /* 350 */ 480, 1140, 1141, 1142, 994, 994, 1005, 1008, 443, 118,
|
|
- /* 360 */ 118, 118, 118, 117, 117, 116, 116, 116, 115, 422,
|
|
- /* 370 */ 121, 122, 112, 1163, 1163, 1004, 1007, 997, 997, 119,
|
|
- /* 380 */ 119, 120, 120, 120, 120, 1052, 1052, 463, 1429, 118,
|
|
- /* 390 */ 118, 118, 118, 117, 117, 116, 116, 116, 115, 422,
|
|
- /* 400 */ 1140, 449, 544, 1424, 1140, 1141, 1142, 233, 964, 1140,
|
|
- /* 410 */ 479, 476, 475, 171, 358, 390, 164, 405, 412, 840,
|
|
- /* 420 */ 474, 164, 185, 332, 71, 71, 1241, 998, 118, 118,
|
|
- /* 430 */ 118, 118, 117, 117, 116, 116, 116, 115, 422, 121,
|
|
- /* 440 */ 122, 112, 1163, 1163, 1004, 1007, 997, 997, 119, 119,
|
|
- /* 450 */ 120, 120, 120, 120, 390, 1140, 1141, 1142, 833, 12,
|
|
- /* 460 */ 313, 507, 163, 354, 1140, 1141, 1142, 114, 111, 211,
|
|
- /* 470 */ 506, 290, 535, 544, 276, 180, 290, 535, 121, 122,
|
|
- /* 480 */ 112, 1163, 1163, 1004, 1007, 997, 997, 119, 119, 120,
|
|
- /* 490 */ 120, 120, 120, 343, 482, 71, 71, 118, 118, 118,
|
|
- /* 500 */ 118, 117, 117, 116, 116, 116, 115, 422, 1140, 209,
|
|
- /* 510 */ 409, 521, 1140, 1107, 1569, 376, 252, 269, 340, 485,
|
|
- /* 520 */ 335, 484, 238, 390, 511, 362, 1107, 1125, 331, 1107,
|
|
- /* 530 */ 191, 407, 286, 32, 455, 441, 118, 118, 118, 118,
|
|
- /* 540 */ 117, 117, 116, 116, 116, 115, 422, 121, 122, 112,
|
|
- /* 550 */ 1163, 1163, 1004, 1007, 997, 997, 119, 119, 120, 120,
|
|
- /* 560 */ 120, 120, 390, 1140, 1141, 1142, 985, 1140, 1141, 1142,
|
|
- /* 570 */ 1140, 233, 490, 1490, 479, 476, 475, 6, 163, 544,
|
|
- /* 580 */ 510, 544, 115, 422, 474, 5, 121, 122, 112, 1163,
|
|
- /* 590 */ 1163, 1004, 1007, 997, 997, 119, 119, 120, 120, 120,
|
|
- /* 600 */ 120, 13, 13, 13, 13, 118, 118, 118, 118, 117,
|
|
- /* 610 */ 117, 116, 116, 116, 115, 422, 401, 500, 406, 544,
|
|
- /* 620 */ 1484, 542, 1140, 890, 890, 1140, 1141, 1142, 1471, 1140,
|
|
- /* 630 */ 275, 390, 806, 807, 808, 969, 420, 420, 420, 16,
|
|
- /* 640 */ 16, 55, 55, 1240, 118, 118, 118, 118, 117, 117,
|
|
- /* 650 */ 116, 116, 116, 115, 422, 121, 122, 112, 1163, 1163,
|
|
- /* 660 */ 1004, 1007, 997, 997, 119, 119, 120, 120, 120, 120,
|
|
- /* 670 */ 390, 1187, 1, 1, 550, 2, 1191, 1140, 1141, 1142,
|
|
- /* 680 */ 194, 291, 896, 136, 1140, 1141, 1142, 895, 519, 1490,
|
|
- /* 690 */ 1271, 3, 378, 6, 121, 122, 112, 1163, 1163, 1004,
|
|
- /* 700 */ 1007, 997, 997, 119, 119, 120, 120, 120, 120, 856,
|
|
- /* 710 */ 544, 922, 544, 118, 118, 118, 118, 117, 117, 116,
|
|
- /* 720 */ 116, 116, 115, 422, 266, 266, 1090, 1567, 1140, 549,
|
|
- /* 730 */ 1567, 1191, 13, 13, 13, 13, 291, 541, 136, 390,
|
|
- /* 740 */ 483, 419, 418, 964, 342, 1271, 466, 408, 857, 279,
|
|
- /* 750 */ 140, 221, 118, 118, 118, 118, 117, 117, 116, 116,
|
|
- /* 760 */ 116, 115, 422, 121, 122, 112, 1163, 1163, 1004, 1007,
|
|
- /* 770 */ 997, 997, 119, 119, 120, 120, 120, 120, 544, 266,
|
|
- /* 780 */ 266, 426, 390, 1140, 1141, 1142, 1170, 828, 1170, 466,
|
|
- /* 790 */ 429, 145, 541, 1144, 399, 313, 437, 301, 836, 1488,
|
|
- /* 800 */ 71, 71, 410, 6, 1088, 471, 221, 100, 112, 1163,
|
|
- /* 810 */ 1163, 1004, 1007, 997, 997, 119, 119, 120, 120, 120,
|
|
- /* 820 */ 120, 118, 118, 118, 118, 117, 117, 116, 116, 116,
|
|
- /* 830 */ 115, 422, 237, 1423, 544, 449, 426, 287, 984, 544,
|
|
- /* 840 */ 236, 235, 234, 828, 97, 527, 427, 1263, 1263, 1144,
|
|
- /* 850 */ 492, 306, 428, 836, 975, 544, 71, 71, 974, 1239,
|
|
- /* 860 */ 544, 51, 51, 300, 118, 118, 118, 118, 117, 117,
|
|
- /* 870 */ 116, 116, 116, 115, 422, 194, 103, 70, 70, 266,
|
|
- /* 880 */ 266, 544, 71, 71, 266, 266, 30, 389, 342, 974,
|
|
- /* 890 */ 974, 976, 541, 526, 1107, 326, 390, 541, 493, 395,
|
|
- /* 900 */ 1468, 195, 528, 13, 13, 1356, 240, 1107, 277, 280,
|
|
- /* 910 */ 1107, 280, 303, 455, 305, 331, 390, 31, 188, 417,
|
|
- /* 920 */ 121, 122, 112, 1163, 1163, 1004, 1007, 997, 997, 119,
|
|
- /* 930 */ 119, 120, 120, 120, 120, 142, 390, 363, 455, 984,
|
|
- /* 940 */ 121, 122, 112, 1163, 1163, 1004, 1007, 997, 997, 119,
|
|
- /* 950 */ 119, 120, 120, 120, 120, 975, 321, 1140, 324, 974,
|
|
- /* 960 */ 121, 110, 112, 1163, 1163, 1004, 1007, 997, 997, 119,
|
|
- /* 970 */ 119, 120, 120, 120, 120, 462, 375, 1183, 118, 118,
|
|
- /* 980 */ 118, 118, 117, 117, 116, 116, 116, 115, 422, 1140,
|
|
- /* 990 */ 974, 974, 976, 304, 9, 364, 244, 360, 118, 118,
|
|
- /* 1000 */ 118, 118, 117, 117, 116, 116, 116, 115, 422, 312,
|
|
- /* 1010 */ 544, 342, 1140, 1141, 1142, 299, 290, 535, 118, 118,
|
|
- /* 1020 */ 118, 118, 117, 117, 116, 116, 116, 115, 422, 1261,
|
|
- /* 1030 */ 1261, 1161, 13, 13, 278, 419, 418, 466, 390, 921,
|
|
- /* 1040 */ 260, 260, 289, 1167, 1140, 1141, 1142, 189, 1169, 266,
|
|
- /* 1050 */ 266, 466, 388, 541, 1184, 544, 1168, 263, 144, 487,
|
|
- /* 1060 */ 920, 544, 541, 122, 112, 1163, 1163, 1004, 1007, 997,
|
|
- /* 1070 */ 997, 119, 119, 120, 120, 120, 120, 71, 71, 1140,
|
|
- /* 1080 */ 1170, 1270, 1170, 13, 13, 896, 1068, 1161, 544, 466,
|
|
- /* 1090 */ 895, 107, 536, 1489, 4, 1266, 1107, 6, 523, 1047,
|
|
- /* 1100 */ 12, 1069, 1090, 1568, 311, 453, 1568, 518, 539, 1107,
|
|
- /* 1110 */ 56, 56, 1107, 1487, 421, 1356, 1070, 6, 343, 285,
|
|
- /* 1120 */ 118, 118, 118, 118, 117, 117, 116, 116, 116, 115,
|
|
- /* 1130 */ 422, 423, 1269, 319, 1140, 1141, 1142, 876, 266, 266,
|
|
- /* 1140 */ 1275, 107, 536, 533, 4, 1486, 293, 877, 1209, 6,
|
|
- /* 1150 */ 210, 541, 541, 164, 1540, 494, 414, 865, 539, 267,
|
|
- /* 1160 */ 267, 1212, 396, 509, 497, 204, 266, 266, 394, 529,
|
|
- /* 1170 */ 8, 984, 541, 517, 544, 920, 456, 105, 105, 541,
|
|
- /* 1180 */ 1088, 423, 266, 266, 106, 415, 423, 546, 545, 266,
|
|
- /* 1190 */ 266, 974, 516, 533, 1371, 541, 15, 15, 266, 266,
|
|
- /* 1200 */ 454, 1118, 541, 266, 266, 1068, 1370, 513, 290, 535,
|
|
- /* 1210 */ 544, 541, 512, 97, 442, 314, 541, 544, 920, 125,
|
|
- /* 1220 */ 1069, 984, 974, 974, 976, 977, 27, 105, 105, 399,
|
|
- /* 1230 */ 341, 1509, 44, 44, 106, 1070, 423, 546, 545, 57,
|
|
- /* 1240 */ 57, 974, 341, 1509, 107, 536, 544, 4, 460, 399,
|
|
- /* 1250 */ 214, 1118, 457, 294, 375, 1089, 532, 297, 544, 537,
|
|
- /* 1260 */ 396, 539, 290, 535, 104, 244, 102, 524, 58, 58,
|
|
- /* 1270 */ 544, 109, 974, 974, 976, 977, 27, 1514, 1129, 425,
|
|
- /* 1280 */ 59, 59, 270, 237, 423, 138, 95, 373, 373, 372,
|
|
- /* 1290 */ 255, 370, 60, 60, 815, 1178, 533, 544, 273, 544,
|
|
- /* 1300 */ 1161, 843, 387, 386, 544, 1307, 544, 215, 210, 296,
|
|
- /* 1310 */ 513, 847, 544, 265, 208, 514, 1306, 295, 274, 61,
|
|
- /* 1320 */ 61, 62, 62, 436, 984, 1160, 45, 45, 46, 46,
|
|
- /* 1330 */ 105, 105, 1184, 920, 47, 47, 1474, 106, 544, 423,
|
|
- /* 1340 */ 546, 545, 218, 544, 974, 935, 1085, 217, 544, 377,
|
|
- /* 1350 */ 395, 107, 536, 936, 4, 156, 1161, 843, 158, 544,
|
|
- /* 1360 */ 49, 49, 141, 544, 38, 50, 50, 544, 539, 307,
|
|
- /* 1370 */ 63, 63, 544, 1448, 216, 974, 974, 976, 977, 27,
|
|
- /* 1380 */ 444, 64, 64, 544, 1447, 65, 65, 544, 524, 14,
|
|
- /* 1390 */ 14, 423, 458, 544, 66, 66, 310, 544, 316, 97,
|
|
- /* 1400 */ 1034, 544, 961, 533, 268, 127, 127, 544, 391, 67,
|
|
- /* 1410 */ 67, 544, 978, 290, 535, 52, 52, 513, 544, 68,
|
|
- /* 1420 */ 68, 1294, 512, 69, 69, 397, 165, 855, 854, 53,
|
|
- /* 1430 */ 53, 984, 966, 151, 151, 243, 430, 105, 105, 199,
|
|
- /* 1440 */ 152, 152, 448, 1303, 106, 243, 423, 546, 545, 1129,
|
|
- /* 1450 */ 425, 974, 320, 270, 862, 863, 1034, 220, 373, 373,
|
|
- /* 1460 */ 372, 255, 370, 450, 323, 815, 243, 544, 978, 544,
|
|
- /* 1470 */ 107, 536, 544, 4, 544, 938, 939, 325, 215, 1046,
|
|
- /* 1480 */ 296, 1046, 974, 974, 976, 977, 27, 539, 295, 76,
|
|
- /* 1490 */ 76, 54, 54, 327, 72, 72, 128, 128, 1503, 1254,
|
|
- /* 1500 */ 107, 536, 544, 4, 1045, 544, 1045, 531, 1238, 544,
|
|
- /* 1510 */ 423, 544, 315, 334, 544, 97, 544, 539, 217, 544,
|
|
- /* 1520 */ 472, 1528, 533, 239, 73, 73, 156, 129, 129, 158,
|
|
- /* 1530 */ 467, 130, 130, 126, 126, 344, 150, 150, 149, 149,
|
|
- /* 1540 */ 423, 134, 134, 329, 1030, 216, 97, 239, 929, 345,
|
|
- /* 1550 */ 984, 243, 533, 1315, 339, 544, 105, 105, 900, 1355,
|
|
- /* 1560 */ 544, 1290, 258, 106, 338, 423, 546, 545, 544, 1301,
|
|
- /* 1570 */ 974, 893, 99, 536, 109, 4, 544, 133, 133, 391,
|
|
- /* 1580 */ 984, 197, 131, 131, 290, 535, 105, 105, 530, 539,
|
|
- /* 1590 */ 132, 132, 1361, 106, 1219, 423, 546, 545, 75, 75,
|
|
- /* 1600 */ 974, 974, 974, 976, 977, 27, 544, 430, 826, 1211,
|
|
- /* 1610 */ 894, 139, 423, 109, 544, 1200, 1199, 1201, 1522, 544,
|
|
- /* 1620 */ 201, 544, 11, 374, 533, 1287, 347, 349, 77, 77,
|
|
- /* 1630 */ 1340, 974, 974, 976, 977, 27, 74, 74, 351, 213,
|
|
- /* 1640 */ 435, 43, 43, 48, 48, 302, 477, 309, 1348, 382,
|
|
- /* 1650 */ 353, 452, 984, 337, 1237, 1420, 1419, 205, 105, 105,
|
|
- /* 1660 */ 192, 367, 193, 534, 1525, 106, 1178, 423, 546, 545,
|
|
- /* 1670 */ 247, 167, 974, 270, 1467, 200, 1465, 1175, 373, 373,
|
|
- /* 1680 */ 372, 255, 370, 398, 79, 815, 83, 82, 1425, 446,
|
|
- /* 1690 */ 161, 177, 169, 95, 1337, 438, 172, 173, 215, 174,
|
|
- /* 1700 */ 296, 175, 35, 974, 974, 976, 977, 27, 295, 1345,
|
|
- /* 1710 */ 439, 470, 223, 36, 379, 445, 1414, 381, 459, 1351,
|
|
- /* 1720 */ 181, 227, 88, 465, 259, 229, 1436, 318, 186, 468,
|
|
- /* 1730 */ 322, 230, 384, 1202, 231, 486, 1257, 1256, 217, 411,
|
|
- /* 1740 */ 1255, 1248, 90, 847, 206, 413, 156, 505, 1539, 158,
|
|
- /* 1750 */ 1226, 1538, 283, 1508, 1227, 336, 385, 284, 1225, 496,
|
|
- /* 1760 */ 1537, 1298, 94, 346, 348, 216, 1247, 499, 1299, 245,
|
|
- /* 1770 */ 246, 1297, 416, 350, 1494, 124, 1493, 10, 524, 361,
|
|
- /* 1780 */ 1400, 101, 96, 288, 508, 253, 1135, 1208, 34, 1296,
|
|
- /* 1790 */ 547, 254, 256, 257, 392, 548, 1197, 1192, 359, 391,
|
|
- /* 1800 */ 1280, 1279, 196, 365, 290, 535, 366, 352, 1452, 1322,
|
|
- /* 1810 */ 1321, 1453, 153, 137, 281, 154, 802, 424, 155, 1451,
|
|
- /* 1820 */ 1450, 198, 292, 202, 203, 78, 212, 430, 271, 135,
|
|
- /* 1830 */ 1044, 1042, 958, 168, 219, 157, 170, 879, 308, 222,
|
|
- /* 1840 */ 1058, 176, 159, 962, 400, 84, 402, 178, 85, 86,
|
|
- /* 1850 */ 87, 166, 160, 393, 1061, 224, 225, 1057, 146, 18,
|
|
- /* 1860 */ 226, 317, 1050, 1172, 243, 464, 182, 228, 37, 183,
|
|
- /* 1870 */ 817, 469, 338, 232, 330, 481, 184, 89, 845, 19,
|
|
- /* 1880 */ 20, 92, 473, 478, 333, 91, 162, 858, 147, 488,
|
|
- /* 1890 */ 282, 1123, 148, 1010, 928, 1093, 39, 93, 40, 495,
|
|
- /* 1900 */ 1094, 187, 498, 207, 262, 264, 923, 242, 1109, 109,
|
|
- /* 1910 */ 1113, 1111, 1097, 33, 21, 1117, 520, 1025, 22, 23,
|
|
- /* 1920 */ 24, 1116, 25, 190, 97, 1011, 1009, 26, 1013, 1067,
|
|
- /* 1930 */ 248, 7, 1066, 249, 1014, 28, 41, 889, 979, 827,
|
|
- /* 1940 */ 108, 29, 250, 540, 251, 1530, 371, 368, 1131, 1130,
|
|
- /* 1950 */ 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1529,
|
|
+ /* 0 */ 568, 208, 568, 118, 115, 229, 568, 118, 115, 229,
|
|
+ /* 10 */ 568, 1314, 377, 1293, 408, 562, 562, 562, 568, 409,
|
|
+ /* 20 */ 378, 1314, 1276, 41, 41, 41, 41, 208, 1526, 71,
|
|
+ /* 30 */ 71, 971, 419, 41, 41, 491, 303, 279, 303, 972,
|
|
+ /* 40 */ 397, 71, 71, 125, 126, 80, 1217, 1217, 1050, 1053,
|
|
+ /* 50 */ 1040, 1040, 123, 123, 124, 124, 124, 124, 476, 409,
|
|
+ /* 60 */ 1241, 1, 1, 575, 2, 1245, 550, 118, 115, 229,
|
|
+ /* 70 */ 317, 480, 146, 480, 524, 118, 115, 229, 529, 1327,
|
|
+ /* 80 */ 417, 523, 142, 125, 126, 80, 1217, 1217, 1050, 1053,
|
|
+ /* 90 */ 1040, 1040, 123, 123, 124, 124, 124, 124, 118, 115,
|
|
+ /* 100 */ 229, 327, 122, 122, 122, 122, 121, 121, 120, 120,
|
|
+ /* 110 */ 120, 119, 116, 444, 284, 284, 284, 284, 442, 442,
|
|
+ /* 120 */ 442, 1567, 376, 1569, 1192, 375, 1163, 565, 1163, 565,
|
|
+ /* 130 */ 409, 1567, 537, 259, 226, 444, 101, 145, 449, 316,
|
|
+ /* 140 */ 559, 240, 122, 122, 122, 122, 121, 121, 120, 120,
|
|
+ /* 150 */ 120, 119, 116, 444, 125, 126, 80, 1217, 1217, 1050,
|
|
+ /* 160 */ 1053, 1040, 1040, 123, 123, 124, 124, 124, 124, 142,
|
|
+ /* 170 */ 294, 1192, 339, 448, 120, 120, 120, 119, 116, 444,
|
|
+ /* 180 */ 127, 1192, 1193, 1194, 148, 441, 440, 568, 119, 116,
|
|
+ /* 190 */ 444, 124, 124, 124, 124, 117, 122, 122, 122, 122,
|
|
+ /* 200 */ 121, 121, 120, 120, 120, 119, 116, 444, 454, 113,
|
|
+ /* 210 */ 13, 13, 546, 122, 122, 122, 122, 121, 121, 120,
|
|
+ /* 220 */ 120, 120, 119, 116, 444, 422, 316, 559, 1192, 1193,
|
|
+ /* 230 */ 1194, 149, 1224, 409, 1224, 124, 124, 124, 124, 122,
|
|
+ /* 240 */ 122, 122, 122, 121, 121, 120, 120, 120, 119, 116,
|
|
+ /* 250 */ 444, 465, 342, 1037, 1037, 1051, 1054, 125, 126, 80,
|
|
+ /* 260 */ 1217, 1217, 1050, 1053, 1040, 1040, 123, 123, 124, 124,
|
|
+ /* 270 */ 124, 124, 1279, 522, 222, 1192, 568, 409, 224, 514,
|
|
+ /* 280 */ 175, 82, 83, 122, 122, 122, 122, 121, 121, 120,
|
|
+ /* 290 */ 120, 120, 119, 116, 444, 1007, 16, 16, 1192, 133,
|
|
+ /* 300 */ 133, 125, 126, 80, 1217, 1217, 1050, 1053, 1040, 1040,
|
|
+ /* 310 */ 123, 123, 124, 124, 124, 124, 122, 122, 122, 122,
|
|
+ /* 320 */ 121, 121, 120, 120, 120, 119, 116, 444, 1041, 546,
|
|
+ /* 330 */ 1192, 373, 1192, 1193, 1194, 252, 1434, 399, 504, 501,
|
|
+ /* 340 */ 500, 111, 560, 566, 4, 926, 926, 433, 499, 340,
|
|
+ /* 350 */ 460, 328, 360, 394, 1237, 1192, 1193, 1194, 563, 568,
|
|
+ /* 360 */ 122, 122, 122, 122, 121, 121, 120, 120, 120, 119,
|
|
+ /* 370 */ 116, 444, 284, 284, 369, 1580, 1607, 441, 440, 154,
|
|
+ /* 380 */ 409, 445, 71, 71, 1286, 565, 1221, 1192, 1193, 1194,
|
|
+ /* 390 */ 85, 1223, 271, 557, 543, 515, 1561, 568, 98, 1222,
|
|
+ /* 400 */ 6, 1278, 472, 142, 125, 126, 80, 1217, 1217, 1050,
|
|
+ /* 410 */ 1053, 1040, 1040, 123, 123, 124, 124, 124, 124, 550,
|
|
+ /* 420 */ 13, 13, 1027, 507, 1224, 1192, 1224, 549, 109, 109,
|
|
+ /* 430 */ 222, 568, 1238, 175, 568, 427, 110, 197, 445, 570,
|
|
+ /* 440 */ 569, 430, 1552, 1017, 325, 551, 1192, 270, 287, 368,
|
|
+ /* 450 */ 510, 363, 509, 257, 71, 71, 543, 71, 71, 359,
|
|
+ /* 460 */ 316, 559, 1613, 122, 122, 122, 122, 121, 121, 120,
|
|
+ /* 470 */ 120, 120, 119, 116, 444, 1017, 1017, 1019, 1020, 27,
|
|
+ /* 480 */ 284, 284, 1192, 1193, 1194, 1158, 568, 1612, 409, 901,
|
|
+ /* 490 */ 190, 550, 356, 565, 550, 937, 533, 517, 1158, 516,
|
|
+ /* 500 */ 413, 1158, 552, 1192, 1193, 1194, 568, 544, 1554, 51,
|
|
+ /* 510 */ 51, 214, 125, 126, 80, 1217, 1217, 1050, 1053, 1040,
|
|
+ /* 520 */ 1040, 123, 123, 124, 124, 124, 124, 1192, 474, 135,
|
|
+ /* 530 */ 135, 409, 284, 284, 1490, 505, 121, 121, 120, 120,
|
|
+ /* 540 */ 120, 119, 116, 444, 1007, 565, 518, 217, 541, 1561,
|
|
+ /* 550 */ 316, 559, 142, 6, 532, 125, 126, 80, 1217, 1217,
|
|
+ /* 560 */ 1050, 1053, 1040, 1040, 123, 123, 124, 124, 124, 124,
|
|
+ /* 570 */ 1555, 122, 122, 122, 122, 121, 121, 120, 120, 120,
|
|
+ /* 580 */ 119, 116, 444, 485, 1192, 1193, 1194, 482, 281, 1267,
|
|
+ /* 590 */ 957, 252, 1192, 373, 504, 501, 500, 1192, 340, 571,
|
|
+ /* 600 */ 1192, 571, 409, 292, 499, 957, 876, 191, 480, 316,
|
|
+ /* 610 */ 559, 384, 290, 380, 122, 122, 122, 122, 121, 121,
|
|
+ /* 620 */ 120, 120, 120, 119, 116, 444, 125, 126, 80, 1217,
|
|
+ /* 630 */ 1217, 1050, 1053, 1040, 1040, 123, 123, 124, 124, 124,
|
|
+ /* 640 */ 124, 409, 394, 1136, 1192, 869, 100, 284, 284, 1192,
|
|
+ /* 650 */ 1193, 1194, 373, 1093, 1192, 1193, 1194, 1192, 1193, 1194,
|
|
+ /* 660 */ 565, 455, 32, 373, 233, 125, 126, 80, 1217, 1217,
|
|
+ /* 670 */ 1050, 1053, 1040, 1040, 123, 123, 124, 124, 124, 124,
|
|
+ /* 680 */ 1433, 959, 568, 228, 958, 122, 122, 122, 122, 121,
|
|
+ /* 690 */ 121, 120, 120, 120, 119, 116, 444, 1158, 228, 1192,
|
|
+ /* 700 */ 157, 1192, 1193, 1194, 1553, 13, 13, 301, 957, 1232,
|
|
+ /* 710 */ 1158, 153, 409, 1158, 373, 1583, 1176, 5, 369, 1580,
|
|
+ /* 720 */ 429, 1238, 3, 957, 122, 122, 122, 122, 121, 121,
|
|
+ /* 730 */ 120, 120, 120, 119, 116, 444, 125, 126, 80, 1217,
|
|
+ /* 740 */ 1217, 1050, 1053, 1040, 1040, 123, 123, 124, 124, 124,
|
|
+ /* 750 */ 124, 409, 208, 567, 1192, 1028, 1192, 1193, 1194, 1192,
|
|
+ /* 760 */ 388, 852, 155, 1552, 286, 402, 1098, 1098, 488, 568,
|
|
+ /* 770 */ 465, 342, 1319, 1319, 1552, 125, 126, 80, 1217, 1217,
|
|
+ /* 780 */ 1050, 1053, 1040, 1040, 123, 123, 124, 124, 124, 124,
|
|
+ /* 790 */ 129, 568, 13, 13, 374, 122, 122, 122, 122, 121,
|
|
+ /* 800 */ 121, 120, 120, 120, 119, 116, 444, 302, 568, 453,
|
|
+ /* 810 */ 528, 1192, 1193, 1194, 13, 13, 1192, 1193, 1194, 1297,
|
|
+ /* 820 */ 463, 1267, 409, 1317, 1317, 1552, 1012, 453, 452, 200,
|
|
+ /* 830 */ 299, 71, 71, 1265, 122, 122, 122, 122, 121, 121,
|
|
+ /* 840 */ 120, 120, 120, 119, 116, 444, 125, 126, 80, 1217,
|
|
+ /* 850 */ 1217, 1050, 1053, 1040, 1040, 123, 123, 124, 124, 124,
|
|
+ /* 860 */ 124, 409, 227, 1073, 1158, 284, 284, 419, 312, 278,
|
|
+ /* 870 */ 278, 285, 285, 1419, 406, 405, 382, 1158, 565, 568,
|
|
+ /* 880 */ 1158, 1196, 565, 1600, 565, 125, 126, 80, 1217, 1217,
|
|
+ /* 890 */ 1050, 1053, 1040, 1040, 123, 123, 124, 124, 124, 124,
|
|
+ /* 900 */ 453, 1482, 13, 13, 1536, 122, 122, 122, 122, 121,
|
|
+ /* 910 */ 121, 120, 120, 120, 119, 116, 444, 201, 568, 354,
|
|
+ /* 920 */ 1586, 575, 2, 1245, 840, 841, 842, 1562, 317, 1212,
|
|
+ /* 930 */ 146, 6, 409, 255, 254, 253, 206, 1327, 9, 1196,
|
|
+ /* 940 */ 262, 71, 71, 424, 122, 122, 122, 122, 121, 121,
|
|
+ /* 950 */ 120, 120, 120, 119, 116, 444, 125, 126, 80, 1217,
|
|
+ /* 960 */ 1217, 1050, 1053, 1040, 1040, 123, 123, 124, 124, 124,
|
|
+ /* 970 */ 124, 568, 284, 284, 568, 1213, 409, 574, 313, 1245,
|
|
+ /* 980 */ 349, 1296, 352, 419, 317, 565, 146, 491, 525, 1643,
|
|
+ /* 990 */ 395, 371, 491, 1327, 70, 70, 1295, 71, 71, 240,
|
|
+ /* 1000 */ 1325, 104, 80, 1217, 1217, 1050, 1053, 1040, 1040, 123,
|
|
+ /* 1010 */ 123, 124, 124, 124, 124, 122, 122, 122, 122, 121,
|
|
+ /* 1020 */ 121, 120, 120, 120, 119, 116, 444, 1114, 284, 284,
|
|
+ /* 1030 */ 428, 448, 1525, 1213, 439, 284, 284, 1489, 1352, 311,
|
|
+ /* 1040 */ 474, 565, 1115, 971, 491, 491, 217, 1263, 565, 1538,
|
|
+ /* 1050 */ 568, 972, 207, 568, 1027, 240, 383, 1116, 519, 122,
|
|
+ /* 1060 */ 122, 122, 122, 121, 121, 120, 120, 120, 119, 116,
|
|
+ /* 1070 */ 444, 1018, 107, 71, 71, 1017, 13, 13, 912, 568,
|
|
+ /* 1080 */ 1495, 568, 284, 284, 97, 526, 491, 448, 913, 1326,
|
|
+ /* 1090 */ 1322, 545, 409, 284, 284, 565, 151, 209, 1495, 1497,
|
|
+ /* 1100 */ 262, 450, 55, 55, 56, 56, 565, 1017, 1017, 1019,
|
|
+ /* 1110 */ 443, 332, 409, 527, 12, 295, 125, 126, 80, 1217,
|
|
+ /* 1120 */ 1217, 1050, 1053, 1040, 1040, 123, 123, 124, 124, 124,
|
|
+ /* 1130 */ 124, 347, 409, 864, 1534, 1213, 125, 126, 80, 1217,
|
|
+ /* 1140 */ 1217, 1050, 1053, 1040, 1040, 123, 123, 124, 124, 124,
|
|
+ /* 1150 */ 124, 1137, 1641, 474, 1641, 371, 125, 114, 80, 1217,
|
|
+ /* 1160 */ 1217, 1050, 1053, 1040, 1040, 123, 123, 124, 124, 124,
|
|
+ /* 1170 */ 124, 1495, 329, 474, 331, 122, 122, 122, 122, 121,
|
|
+ /* 1180 */ 121, 120, 120, 120, 119, 116, 444, 203, 1419, 568,
|
|
+ /* 1190 */ 1294, 864, 464, 1213, 436, 122, 122, 122, 122, 121,
|
|
+ /* 1200 */ 121, 120, 120, 120, 119, 116, 444, 553, 1137, 1642,
|
|
+ /* 1210 */ 539, 1642, 15, 15, 892, 122, 122, 122, 122, 121,
|
|
+ /* 1220 */ 121, 120, 120, 120, 119, 116, 444, 568, 298, 538,
|
|
+ /* 1230 */ 1135, 1419, 1559, 1560, 1331, 409, 6, 6, 1169, 1268,
|
|
+ /* 1240 */ 415, 320, 284, 284, 1419, 508, 565, 525, 300, 457,
|
|
+ /* 1250 */ 43, 43, 568, 893, 12, 565, 330, 478, 425, 407,
|
|
+ /* 1260 */ 126, 80, 1217, 1217, 1050, 1053, 1040, 1040, 123, 123,
|
|
+ /* 1270 */ 124, 124, 124, 124, 568, 57, 57, 288, 1192, 1419,
|
|
+ /* 1280 */ 496, 458, 392, 392, 391, 273, 389, 1135, 1558, 849,
|
|
+ /* 1290 */ 1169, 407, 6, 568, 321, 1158, 470, 44, 44, 1557,
|
|
+ /* 1300 */ 1114, 426, 234, 6, 323, 256, 540, 256, 1158, 431,
|
|
+ /* 1310 */ 568, 1158, 322, 17, 487, 1115, 58, 58, 122, 122,
|
|
+ /* 1320 */ 122, 122, 121, 121, 120, 120, 120, 119, 116, 444,
|
|
+ /* 1330 */ 1116, 216, 481, 59, 59, 1192, 1193, 1194, 111, 560,
|
|
+ /* 1340 */ 324, 4, 236, 456, 526, 568, 237, 456, 568, 437,
|
|
+ /* 1350 */ 168, 556, 420, 141, 479, 563, 568, 293, 568, 1095,
|
|
+ /* 1360 */ 568, 293, 568, 1095, 531, 568, 872, 8, 60, 60,
|
|
+ /* 1370 */ 235, 61, 61, 568, 414, 568, 414, 568, 445, 62,
|
|
+ /* 1380 */ 62, 45, 45, 46, 46, 47, 47, 199, 49, 49,
|
|
+ /* 1390 */ 557, 568, 359, 568, 100, 486, 50, 50, 63, 63,
|
|
+ /* 1400 */ 64, 64, 561, 415, 535, 410, 568, 1027, 568, 534,
|
|
+ /* 1410 */ 316, 559, 316, 559, 65, 65, 14, 14, 568, 1027,
|
|
+ /* 1420 */ 568, 512, 932, 872, 1018, 109, 109, 931, 1017, 66,
|
|
+ /* 1430 */ 66, 131, 131, 110, 451, 445, 570, 569, 416, 177,
|
|
+ /* 1440 */ 1017, 132, 132, 67, 67, 568, 467, 568, 932, 471,
|
|
+ /* 1450 */ 1364, 283, 226, 931, 315, 1363, 407, 568, 459, 407,
|
|
+ /* 1460 */ 1017, 1017, 1019, 239, 407, 86, 213, 1350, 52, 52,
|
|
+ /* 1470 */ 68, 68, 1017, 1017, 1019, 1020, 27, 1585, 1180, 447,
|
|
+ /* 1480 */ 69, 69, 288, 97, 108, 1541, 106, 392, 392, 391,
|
|
+ /* 1490 */ 273, 389, 568, 879, 849, 883, 568, 111, 560, 466,
|
|
+ /* 1500 */ 4, 568, 152, 30, 38, 568, 1132, 234, 396, 323,
|
|
+ /* 1510 */ 111, 560, 527, 4, 563, 53, 53, 322, 568, 163,
|
|
+ /* 1520 */ 163, 568, 337, 468, 164, 164, 333, 563, 76, 76,
|
|
+ /* 1530 */ 568, 289, 1514, 568, 31, 1513, 568, 445, 338, 483,
|
|
+ /* 1540 */ 100, 54, 54, 344, 72, 72, 296, 236, 1080, 557,
|
|
+ /* 1550 */ 445, 879, 1360, 134, 134, 168, 73, 73, 141, 161,
|
|
+ /* 1560 */ 161, 1574, 557, 535, 568, 319, 568, 348, 536, 1009,
|
|
+ /* 1570 */ 473, 261, 261, 891, 890, 235, 535, 568, 1027, 568,
|
|
+ /* 1580 */ 475, 534, 261, 367, 109, 109, 521, 136, 136, 130,
|
|
+ /* 1590 */ 130, 1027, 110, 366, 445, 570, 569, 109, 109, 1017,
|
|
+ /* 1600 */ 162, 162, 156, 156, 568, 110, 1080, 445, 570, 569,
|
|
+ /* 1610 */ 410, 351, 1017, 568, 353, 316, 559, 568, 343, 568,
|
|
+ /* 1620 */ 100, 497, 357, 258, 100, 898, 899, 140, 140, 355,
|
|
+ /* 1630 */ 1310, 1017, 1017, 1019, 1020, 27, 139, 139, 362, 451,
|
|
+ /* 1640 */ 137, 137, 138, 138, 1017, 1017, 1019, 1020, 27, 1180,
|
|
+ /* 1650 */ 447, 568, 372, 288, 111, 560, 1021, 4, 392, 392,
|
|
+ /* 1660 */ 391, 273, 389, 568, 1141, 849, 568, 1076, 568, 258,
|
|
+ /* 1670 */ 492, 563, 568, 211, 75, 75, 555, 962, 234, 261,
|
|
+ /* 1680 */ 323, 111, 560, 929, 4, 113, 77, 77, 322, 74,
|
|
+ /* 1690 */ 74, 42, 42, 1373, 445, 48, 48, 1418, 563, 974,
|
|
+ /* 1700 */ 975, 1092, 1091, 1092, 1091, 862, 557, 150, 930, 1346,
|
|
+ /* 1710 */ 113, 1358, 554, 1424, 1021, 1275, 1266, 1254, 236, 1253,
|
|
+ /* 1720 */ 1255, 445, 1593, 1343, 308, 276, 168, 309, 11, 141,
|
|
+ /* 1730 */ 393, 310, 232, 557, 1405, 1027, 335, 291, 1400, 219,
|
|
+ /* 1740 */ 336, 109, 109, 936, 297, 1410, 235, 341, 477, 110,
|
|
+ /* 1750 */ 502, 445, 570, 569, 1393, 1409, 1017, 400, 1293, 365,
|
|
+ /* 1760 */ 223, 1486, 1027, 1485, 1355, 1356, 1354, 1353, 109, 109,
|
|
+ /* 1770 */ 204, 1596, 1232, 558, 265, 218, 110, 205, 445, 570,
|
|
+ /* 1780 */ 569, 410, 387, 1017, 1533, 179, 316, 559, 1017, 1017,
|
|
+ /* 1790 */ 1019, 1020, 27, 230, 1531, 1229, 79, 560, 85, 4,
|
|
+ /* 1800 */ 418, 215, 548, 81, 84, 188, 1406, 173, 181, 461,
|
|
+ /* 1810 */ 451, 35, 462, 563, 183, 1017, 1017, 1019, 1020, 27,
|
|
+ /* 1820 */ 184, 1491, 185, 186, 495, 242, 98, 398, 1412, 36,
|
|
+ /* 1830 */ 1411, 484, 91, 469, 401, 1414, 445, 192, 1480, 246,
|
|
+ /* 1840 */ 1502, 490, 346, 277, 248, 196, 493, 511, 557, 350,
|
|
+ /* 1850 */ 1256, 249, 250, 403, 1313, 1312, 111, 560, 432, 4,
|
|
+ /* 1860 */ 1311, 1304, 93, 1611, 883, 1610, 224, 404, 434, 520,
|
|
+ /* 1870 */ 263, 435, 1579, 563, 1283, 1282, 364, 1027, 306, 1281,
|
|
+ /* 1880 */ 264, 1609, 1565, 109, 109, 370, 1303, 307, 1564, 438,
|
|
+ /* 1890 */ 128, 110, 1378, 445, 570, 569, 445, 546, 1017, 10,
|
|
+ /* 1900 */ 1466, 105, 381, 1377, 34, 572, 99, 1336, 557, 314,
|
|
+ /* 1910 */ 1186, 530, 272, 274, 379, 210, 1335, 547, 385, 386,
|
|
+ /* 1920 */ 275, 573, 1251, 1246, 411, 412, 1518, 165, 178, 1519,
|
|
+ /* 1930 */ 1017, 1017, 1019, 1020, 27, 1517, 1516, 1027, 78, 147,
|
|
+ /* 1940 */ 166, 220, 221, 109, 109, 836, 304, 167, 446, 212,
|
|
+ /* 1950 */ 318, 110, 231, 445, 570, 569, 144, 1090, 1017, 1088,
|
|
+ /* 1960 */ 326, 180, 169, 1212, 182, 334, 238, 915, 241, 1104,
|
|
+ /* 1970 */ 187, 170, 171, 421, 87, 88, 423, 189, 89, 90,
|
|
+ /* 1980 */ 172, 1107, 243, 1103, 244, 158, 18, 245, 345, 247,
|
|
+ /* 1990 */ 1017, 1017, 1019, 1020, 27, 261, 1096, 193, 1226, 489,
|
|
+ /* 2000 */ 194, 37, 366, 851, 494, 251, 195, 506, 92, 19,
|
|
+ /* 2010 */ 498, 358, 20, 503, 881, 361, 94, 894, 305, 159,
|
|
+ /* 2020 */ 513, 39, 95, 1174, 160, 1056, 966, 1143, 96, 174,
|
|
+ /* 2030 */ 1142, 225, 280, 282, 198, 960, 113, 1164, 1160, 260,
|
|
+ /* 2040 */ 21, 22, 23, 1162, 1168, 1167, 1148, 24, 33, 25,
|
|
+ /* 2050 */ 202, 542, 26, 100, 1071, 102, 1057, 103, 7, 1055,
|
|
+ /* 2060 */ 1059, 1113, 1060, 1112, 266, 267, 28, 40, 390, 1022,
|
|
+ /* 2070 */ 863, 112, 29, 564, 1182, 1181, 268, 176, 143, 925,
|
|
+ /* 2080 */ 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242,
|
|
+ /* 2090 */ 1242, 1242, 1242, 1242, 269, 1602, 1242, 1601,
|
|
};
|
|
static const YYCODETYPE yy_lookahead[] = {
|
|
- /* 0 */ 189, 211, 189, 189, 218, 189, 220, 189, 267, 268,
|
|
- /* 10 */ 269, 189, 210, 189, 228, 189, 267, 268, 269, 19,
|
|
- /* 20 */ 218, 189, 211, 212, 211, 212, 211, 211, 212, 211,
|
|
- /* 30 */ 212, 31, 211, 211, 212, 211, 212, 288, 300, 39,
|
|
- /* 40 */ 21, 189, 304, 43, 44, 45, 46, 47, 48, 49,
|
|
- /* 50 */ 50, 51, 52, 53, 54, 55, 56, 57, 225, 19,
|
|
- /* 60 */ 189, 183, 184, 185, 186, 189, 248, 263, 236, 191,
|
|
- /* 70 */ 248, 193, 248, 197, 208, 257, 262, 201, 200, 257,
|
|
- /* 80 */ 200, 257, 81, 43, 44, 45, 46, 47, 48, 49,
|
|
- /* 90 */ 50, 51, 52, 53, 54, 55, 56, 57, 189, 80,
|
|
- /* 100 */ 189, 101, 102, 103, 104, 105, 106, 107, 108, 109,
|
|
- /* 110 */ 110, 111, 234, 235, 234, 235, 305, 306, 305, 118,
|
|
- /* 120 */ 307, 305, 306, 297, 298, 247, 86, 247, 88, 19,
|
|
- /* 130 */ 259, 251, 252, 267, 268, 269, 26, 136, 137, 261,
|
|
- /* 140 */ 121, 101, 102, 103, 104, 105, 106, 107, 108, 109,
|
|
- /* 150 */ 110, 111, 59, 43, 44, 45, 46, 47, 48, 49,
|
|
- /* 160 */ 50, 51, 52, 53, 54, 55, 56, 57, 259, 291,
|
|
- /* 170 */ 105, 106, 107, 108, 109, 110, 111, 158, 189, 69,
|
|
- /* 180 */ 101, 102, 103, 104, 105, 106, 107, 108, 109, 110,
|
|
- /* 190 */ 111, 107, 108, 109, 110, 111, 205, 206, 207, 19,
|
|
- /* 200 */ 19, 54, 55, 56, 57, 58, 29, 114, 115, 116,
|
|
- /* 210 */ 33, 101, 102, 103, 104, 105, 106, 107, 108, 109,
|
|
- /* 220 */ 110, 111, 233, 43, 44, 45, 46, 47, 48, 49,
|
|
- /* 230 */ 50, 51, 52, 53, 54, 55, 56, 57, 19, 126,
|
|
- /* 240 */ 127, 148, 65, 24, 214, 200, 59, 67, 101, 102,
|
|
- /* 250 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 22,
|
|
- /* 260 */ 189, 111, 43, 44, 45, 46, 47, 48, 49, 50,
|
|
- /* 270 */ 51, 52, 53, 54, 55, 56, 57, 206, 207, 234,
|
|
- /* 280 */ 235, 101, 102, 103, 104, 105, 106, 107, 108, 109,
|
|
- /* 290 */ 110, 111, 247, 76, 107, 114, 59, 267, 268, 269,
|
|
- /* 300 */ 189, 114, 115, 116, 162, 163, 89, 19, 263, 92,
|
|
- /* 310 */ 189, 23, 54, 55, 56, 57, 189, 206, 207, 22,
|
|
- /* 320 */ 101, 102, 103, 104, 105, 106, 107, 108, 109, 110,
|
|
- /* 330 */ 111, 43, 44, 45, 46, 47, 48, 49, 50, 51,
|
|
- /* 340 */ 52, 53, 54, 55, 56, 57, 19, 189, 277, 59,
|
|
- /* 350 */ 23, 114, 115, 116, 46, 47, 48, 49, 61, 101,
|
|
+ /* 0 */ 193, 193, 193, 274, 275, 276, 193, 274, 275, 276,
|
|
+ /* 10 */ 193, 223, 219, 225, 206, 210, 211, 212, 193, 19,
|
|
+ /* 20 */ 219, 233, 216, 216, 217, 216, 217, 193, 295, 216,
|
|
+ /* 30 */ 217, 31, 193, 216, 217, 193, 228, 213, 230, 39,
|
|
+ /* 40 */ 206, 216, 217, 43, 44, 45, 46, 47, 48, 49,
|
|
+ /* 50 */ 50, 51, 52, 53, 54, 55, 56, 57, 193, 19,
|
|
+ /* 60 */ 185, 186, 187, 188, 189, 190, 253, 274, 275, 276,
|
|
+ /* 70 */ 195, 193, 197, 193, 261, 274, 275, 276, 253, 204,
|
|
+ /* 80 */ 238, 204, 81, 43, 44, 45, 46, 47, 48, 49,
|
|
+ /* 90 */ 50, 51, 52, 53, 54, 55, 56, 57, 274, 275,
|
|
+ /* 100 */ 276, 262, 102, 103, 104, 105, 106, 107, 108, 109,
|
|
+ /* 110 */ 110, 111, 112, 113, 239, 240, 239, 240, 210, 211,
|
|
+ /* 120 */ 212, 314, 315, 314, 59, 316, 86, 252, 88, 252,
|
|
+ /* 130 */ 19, 314, 315, 256, 257, 113, 25, 72, 296, 138,
|
|
+ /* 140 */ 139, 266, 102, 103, 104, 105, 106, 107, 108, 109,
|
|
+ /* 150 */ 110, 111, 112, 113, 43, 44, 45, 46, 47, 48,
|
|
+ /* 160 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 81,
|
|
+ /* 170 */ 292, 59, 292, 298, 108, 109, 110, 111, 112, 113,
|
|
+ /* 180 */ 69, 116, 117, 118, 72, 106, 107, 193, 111, 112,
|
|
+ /* 190 */ 113, 54, 55, 56, 57, 58, 102, 103, 104, 105,
|
|
+ /* 200 */ 106, 107, 108, 109, 110, 111, 112, 113, 120, 25,
|
|
+ /* 210 */ 216, 217, 145, 102, 103, 104, 105, 106, 107, 108,
|
|
+ /* 220 */ 109, 110, 111, 112, 113, 231, 138, 139, 116, 117,
|
|
+ /* 230 */ 118, 164, 153, 19, 155, 54, 55, 56, 57, 102,
|
|
+ /* 240 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 112,
|
|
+ /* 250 */ 113, 128, 129, 46, 47, 48, 49, 43, 44, 45,
|
|
+ /* 260 */ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
|
|
+ /* 270 */ 56, 57, 216, 193, 25, 59, 193, 19, 165, 166,
|
|
+ /* 280 */ 193, 67, 24, 102, 103, 104, 105, 106, 107, 108,
|
|
+ /* 290 */ 109, 110, 111, 112, 113, 73, 216, 217, 59, 216,
|
|
+ /* 300 */ 217, 43, 44, 45, 46, 47, 48, 49, 50, 51,
|
|
+ /* 310 */ 52, 53, 54, 55, 56, 57, 102, 103, 104, 105,
|
|
+ /* 320 */ 106, 107, 108, 109, 110, 111, 112, 113, 121, 145,
|
|
+ /* 330 */ 59, 193, 116, 117, 118, 119, 273, 204, 122, 123,
|
|
+ /* 340 */ 124, 19, 20, 134, 22, 136, 137, 19, 132, 127,
|
|
+ /* 350 */ 128, 129, 24, 22, 23, 116, 117, 118, 36, 193,
|
|
/* 360 */ 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
|
|
- /* 370 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
|
|
- /* 380 */ 53, 54, 55, 56, 57, 125, 126, 127, 277, 101,
|
|
- /* 390 */ 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
|
|
- /* 400 */ 59, 189, 189, 276, 114, 115, 116, 117, 73, 59,
|
|
- /* 410 */ 120, 121, 122, 72, 214, 19, 81, 259, 19, 23,
|
|
- /* 420 */ 130, 81, 72, 24, 211, 212, 221, 119, 101, 102,
|
|
- /* 430 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 43,
|
|
- /* 440 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
|
|
- /* 450 */ 54, 55, 56, 57, 19, 114, 115, 116, 23, 208,
|
|
- /* 460 */ 125, 248, 189, 189, 114, 115, 116, 267, 268, 269,
|
|
- /* 470 */ 189, 136, 137, 189, 262, 22, 136, 137, 43, 44,
|
|
- /* 480 */ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
|
|
- /* 490 */ 55, 56, 57, 189, 95, 211, 212, 101, 102, 103,
|
|
- /* 500 */ 104, 105, 106, 107, 108, 109, 110, 111, 59, 189,
|
|
- /* 510 */ 111, 189, 59, 76, 294, 295, 117, 118, 119, 120,
|
|
- /* 520 */ 121, 122, 123, 19, 87, 189, 89, 23, 129, 92,
|
|
- /* 530 */ 279, 227, 248, 22, 189, 284, 101, 102, 103, 104,
|
|
- /* 540 */ 105, 106, 107, 108, 109, 110, 111, 43, 44, 45,
|
|
- /* 550 */ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
|
|
- /* 560 */ 56, 57, 19, 114, 115, 116, 23, 114, 115, 116,
|
|
- /* 570 */ 59, 117, 299, 300, 120, 121, 122, 304, 189, 189,
|
|
- /* 580 */ 143, 189, 110, 111, 130, 22, 43, 44, 45, 46,
|
|
- /* 590 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
|
|
- /* 600 */ 57, 211, 212, 211, 212, 101, 102, 103, 104, 105,
|
|
- /* 610 */ 106, 107, 108, 109, 110, 111, 226, 189, 226, 189,
|
|
- /* 620 */ 298, 132, 59, 134, 135, 114, 115, 116, 189, 59,
|
|
- /* 630 */ 285, 19, 7, 8, 9, 23, 205, 206, 207, 211,
|
|
- /* 640 */ 212, 211, 212, 221, 101, 102, 103, 104, 105, 106,
|
|
- /* 650 */ 107, 108, 109, 110, 111, 43, 44, 45, 46, 47,
|
|
- /* 660 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
|
|
- /* 670 */ 19, 181, 182, 183, 184, 185, 186, 114, 115, 116,
|
|
- /* 680 */ 189, 191, 133, 193, 114, 115, 116, 138, 299, 300,
|
|
- /* 690 */ 200, 22, 201, 304, 43, 44, 45, 46, 47, 48,
|
|
- /* 700 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 35,
|
|
- /* 710 */ 189, 141, 189, 101, 102, 103, 104, 105, 106, 107,
|
|
- /* 720 */ 108, 109, 110, 111, 234, 235, 22, 23, 59, 184,
|
|
- /* 730 */ 26, 186, 211, 212, 211, 212, 191, 247, 193, 19,
|
|
- /* 740 */ 66, 105, 106, 73, 189, 200, 189, 226, 74, 226,
|
|
- /* 750 */ 22, 261, 101, 102, 103, 104, 105, 106, 107, 108,
|
|
- /* 760 */ 109, 110, 111, 43, 44, 45, 46, 47, 48, 49,
|
|
- /* 770 */ 50, 51, 52, 53, 54, 55, 56, 57, 189, 234,
|
|
- /* 780 */ 235, 291, 19, 114, 115, 116, 150, 59, 152, 189,
|
|
- /* 790 */ 233, 236, 247, 59, 189, 125, 126, 127, 59, 300,
|
|
- /* 800 */ 211, 212, 128, 304, 100, 19, 261, 156, 45, 46,
|
|
- /* 810 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
|
|
- /* 820 */ 57, 101, 102, 103, 104, 105, 106, 107, 108, 109,
|
|
- /* 830 */ 110, 111, 46, 233, 189, 189, 291, 248, 99, 189,
|
|
- /* 840 */ 125, 126, 127, 115, 26, 200, 289, 230, 231, 115,
|
|
- /* 850 */ 200, 16, 189, 114, 115, 189, 211, 212, 119, 221,
|
|
- /* 860 */ 189, 211, 212, 258, 101, 102, 103, 104, 105, 106,
|
|
- /* 870 */ 107, 108, 109, 110, 111, 189, 156, 211, 212, 234,
|
|
- /* 880 */ 235, 189, 211, 212, 234, 235, 22, 201, 189, 150,
|
|
- /* 890 */ 151, 152, 247, 248, 76, 16, 19, 247, 248, 113,
|
|
- /* 900 */ 189, 24, 257, 211, 212, 189, 26, 89, 262, 223,
|
|
- /* 910 */ 92, 225, 77, 189, 79, 129, 19, 53, 226, 248,
|
|
- /* 920 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
|
|
- /* 930 */ 53, 54, 55, 56, 57, 236, 19, 271, 189, 99,
|
|
- /* 940 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
|
|
- /* 950 */ 53, 54, 55, 56, 57, 115, 77, 59, 79, 119,
|
|
- /* 960 */ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
|
|
- /* 970 */ 53, 54, 55, 56, 57, 259, 22, 23, 101, 102,
|
|
- /* 980 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 59,
|
|
- /* 990 */ 150, 151, 152, 158, 22, 244, 24, 246, 101, 102,
|
|
- /* 1000 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 285,
|
|
- /* 1010 */ 189, 189, 114, 115, 116, 200, 136, 137, 101, 102,
|
|
- /* 1020 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 230,
|
|
- /* 1030 */ 231, 59, 211, 212, 285, 105, 106, 189, 19, 141,
|
|
- /* 1040 */ 234, 235, 239, 113, 114, 115, 116, 226, 118, 234,
|
|
- /* 1050 */ 235, 189, 249, 247, 100, 189, 126, 23, 236, 107,
|
|
- /* 1060 */ 26, 189, 247, 44, 45, 46, 47, 48, 49, 50,
|
|
- /* 1070 */ 51, 52, 53, 54, 55, 56, 57, 211, 212, 59,
|
|
- /* 1080 */ 150, 233, 152, 211, 212, 133, 12, 115, 189, 189,
|
|
- /* 1090 */ 138, 19, 20, 300, 22, 233, 76, 304, 226, 11,
|
|
- /* 1100 */ 208, 27, 22, 23, 200, 19, 26, 87, 36, 89,
|
|
- /* 1110 */ 211, 212, 92, 300, 248, 189, 42, 304, 189, 250,
|
|
- /* 1120 */ 101, 102, 103, 104, 105, 106, 107, 108, 109, 110,
|
|
- /* 1130 */ 111, 59, 200, 233, 114, 115, 116, 63, 234, 235,
|
|
- /* 1140 */ 235, 19, 20, 71, 22, 300, 189, 73, 200, 304,
|
|
- /* 1150 */ 116, 247, 247, 81, 23, 200, 227, 26, 36, 234,
|
|
- /* 1160 */ 235, 203, 204, 143, 200, 26, 234, 235, 194, 200,
|
|
- /* 1170 */ 48, 99, 247, 66, 189, 141, 284, 105, 106, 247,
|
|
- /* 1180 */ 100, 59, 234, 235, 112, 259, 114, 115, 116, 234,
|
|
- /* 1190 */ 235, 119, 85, 71, 266, 247, 211, 212, 234, 235,
|
|
- /* 1200 */ 114, 94, 247, 234, 235, 12, 266, 85, 136, 137,
|
|
- /* 1210 */ 189, 247, 90, 26, 126, 127, 247, 189, 26, 22,
|
|
- /* 1220 */ 27, 99, 150, 151, 152, 153, 154, 105, 106, 189,
|
|
- /* 1230 */ 302, 303, 211, 212, 112, 42, 114, 115, 116, 211,
|
|
- /* 1240 */ 212, 119, 302, 303, 19, 20, 189, 22, 274, 189,
|
|
- /* 1250 */ 15, 144, 278, 189, 22, 23, 63, 189, 189, 203,
|
|
- /* 1260 */ 204, 36, 136, 137, 155, 24, 157, 143, 211, 212,
|
|
- /* 1270 */ 189, 26, 150, 151, 152, 153, 154, 0, 1, 2,
|
|
- /* 1280 */ 211, 212, 5, 46, 59, 161, 147, 10, 11, 12,
|
|
- /* 1290 */ 13, 14, 211, 212, 17, 60, 71, 189, 258, 189,
|
|
- /* 1300 */ 59, 59, 105, 106, 189, 189, 189, 30, 116, 32,
|
|
- /* 1310 */ 85, 124, 189, 251, 252, 90, 189, 40, 258, 211,
|
|
- /* 1320 */ 212, 211, 212, 189, 99, 26, 211, 212, 211, 212,
|
|
- /* 1330 */ 105, 106, 100, 141, 211, 212, 189, 112, 189, 114,
|
|
- /* 1340 */ 115, 116, 24, 189, 119, 31, 23, 70, 189, 26,
|
|
- /* 1350 */ 113, 19, 20, 39, 22, 78, 115, 115, 81, 189,
|
|
- /* 1360 */ 211, 212, 22, 189, 24, 211, 212, 189, 36, 189,
|
|
- /* 1370 */ 211, 212, 189, 189, 97, 150, 151, 152, 153, 154,
|
|
- /* 1380 */ 127, 211, 212, 189, 189, 211, 212, 189, 143, 211,
|
|
- /* 1390 */ 212, 59, 189, 189, 211, 212, 23, 189, 189, 26,
|
|
- /* 1400 */ 59, 189, 149, 71, 22, 211, 212, 189, 131, 211,
|
|
- /* 1410 */ 212, 189, 59, 136, 137, 211, 212, 85, 189, 211,
|
|
- /* 1420 */ 212, 253, 90, 211, 212, 292, 293, 118, 119, 211,
|
|
- /* 1430 */ 212, 99, 23, 211, 212, 26, 159, 105, 106, 140,
|
|
- /* 1440 */ 211, 212, 23, 189, 112, 26, 114, 115, 116, 1,
|
|
- /* 1450 */ 2, 119, 189, 5, 7, 8, 115, 139, 10, 11,
|
|
- /* 1460 */ 12, 13, 14, 23, 189, 17, 26, 189, 115, 189,
|
|
- /* 1470 */ 19, 20, 189, 22, 189, 83, 84, 189, 30, 150,
|
|
- /* 1480 */ 32, 152, 150, 151, 152, 153, 154, 36, 40, 211,
|
|
- /* 1490 */ 212, 211, 212, 189, 211, 212, 211, 212, 309, 189,
|
|
- /* 1500 */ 19, 20, 189, 22, 150, 189, 152, 231, 189, 189,
|
|
- /* 1510 */ 59, 189, 23, 189, 189, 26, 189, 36, 70, 189,
|
|
- /* 1520 */ 23, 139, 71, 26, 211, 212, 78, 211, 212, 81,
|
|
- /* 1530 */ 281, 211, 212, 211, 212, 189, 211, 212, 211, 212,
|
|
- /* 1540 */ 59, 211, 212, 23, 23, 97, 26, 26, 23, 189,
|
|
- /* 1550 */ 99, 26, 71, 189, 119, 189, 105, 106, 107, 189,
|
|
- /* 1560 */ 189, 189, 280, 112, 129, 114, 115, 116, 189, 189,
|
|
- /* 1570 */ 119, 23, 19, 20, 26, 22, 189, 211, 212, 131,
|
|
- /* 1580 */ 99, 237, 211, 212, 136, 137, 105, 106, 189, 36,
|
|
- /* 1590 */ 211, 212, 189, 112, 189, 114, 115, 116, 211, 212,
|
|
- /* 1600 */ 119, 150, 151, 152, 153, 154, 189, 159, 23, 189,
|
|
- /* 1610 */ 23, 26, 59, 26, 189, 189, 189, 189, 189, 189,
|
|
- /* 1620 */ 209, 189, 238, 187, 71, 250, 250, 250, 211, 212,
|
|
- /* 1630 */ 241, 150, 151, 152, 153, 154, 211, 212, 250, 290,
|
|
- /* 1640 */ 254, 211, 212, 211, 212, 254, 215, 286, 241, 241,
|
|
- /* 1650 */ 254, 286, 99, 214, 220, 214, 214, 224, 105, 106,
|
|
- /* 1660 */ 244, 240, 244, 273, 192, 112, 60, 114, 115, 116,
|
|
- /* 1670 */ 139, 290, 119, 5, 196, 238, 196, 38, 10, 11,
|
|
- /* 1680 */ 12, 13, 14, 196, 287, 17, 148, 287, 276, 113,
|
|
- /* 1690 */ 43, 22, 229, 147, 241, 18, 232, 232, 30, 232,
|
|
- /* 1700 */ 32, 232, 264, 150, 151, 152, 153, 154, 40, 265,
|
|
- /* 1710 */ 196, 18, 195, 264, 241, 241, 241, 265, 196, 229,
|
|
- /* 1720 */ 229, 195, 155, 62, 196, 195, 283, 282, 22, 216,
|
|
- /* 1730 */ 196, 195, 216, 196, 195, 113, 213, 213, 70, 64,
|
|
- /* 1740 */ 213, 222, 22, 124, 162, 111, 78, 142, 219, 81,
|
|
- /* 1750 */ 215, 219, 275, 303, 213, 213, 216, 275, 213, 216,
|
|
- /* 1760 */ 213, 256, 113, 255, 255, 97, 222, 216, 256, 196,
|
|
- /* 1770 */ 91, 256, 82, 255, 308, 146, 308, 22, 143, 196,
|
|
- /* 1780 */ 270, 155, 145, 272, 144, 25, 13, 199, 26, 256,
|
|
- /* 1790 */ 198, 190, 190, 6, 296, 188, 188, 188, 244, 131,
|
|
- /* 1800 */ 245, 245, 243, 242, 136, 137, 241, 255, 208, 260,
|
|
- /* 1810 */ 260, 208, 202, 217, 217, 202, 4, 3, 202, 208,
|
|
- /* 1820 */ 208, 22, 160, 209, 209, 208, 15, 159, 98, 16,
|
|
- /* 1830 */ 23, 23, 137, 148, 24, 128, 140, 20, 16, 142,
|
|
- /* 1840 */ 1, 140, 128, 149, 61, 53, 37, 148, 53, 53,
|
|
- /* 1850 */ 53, 293, 128, 296, 114, 34, 139, 1, 5, 22,
|
|
- /* 1860 */ 113, 158, 68, 75, 26, 41, 68, 139, 24, 113,
|
|
- /* 1870 */ 20, 19, 129, 123, 23, 96, 22, 22, 59, 22,
|
|
- /* 1880 */ 22, 147, 67, 67, 24, 22, 37, 28, 23, 22,
|
|
- /* 1890 */ 67, 23, 23, 23, 114, 23, 22, 26, 22, 24,
|
|
- /* 1900 */ 23, 22, 24, 139, 23, 23, 141, 34, 88, 26,
|
|
- /* 1910 */ 75, 86, 23, 22, 34, 75, 24, 23, 34, 34,
|
|
- /* 1920 */ 34, 93, 34, 26, 26, 23, 23, 34, 23, 23,
|
|
- /* 1930 */ 26, 44, 23, 22, 11, 22, 22, 133, 23, 23,
|
|
- /* 1940 */ 22, 22, 139, 26, 139, 139, 15, 23, 1, 1,
|
|
- /* 1950 */ 310, 310, 310, 310, 310, 310, 310, 139, 310, 310,
|
|
- /* 1960 */ 310, 310, 310, 310, 310, 310, 310, 310, 310, 310,
|
|
- /* 1970 */ 310, 310, 310, 310, 310, 310, 310, 310, 310, 310,
|
|
- /* 1980 */ 310, 310, 310, 310, 310, 310, 310, 310, 310, 310,
|
|
- /* 1990 */ 310, 310, 310, 310, 310, 310, 310, 310, 310, 310,
|
|
- /* 2000 */ 310, 310, 310, 310, 310, 310, 310, 310, 310, 310,
|
|
- /* 2010 */ 310, 310, 310, 310, 310, 310, 310, 310, 310, 310,
|
|
- /* 2020 */ 310, 310, 310, 310, 310, 310, 310, 310, 310, 310,
|
|
- /* 2030 */ 310, 310, 310, 310, 310, 310, 310, 310, 310, 310,
|
|
- /* 2040 */ 310, 310, 310, 310, 310, 310, 310, 310, 310, 310,
|
|
- /* 2050 */ 310, 310, 310, 310, 310, 310, 310, 310, 310, 310,
|
|
- /* 2060 */ 310, 310, 310, 310, 310, 310, 310, 310, 310, 310,
|
|
- /* 2070 */ 310, 310, 310, 310, 310, 310, 310, 310, 310, 310,
|
|
- /* 2080 */ 310, 310, 310, 310, 310, 310, 310, 310, 310, 310,
|
|
- /* 2090 */ 310, 310, 310, 310, 310, 310, 310, 310, 310, 310,
|
|
- /* 2100 */ 310, 310, 310, 310, 310, 310, 310, 310, 310, 310,
|
|
- /* 2110 */ 310, 310, 310, 310, 310, 310, 310, 310, 310, 310,
|
|
- /* 2120 */ 310, 310, 310, 310, 310, 310, 310, 310, 310, 310,
|
|
- /* 2130 */ 310, 310, 310, 310, 310, 310, 310, 310, 310,
|
|
+ /* 370 */ 112, 113, 239, 240, 311, 312, 215, 106, 107, 241,
|
|
+ /* 380 */ 19, 59, 216, 217, 223, 252, 115, 116, 117, 118,
|
|
+ /* 390 */ 151, 120, 26, 71, 193, 308, 309, 193, 149, 128,
|
|
+ /* 400 */ 313, 216, 269, 81, 43, 44, 45, 46, 47, 48,
|
|
+ /* 410 */ 49, 50, 51, 52, 53, 54, 55, 56, 57, 253,
|
|
+ /* 420 */ 216, 217, 100, 95, 153, 59, 155, 261, 106, 107,
|
|
+ /* 430 */ 25, 193, 101, 193, 193, 231, 114, 25, 116, 117,
|
|
+ /* 440 */ 118, 113, 304, 121, 193, 204, 59, 119, 120, 121,
|
|
+ /* 450 */ 122, 123, 124, 125, 216, 217, 193, 216, 217, 131,
|
|
+ /* 460 */ 138, 139, 230, 102, 103, 104, 105, 106, 107, 108,
|
|
+ /* 470 */ 109, 110, 111, 112, 113, 153, 154, 155, 156, 157,
|
|
+ /* 480 */ 239, 240, 116, 117, 118, 76, 193, 23, 19, 25,
|
|
+ /* 490 */ 22, 253, 23, 252, 253, 108, 87, 204, 89, 261,
|
|
+ /* 500 */ 198, 92, 261, 116, 117, 118, 193, 306, 307, 216,
|
|
+ /* 510 */ 217, 150, 43, 44, 45, 46, 47, 48, 49, 50,
|
|
+ /* 520 */ 51, 52, 53, 54, 55, 56, 57, 59, 193, 216,
|
|
+ /* 530 */ 217, 19, 239, 240, 283, 23, 106, 107, 108, 109,
|
|
+ /* 540 */ 110, 111, 112, 113, 73, 252, 253, 142, 308, 309,
|
|
+ /* 550 */ 138, 139, 81, 313, 145, 43, 44, 45, 46, 47,
|
|
+ /* 560 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
|
|
+ /* 570 */ 307, 102, 103, 104, 105, 106, 107, 108, 109, 110,
|
|
+ /* 580 */ 111, 112, 113, 281, 116, 117, 118, 285, 23, 193,
|
|
+ /* 590 */ 25, 119, 59, 193, 122, 123, 124, 59, 127, 203,
|
|
+ /* 600 */ 59, 205, 19, 268, 132, 25, 23, 22, 193, 138,
|
|
+ /* 610 */ 139, 249, 204, 251, 102, 103, 104, 105, 106, 107,
|
|
+ /* 620 */ 108, 109, 110, 111, 112, 113, 43, 44, 45, 46,
|
|
+ /* 630 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
|
|
+ /* 640 */ 57, 19, 22, 23, 59, 23, 25, 239, 240, 116,
|
|
+ /* 650 */ 117, 118, 193, 11, 116, 117, 118, 116, 117, 118,
|
|
+ /* 660 */ 252, 269, 22, 193, 15, 43, 44, 45, 46, 47,
|
|
+ /* 670 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
|
|
+ /* 680 */ 273, 143, 193, 118, 143, 102, 103, 104, 105, 106,
|
|
+ /* 690 */ 107, 108, 109, 110, 111, 112, 113, 76, 118, 59,
|
|
+ /* 700 */ 241, 116, 117, 118, 304, 216, 217, 292, 143, 60,
|
|
+ /* 710 */ 89, 241, 19, 92, 193, 193, 23, 22, 311, 312,
|
|
+ /* 720 */ 231, 101, 22, 143, 102, 103, 104, 105, 106, 107,
|
|
+ /* 730 */ 108, 109, 110, 111, 112, 113, 43, 44, 45, 46,
|
|
+ /* 740 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
|
|
+ /* 750 */ 57, 19, 193, 193, 59, 23, 116, 117, 118, 59,
|
|
+ /* 760 */ 201, 21, 241, 304, 22, 206, 127, 128, 129, 193,
|
|
+ /* 770 */ 128, 129, 235, 236, 304, 43, 44, 45, 46, 47,
|
|
+ /* 780 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
|
|
+ /* 790 */ 22, 193, 216, 217, 193, 102, 103, 104, 105, 106,
|
|
+ /* 800 */ 107, 108, 109, 110, 111, 112, 113, 231, 193, 193,
|
|
+ /* 810 */ 193, 116, 117, 118, 216, 217, 116, 117, 118, 226,
|
|
+ /* 820 */ 80, 193, 19, 235, 236, 304, 23, 211, 212, 231,
|
|
+ /* 830 */ 204, 216, 217, 205, 102, 103, 104, 105, 106, 107,
|
|
+ /* 840 */ 108, 109, 110, 111, 112, 113, 43, 44, 45, 46,
|
|
+ /* 850 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
|
|
+ /* 860 */ 57, 19, 193, 123, 76, 239, 240, 193, 253, 239,
|
|
+ /* 870 */ 240, 239, 240, 193, 106, 107, 193, 89, 252, 193,
|
|
+ /* 880 */ 92, 59, 252, 141, 252, 43, 44, 45, 46, 47,
|
|
+ /* 890 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
|
|
+ /* 900 */ 284, 161, 216, 217, 193, 102, 103, 104, 105, 106,
|
|
+ /* 910 */ 107, 108, 109, 110, 111, 112, 113, 231, 193, 16,
|
|
+ /* 920 */ 187, 188, 189, 190, 7, 8, 9, 309, 195, 25,
|
|
+ /* 930 */ 197, 313, 19, 127, 128, 129, 262, 204, 22, 117,
|
|
+ /* 940 */ 24, 216, 217, 263, 102, 103, 104, 105, 106, 107,
|
|
+ /* 950 */ 108, 109, 110, 111, 112, 113, 43, 44, 45, 46,
|
|
+ /* 960 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
|
|
+ /* 970 */ 57, 193, 239, 240, 193, 59, 19, 188, 253, 190,
|
|
+ /* 980 */ 77, 226, 79, 193, 195, 252, 197, 193, 19, 301,
|
|
+ /* 990 */ 302, 193, 193, 204, 216, 217, 226, 216, 217, 266,
|
|
+ /* 1000 */ 204, 159, 45, 46, 47, 48, 49, 50, 51, 52,
|
|
+ /* 1010 */ 53, 54, 55, 56, 57, 102, 103, 104, 105, 106,
|
|
+ /* 1020 */ 107, 108, 109, 110, 111, 112, 113, 12, 239, 240,
|
|
+ /* 1030 */ 232, 298, 238, 117, 253, 239, 240, 238, 259, 260,
|
|
+ /* 1040 */ 193, 252, 27, 31, 193, 193, 142, 204, 252, 193,
|
|
+ /* 1050 */ 193, 39, 262, 193, 100, 266, 278, 42, 204, 102,
|
|
+ /* 1060 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 112,
|
|
+ /* 1070 */ 113, 117, 159, 216, 217, 121, 216, 217, 63, 193,
|
|
+ /* 1080 */ 193, 193, 239, 240, 115, 116, 193, 298, 73, 238,
|
|
+ /* 1090 */ 238, 231, 19, 239, 240, 252, 22, 24, 211, 212,
|
|
+ /* 1100 */ 24, 193, 216, 217, 216, 217, 252, 153, 154, 155,
|
|
+ /* 1110 */ 253, 16, 19, 144, 213, 268, 43, 44, 45, 46,
|
|
+ /* 1120 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
|
|
+ /* 1130 */ 57, 238, 19, 59, 193, 59, 43, 44, 45, 46,
|
|
+ /* 1140 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
|
|
+ /* 1150 */ 57, 22, 23, 193, 25, 193, 43, 44, 45, 46,
|
|
+ /* 1160 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
|
|
+ /* 1170 */ 57, 284, 77, 193, 79, 102, 103, 104, 105, 106,
|
|
+ /* 1180 */ 107, 108, 109, 110, 111, 112, 113, 286, 193, 193,
|
|
+ /* 1190 */ 193, 117, 291, 117, 232, 102, 103, 104, 105, 106,
|
|
+ /* 1200 */ 107, 108, 109, 110, 111, 112, 113, 204, 22, 23,
|
|
+ /* 1210 */ 66, 25, 216, 217, 35, 102, 103, 104, 105, 106,
|
|
+ /* 1220 */ 107, 108, 109, 110, 111, 112, 113, 193, 268, 85,
|
|
+ /* 1230 */ 101, 193, 309, 309, 240, 19, 313, 313, 94, 208,
|
|
+ /* 1240 */ 209, 193, 239, 240, 193, 66, 252, 19, 268, 244,
|
|
+ /* 1250 */ 216, 217, 193, 74, 213, 252, 161, 19, 263, 254,
|
|
+ /* 1260 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
|
|
+ /* 1270 */ 54, 55, 56, 57, 193, 216, 217, 5, 59, 193,
|
|
+ /* 1280 */ 19, 244, 10, 11, 12, 13, 14, 101, 309, 17,
|
|
+ /* 1290 */ 146, 254, 313, 193, 193, 76, 115, 216, 217, 309,
|
|
+ /* 1300 */ 12, 263, 30, 313, 32, 46, 87, 46, 89, 130,
|
|
+ /* 1310 */ 193, 92, 40, 22, 263, 27, 216, 217, 102, 103,
|
|
+ /* 1320 */ 104, 105, 106, 107, 108, 109, 110, 111, 112, 113,
|
|
+ /* 1330 */ 42, 150, 291, 216, 217, 116, 117, 118, 19, 20,
|
|
+ /* 1340 */ 193, 22, 70, 260, 116, 193, 24, 264, 193, 263,
|
|
+ /* 1350 */ 78, 63, 61, 81, 116, 36, 193, 260, 193, 29,
|
|
+ /* 1360 */ 193, 264, 193, 33, 145, 193, 59, 48, 216, 217,
|
|
+ /* 1370 */ 98, 216, 217, 193, 115, 193, 115, 193, 59, 216,
|
|
+ /* 1380 */ 217, 216, 217, 216, 217, 216, 217, 255, 216, 217,
|
|
+ /* 1390 */ 71, 193, 131, 193, 25, 65, 216, 217, 216, 217,
|
|
+ /* 1400 */ 216, 217, 208, 209, 85, 133, 193, 100, 193, 90,
|
|
+ /* 1410 */ 138, 139, 138, 139, 216, 217, 216, 217, 193, 100,
|
|
+ /* 1420 */ 193, 108, 135, 116, 117, 106, 107, 140, 121, 216,
|
|
+ /* 1430 */ 217, 216, 217, 114, 162, 116, 117, 118, 299, 300,
|
|
+ /* 1440 */ 121, 216, 217, 216, 217, 193, 244, 193, 135, 244,
|
|
+ /* 1450 */ 193, 256, 257, 140, 244, 193, 254, 193, 193, 254,
|
|
+ /* 1460 */ 153, 154, 155, 141, 254, 149, 150, 258, 216, 217,
|
|
+ /* 1470 */ 216, 217, 153, 154, 155, 156, 157, 0, 1, 2,
|
|
+ /* 1480 */ 216, 217, 5, 115, 158, 193, 160, 10, 11, 12,
|
|
+ /* 1490 */ 13, 14, 193, 59, 17, 126, 193, 19, 20, 129,
|
|
+ /* 1500 */ 22, 193, 22, 22, 24, 193, 23, 30, 25, 32,
|
|
+ /* 1510 */ 19, 20, 144, 22, 36, 216, 217, 40, 193, 216,
|
|
+ /* 1520 */ 217, 193, 152, 129, 216, 217, 193, 36, 216, 217,
|
|
+ /* 1530 */ 193, 99, 193, 193, 53, 193, 193, 59, 23, 193,
|
|
+ /* 1540 */ 25, 216, 217, 193, 216, 217, 152, 70, 59, 71,
|
|
+ /* 1550 */ 59, 117, 193, 216, 217, 78, 216, 217, 81, 216,
|
|
+ /* 1560 */ 217, 318, 71, 85, 193, 133, 193, 193, 90, 23,
|
|
+ /* 1570 */ 23, 25, 25, 120, 121, 98, 85, 193, 100, 193,
|
|
+ /* 1580 */ 23, 90, 25, 121, 106, 107, 19, 216, 217, 216,
|
|
+ /* 1590 */ 217, 100, 114, 131, 116, 117, 118, 106, 107, 121,
|
|
+ /* 1600 */ 216, 217, 216, 217, 193, 114, 117, 116, 117, 118,
|
|
+ /* 1610 */ 133, 193, 121, 193, 193, 138, 139, 193, 23, 193,
|
|
+ /* 1620 */ 25, 23, 23, 25, 25, 7, 8, 216, 217, 193,
|
|
+ /* 1630 */ 193, 153, 154, 155, 156, 157, 216, 217, 193, 162,
|
|
+ /* 1640 */ 216, 217, 216, 217, 153, 154, 155, 156, 157, 1,
|
|
+ /* 1650 */ 2, 193, 193, 5, 19, 20, 59, 22, 10, 11,
|
|
+ /* 1660 */ 12, 13, 14, 193, 97, 17, 193, 23, 193, 25,
|
|
+ /* 1670 */ 288, 36, 193, 242, 216, 217, 236, 23, 30, 25,
|
|
+ /* 1680 */ 32, 19, 20, 23, 22, 25, 216, 217, 40, 216,
|
|
+ /* 1690 */ 217, 216, 217, 193, 59, 216, 217, 193, 36, 83,
|
|
+ /* 1700 */ 84, 153, 153, 155, 155, 23, 71, 25, 23, 193,
|
|
+ /* 1710 */ 25, 193, 193, 193, 117, 193, 193, 193, 70, 193,
|
|
+ /* 1720 */ 193, 59, 193, 255, 255, 287, 78, 255, 243, 81,
|
|
+ /* 1730 */ 191, 255, 297, 71, 271, 100, 293, 245, 267, 214,
|
|
+ /* 1740 */ 246, 106, 107, 108, 246, 271, 98, 245, 293, 114,
|
|
+ /* 1750 */ 220, 116, 117, 118, 267, 271, 121, 271, 225, 219,
|
|
+ /* 1760 */ 229, 219, 100, 219, 259, 259, 259, 259, 106, 107,
|
|
+ /* 1770 */ 249, 196, 60, 280, 141, 243, 114, 249, 116, 117,
|
|
+ /* 1780 */ 118, 133, 245, 121, 200, 297, 138, 139, 153, 154,
|
|
+ /* 1790 */ 155, 156, 157, 297, 200, 38, 19, 20, 151, 22,
|
|
+ /* 1800 */ 200, 150, 140, 294, 294, 22, 272, 43, 234, 18,
|
|
+ /* 1810 */ 162, 270, 200, 36, 237, 153, 154, 155, 156, 157,
|
|
+ /* 1820 */ 237, 283, 237, 237, 18, 199, 149, 246, 272, 270,
|
|
+ /* 1830 */ 272, 200, 158, 246, 246, 234, 59, 234, 246, 199,
|
|
+ /* 1840 */ 290, 62, 289, 200, 199, 22, 221, 115, 71, 200,
|
|
+ /* 1850 */ 200, 199, 199, 221, 218, 218, 19, 20, 64, 22,
|
|
+ /* 1860 */ 218, 227, 22, 224, 126, 224, 165, 221, 24, 305,
|
|
+ /* 1870 */ 200, 113, 312, 36, 218, 220, 218, 100, 282, 218,
|
|
+ /* 1880 */ 91, 218, 317, 106, 107, 221, 227, 282, 317, 82,
|
|
+ /* 1890 */ 148, 114, 265, 116, 117, 118, 59, 145, 121, 22,
|
|
+ /* 1900 */ 277, 158, 200, 265, 25, 202, 147, 250, 71, 279,
|
|
+ /* 1910 */ 13, 146, 194, 194, 249, 248, 250, 140, 247, 246,
|
|
+ /* 1920 */ 6, 192, 192, 192, 303, 303, 213, 207, 300, 213,
|
|
+ /* 1930 */ 153, 154, 155, 156, 157, 213, 213, 100, 213, 222,
|
|
+ /* 1940 */ 207, 214, 214, 106, 107, 4, 222, 207, 3, 22,
|
|
+ /* 1950 */ 163, 114, 15, 116, 117, 118, 16, 23, 121, 23,
|
|
+ /* 1960 */ 139, 151, 130, 25, 142, 16, 24, 20, 144, 1,
|
|
+ /* 1970 */ 142, 130, 130, 61, 53, 53, 37, 151, 53, 53,
|
|
+ /* 1980 */ 130, 116, 34, 1, 141, 5, 22, 115, 161, 141,
|
|
+ /* 1990 */ 153, 154, 155, 156, 157, 25, 68, 68, 75, 41,
|
|
+ /* 2000 */ 115, 24, 131, 20, 19, 125, 22, 96, 22, 22,
|
|
+ /* 2010 */ 67, 23, 22, 67, 59, 24, 22, 28, 67, 23,
|
|
+ /* 2020 */ 22, 22, 149, 23, 23, 23, 116, 23, 25, 37,
|
|
+ /* 2030 */ 97, 141, 23, 23, 22, 143, 25, 75, 88, 34,
|
|
+ /* 2040 */ 34, 34, 34, 86, 75, 93, 23, 34, 22, 34,
|
|
+ /* 2050 */ 25, 24, 34, 25, 23, 142, 23, 142, 44, 23,
|
|
+ /* 2060 */ 23, 23, 11, 23, 25, 22, 22, 22, 15, 23,
|
|
+ /* 2070 */ 23, 22, 22, 25, 1, 1, 141, 25, 23, 135,
|
|
+ /* 2080 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
|
|
+ /* 2090 */ 319, 319, 319, 319, 141, 141, 319, 141, 319, 319,
|
|
+ /* 2100 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
|
|
+ /* 2110 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
|
|
+ /* 2120 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
|
|
+ /* 2130 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
|
|
+ /* 2140 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
|
|
+ /* 2150 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
|
|
+ /* 2160 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
|
|
+ /* 2170 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
|
|
+ /* 2180 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
|
|
+ /* 2190 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
|
|
+ /* 2200 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
|
|
+ /* 2210 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
|
|
+ /* 2220 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
|
|
+ /* 2230 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
|
|
+ /* 2240 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
|
|
+ /* 2250 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
|
|
+ /* 2260 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
|
|
+ /* 2270 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
|
|
+ /* 2280 */ 319, 319, 319,
|
|
};
|
|
-#define YY_SHIFT_COUNT (550)
|
|
+#define YY_SHIFT_COUNT (575)
|
|
#define YY_SHIFT_MIN (0)
|
|
-#define YY_SHIFT_MAX (1948)
|
|
+#define YY_SHIFT_MAX (2074)
|
|
static const unsigned short int yy_shift_ofst[] = {
|
|
- /* 0 */ 1448, 1277, 1668, 1072, 1072, 340, 1122, 1225, 1332, 1481,
|
|
- /* 10 */ 1481, 1481, 335, 0, 0, 180, 897, 1481, 1481, 1481,
|
|
- /* 20 */ 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481,
|
|
- /* 30 */ 930, 930, 1020, 1020, 290, 1, 340, 340, 340, 340,
|
|
- /* 40 */ 340, 340, 40, 110, 219, 288, 327, 396, 435, 504,
|
|
- /* 50 */ 543, 612, 651, 720, 877, 897, 897, 897, 897, 897,
|
|
- /* 60 */ 897, 897, 897, 897, 897, 897, 897, 897, 897, 897,
|
|
- /* 70 */ 897, 897, 897, 917, 897, 1019, 763, 763, 1451, 1481,
|
|
- /* 80 */ 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481,
|
|
- /* 90 */ 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481,
|
|
- /* 100 */ 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481,
|
|
- /* 110 */ 1481, 1481, 1553, 1481, 1481, 1481, 1481, 1481, 1481, 1481,
|
|
- /* 120 */ 1481, 1481, 1481, 1481, 1481, 1481, 147, 258, 258, 258,
|
|
- /* 130 */ 258, 258, 79, 65, 84, 449, 19, 786, 449, 636,
|
|
- /* 140 */ 636, 449, 880, 880, 880, 880, 113, 142, 142, 472,
|
|
- /* 150 */ 150, 1958, 1958, 399, 399, 399, 93, 237, 341, 237,
|
|
- /* 160 */ 237, 1074, 1074, 437, 350, 704, 1080, 449, 449, 449,
|
|
- /* 170 */ 449, 449, 449, 449, 449, 449, 449, 449, 449, 449,
|
|
- /* 180 */ 449, 449, 449, 449, 449, 449, 449, 449, 818, 818,
|
|
- /* 190 */ 449, 1088, 217, 217, 734, 734, 1124, 1126, 1958, 1958,
|
|
- /* 200 */ 1958, 739, 840, 840, 453, 454, 511, 187, 563, 570,
|
|
- /* 210 */ 898, 669, 449, 449, 449, 449, 449, 449, 449, 449,
|
|
- /* 220 */ 449, 670, 449, 449, 449, 449, 449, 449, 449, 449,
|
|
- /* 230 */ 449, 449, 449, 449, 674, 674, 674, 449, 449, 449,
|
|
- /* 240 */ 449, 1034, 449, 449, 449, 972, 1107, 449, 449, 1193,
|
|
- /* 250 */ 449, 449, 449, 449, 449, 449, 449, 449, 260, 177,
|
|
- /* 260 */ 489, 1241, 1241, 1241, 1241, 1192, 489, 489, 952, 1197,
|
|
- /* 270 */ 625, 1235, 1139, 181, 181, 1086, 1139, 1139, 1086, 1187,
|
|
- /* 280 */ 1131, 1237, 1314, 1314, 1314, 181, 1245, 1245, 1109, 1299,
|
|
- /* 290 */ 549, 1340, 1606, 1531, 1531, 1639, 1639, 1531, 1538, 1576,
|
|
- /* 300 */ 1669, 1647, 1546, 1677, 1677, 1677, 1677, 1531, 1693, 1546,
|
|
- /* 310 */ 1546, 1576, 1669, 1647, 1647, 1546, 1531, 1693, 1567, 1661,
|
|
- /* 320 */ 1531, 1693, 1706, 1531, 1693, 1531, 1693, 1706, 1622, 1622,
|
|
- /* 330 */ 1622, 1675, 1720, 1720, 1706, 1622, 1619, 1622, 1675, 1622,
|
|
- /* 340 */ 1622, 1582, 1706, 1634, 1634, 1706, 1605, 1649, 1605, 1649,
|
|
- /* 350 */ 1605, 1649, 1605, 1649, 1531, 1679, 1679, 1690, 1690, 1629,
|
|
- /* 360 */ 1635, 1755, 1531, 1626, 1629, 1637, 1640, 1546, 1760, 1762,
|
|
- /* 370 */ 1773, 1773, 1787, 1787, 1787, 1958, 1958, 1958, 1958, 1958,
|
|
- /* 380 */ 1958, 1958, 1958, 1958, 1958, 1958, 1958, 1958, 1958, 1958,
|
|
- /* 390 */ 308, 835, 954, 1232, 879, 715, 728, 1323, 864, 1318,
|
|
- /* 400 */ 1253, 1373, 297, 1409, 1419, 1440, 1489, 1497, 1520, 1242,
|
|
- /* 410 */ 1309, 1447, 1435, 1341, 1521, 1525, 1392, 1548, 1329, 1354,
|
|
- /* 420 */ 1585, 1587, 1353, 1382, 1812, 1814, 1799, 1662, 1811, 1730,
|
|
- /* 430 */ 1813, 1807, 1808, 1695, 1685, 1707, 1810, 1696, 1817, 1697,
|
|
- /* 440 */ 1822, 1839, 1701, 1694, 1714, 1783, 1809, 1699, 1792, 1795,
|
|
- /* 450 */ 1796, 1797, 1724, 1740, 1821, 1717, 1856, 1853, 1837, 1747,
|
|
- /* 460 */ 1703, 1794, 1838, 1798, 1788, 1824, 1728, 1756, 1844, 1850,
|
|
- /* 470 */ 1852, 1743, 1750, 1854, 1815, 1855, 1857, 1851, 1858, 1816,
|
|
- /* 480 */ 1819, 1860, 1779, 1859, 1863, 1823, 1849, 1865, 1734, 1867,
|
|
- /* 490 */ 1868, 1869, 1870, 1871, 1872, 1874, 1875, 1877, 1876, 1878,
|
|
- /* 500 */ 1764, 1881, 1882, 1780, 1873, 1879, 1765, 1883, 1880, 1884,
|
|
- /* 510 */ 1885, 1886, 1820, 1835, 1825, 1887, 1840, 1828, 1888, 1889,
|
|
- /* 520 */ 1891, 1892, 1897, 1898, 1893, 1894, 1883, 1902, 1903, 1905,
|
|
- /* 530 */ 1906, 1904, 1909, 1911, 1923, 1913, 1914, 1915, 1916, 1918,
|
|
- /* 540 */ 1919, 1917, 1804, 1803, 1805, 1806, 1818, 1924, 1931, 1947,
|
|
- /* 550 */ 1948,
|
|
+ /* 0 */ 1648, 1477, 1272, 322, 322, 1, 1319, 1478, 1491, 1837,
|
|
+ /* 10 */ 1837, 1837, 471, 0, 0, 214, 1093, 1837, 1837, 1837,
|
|
+ /* 20 */ 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837,
|
|
+ /* 30 */ 271, 271, 1219, 1219, 216, 88, 1, 1, 1, 1,
|
|
+ /* 40 */ 1, 40, 111, 258, 361, 469, 512, 583, 622, 693,
|
|
+ /* 50 */ 732, 803, 842, 913, 1073, 1093, 1093, 1093, 1093, 1093,
|
|
+ /* 60 */ 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1093,
|
|
+ /* 70 */ 1093, 1093, 1093, 1113, 1093, 1216, 957, 957, 1635, 1662,
|
|
+ /* 80 */ 1777, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837,
|
|
+ /* 90 */ 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837,
|
|
+ /* 100 */ 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837,
|
|
+ /* 110 */ 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837,
|
|
+ /* 120 */ 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837,
|
|
+ /* 130 */ 137, 181, 181, 181, 181, 181, 181, 181, 94, 430,
|
|
+ /* 140 */ 66, 65, 112, 366, 533, 533, 740, 1261, 533, 533,
|
|
+ /* 150 */ 79, 79, 533, 412, 412, 412, 77, 412, 123, 113,
|
|
+ /* 160 */ 113, 22, 22, 2098, 2098, 328, 328, 328, 239, 468,
|
|
+ /* 170 */ 468, 468, 468, 1015, 1015, 409, 366, 1129, 1186, 533,
|
|
+ /* 180 */ 533, 533, 533, 533, 533, 533, 533, 533, 533, 533,
|
|
+ /* 190 */ 533, 533, 533, 533, 533, 533, 533, 533, 533, 969,
|
|
+ /* 200 */ 621, 621, 533, 642, 788, 788, 1228, 1228, 822, 822,
|
|
+ /* 210 */ 67, 1274, 2098, 2098, 2098, 2098, 2098, 2098, 2098, 1307,
|
|
+ /* 220 */ 954, 954, 585, 472, 640, 387, 695, 538, 541, 700,
|
|
+ /* 230 */ 533, 533, 533, 533, 533, 533, 533, 533, 533, 533,
|
|
+ /* 240 */ 222, 533, 533, 533, 533, 533, 533, 533, 533, 533,
|
|
+ /* 250 */ 533, 533, 533, 1179, 1179, 1179, 533, 533, 533, 565,
|
|
+ /* 260 */ 533, 533, 533, 916, 1144, 533, 533, 1288, 533, 533,
|
|
+ /* 270 */ 533, 533, 533, 533, 533, 533, 639, 1330, 209, 1076,
|
|
+ /* 280 */ 1076, 1076, 1076, 580, 209, 209, 1313, 768, 917, 649,
|
|
+ /* 290 */ 1181, 1316, 405, 1316, 1238, 249, 1181, 1181, 249, 1181,
|
|
+ /* 300 */ 405, 1238, 1369, 464, 1259, 1012, 1012, 1012, 1368, 1368,
|
|
+ /* 310 */ 1368, 1368, 184, 184, 1326, 904, 1287, 1480, 1712, 1712,
|
|
+ /* 320 */ 1633, 1633, 1757, 1757, 1633, 1647, 1651, 1783, 1764, 1791,
|
|
+ /* 330 */ 1791, 1791, 1791, 1633, 1806, 1677, 1651, 1651, 1677, 1783,
|
|
+ /* 340 */ 1764, 1677, 1764, 1677, 1633, 1806, 1674, 1779, 1633, 1806,
|
|
+ /* 350 */ 1823, 1633, 1806, 1633, 1806, 1823, 1732, 1732, 1732, 1794,
|
|
+ /* 360 */ 1840, 1840, 1823, 1732, 1738, 1732, 1794, 1732, 1732, 1701,
|
|
+ /* 370 */ 1844, 1758, 1758, 1823, 1633, 1789, 1789, 1807, 1807, 1742,
|
|
+ /* 380 */ 1752, 1877, 1633, 1743, 1742, 1759, 1765, 1677, 1879, 1897,
|
|
+ /* 390 */ 1897, 1914, 1914, 1914, 2098, 2098, 2098, 2098, 2098, 2098,
|
|
+ /* 400 */ 2098, 2098, 2098, 2098, 2098, 2098, 2098, 2098, 2098, 207,
|
|
+ /* 410 */ 1095, 331, 620, 903, 806, 1074, 1483, 1432, 1481, 1322,
|
|
+ /* 420 */ 1370, 1394, 1515, 1291, 1546, 1547, 1557, 1595, 1598, 1599,
|
|
+ /* 430 */ 1434, 1453, 1618, 1462, 1567, 1489, 1644, 1654, 1616, 1660,
|
|
+ /* 440 */ 1548, 1549, 1682, 1685, 1597, 742, 1941, 1945, 1927, 1787,
|
|
+ /* 450 */ 1937, 1940, 1934, 1936, 1821, 1810, 1832, 1938, 1938, 1942,
|
|
+ /* 460 */ 1822, 1947, 1824, 1949, 1968, 1828, 1841, 1938, 1842, 1912,
|
|
+ /* 470 */ 1939, 1938, 1826, 1921, 1922, 1925, 1926, 1850, 1865, 1948,
|
|
+ /* 480 */ 1843, 1982, 1980, 1964, 1872, 1827, 1928, 1970, 1929, 1923,
|
|
+ /* 490 */ 1958, 1848, 1885, 1977, 1983, 1985, 1871, 1880, 1984, 1943,
|
|
+ /* 500 */ 1986, 1987, 1988, 1990, 1946, 1955, 1991, 1911, 1989, 1994,
|
|
+ /* 510 */ 1951, 1992, 1996, 1873, 1998, 2000, 2001, 2002, 2003, 2004,
|
|
+ /* 520 */ 1999, 1933, 1890, 2009, 2010, 1910, 2005, 2012, 1892, 2011,
|
|
+ /* 530 */ 2006, 2007, 2008, 2013, 1950, 1962, 1957, 2014, 1969, 1952,
|
|
+ /* 540 */ 2015, 2023, 2026, 2027, 2025, 2028, 2018, 1913, 1915, 2031,
|
|
+ /* 550 */ 2011, 2033, 2036, 2037, 2038, 2039, 2040, 2043, 2051, 2044,
|
|
+ /* 560 */ 2045, 2046, 2047, 2049, 2050, 2048, 1944, 1935, 1953, 1954,
|
|
+ /* 570 */ 1956, 2052, 2055, 2053, 2073, 2074,
|
|
};
|
|
-#define YY_REDUCE_COUNT (389)
|
|
-#define YY_REDUCE_MIN (-262)
|
|
-#define YY_REDUCE_MAX (1617)
|
|
+#define YY_REDUCE_COUNT (408)
|
|
+#define YY_REDUCE_MIN (-271)
|
|
+#define YY_REDUCE_MAX (1740)
|
|
static const short yy_reduce_ofst[] = {
|
|
- /* 0 */ 490, -122, 545, 645, 650, -120, -189, -187, -184, -182,
|
|
- /* 10 */ -178, -176, 45, 30, 200, -251, -134, 390, 392, 521,
|
|
- /* 20 */ 523, 213, 692, 821, 284, 589, 872, 666, 671, 866,
|
|
- /* 30 */ 71, 111, 273, 389, 686, 815, 904, 932, 948, 955,
|
|
- /* 40 */ 964, 969, -259, -259, -259, -259, -259, -259, -259, -259,
|
|
- /* 50 */ -259, -259, -259, -259, -259, -259, -259, -259, -259, -259,
|
|
- /* 60 */ -259, -259, -259, -259, -259, -259, -259, -259, -259, -259,
|
|
- /* 70 */ -259, -259, -259, -259, -259, -259, -259, -259, 428, 430,
|
|
- /* 80 */ 899, 985, 1021, 1028, 1057, 1069, 1081, 1108, 1110, 1115,
|
|
- /* 90 */ 1117, 1123, 1149, 1154, 1159, 1170, 1174, 1178, 1183, 1194,
|
|
- /* 100 */ 1198, 1204, 1208, 1212, 1218, 1222, 1229, 1278, 1280, 1283,
|
|
- /* 110 */ 1285, 1313, 1316, 1320, 1322, 1325, 1327, 1330, 1366, 1371,
|
|
- /* 120 */ 1379, 1387, 1417, 1425, 1430, 1432, -259, -259, -259, -259,
|
|
- /* 130 */ -259, -259, -259, -259, -259, 557, 974, -214, -174, -9,
|
|
- /* 140 */ 431, -124, 806, 925, 806, 925, 251, 928, 940, -259,
|
|
- /* 150 */ -259, -259, -259, -198, -198, -198, 127, -186, -168, 212,
|
|
- /* 160 */ 646, 617, 799, -262, 555, 220, 220, 491, 605, 1040,
|
|
- /* 170 */ 1060, 699, -11, 600, 848, 862, 345, -129, 724, -91,
|
|
- /* 180 */ 158, 749, 716, 900, 304, 822, 929, 926, 499, 793,
|
|
- /* 190 */ 322, 892, 813, 845, 958, 1056, 751, 905, 1133, 1062,
|
|
- /* 200 */ 803, -210, -185, -179, -148, -167, -89, 121, 274, 281,
|
|
- /* 210 */ 320, 336, 439, 663, 711, 957, 1064, 1068, 1116, 1127,
|
|
- /* 220 */ 1134, -196, 1147, 1180, 1184, 1195, 1203, 1209, 1254, 1263,
|
|
- /* 230 */ 1275, 1288, 1304, 1310, 205, 422, 638, 1319, 1324, 1346,
|
|
- /* 240 */ 1360, 1168, 1364, 1370, 1372, 869, 1189, 1380, 1399, 1276,
|
|
- /* 250 */ 1403, 121, 1405, 1420, 1426, 1427, 1428, 1429, 1249, 1282,
|
|
- /* 260 */ 1344, 1375, 1376, 1377, 1388, 1168, 1344, 1344, 1384, 1411,
|
|
- /* 270 */ 1436, 1349, 1389, 1386, 1391, 1361, 1407, 1408, 1365, 1431,
|
|
- /* 280 */ 1433, 1434, 1439, 1441, 1442, 1396, 1416, 1418, 1390, 1421,
|
|
- /* 290 */ 1437, 1472, 1381, 1478, 1480, 1397, 1400, 1487, 1412, 1444,
|
|
- /* 300 */ 1438, 1463, 1453, 1464, 1465, 1467, 1469, 1514, 1517, 1473,
|
|
- /* 310 */ 1474, 1452, 1449, 1490, 1491, 1475, 1522, 1526, 1443, 1445,
|
|
- /* 320 */ 1528, 1530, 1513, 1534, 1536, 1537, 1539, 1516, 1523, 1524,
|
|
- /* 330 */ 1527, 1519, 1529, 1532, 1540, 1541, 1535, 1542, 1544, 1545,
|
|
- /* 340 */ 1547, 1450, 1543, 1477, 1482, 1551, 1505, 1508, 1512, 1509,
|
|
- /* 350 */ 1515, 1518, 1533, 1552, 1573, 1466, 1468, 1549, 1550, 1555,
|
|
- /* 360 */ 1554, 1510, 1583, 1511, 1556, 1559, 1561, 1565, 1588, 1592,
|
|
- /* 370 */ 1601, 1602, 1607, 1608, 1609, 1498, 1557, 1558, 1610, 1600,
|
|
- /* 380 */ 1603, 1611, 1612, 1613, 1596, 1597, 1614, 1615, 1617, 1616,
|
|
+ /* 0 */ -125, 733, 789, 241, 293, -123, -193, -191, -183, -187,
|
|
+ /* 10 */ 166, 238, 133, -207, -199, -267, -176, -6, 204, 489,
|
|
+ /* 20 */ 576, -175, 598, 686, 615, 725, 860, 778, 781, 857,
|
|
+ /* 30 */ 616, 887, 87, 240, -192, 408, 626, 796, 843, 854,
|
|
+ /* 40 */ 1003, -271, -271, -271, -271, -271, -271, -271, -271, -271,
|
|
+ /* 50 */ -271, -271, -271, -271, -271, -271, -271, -271, -271, -271,
|
|
+ /* 60 */ -271, -271, -271, -271, -271, -271, -271, -271, -271, -271,
|
|
+ /* 70 */ -271, -271, -271, -271, -271, -271, -271, -271, 80, 83,
|
|
+ /* 80 */ 313, 886, 888, 996, 1034, 1059, 1081, 1100, 1117, 1152,
|
|
+ /* 90 */ 1155, 1163, 1165, 1167, 1169, 1172, 1180, 1182, 1184, 1198,
|
|
+ /* 100 */ 1200, 1213, 1215, 1225, 1227, 1252, 1254, 1264, 1299, 1303,
|
|
+ /* 110 */ 1308, 1312, 1325, 1328, 1337, 1340, 1343, 1371, 1373, 1384,
|
|
+ /* 120 */ 1386, 1411, 1420, 1424, 1426, 1458, 1470, 1473, 1475, 1479,
|
|
+ /* 130 */ -271, -271, -271, -271, -271, -271, -271, -271, -271, -271,
|
|
+ /* 140 */ -271, 138, 459, 396, -158, 470, 302, -212, 521, 201,
|
|
+ /* 150 */ -195, -92, 559, 630, 632, 630, -271, 632, 901, 63,
|
|
+ /* 160 */ 407, -271, -271, -271, -271, 161, 161, 161, 251, 335,
|
|
+ /* 170 */ 847, 960, 980, 537, 588, 618, 628, 688, 688, -166,
|
|
+ /* 180 */ -161, 674, 790, 794, 799, 851, 852, -122, 680, -120,
|
|
+ /* 190 */ 995, 1038, 415, 1051, 893, 798, 962, 400, 1086, 779,
|
|
+ /* 200 */ 923, 924, 263, 1041, 979, 990, 1083, 1097, 1031, 1194,
|
|
+ /* 210 */ 362, 994, 1139, 1005, 1037, 1202, 1205, 1195, 1210, -194,
|
|
+ /* 220 */ 56, 185, -135, 232, 522, 560, 601, 617, 669, 683,
|
|
+ /* 230 */ 711, 856, 908, 941, 1048, 1101, 1147, 1257, 1262, 1265,
|
|
+ /* 240 */ 392, 1292, 1333, 1339, 1342, 1346, 1350, 1359, 1374, 1418,
|
|
+ /* 250 */ 1421, 1436, 1437, 593, 755, 770, 997, 1445, 1459, 1209,
|
|
+ /* 260 */ 1500, 1504, 1516, 1132, 1243, 1518, 1519, 1440, 1520, 560,
|
|
+ /* 270 */ 1522, 1523, 1524, 1526, 1527, 1529, 1382, 1438, 1431, 1468,
|
|
+ /* 280 */ 1469, 1472, 1476, 1209, 1431, 1431, 1485, 1525, 1539, 1435,
|
|
+ /* 290 */ 1463, 1471, 1492, 1487, 1443, 1494, 1474, 1484, 1498, 1486,
|
|
+ /* 300 */ 1502, 1455, 1530, 1531, 1533, 1540, 1542, 1544, 1505, 1506,
|
|
+ /* 310 */ 1507, 1508, 1521, 1528, 1493, 1537, 1532, 1575, 1488, 1496,
|
|
+ /* 320 */ 1584, 1594, 1509, 1510, 1600, 1538, 1534, 1541, 1574, 1577,
|
|
+ /* 330 */ 1583, 1585, 1586, 1612, 1626, 1581, 1556, 1558, 1587, 1559,
|
|
+ /* 340 */ 1601, 1588, 1603, 1592, 1631, 1640, 1550, 1553, 1643, 1645,
|
|
+ /* 350 */ 1625, 1649, 1652, 1650, 1653, 1632, 1636, 1637, 1642, 1634,
|
|
+ /* 360 */ 1639, 1641, 1646, 1656, 1655, 1658, 1659, 1661, 1663, 1560,
|
|
+ /* 370 */ 1564, 1596, 1605, 1664, 1670, 1565, 1571, 1627, 1638, 1657,
|
|
+ /* 380 */ 1665, 1623, 1702, 1630, 1666, 1667, 1671, 1673, 1703, 1718,
|
|
+ /* 390 */ 1719, 1729, 1730, 1731, 1621, 1622, 1628, 1720, 1713, 1716,
|
|
+ /* 400 */ 1722, 1723, 1733, 1717, 1724, 1727, 1728, 1725, 1740,
|
|
};
|
|
static const YYACTIONTYPE yy_default[] = {
|
|
- /* 0 */ 1573, 1573, 1573, 1409, 1186, 1295, 1186, 1186, 1186, 1409,
|
|
- /* 10 */ 1409, 1409, 1186, 1325, 1325, 1462, 1217, 1186, 1186, 1186,
|
|
- /* 20 */ 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1408, 1186, 1186,
|
|
- /* 30 */ 1186, 1186, 1492, 1492, 1186, 1186, 1186, 1186, 1186, 1186,
|
|
- /* 40 */ 1186, 1186, 1186, 1334, 1186, 1186, 1186, 1186, 1186, 1186,
|
|
- /* 50 */ 1410, 1411, 1186, 1186, 1186, 1461, 1463, 1426, 1344, 1343,
|
|
- /* 60 */ 1342, 1341, 1444, 1312, 1339, 1332, 1336, 1404, 1405, 1403,
|
|
- /* 70 */ 1407, 1411, 1410, 1186, 1335, 1375, 1389, 1374, 1186, 1186,
|
|
- /* 80 */ 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186,
|
|
- /* 90 */ 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186,
|
|
- /* 100 */ 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186,
|
|
- /* 110 */ 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186,
|
|
- /* 120 */ 1186, 1186, 1186, 1186, 1186, 1186, 1383, 1388, 1394, 1387,
|
|
- /* 130 */ 1384, 1377, 1376, 1378, 1379, 1186, 1207, 1259, 1186, 1186,
|
|
- /* 140 */ 1186, 1186, 1480, 1479, 1186, 1186, 1217, 1369, 1368, 1380,
|
|
- /* 150 */ 1381, 1391, 1390, 1469, 1527, 1526, 1427, 1186, 1186, 1186,
|
|
- /* 160 */ 1186, 1186, 1186, 1492, 1186, 1186, 1186, 1186, 1186, 1186,
|
|
- /* 170 */ 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186,
|
|
- /* 180 */ 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1492, 1492,
|
|
- /* 190 */ 1186, 1217, 1492, 1492, 1213, 1213, 1319, 1186, 1475, 1295,
|
|
- /* 200 */ 1286, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186,
|
|
- /* 210 */ 1186, 1186, 1186, 1186, 1186, 1466, 1464, 1186, 1186, 1186,
|
|
- /* 220 */ 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186,
|
|
- /* 230 */ 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186,
|
|
- /* 240 */ 1186, 1186, 1186, 1186, 1186, 1291, 1186, 1186, 1186, 1186,
|
|
- /* 250 */ 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1521, 1186, 1439,
|
|
- /* 260 */ 1273, 1291, 1291, 1291, 1291, 1293, 1274, 1272, 1285, 1218,
|
|
- /* 270 */ 1193, 1565, 1338, 1314, 1314, 1562, 1338, 1338, 1562, 1234,
|
|
- /* 280 */ 1543, 1229, 1325, 1325, 1325, 1314, 1319, 1319, 1406, 1292,
|
|
- /* 290 */ 1285, 1186, 1565, 1300, 1300, 1564, 1564, 1300, 1427, 1347,
|
|
- /* 300 */ 1353, 1262, 1338, 1268, 1268, 1268, 1268, 1300, 1204, 1338,
|
|
- /* 310 */ 1338, 1347, 1353, 1262, 1262, 1338, 1300, 1204, 1443, 1559,
|
|
- /* 320 */ 1300, 1204, 1417, 1300, 1204, 1300, 1204, 1417, 1260, 1260,
|
|
- /* 330 */ 1260, 1249, 1186, 1186, 1417, 1260, 1234, 1260, 1249, 1260,
|
|
- /* 340 */ 1260, 1510, 1417, 1421, 1421, 1417, 1318, 1313, 1318, 1313,
|
|
- /* 350 */ 1318, 1313, 1318, 1313, 1300, 1502, 1502, 1328, 1328, 1333,
|
|
- /* 360 */ 1319, 1412, 1300, 1186, 1333, 1331, 1329, 1338, 1210, 1252,
|
|
- /* 370 */ 1524, 1524, 1520, 1520, 1520, 1570, 1570, 1475, 1536, 1217,
|
|
- /* 380 */ 1217, 1217, 1217, 1536, 1236, 1236, 1218, 1218, 1217, 1536,
|
|
- /* 390 */ 1186, 1186, 1186, 1186, 1186, 1186, 1531, 1186, 1428, 1304,
|
|
- /* 400 */ 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186,
|
|
- /* 410 */ 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186,
|
|
- /* 420 */ 1186, 1186, 1186, 1358, 1186, 1189, 1472, 1186, 1186, 1470,
|
|
- /* 430 */ 1186, 1186, 1186, 1186, 1186, 1186, 1305, 1186, 1186, 1186,
|
|
- /* 440 */ 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186,
|
|
- /* 450 */ 1186, 1186, 1186, 1186, 1186, 1561, 1186, 1186, 1186, 1186,
|
|
- /* 460 */ 1186, 1186, 1442, 1441, 1186, 1186, 1302, 1186, 1186, 1186,
|
|
- /* 470 */ 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186,
|
|
- /* 480 */ 1232, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186,
|
|
- /* 490 */ 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186,
|
|
- /* 500 */ 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1330, 1186, 1186,
|
|
- /* 510 */ 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186,
|
|
- /* 520 */ 1186, 1186, 1507, 1320, 1186, 1186, 1552, 1186, 1186, 1186,
|
|
- /* 530 */ 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186,
|
|
- /* 540 */ 1186, 1547, 1276, 1360, 1186, 1359, 1363, 1186, 1198, 1186,
|
|
- /* 550 */ 1186,
|
|
+ /* 0 */ 1647, 1647, 1647, 1475, 1240, 1351, 1240, 1240, 1240, 1475,
|
|
+ /* 10 */ 1475, 1475, 1240, 1381, 1381, 1528, 1273, 1240, 1240, 1240,
|
|
+ /* 20 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1474, 1240, 1240,
|
|
+ /* 30 */ 1240, 1240, 1563, 1563, 1240, 1240, 1240, 1240, 1240, 1240,
|
|
+ /* 40 */ 1240, 1240, 1390, 1240, 1397, 1240, 1240, 1240, 1240, 1240,
|
|
+ /* 50 */ 1476, 1477, 1240, 1240, 1240, 1527, 1529, 1492, 1404, 1403,
|
|
+ /* 60 */ 1402, 1401, 1510, 1369, 1395, 1388, 1392, 1470, 1471, 1469,
|
|
+ /* 70 */ 1473, 1477, 1476, 1240, 1391, 1438, 1454, 1437, 1240, 1240,
|
|
+ /* 80 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
|
|
+ /* 90 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
|
|
+ /* 100 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
|
|
+ /* 110 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
|
|
+ /* 120 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
|
|
+ /* 130 */ 1446, 1453, 1452, 1451, 1460, 1450, 1447, 1440, 1439, 1441,
|
|
+ /* 140 */ 1442, 1240, 1240, 1264, 1240, 1240, 1261, 1315, 1240, 1240,
|
|
+ /* 150 */ 1240, 1240, 1240, 1547, 1546, 1240, 1443, 1240, 1273, 1432,
|
|
+ /* 160 */ 1431, 1457, 1444, 1456, 1455, 1535, 1599, 1598, 1493, 1240,
|
|
+ /* 170 */ 1240, 1240, 1240, 1240, 1240, 1563, 1240, 1240, 1240, 1240,
|
|
+ /* 180 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
|
|
+ /* 190 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1371,
|
|
+ /* 200 */ 1563, 1563, 1240, 1273, 1563, 1563, 1372, 1372, 1269, 1269,
|
|
+ /* 210 */ 1375, 1240, 1542, 1342, 1342, 1342, 1342, 1351, 1342, 1240,
|
|
+ /* 220 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
|
|
+ /* 230 */ 1240, 1240, 1240, 1240, 1532, 1530, 1240, 1240, 1240, 1240,
|
|
+ /* 240 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
|
|
+ /* 250 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
|
|
+ /* 260 */ 1240, 1240, 1240, 1347, 1240, 1240, 1240, 1240, 1240, 1240,
|
|
+ /* 270 */ 1240, 1240, 1240, 1240, 1240, 1592, 1240, 1505, 1329, 1347,
|
|
+ /* 280 */ 1347, 1347, 1347, 1349, 1330, 1328, 1341, 1274, 1247, 1639,
|
|
+ /* 290 */ 1407, 1396, 1348, 1396, 1636, 1394, 1407, 1407, 1394, 1407,
|
|
+ /* 300 */ 1348, 1636, 1290, 1615, 1285, 1381, 1381, 1381, 1371, 1371,
|
|
+ /* 310 */ 1371, 1371, 1375, 1375, 1472, 1348, 1341, 1240, 1639, 1639,
|
|
+ /* 320 */ 1357, 1357, 1638, 1638, 1357, 1493, 1623, 1416, 1318, 1324,
|
|
+ /* 330 */ 1324, 1324, 1324, 1357, 1258, 1394, 1623, 1623, 1394, 1416,
|
|
+ /* 340 */ 1318, 1394, 1318, 1394, 1357, 1258, 1509, 1633, 1357, 1258,
|
|
+ /* 350 */ 1483, 1357, 1258, 1357, 1258, 1483, 1316, 1316, 1316, 1305,
|
|
+ /* 360 */ 1240, 1240, 1483, 1316, 1290, 1316, 1305, 1316, 1316, 1581,
|
|
+ /* 370 */ 1240, 1487, 1487, 1483, 1357, 1573, 1573, 1384, 1384, 1389,
|
|
+ /* 380 */ 1375, 1478, 1357, 1240, 1389, 1387, 1385, 1394, 1308, 1595,
|
|
+ /* 390 */ 1595, 1591, 1591, 1591, 1644, 1644, 1542, 1608, 1273, 1273,
|
|
+ /* 400 */ 1273, 1273, 1608, 1292, 1292, 1274, 1274, 1273, 1608, 1240,
|
|
+ /* 410 */ 1240, 1240, 1240, 1240, 1240, 1603, 1240, 1537, 1494, 1361,
|
|
+ /* 420 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
|
|
+ /* 430 */ 1240, 1240, 1240, 1240, 1548, 1240, 1240, 1240, 1240, 1240,
|
|
+ /* 440 */ 1240, 1240, 1240, 1240, 1240, 1421, 1240, 1243, 1539, 1240,
|
|
+ /* 450 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1398, 1399, 1362,
|
|
+ /* 460 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1413, 1240, 1240,
|
|
+ /* 470 */ 1240, 1408, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
|
|
+ /* 480 */ 1635, 1240, 1240, 1240, 1240, 1240, 1240, 1508, 1507, 1240,
|
|
+ /* 490 */ 1240, 1359, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
|
|
+ /* 500 */ 1240, 1240, 1240, 1240, 1240, 1288, 1240, 1240, 1240, 1240,
|
|
+ /* 510 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
|
|
+ /* 520 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1386,
|
|
+ /* 530 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
|
|
+ /* 540 */ 1240, 1240, 1240, 1240, 1578, 1376, 1240, 1240, 1240, 1240,
|
|
+ /* 550 */ 1626, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
|
|
+ /* 560 */ 1240, 1240, 1240, 1240, 1240, 1619, 1332, 1423, 1240, 1422,
|
|
+ /* 570 */ 1426, 1262, 1240, 1252, 1240, 1240,
|
|
};
|
|
/********** End of lemon-generated parsing tables *****************************/
|
|
|
|
-/* The next table maps tokens (terminal symbols) into fallback tokens.
|
|
+/* The next table maps tokens (terminal symbols) into fallback tokens.
|
|
** If a construct like the following:
|
|
-**
|
|
+**
|
|
** %fallback ID X Y Z.
|
|
**
|
|
** appears in the grammar, then ID becomes a fallback token for X, Y,
|
|
@@ -153291,8 +168055,8 @@ static const YYCODETYPE yyFallback[] = {
|
|
0, /* LP => nothing */
|
|
0, /* RP => nothing */
|
|
0, /* AS => nothing */
|
|
- 59, /* WITHOUT => ID */
|
|
0, /* COMMA => nothing */
|
|
+ 59, /* WITHOUT => ID */
|
|
59, /* ABORT => ID */
|
|
59, /* ACTION => ID */
|
|
59, /* AFTER => ID */
|
|
@@ -153363,6 +168127,7 @@ static const YYCODETYPE yyFallback[] = {
|
|
59, /* TIES => ID */
|
|
59, /* GENERATED => ID */
|
|
59, /* ALWAYS => ID */
|
|
+ 59, /* MATERIALIZED => ID */
|
|
59, /* REINDEX => ID */
|
|
59, /* RENAME => ID */
|
|
59, /* CTIME_KW => ID */
|
|
@@ -153377,6 +168142,7 @@ static const YYCODETYPE yyFallback[] = {
|
|
0, /* SLASH => nothing */
|
|
0, /* REM => nothing */
|
|
0, /* CONCAT => nothing */
|
|
+ 0, /* PTR => nothing */
|
|
0, /* COLLATE => nothing */
|
|
0, /* BITNOT => nothing */
|
|
0, /* ON => nothing */
|
|
@@ -153414,6 +168180,7 @@ static const YYCODETYPE yyFallback[] = {
|
|
0, /* HAVING => nothing */
|
|
0, /* LIMIT => nothing */
|
|
0, /* WHERE => nothing */
|
|
+ 0, /* RETURNING => nothing */
|
|
0, /* INTO => nothing */
|
|
0, /* NOTHING => nothing */
|
|
0, /* FLOAT => nothing */
|
|
@@ -153445,6 +168212,7 @@ static const YYCODETYPE yyFallback[] = {
|
|
0, /* IF_NULL_ROW => nothing */
|
|
0, /* ASTERISK => nothing */
|
|
0, /* SPAN => nothing */
|
|
+ 0, /* ERROR => nothing */
|
|
0, /* SPACE => nothing */
|
|
0, /* ILLEGAL => nothing */
|
|
};
|
|
@@ -153498,6 +168266,7 @@ struct yyParser {
|
|
};
|
|
typedef struct yyParser yyParser;
|
|
|
|
+/* #include <assert.h> */
|
|
#ifndef NDEBUG
|
|
/* #include <stdio.h> */
|
|
static FILE *yyTraceFILE = 0;
|
|
@@ -153505,10 +168274,10 @@ static char *yyTracePrompt = 0;
|
|
#endif /* NDEBUG */
|
|
|
|
#ifndef NDEBUG
|
|
-/*
|
|
+/*
|
|
** Turn parser tracing on by giving a stream to which to write the trace
|
|
** and a prompt to preface each trace message. Tracing is turned off
|
|
-** by making either argument NULL
|
|
+** by making either argument NULL
|
|
**
|
|
** Inputs:
|
|
** <ul>
|
|
@@ -153533,7 +168302,7 @@ SQLITE_PRIVATE void sqlite3ParserTrace(FILE *TraceFILE, char *zTracePrompt){
|
|
#if defined(YYCOVERAGE) || !defined(NDEBUG)
|
|
/* For tracing shifts, the names of all terminals and nonterminals
|
|
** are required. The following table supplies these names */
|
|
-static const char *const yyTokenName[] = {
|
|
+static const char *const yyTokenName[] = {
|
|
/* 0 */ "$",
|
|
/* 1 */ "SEMI",
|
|
/* 2 */ "EXPLAIN",
|
|
@@ -153559,8 +168328,8 @@ static const char *const yyTokenName[] = {
|
|
/* 22 */ "LP",
|
|
/* 23 */ "RP",
|
|
/* 24 */ "AS",
|
|
- /* 25 */ "WITHOUT",
|
|
- /* 26 */ "COMMA",
|
|
+ /* 25 */ "COMMA",
|
|
+ /* 26 */ "WITHOUT",
|
|
/* 27 */ "ABORT",
|
|
/* 28 */ "ACTION",
|
|
/* 29 */ "AFTER",
|
|
@@ -153631,219 +168400,228 @@ static const char *const yyTokenName[] = {
|
|
/* 94 */ "TIES",
|
|
/* 95 */ "GENERATED",
|
|
/* 96 */ "ALWAYS",
|
|
- /* 97 */ "REINDEX",
|
|
- /* 98 */ "RENAME",
|
|
- /* 99 */ "CTIME_KW",
|
|
- /* 100 */ "ANY",
|
|
- /* 101 */ "BITAND",
|
|
- /* 102 */ "BITOR",
|
|
- /* 103 */ "LSHIFT",
|
|
- /* 104 */ "RSHIFT",
|
|
- /* 105 */ "PLUS",
|
|
- /* 106 */ "MINUS",
|
|
- /* 107 */ "STAR",
|
|
- /* 108 */ "SLASH",
|
|
- /* 109 */ "REM",
|
|
- /* 110 */ "CONCAT",
|
|
- /* 111 */ "COLLATE",
|
|
- /* 112 */ "BITNOT",
|
|
- /* 113 */ "ON",
|
|
- /* 114 */ "INDEXED",
|
|
- /* 115 */ "STRING",
|
|
- /* 116 */ "JOIN_KW",
|
|
- /* 117 */ "CONSTRAINT",
|
|
- /* 118 */ "DEFAULT",
|
|
- /* 119 */ "NULL",
|
|
- /* 120 */ "PRIMARY",
|
|
- /* 121 */ "UNIQUE",
|
|
- /* 122 */ "CHECK",
|
|
- /* 123 */ "REFERENCES",
|
|
- /* 124 */ "AUTOINCR",
|
|
- /* 125 */ "INSERT",
|
|
- /* 126 */ "DELETE",
|
|
- /* 127 */ "UPDATE",
|
|
- /* 128 */ "SET",
|
|
- /* 129 */ "DEFERRABLE",
|
|
- /* 130 */ "FOREIGN",
|
|
- /* 131 */ "DROP",
|
|
- /* 132 */ "UNION",
|
|
- /* 133 */ "ALL",
|
|
- /* 134 */ "EXCEPT",
|
|
- /* 135 */ "INTERSECT",
|
|
- /* 136 */ "SELECT",
|
|
- /* 137 */ "VALUES",
|
|
- /* 138 */ "DISTINCT",
|
|
- /* 139 */ "DOT",
|
|
- /* 140 */ "FROM",
|
|
- /* 141 */ "JOIN",
|
|
- /* 142 */ "USING",
|
|
- /* 143 */ "ORDER",
|
|
- /* 144 */ "GROUP",
|
|
- /* 145 */ "HAVING",
|
|
- /* 146 */ "LIMIT",
|
|
- /* 147 */ "WHERE",
|
|
- /* 148 */ "INTO",
|
|
- /* 149 */ "NOTHING",
|
|
- /* 150 */ "FLOAT",
|
|
- /* 151 */ "BLOB",
|
|
- /* 152 */ "INTEGER",
|
|
- /* 153 */ "VARIABLE",
|
|
- /* 154 */ "CASE",
|
|
- /* 155 */ "WHEN",
|
|
- /* 156 */ "THEN",
|
|
- /* 157 */ "ELSE",
|
|
- /* 158 */ "INDEX",
|
|
- /* 159 */ "ALTER",
|
|
- /* 160 */ "ADD",
|
|
- /* 161 */ "WINDOW",
|
|
- /* 162 */ "OVER",
|
|
- /* 163 */ "FILTER",
|
|
- /* 164 */ "COLUMN",
|
|
- /* 165 */ "AGG_FUNCTION",
|
|
- /* 166 */ "AGG_COLUMN",
|
|
- /* 167 */ "TRUEFALSE",
|
|
- /* 168 */ "ISNOT",
|
|
- /* 169 */ "FUNCTION",
|
|
- /* 170 */ "UMINUS",
|
|
- /* 171 */ "UPLUS",
|
|
- /* 172 */ "TRUTH",
|
|
- /* 173 */ "REGISTER",
|
|
- /* 174 */ "VECTOR",
|
|
- /* 175 */ "SELECT_COLUMN",
|
|
- /* 176 */ "IF_NULL_ROW",
|
|
- /* 177 */ "ASTERISK",
|
|
- /* 178 */ "SPAN",
|
|
- /* 179 */ "SPACE",
|
|
- /* 180 */ "ILLEGAL",
|
|
- /* 181 */ "input",
|
|
- /* 182 */ "cmdlist",
|
|
- /* 183 */ "ecmd",
|
|
- /* 184 */ "cmdx",
|
|
- /* 185 */ "explain",
|
|
- /* 186 */ "cmd",
|
|
- /* 187 */ "transtype",
|
|
- /* 188 */ "trans_opt",
|
|
- /* 189 */ "nm",
|
|
- /* 190 */ "savepoint_opt",
|
|
- /* 191 */ "create_table",
|
|
- /* 192 */ "create_table_args",
|
|
- /* 193 */ "createkw",
|
|
- /* 194 */ "temp",
|
|
- /* 195 */ "ifnotexists",
|
|
- /* 196 */ "dbnm",
|
|
- /* 197 */ "columnlist",
|
|
- /* 198 */ "conslist_opt",
|
|
- /* 199 */ "table_options",
|
|
- /* 200 */ "select",
|
|
- /* 201 */ "columnname",
|
|
- /* 202 */ "carglist",
|
|
- /* 203 */ "typetoken",
|
|
- /* 204 */ "typename",
|
|
- /* 205 */ "signed",
|
|
- /* 206 */ "plus_num",
|
|
- /* 207 */ "minus_num",
|
|
- /* 208 */ "scanpt",
|
|
- /* 209 */ "scantok",
|
|
- /* 210 */ "ccons",
|
|
- /* 211 */ "term",
|
|
- /* 212 */ "expr",
|
|
- /* 213 */ "onconf",
|
|
- /* 214 */ "sortorder",
|
|
- /* 215 */ "autoinc",
|
|
- /* 216 */ "eidlist_opt",
|
|
- /* 217 */ "refargs",
|
|
- /* 218 */ "defer_subclause",
|
|
- /* 219 */ "generated",
|
|
- /* 220 */ "refarg",
|
|
- /* 221 */ "refact",
|
|
- /* 222 */ "init_deferred_pred_opt",
|
|
- /* 223 */ "conslist",
|
|
- /* 224 */ "tconscomma",
|
|
- /* 225 */ "tcons",
|
|
- /* 226 */ "sortlist",
|
|
- /* 227 */ "eidlist",
|
|
- /* 228 */ "defer_subclause_opt",
|
|
- /* 229 */ "orconf",
|
|
- /* 230 */ "resolvetype",
|
|
- /* 231 */ "raisetype",
|
|
- /* 232 */ "ifexists",
|
|
- /* 233 */ "fullname",
|
|
- /* 234 */ "selectnowith",
|
|
- /* 235 */ "oneselect",
|
|
- /* 236 */ "wqlist",
|
|
- /* 237 */ "multiselect_op",
|
|
- /* 238 */ "distinct",
|
|
- /* 239 */ "selcollist",
|
|
- /* 240 */ "from",
|
|
- /* 241 */ "where_opt",
|
|
- /* 242 */ "groupby_opt",
|
|
- /* 243 */ "having_opt",
|
|
- /* 244 */ "orderby_opt",
|
|
- /* 245 */ "limit_opt",
|
|
- /* 246 */ "window_clause",
|
|
- /* 247 */ "values",
|
|
- /* 248 */ "nexprlist",
|
|
- /* 249 */ "sclp",
|
|
- /* 250 */ "as",
|
|
- /* 251 */ "seltablist",
|
|
- /* 252 */ "stl_prefix",
|
|
- /* 253 */ "joinop",
|
|
- /* 254 */ "indexed_opt",
|
|
- /* 255 */ "on_opt",
|
|
- /* 256 */ "using_opt",
|
|
- /* 257 */ "exprlist",
|
|
- /* 258 */ "xfullname",
|
|
- /* 259 */ "idlist",
|
|
- /* 260 */ "nulls",
|
|
- /* 261 */ "with",
|
|
- /* 262 */ "setlist",
|
|
- /* 263 */ "insert_cmd",
|
|
- /* 264 */ "idlist_opt",
|
|
- /* 265 */ "upsert",
|
|
- /* 266 */ "filter_over",
|
|
- /* 267 */ "likeop",
|
|
- /* 268 */ "between_op",
|
|
- /* 269 */ "in_op",
|
|
- /* 270 */ "paren_exprlist",
|
|
- /* 271 */ "case_operand",
|
|
- /* 272 */ "case_exprlist",
|
|
- /* 273 */ "case_else",
|
|
- /* 274 */ "uniqueflag",
|
|
- /* 275 */ "collate",
|
|
- /* 276 */ "vinto",
|
|
- /* 277 */ "nmnum",
|
|
- /* 278 */ "trigger_decl",
|
|
- /* 279 */ "trigger_cmd_list",
|
|
- /* 280 */ "trigger_time",
|
|
- /* 281 */ "trigger_event",
|
|
- /* 282 */ "foreach_clause",
|
|
- /* 283 */ "when_clause",
|
|
- /* 284 */ "trigger_cmd",
|
|
- /* 285 */ "trnm",
|
|
- /* 286 */ "tridxby",
|
|
- /* 287 */ "database_kw_opt",
|
|
- /* 288 */ "key_opt",
|
|
- /* 289 */ "add_column_fullname",
|
|
- /* 290 */ "kwcolumn_opt",
|
|
- /* 291 */ "create_vtab",
|
|
- /* 292 */ "vtabarglist",
|
|
- /* 293 */ "vtabarg",
|
|
- /* 294 */ "vtabargtoken",
|
|
- /* 295 */ "lp",
|
|
- /* 296 */ "anylist",
|
|
- /* 297 */ "windowdefn_list",
|
|
- /* 298 */ "windowdefn",
|
|
- /* 299 */ "window",
|
|
- /* 300 */ "frame_opt",
|
|
- /* 301 */ "part_opt",
|
|
- /* 302 */ "filter_clause",
|
|
- /* 303 */ "over_clause",
|
|
- /* 304 */ "range_or_rows",
|
|
- /* 305 */ "frame_bound",
|
|
- /* 306 */ "frame_bound_s",
|
|
- /* 307 */ "frame_bound_e",
|
|
- /* 308 */ "frame_exclude_opt",
|
|
- /* 309 */ "frame_exclude",
|
|
+ /* 97 */ "MATERIALIZED",
|
|
+ /* 98 */ "REINDEX",
|
|
+ /* 99 */ "RENAME",
|
|
+ /* 100 */ "CTIME_KW",
|
|
+ /* 101 */ "ANY",
|
|
+ /* 102 */ "BITAND",
|
|
+ /* 103 */ "BITOR",
|
|
+ /* 104 */ "LSHIFT",
|
|
+ /* 105 */ "RSHIFT",
|
|
+ /* 106 */ "PLUS",
|
|
+ /* 107 */ "MINUS",
|
|
+ /* 108 */ "STAR",
|
|
+ /* 109 */ "SLASH",
|
|
+ /* 110 */ "REM",
|
|
+ /* 111 */ "CONCAT",
|
|
+ /* 112 */ "PTR",
|
|
+ /* 113 */ "COLLATE",
|
|
+ /* 114 */ "BITNOT",
|
|
+ /* 115 */ "ON",
|
|
+ /* 116 */ "INDEXED",
|
|
+ /* 117 */ "STRING",
|
|
+ /* 118 */ "JOIN_KW",
|
|
+ /* 119 */ "CONSTRAINT",
|
|
+ /* 120 */ "DEFAULT",
|
|
+ /* 121 */ "NULL",
|
|
+ /* 122 */ "PRIMARY",
|
|
+ /* 123 */ "UNIQUE",
|
|
+ /* 124 */ "CHECK",
|
|
+ /* 125 */ "REFERENCES",
|
|
+ /* 126 */ "AUTOINCR",
|
|
+ /* 127 */ "INSERT",
|
|
+ /* 128 */ "DELETE",
|
|
+ /* 129 */ "UPDATE",
|
|
+ /* 130 */ "SET",
|
|
+ /* 131 */ "DEFERRABLE",
|
|
+ /* 132 */ "FOREIGN",
|
|
+ /* 133 */ "DROP",
|
|
+ /* 134 */ "UNION",
|
|
+ /* 135 */ "ALL",
|
|
+ /* 136 */ "EXCEPT",
|
|
+ /* 137 */ "INTERSECT",
|
|
+ /* 138 */ "SELECT",
|
|
+ /* 139 */ "VALUES",
|
|
+ /* 140 */ "DISTINCT",
|
|
+ /* 141 */ "DOT",
|
|
+ /* 142 */ "FROM",
|
|
+ /* 143 */ "JOIN",
|
|
+ /* 144 */ "USING",
|
|
+ /* 145 */ "ORDER",
|
|
+ /* 146 */ "GROUP",
|
|
+ /* 147 */ "HAVING",
|
|
+ /* 148 */ "LIMIT",
|
|
+ /* 149 */ "WHERE",
|
|
+ /* 150 */ "RETURNING",
|
|
+ /* 151 */ "INTO",
|
|
+ /* 152 */ "NOTHING",
|
|
+ /* 153 */ "FLOAT",
|
|
+ /* 154 */ "BLOB",
|
|
+ /* 155 */ "INTEGER",
|
|
+ /* 156 */ "VARIABLE",
|
|
+ /* 157 */ "CASE",
|
|
+ /* 158 */ "WHEN",
|
|
+ /* 159 */ "THEN",
|
|
+ /* 160 */ "ELSE",
|
|
+ /* 161 */ "INDEX",
|
|
+ /* 162 */ "ALTER",
|
|
+ /* 163 */ "ADD",
|
|
+ /* 164 */ "WINDOW",
|
|
+ /* 165 */ "OVER",
|
|
+ /* 166 */ "FILTER",
|
|
+ /* 167 */ "COLUMN",
|
|
+ /* 168 */ "AGG_FUNCTION",
|
|
+ /* 169 */ "AGG_COLUMN",
|
|
+ /* 170 */ "TRUEFALSE",
|
|
+ /* 171 */ "ISNOT",
|
|
+ /* 172 */ "FUNCTION",
|
|
+ /* 173 */ "UMINUS",
|
|
+ /* 174 */ "UPLUS",
|
|
+ /* 175 */ "TRUTH",
|
|
+ /* 176 */ "REGISTER",
|
|
+ /* 177 */ "VECTOR",
|
|
+ /* 178 */ "SELECT_COLUMN",
|
|
+ /* 179 */ "IF_NULL_ROW",
|
|
+ /* 180 */ "ASTERISK",
|
|
+ /* 181 */ "SPAN",
|
|
+ /* 182 */ "ERROR",
|
|
+ /* 183 */ "SPACE",
|
|
+ /* 184 */ "ILLEGAL",
|
|
+ /* 185 */ "input",
|
|
+ /* 186 */ "cmdlist",
|
|
+ /* 187 */ "ecmd",
|
|
+ /* 188 */ "cmdx",
|
|
+ /* 189 */ "explain",
|
|
+ /* 190 */ "cmd",
|
|
+ /* 191 */ "transtype",
|
|
+ /* 192 */ "trans_opt",
|
|
+ /* 193 */ "nm",
|
|
+ /* 194 */ "savepoint_opt",
|
|
+ /* 195 */ "create_table",
|
|
+ /* 196 */ "create_table_args",
|
|
+ /* 197 */ "createkw",
|
|
+ /* 198 */ "temp",
|
|
+ /* 199 */ "ifnotexists",
|
|
+ /* 200 */ "dbnm",
|
|
+ /* 201 */ "columnlist",
|
|
+ /* 202 */ "conslist_opt",
|
|
+ /* 203 */ "table_option_set",
|
|
+ /* 204 */ "select",
|
|
+ /* 205 */ "table_option",
|
|
+ /* 206 */ "columnname",
|
|
+ /* 207 */ "carglist",
|
|
+ /* 208 */ "typetoken",
|
|
+ /* 209 */ "typename",
|
|
+ /* 210 */ "signed",
|
|
+ /* 211 */ "plus_num",
|
|
+ /* 212 */ "minus_num",
|
|
+ /* 213 */ "scanpt",
|
|
+ /* 214 */ "scantok",
|
|
+ /* 215 */ "ccons",
|
|
+ /* 216 */ "term",
|
|
+ /* 217 */ "expr",
|
|
+ /* 218 */ "onconf",
|
|
+ /* 219 */ "sortorder",
|
|
+ /* 220 */ "autoinc",
|
|
+ /* 221 */ "eidlist_opt",
|
|
+ /* 222 */ "refargs",
|
|
+ /* 223 */ "defer_subclause",
|
|
+ /* 224 */ "generated",
|
|
+ /* 225 */ "refarg",
|
|
+ /* 226 */ "refact",
|
|
+ /* 227 */ "init_deferred_pred_opt",
|
|
+ /* 228 */ "conslist",
|
|
+ /* 229 */ "tconscomma",
|
|
+ /* 230 */ "tcons",
|
|
+ /* 231 */ "sortlist",
|
|
+ /* 232 */ "eidlist",
|
|
+ /* 233 */ "defer_subclause_opt",
|
|
+ /* 234 */ "orconf",
|
|
+ /* 235 */ "resolvetype",
|
|
+ /* 236 */ "raisetype",
|
|
+ /* 237 */ "ifexists",
|
|
+ /* 238 */ "fullname",
|
|
+ /* 239 */ "selectnowith",
|
|
+ /* 240 */ "oneselect",
|
|
+ /* 241 */ "wqlist",
|
|
+ /* 242 */ "multiselect_op",
|
|
+ /* 243 */ "distinct",
|
|
+ /* 244 */ "selcollist",
|
|
+ /* 245 */ "from",
|
|
+ /* 246 */ "where_opt",
|
|
+ /* 247 */ "groupby_opt",
|
|
+ /* 248 */ "having_opt",
|
|
+ /* 249 */ "orderby_opt",
|
|
+ /* 250 */ "limit_opt",
|
|
+ /* 251 */ "window_clause",
|
|
+ /* 252 */ "values",
|
|
+ /* 253 */ "nexprlist",
|
|
+ /* 254 */ "sclp",
|
|
+ /* 255 */ "as",
|
|
+ /* 256 */ "seltablist",
|
|
+ /* 257 */ "stl_prefix",
|
|
+ /* 258 */ "joinop",
|
|
+ /* 259 */ "on_using",
|
|
+ /* 260 */ "indexed_by",
|
|
+ /* 261 */ "exprlist",
|
|
+ /* 262 */ "xfullname",
|
|
+ /* 263 */ "idlist",
|
|
+ /* 264 */ "indexed_opt",
|
|
+ /* 265 */ "nulls",
|
|
+ /* 266 */ "with",
|
|
+ /* 267 */ "where_opt_ret",
|
|
+ /* 268 */ "setlist",
|
|
+ /* 269 */ "insert_cmd",
|
|
+ /* 270 */ "idlist_opt",
|
|
+ /* 271 */ "upsert",
|
|
+ /* 272 */ "returning",
|
|
+ /* 273 */ "filter_over",
|
|
+ /* 274 */ "likeop",
|
|
+ /* 275 */ "between_op",
|
|
+ /* 276 */ "in_op",
|
|
+ /* 277 */ "paren_exprlist",
|
|
+ /* 278 */ "case_operand",
|
|
+ /* 279 */ "case_exprlist",
|
|
+ /* 280 */ "case_else",
|
|
+ /* 281 */ "uniqueflag",
|
|
+ /* 282 */ "collate",
|
|
+ /* 283 */ "vinto",
|
|
+ /* 284 */ "nmnum",
|
|
+ /* 285 */ "trigger_decl",
|
|
+ /* 286 */ "trigger_cmd_list",
|
|
+ /* 287 */ "trigger_time",
|
|
+ /* 288 */ "trigger_event",
|
|
+ /* 289 */ "foreach_clause",
|
|
+ /* 290 */ "when_clause",
|
|
+ /* 291 */ "trigger_cmd",
|
|
+ /* 292 */ "trnm",
|
|
+ /* 293 */ "tridxby",
|
|
+ /* 294 */ "database_kw_opt",
|
|
+ /* 295 */ "key_opt",
|
|
+ /* 296 */ "add_column_fullname",
|
|
+ /* 297 */ "kwcolumn_opt",
|
|
+ /* 298 */ "create_vtab",
|
|
+ /* 299 */ "vtabarglist",
|
|
+ /* 300 */ "vtabarg",
|
|
+ /* 301 */ "vtabargtoken",
|
|
+ /* 302 */ "lp",
|
|
+ /* 303 */ "anylist",
|
|
+ /* 304 */ "wqitem",
|
|
+ /* 305 */ "wqas",
|
|
+ /* 306 */ "windowdefn_list",
|
|
+ /* 307 */ "windowdefn",
|
|
+ /* 308 */ "window",
|
|
+ /* 309 */ "frame_opt",
|
|
+ /* 310 */ "part_opt",
|
|
+ /* 311 */ "filter_clause",
|
|
+ /* 312 */ "over_clause",
|
|
+ /* 313 */ "range_or_rows",
|
|
+ /* 314 */ "frame_bound",
|
|
+ /* 315 */ "frame_bound_s",
|
|
+ /* 316 */ "frame_bound_e",
|
|
+ /* 317 */ "frame_exclude_opt",
|
|
+ /* 318 */ "frame_exclude",
|
|
};
|
|
#endif /* defined(YYCOVERAGE) || !defined(NDEBUG) */
|
|
|
|
@@ -153870,372 +168648,392 @@ static const char *const yyRuleName[] = {
|
|
/* 16 */ "ifnotexists ::= IF NOT EXISTS",
|
|
/* 17 */ "temp ::= TEMP",
|
|
/* 18 */ "temp ::=",
|
|
- /* 19 */ "create_table_args ::= LP columnlist conslist_opt RP table_options",
|
|
+ /* 19 */ "create_table_args ::= LP columnlist conslist_opt RP table_option_set",
|
|
/* 20 */ "create_table_args ::= AS select",
|
|
- /* 21 */ "table_options ::=",
|
|
- /* 22 */ "table_options ::= WITHOUT nm",
|
|
- /* 23 */ "columnname ::= nm typetoken",
|
|
- /* 24 */ "typetoken ::=",
|
|
- /* 25 */ "typetoken ::= typename LP signed RP",
|
|
- /* 26 */ "typetoken ::= typename LP signed COMMA signed RP",
|
|
- /* 27 */ "typename ::= typename ID|STRING",
|
|
- /* 28 */ "scanpt ::=",
|
|
- /* 29 */ "scantok ::=",
|
|
- /* 30 */ "ccons ::= CONSTRAINT nm",
|
|
- /* 31 */ "ccons ::= DEFAULT scantok term",
|
|
- /* 32 */ "ccons ::= DEFAULT LP expr RP",
|
|
- /* 33 */ "ccons ::= DEFAULT PLUS scantok term",
|
|
- /* 34 */ "ccons ::= DEFAULT MINUS scantok term",
|
|
- /* 35 */ "ccons ::= DEFAULT scantok ID|INDEXED",
|
|
- /* 36 */ "ccons ::= NOT NULL onconf",
|
|
- /* 37 */ "ccons ::= PRIMARY KEY sortorder onconf autoinc",
|
|
- /* 38 */ "ccons ::= UNIQUE onconf",
|
|
- /* 39 */ "ccons ::= CHECK LP expr RP",
|
|
- /* 40 */ "ccons ::= REFERENCES nm eidlist_opt refargs",
|
|
- /* 41 */ "ccons ::= defer_subclause",
|
|
- /* 42 */ "ccons ::= COLLATE ID|STRING",
|
|
- /* 43 */ "generated ::= LP expr RP",
|
|
- /* 44 */ "generated ::= LP expr RP ID",
|
|
- /* 45 */ "autoinc ::=",
|
|
- /* 46 */ "autoinc ::= AUTOINCR",
|
|
- /* 47 */ "refargs ::=",
|
|
- /* 48 */ "refargs ::= refargs refarg",
|
|
- /* 49 */ "refarg ::= MATCH nm",
|
|
- /* 50 */ "refarg ::= ON INSERT refact",
|
|
- /* 51 */ "refarg ::= ON DELETE refact",
|
|
- /* 52 */ "refarg ::= ON UPDATE refact",
|
|
- /* 53 */ "refact ::= SET NULL",
|
|
- /* 54 */ "refact ::= SET DEFAULT",
|
|
- /* 55 */ "refact ::= CASCADE",
|
|
- /* 56 */ "refact ::= RESTRICT",
|
|
- /* 57 */ "refact ::= NO ACTION",
|
|
- /* 58 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt",
|
|
- /* 59 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt",
|
|
- /* 60 */ "init_deferred_pred_opt ::=",
|
|
- /* 61 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED",
|
|
- /* 62 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE",
|
|
- /* 63 */ "conslist_opt ::=",
|
|
- /* 64 */ "tconscomma ::= COMMA",
|
|
- /* 65 */ "tcons ::= CONSTRAINT nm",
|
|
- /* 66 */ "tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf",
|
|
- /* 67 */ "tcons ::= UNIQUE LP sortlist RP onconf",
|
|
- /* 68 */ "tcons ::= CHECK LP expr RP onconf",
|
|
- /* 69 */ "tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt",
|
|
- /* 70 */ "defer_subclause_opt ::=",
|
|
- /* 71 */ "onconf ::=",
|
|
- /* 72 */ "onconf ::= ON CONFLICT resolvetype",
|
|
- /* 73 */ "orconf ::=",
|
|
- /* 74 */ "orconf ::= OR resolvetype",
|
|
- /* 75 */ "resolvetype ::= IGNORE",
|
|
- /* 76 */ "resolvetype ::= REPLACE",
|
|
- /* 77 */ "cmd ::= DROP TABLE ifexists fullname",
|
|
- /* 78 */ "ifexists ::= IF EXISTS",
|
|
- /* 79 */ "ifexists ::=",
|
|
- /* 80 */ "cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select",
|
|
- /* 81 */ "cmd ::= DROP VIEW ifexists fullname",
|
|
- /* 82 */ "cmd ::= select",
|
|
- /* 83 */ "select ::= WITH wqlist selectnowith",
|
|
- /* 84 */ "select ::= WITH RECURSIVE wqlist selectnowith",
|
|
- /* 85 */ "select ::= selectnowith",
|
|
- /* 86 */ "selectnowith ::= selectnowith multiselect_op oneselect",
|
|
- /* 87 */ "multiselect_op ::= UNION",
|
|
- /* 88 */ "multiselect_op ::= UNION ALL",
|
|
- /* 89 */ "multiselect_op ::= EXCEPT|INTERSECT",
|
|
- /* 90 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt",
|
|
- /* 91 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt",
|
|
- /* 92 */ "values ::= VALUES LP nexprlist RP",
|
|
- /* 93 */ "values ::= values COMMA LP nexprlist RP",
|
|
- /* 94 */ "distinct ::= DISTINCT",
|
|
- /* 95 */ "distinct ::= ALL",
|
|
- /* 96 */ "distinct ::=",
|
|
- /* 97 */ "sclp ::=",
|
|
- /* 98 */ "selcollist ::= sclp scanpt expr scanpt as",
|
|
- /* 99 */ "selcollist ::= sclp scanpt STAR",
|
|
- /* 100 */ "selcollist ::= sclp scanpt nm DOT STAR",
|
|
- /* 101 */ "as ::= AS nm",
|
|
- /* 102 */ "as ::=",
|
|
- /* 103 */ "from ::=",
|
|
- /* 104 */ "from ::= FROM seltablist",
|
|
- /* 105 */ "stl_prefix ::= seltablist joinop",
|
|
- /* 106 */ "stl_prefix ::=",
|
|
- /* 107 */ "seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt",
|
|
- /* 108 */ "seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt",
|
|
- /* 109 */ "seltablist ::= stl_prefix LP select RP as on_opt using_opt",
|
|
- /* 110 */ "seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt",
|
|
- /* 111 */ "dbnm ::=",
|
|
- /* 112 */ "dbnm ::= DOT nm",
|
|
- /* 113 */ "fullname ::= nm",
|
|
- /* 114 */ "fullname ::= nm DOT nm",
|
|
- /* 115 */ "xfullname ::= nm",
|
|
- /* 116 */ "xfullname ::= nm DOT nm",
|
|
- /* 117 */ "xfullname ::= nm DOT nm AS nm",
|
|
- /* 118 */ "xfullname ::= nm AS nm",
|
|
- /* 119 */ "joinop ::= COMMA|JOIN",
|
|
- /* 120 */ "joinop ::= JOIN_KW JOIN",
|
|
- /* 121 */ "joinop ::= JOIN_KW nm JOIN",
|
|
- /* 122 */ "joinop ::= JOIN_KW nm nm JOIN",
|
|
- /* 123 */ "on_opt ::= ON expr",
|
|
- /* 124 */ "on_opt ::=",
|
|
- /* 125 */ "indexed_opt ::=",
|
|
- /* 126 */ "indexed_opt ::= INDEXED BY nm",
|
|
- /* 127 */ "indexed_opt ::= NOT INDEXED",
|
|
- /* 128 */ "using_opt ::= USING LP idlist RP",
|
|
- /* 129 */ "using_opt ::=",
|
|
- /* 130 */ "orderby_opt ::=",
|
|
- /* 131 */ "orderby_opt ::= ORDER BY sortlist",
|
|
- /* 132 */ "sortlist ::= sortlist COMMA expr sortorder nulls",
|
|
- /* 133 */ "sortlist ::= expr sortorder nulls",
|
|
- /* 134 */ "sortorder ::= ASC",
|
|
- /* 135 */ "sortorder ::= DESC",
|
|
- /* 136 */ "sortorder ::=",
|
|
- /* 137 */ "nulls ::= NULLS FIRST",
|
|
- /* 138 */ "nulls ::= NULLS LAST",
|
|
- /* 139 */ "nulls ::=",
|
|
- /* 140 */ "groupby_opt ::=",
|
|
- /* 141 */ "groupby_opt ::= GROUP BY nexprlist",
|
|
- /* 142 */ "having_opt ::=",
|
|
- /* 143 */ "having_opt ::= HAVING expr",
|
|
- /* 144 */ "limit_opt ::=",
|
|
- /* 145 */ "limit_opt ::= LIMIT expr",
|
|
- /* 146 */ "limit_opt ::= LIMIT expr OFFSET expr",
|
|
- /* 147 */ "limit_opt ::= LIMIT expr COMMA expr",
|
|
- /* 148 */ "cmd ::= with DELETE FROM xfullname indexed_opt where_opt",
|
|
- /* 149 */ "where_opt ::=",
|
|
- /* 150 */ "where_opt ::= WHERE expr",
|
|
- /* 151 */ "cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist where_opt",
|
|
- /* 152 */ "setlist ::= setlist COMMA nm EQ expr",
|
|
- /* 153 */ "setlist ::= setlist COMMA LP idlist RP EQ expr",
|
|
- /* 154 */ "setlist ::= nm EQ expr",
|
|
- /* 155 */ "setlist ::= LP idlist RP EQ expr",
|
|
- /* 156 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert",
|
|
- /* 157 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES",
|
|
- /* 158 */ "upsert ::=",
|
|
- /* 159 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt",
|
|
- /* 160 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING",
|
|
- /* 161 */ "upsert ::= ON CONFLICT DO NOTHING",
|
|
- /* 162 */ "insert_cmd ::= INSERT orconf",
|
|
- /* 163 */ "insert_cmd ::= REPLACE",
|
|
- /* 164 */ "idlist_opt ::=",
|
|
- /* 165 */ "idlist_opt ::= LP idlist RP",
|
|
- /* 166 */ "idlist ::= idlist COMMA nm",
|
|
- /* 167 */ "idlist ::= nm",
|
|
- /* 168 */ "expr ::= LP expr RP",
|
|
- /* 169 */ "expr ::= ID|INDEXED",
|
|
- /* 170 */ "expr ::= JOIN_KW",
|
|
- /* 171 */ "expr ::= nm DOT nm",
|
|
- /* 172 */ "expr ::= nm DOT nm DOT nm",
|
|
- /* 173 */ "term ::= NULL|FLOAT|BLOB",
|
|
- /* 174 */ "term ::= STRING",
|
|
- /* 175 */ "term ::= INTEGER",
|
|
- /* 176 */ "expr ::= VARIABLE",
|
|
- /* 177 */ "expr ::= expr COLLATE ID|STRING",
|
|
- /* 178 */ "expr ::= CAST LP expr AS typetoken RP",
|
|
- /* 179 */ "expr ::= ID|INDEXED LP distinct exprlist RP",
|
|
- /* 180 */ "expr ::= ID|INDEXED LP STAR RP",
|
|
- /* 181 */ "expr ::= ID|INDEXED LP distinct exprlist RP filter_over",
|
|
- /* 182 */ "expr ::= ID|INDEXED LP STAR RP filter_over",
|
|
- /* 183 */ "term ::= CTIME_KW",
|
|
- /* 184 */ "expr ::= LP nexprlist COMMA expr RP",
|
|
- /* 185 */ "expr ::= expr AND expr",
|
|
- /* 186 */ "expr ::= expr OR expr",
|
|
- /* 187 */ "expr ::= expr LT|GT|GE|LE expr",
|
|
- /* 188 */ "expr ::= expr EQ|NE expr",
|
|
- /* 189 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr",
|
|
- /* 190 */ "expr ::= expr PLUS|MINUS expr",
|
|
- /* 191 */ "expr ::= expr STAR|SLASH|REM expr",
|
|
- /* 192 */ "expr ::= expr CONCAT expr",
|
|
- /* 193 */ "likeop ::= NOT LIKE_KW|MATCH",
|
|
- /* 194 */ "expr ::= expr likeop expr",
|
|
- /* 195 */ "expr ::= expr likeop expr ESCAPE expr",
|
|
- /* 196 */ "expr ::= expr ISNULL|NOTNULL",
|
|
- /* 197 */ "expr ::= expr NOT NULL",
|
|
- /* 198 */ "expr ::= expr IS expr",
|
|
- /* 199 */ "expr ::= expr IS NOT expr",
|
|
- /* 200 */ "expr ::= NOT expr",
|
|
- /* 201 */ "expr ::= BITNOT expr",
|
|
- /* 202 */ "expr ::= PLUS|MINUS expr",
|
|
- /* 203 */ "between_op ::= BETWEEN",
|
|
- /* 204 */ "between_op ::= NOT BETWEEN",
|
|
- /* 205 */ "expr ::= expr between_op expr AND expr",
|
|
- /* 206 */ "in_op ::= IN",
|
|
- /* 207 */ "in_op ::= NOT IN",
|
|
- /* 208 */ "expr ::= expr in_op LP exprlist RP",
|
|
- /* 209 */ "expr ::= LP select RP",
|
|
- /* 210 */ "expr ::= expr in_op LP select RP",
|
|
- /* 211 */ "expr ::= expr in_op nm dbnm paren_exprlist",
|
|
- /* 212 */ "expr ::= EXISTS LP select RP",
|
|
- /* 213 */ "expr ::= CASE case_operand case_exprlist case_else END",
|
|
- /* 214 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr",
|
|
- /* 215 */ "case_exprlist ::= WHEN expr THEN expr",
|
|
- /* 216 */ "case_else ::= ELSE expr",
|
|
- /* 217 */ "case_else ::=",
|
|
- /* 218 */ "case_operand ::= expr",
|
|
- /* 219 */ "case_operand ::=",
|
|
- /* 220 */ "exprlist ::=",
|
|
- /* 221 */ "nexprlist ::= nexprlist COMMA expr",
|
|
- /* 222 */ "nexprlist ::= expr",
|
|
- /* 223 */ "paren_exprlist ::=",
|
|
- /* 224 */ "paren_exprlist ::= LP exprlist RP",
|
|
- /* 225 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt",
|
|
- /* 226 */ "uniqueflag ::= UNIQUE",
|
|
- /* 227 */ "uniqueflag ::=",
|
|
- /* 228 */ "eidlist_opt ::=",
|
|
- /* 229 */ "eidlist_opt ::= LP eidlist RP",
|
|
- /* 230 */ "eidlist ::= eidlist COMMA nm collate sortorder",
|
|
- /* 231 */ "eidlist ::= nm collate sortorder",
|
|
- /* 232 */ "collate ::=",
|
|
- /* 233 */ "collate ::= COLLATE ID|STRING",
|
|
- /* 234 */ "cmd ::= DROP INDEX ifexists fullname",
|
|
- /* 235 */ "cmd ::= VACUUM vinto",
|
|
- /* 236 */ "cmd ::= VACUUM nm vinto",
|
|
- /* 237 */ "vinto ::= INTO expr",
|
|
- /* 238 */ "vinto ::=",
|
|
- /* 239 */ "cmd ::= PRAGMA nm dbnm",
|
|
- /* 240 */ "cmd ::= PRAGMA nm dbnm EQ nmnum",
|
|
- /* 241 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP",
|
|
- /* 242 */ "cmd ::= PRAGMA nm dbnm EQ minus_num",
|
|
- /* 243 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP",
|
|
- /* 244 */ "plus_num ::= PLUS INTEGER|FLOAT",
|
|
- /* 245 */ "minus_num ::= MINUS INTEGER|FLOAT",
|
|
- /* 246 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END",
|
|
- /* 247 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause",
|
|
- /* 248 */ "trigger_time ::= BEFORE|AFTER",
|
|
- /* 249 */ "trigger_time ::= INSTEAD OF",
|
|
- /* 250 */ "trigger_time ::=",
|
|
- /* 251 */ "trigger_event ::= DELETE|INSERT",
|
|
- /* 252 */ "trigger_event ::= UPDATE",
|
|
- /* 253 */ "trigger_event ::= UPDATE OF idlist",
|
|
- /* 254 */ "when_clause ::=",
|
|
- /* 255 */ "when_clause ::= WHEN expr",
|
|
- /* 256 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI",
|
|
- /* 257 */ "trigger_cmd_list ::= trigger_cmd SEMI",
|
|
- /* 258 */ "trnm ::= nm DOT nm",
|
|
- /* 259 */ "tridxby ::= INDEXED BY nm",
|
|
- /* 260 */ "tridxby ::= NOT INDEXED",
|
|
- /* 261 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt scanpt",
|
|
- /* 262 */ "trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt",
|
|
- /* 263 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt",
|
|
- /* 264 */ "trigger_cmd ::= scanpt select scanpt",
|
|
- /* 265 */ "expr ::= RAISE LP IGNORE RP",
|
|
- /* 266 */ "expr ::= RAISE LP raisetype COMMA nm RP",
|
|
- /* 267 */ "raisetype ::= ROLLBACK",
|
|
- /* 268 */ "raisetype ::= ABORT",
|
|
- /* 269 */ "raisetype ::= FAIL",
|
|
- /* 270 */ "cmd ::= DROP TRIGGER ifexists fullname",
|
|
- /* 271 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt",
|
|
- /* 272 */ "cmd ::= DETACH database_kw_opt expr",
|
|
- /* 273 */ "key_opt ::=",
|
|
- /* 274 */ "key_opt ::= KEY expr",
|
|
- /* 275 */ "cmd ::= REINDEX",
|
|
- /* 276 */ "cmd ::= REINDEX nm dbnm",
|
|
- /* 277 */ "cmd ::= ANALYZE",
|
|
- /* 278 */ "cmd ::= ANALYZE nm dbnm",
|
|
- /* 279 */ "cmd ::= ALTER TABLE fullname RENAME TO nm",
|
|
- /* 280 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist",
|
|
- /* 281 */ "add_column_fullname ::= fullname",
|
|
- /* 282 */ "cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm",
|
|
- /* 283 */ "cmd ::= create_vtab",
|
|
- /* 284 */ "cmd ::= create_vtab LP vtabarglist RP",
|
|
- /* 285 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm",
|
|
- /* 286 */ "vtabarg ::=",
|
|
- /* 287 */ "vtabargtoken ::= ANY",
|
|
- /* 288 */ "vtabargtoken ::= lp anylist RP",
|
|
- /* 289 */ "lp ::= LP",
|
|
- /* 290 */ "with ::= WITH wqlist",
|
|
- /* 291 */ "with ::= WITH RECURSIVE wqlist",
|
|
- /* 292 */ "wqlist ::= nm eidlist_opt AS LP select RP",
|
|
- /* 293 */ "wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP",
|
|
- /* 294 */ "windowdefn_list ::= windowdefn",
|
|
- /* 295 */ "windowdefn_list ::= windowdefn_list COMMA windowdefn",
|
|
- /* 296 */ "windowdefn ::= nm AS LP window RP",
|
|
- /* 297 */ "window ::= PARTITION BY nexprlist orderby_opt frame_opt",
|
|
- /* 298 */ "window ::= nm PARTITION BY nexprlist orderby_opt frame_opt",
|
|
- /* 299 */ "window ::= ORDER BY sortlist frame_opt",
|
|
- /* 300 */ "window ::= nm ORDER BY sortlist frame_opt",
|
|
- /* 301 */ "window ::= frame_opt",
|
|
- /* 302 */ "window ::= nm frame_opt",
|
|
- /* 303 */ "frame_opt ::=",
|
|
- /* 304 */ "frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt",
|
|
- /* 305 */ "frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt",
|
|
- /* 306 */ "range_or_rows ::= RANGE|ROWS|GROUPS",
|
|
- /* 307 */ "frame_bound_s ::= frame_bound",
|
|
- /* 308 */ "frame_bound_s ::= UNBOUNDED PRECEDING",
|
|
- /* 309 */ "frame_bound_e ::= frame_bound",
|
|
- /* 310 */ "frame_bound_e ::= UNBOUNDED FOLLOWING",
|
|
- /* 311 */ "frame_bound ::= expr PRECEDING|FOLLOWING",
|
|
- /* 312 */ "frame_bound ::= CURRENT ROW",
|
|
- /* 313 */ "frame_exclude_opt ::=",
|
|
- /* 314 */ "frame_exclude_opt ::= EXCLUDE frame_exclude",
|
|
- /* 315 */ "frame_exclude ::= NO OTHERS",
|
|
- /* 316 */ "frame_exclude ::= CURRENT ROW",
|
|
- /* 317 */ "frame_exclude ::= GROUP|TIES",
|
|
- /* 318 */ "window_clause ::= WINDOW windowdefn_list",
|
|
- /* 319 */ "filter_over ::= filter_clause over_clause",
|
|
- /* 320 */ "filter_over ::= over_clause",
|
|
- /* 321 */ "filter_over ::= filter_clause",
|
|
- /* 322 */ "over_clause ::= OVER LP window RP",
|
|
- /* 323 */ "over_clause ::= OVER nm",
|
|
- /* 324 */ "filter_clause ::= FILTER LP WHERE expr RP",
|
|
- /* 325 */ "input ::= cmdlist",
|
|
- /* 326 */ "cmdlist ::= cmdlist ecmd",
|
|
- /* 327 */ "cmdlist ::= ecmd",
|
|
- /* 328 */ "ecmd ::= SEMI",
|
|
- /* 329 */ "ecmd ::= cmdx SEMI",
|
|
- /* 330 */ "ecmd ::= explain cmdx SEMI",
|
|
- /* 331 */ "trans_opt ::=",
|
|
- /* 332 */ "trans_opt ::= TRANSACTION",
|
|
- /* 333 */ "trans_opt ::= TRANSACTION nm",
|
|
- /* 334 */ "savepoint_opt ::= SAVEPOINT",
|
|
- /* 335 */ "savepoint_opt ::=",
|
|
- /* 336 */ "cmd ::= create_table create_table_args",
|
|
- /* 337 */ "columnlist ::= columnlist COMMA columnname carglist",
|
|
- /* 338 */ "columnlist ::= columnname carglist",
|
|
- /* 339 */ "nm ::= ID|INDEXED",
|
|
- /* 340 */ "nm ::= STRING",
|
|
- /* 341 */ "nm ::= JOIN_KW",
|
|
- /* 342 */ "typetoken ::= typename",
|
|
- /* 343 */ "typename ::= ID|STRING",
|
|
- /* 344 */ "signed ::= plus_num",
|
|
- /* 345 */ "signed ::= minus_num",
|
|
- /* 346 */ "carglist ::= carglist ccons",
|
|
- /* 347 */ "carglist ::=",
|
|
- /* 348 */ "ccons ::= NULL onconf",
|
|
- /* 349 */ "ccons ::= GENERATED ALWAYS AS generated",
|
|
- /* 350 */ "ccons ::= AS generated",
|
|
- /* 351 */ "conslist_opt ::= COMMA conslist",
|
|
- /* 352 */ "conslist ::= conslist tconscomma tcons",
|
|
- /* 353 */ "conslist ::= tcons",
|
|
- /* 354 */ "tconscomma ::=",
|
|
- /* 355 */ "defer_subclause_opt ::= defer_subclause",
|
|
- /* 356 */ "resolvetype ::= raisetype",
|
|
- /* 357 */ "selectnowith ::= oneselect",
|
|
- /* 358 */ "oneselect ::= values",
|
|
- /* 359 */ "sclp ::= selcollist COMMA",
|
|
- /* 360 */ "as ::= ID|STRING",
|
|
- /* 361 */ "expr ::= term",
|
|
- /* 362 */ "likeop ::= LIKE_KW|MATCH",
|
|
- /* 363 */ "exprlist ::= nexprlist",
|
|
- /* 364 */ "nmnum ::= plus_num",
|
|
- /* 365 */ "nmnum ::= nm",
|
|
- /* 366 */ "nmnum ::= ON",
|
|
- /* 367 */ "nmnum ::= DELETE",
|
|
- /* 368 */ "nmnum ::= DEFAULT",
|
|
- /* 369 */ "plus_num ::= INTEGER|FLOAT",
|
|
- /* 370 */ "foreach_clause ::=",
|
|
- /* 371 */ "foreach_clause ::= FOR EACH ROW",
|
|
- /* 372 */ "trnm ::= nm",
|
|
- /* 373 */ "tridxby ::=",
|
|
- /* 374 */ "database_kw_opt ::= DATABASE",
|
|
- /* 375 */ "database_kw_opt ::=",
|
|
- /* 376 */ "kwcolumn_opt ::=",
|
|
- /* 377 */ "kwcolumn_opt ::= COLUMNKW",
|
|
- /* 378 */ "vtabarglist ::= vtabarg",
|
|
- /* 379 */ "vtabarglist ::= vtabarglist COMMA vtabarg",
|
|
- /* 380 */ "vtabarg ::= vtabarg vtabargtoken",
|
|
- /* 381 */ "anylist ::=",
|
|
- /* 382 */ "anylist ::= anylist LP anylist RP",
|
|
- /* 383 */ "anylist ::= anylist ANY",
|
|
- /* 384 */ "with ::=",
|
|
+ /* 21 */ "table_option_set ::=",
|
|
+ /* 22 */ "table_option_set ::= table_option_set COMMA table_option",
|
|
+ /* 23 */ "table_option ::= WITHOUT nm",
|
|
+ /* 24 */ "table_option ::= nm",
|
|
+ /* 25 */ "columnname ::= nm typetoken",
|
|
+ /* 26 */ "typetoken ::=",
|
|
+ /* 27 */ "typetoken ::= typename LP signed RP",
|
|
+ /* 28 */ "typetoken ::= typename LP signed COMMA signed RP",
|
|
+ /* 29 */ "typename ::= typename ID|STRING",
|
|
+ /* 30 */ "scanpt ::=",
|
|
+ /* 31 */ "scantok ::=",
|
|
+ /* 32 */ "ccons ::= CONSTRAINT nm",
|
|
+ /* 33 */ "ccons ::= DEFAULT scantok term",
|
|
+ /* 34 */ "ccons ::= DEFAULT LP expr RP",
|
|
+ /* 35 */ "ccons ::= DEFAULT PLUS scantok term",
|
|
+ /* 36 */ "ccons ::= DEFAULT MINUS scantok term",
|
|
+ /* 37 */ "ccons ::= DEFAULT scantok ID|INDEXED",
|
|
+ /* 38 */ "ccons ::= NOT NULL onconf",
|
|
+ /* 39 */ "ccons ::= PRIMARY KEY sortorder onconf autoinc",
|
|
+ /* 40 */ "ccons ::= UNIQUE onconf",
|
|
+ /* 41 */ "ccons ::= CHECK LP expr RP",
|
|
+ /* 42 */ "ccons ::= REFERENCES nm eidlist_opt refargs",
|
|
+ /* 43 */ "ccons ::= defer_subclause",
|
|
+ /* 44 */ "ccons ::= COLLATE ID|STRING",
|
|
+ /* 45 */ "generated ::= LP expr RP",
|
|
+ /* 46 */ "generated ::= LP expr RP ID",
|
|
+ /* 47 */ "autoinc ::=",
|
|
+ /* 48 */ "autoinc ::= AUTOINCR",
|
|
+ /* 49 */ "refargs ::=",
|
|
+ /* 50 */ "refargs ::= refargs refarg",
|
|
+ /* 51 */ "refarg ::= MATCH nm",
|
|
+ /* 52 */ "refarg ::= ON INSERT refact",
|
|
+ /* 53 */ "refarg ::= ON DELETE refact",
|
|
+ /* 54 */ "refarg ::= ON UPDATE refact",
|
|
+ /* 55 */ "refact ::= SET NULL",
|
|
+ /* 56 */ "refact ::= SET DEFAULT",
|
|
+ /* 57 */ "refact ::= CASCADE",
|
|
+ /* 58 */ "refact ::= RESTRICT",
|
|
+ /* 59 */ "refact ::= NO ACTION",
|
|
+ /* 60 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt",
|
|
+ /* 61 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt",
|
|
+ /* 62 */ "init_deferred_pred_opt ::=",
|
|
+ /* 63 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED",
|
|
+ /* 64 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE",
|
|
+ /* 65 */ "conslist_opt ::=",
|
|
+ /* 66 */ "tconscomma ::= COMMA",
|
|
+ /* 67 */ "tcons ::= CONSTRAINT nm",
|
|
+ /* 68 */ "tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf",
|
|
+ /* 69 */ "tcons ::= UNIQUE LP sortlist RP onconf",
|
|
+ /* 70 */ "tcons ::= CHECK LP expr RP onconf",
|
|
+ /* 71 */ "tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt",
|
|
+ /* 72 */ "defer_subclause_opt ::=",
|
|
+ /* 73 */ "onconf ::=",
|
|
+ /* 74 */ "onconf ::= ON CONFLICT resolvetype",
|
|
+ /* 75 */ "orconf ::=",
|
|
+ /* 76 */ "orconf ::= OR resolvetype",
|
|
+ /* 77 */ "resolvetype ::= IGNORE",
|
|
+ /* 78 */ "resolvetype ::= REPLACE",
|
|
+ /* 79 */ "cmd ::= DROP TABLE ifexists fullname",
|
|
+ /* 80 */ "ifexists ::= IF EXISTS",
|
|
+ /* 81 */ "ifexists ::=",
|
|
+ /* 82 */ "cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select",
|
|
+ /* 83 */ "cmd ::= DROP VIEW ifexists fullname",
|
|
+ /* 84 */ "cmd ::= select",
|
|
+ /* 85 */ "select ::= WITH wqlist selectnowith",
|
|
+ /* 86 */ "select ::= WITH RECURSIVE wqlist selectnowith",
|
|
+ /* 87 */ "select ::= selectnowith",
|
|
+ /* 88 */ "selectnowith ::= selectnowith multiselect_op oneselect",
|
|
+ /* 89 */ "multiselect_op ::= UNION",
|
|
+ /* 90 */ "multiselect_op ::= UNION ALL",
|
|
+ /* 91 */ "multiselect_op ::= EXCEPT|INTERSECT",
|
|
+ /* 92 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt",
|
|
+ /* 93 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt",
|
|
+ /* 94 */ "values ::= VALUES LP nexprlist RP",
|
|
+ /* 95 */ "values ::= values COMMA LP nexprlist RP",
|
|
+ /* 96 */ "distinct ::= DISTINCT",
|
|
+ /* 97 */ "distinct ::= ALL",
|
|
+ /* 98 */ "distinct ::=",
|
|
+ /* 99 */ "sclp ::=",
|
|
+ /* 100 */ "selcollist ::= sclp scanpt expr scanpt as",
|
|
+ /* 101 */ "selcollist ::= sclp scanpt STAR",
|
|
+ /* 102 */ "selcollist ::= sclp scanpt nm DOT STAR",
|
|
+ /* 103 */ "as ::= AS nm",
|
|
+ /* 104 */ "as ::=",
|
|
+ /* 105 */ "from ::=",
|
|
+ /* 106 */ "from ::= FROM seltablist",
|
|
+ /* 107 */ "stl_prefix ::= seltablist joinop",
|
|
+ /* 108 */ "stl_prefix ::=",
|
|
+ /* 109 */ "seltablist ::= stl_prefix nm dbnm as on_using",
|
|
+ /* 110 */ "seltablist ::= stl_prefix nm dbnm as indexed_by on_using",
|
|
+ /* 111 */ "seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using",
|
|
+ /* 112 */ "seltablist ::= stl_prefix LP select RP as on_using",
|
|
+ /* 113 */ "seltablist ::= stl_prefix LP seltablist RP as on_using",
|
|
+ /* 114 */ "dbnm ::=",
|
|
+ /* 115 */ "dbnm ::= DOT nm",
|
|
+ /* 116 */ "fullname ::= nm",
|
|
+ /* 117 */ "fullname ::= nm DOT nm",
|
|
+ /* 118 */ "xfullname ::= nm",
|
|
+ /* 119 */ "xfullname ::= nm DOT nm",
|
|
+ /* 120 */ "xfullname ::= nm DOT nm AS nm",
|
|
+ /* 121 */ "xfullname ::= nm AS nm",
|
|
+ /* 122 */ "joinop ::= COMMA|JOIN",
|
|
+ /* 123 */ "joinop ::= JOIN_KW JOIN",
|
|
+ /* 124 */ "joinop ::= JOIN_KW nm JOIN",
|
|
+ /* 125 */ "joinop ::= JOIN_KW nm nm JOIN",
|
|
+ /* 126 */ "on_using ::= ON expr",
|
|
+ /* 127 */ "on_using ::= USING LP idlist RP",
|
|
+ /* 128 */ "on_using ::=",
|
|
+ /* 129 */ "indexed_opt ::=",
|
|
+ /* 130 */ "indexed_by ::= INDEXED BY nm",
|
|
+ /* 131 */ "indexed_by ::= NOT INDEXED",
|
|
+ /* 132 */ "orderby_opt ::=",
|
|
+ /* 133 */ "orderby_opt ::= ORDER BY sortlist",
|
|
+ /* 134 */ "sortlist ::= sortlist COMMA expr sortorder nulls",
|
|
+ /* 135 */ "sortlist ::= expr sortorder nulls",
|
|
+ /* 136 */ "sortorder ::= ASC",
|
|
+ /* 137 */ "sortorder ::= DESC",
|
|
+ /* 138 */ "sortorder ::=",
|
|
+ /* 139 */ "nulls ::= NULLS FIRST",
|
|
+ /* 140 */ "nulls ::= NULLS LAST",
|
|
+ /* 141 */ "nulls ::=",
|
|
+ /* 142 */ "groupby_opt ::=",
|
|
+ /* 143 */ "groupby_opt ::= GROUP BY nexprlist",
|
|
+ /* 144 */ "having_opt ::=",
|
|
+ /* 145 */ "having_opt ::= HAVING expr",
|
|
+ /* 146 */ "limit_opt ::=",
|
|
+ /* 147 */ "limit_opt ::= LIMIT expr",
|
|
+ /* 148 */ "limit_opt ::= LIMIT expr OFFSET expr",
|
|
+ /* 149 */ "limit_opt ::= LIMIT expr COMMA expr",
|
|
+ /* 150 */ "cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret",
|
|
+ /* 151 */ "where_opt ::=",
|
|
+ /* 152 */ "where_opt ::= WHERE expr",
|
|
+ /* 153 */ "where_opt_ret ::=",
|
|
+ /* 154 */ "where_opt_ret ::= WHERE expr",
|
|
+ /* 155 */ "where_opt_ret ::= RETURNING selcollist",
|
|
+ /* 156 */ "where_opt_ret ::= WHERE expr RETURNING selcollist",
|
|
+ /* 157 */ "cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret",
|
|
+ /* 158 */ "setlist ::= setlist COMMA nm EQ expr",
|
|
+ /* 159 */ "setlist ::= setlist COMMA LP idlist RP EQ expr",
|
|
+ /* 160 */ "setlist ::= nm EQ expr",
|
|
+ /* 161 */ "setlist ::= LP idlist RP EQ expr",
|
|
+ /* 162 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert",
|
|
+ /* 163 */ "cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning",
|
|
+ /* 164 */ "upsert ::=",
|
|
+ /* 165 */ "upsert ::= RETURNING selcollist",
|
|
+ /* 166 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert",
|
|
+ /* 167 */ "upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert",
|
|
+ /* 168 */ "upsert ::= ON CONFLICT DO NOTHING returning",
|
|
+ /* 169 */ "upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning",
|
|
+ /* 170 */ "returning ::= RETURNING selcollist",
|
|
+ /* 171 */ "insert_cmd ::= INSERT orconf",
|
|
+ /* 172 */ "insert_cmd ::= REPLACE",
|
|
+ /* 173 */ "idlist_opt ::=",
|
|
+ /* 174 */ "idlist_opt ::= LP idlist RP",
|
|
+ /* 175 */ "idlist ::= idlist COMMA nm",
|
|
+ /* 176 */ "idlist ::= nm",
|
|
+ /* 177 */ "expr ::= LP expr RP",
|
|
+ /* 178 */ "expr ::= ID|INDEXED",
|
|
+ /* 179 */ "expr ::= JOIN_KW",
|
|
+ /* 180 */ "expr ::= nm DOT nm",
|
|
+ /* 181 */ "expr ::= nm DOT nm DOT nm",
|
|
+ /* 182 */ "term ::= NULL|FLOAT|BLOB",
|
|
+ /* 183 */ "term ::= STRING",
|
|
+ /* 184 */ "term ::= INTEGER",
|
|
+ /* 185 */ "expr ::= VARIABLE",
|
|
+ /* 186 */ "expr ::= expr COLLATE ID|STRING",
|
|
+ /* 187 */ "expr ::= CAST LP expr AS typetoken RP",
|
|
+ /* 188 */ "expr ::= ID|INDEXED LP distinct exprlist RP",
|
|
+ /* 189 */ "expr ::= ID|INDEXED LP STAR RP",
|
|
+ /* 190 */ "expr ::= ID|INDEXED LP distinct exprlist RP filter_over",
|
|
+ /* 191 */ "expr ::= ID|INDEXED LP STAR RP filter_over",
|
|
+ /* 192 */ "term ::= CTIME_KW",
|
|
+ /* 193 */ "expr ::= LP nexprlist COMMA expr RP",
|
|
+ /* 194 */ "expr ::= expr AND expr",
|
|
+ /* 195 */ "expr ::= expr OR expr",
|
|
+ /* 196 */ "expr ::= expr LT|GT|GE|LE expr",
|
|
+ /* 197 */ "expr ::= expr EQ|NE expr",
|
|
+ /* 198 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr",
|
|
+ /* 199 */ "expr ::= expr PLUS|MINUS expr",
|
|
+ /* 200 */ "expr ::= expr STAR|SLASH|REM expr",
|
|
+ /* 201 */ "expr ::= expr CONCAT expr",
|
|
+ /* 202 */ "likeop ::= NOT LIKE_KW|MATCH",
|
|
+ /* 203 */ "expr ::= expr likeop expr",
|
|
+ /* 204 */ "expr ::= expr likeop expr ESCAPE expr",
|
|
+ /* 205 */ "expr ::= expr ISNULL|NOTNULL",
|
|
+ /* 206 */ "expr ::= expr NOT NULL",
|
|
+ /* 207 */ "expr ::= expr IS expr",
|
|
+ /* 208 */ "expr ::= expr IS NOT expr",
|
|
+ /* 209 */ "expr ::= expr IS NOT DISTINCT FROM expr",
|
|
+ /* 210 */ "expr ::= expr IS DISTINCT FROM expr",
|
|
+ /* 211 */ "expr ::= NOT expr",
|
|
+ /* 212 */ "expr ::= BITNOT expr",
|
|
+ /* 213 */ "expr ::= PLUS|MINUS expr",
|
|
+ /* 214 */ "expr ::= expr PTR expr",
|
|
+ /* 215 */ "between_op ::= BETWEEN",
|
|
+ /* 216 */ "between_op ::= NOT BETWEEN",
|
|
+ /* 217 */ "expr ::= expr between_op expr AND expr",
|
|
+ /* 218 */ "in_op ::= IN",
|
|
+ /* 219 */ "in_op ::= NOT IN",
|
|
+ /* 220 */ "expr ::= expr in_op LP exprlist RP",
|
|
+ /* 221 */ "expr ::= LP select RP",
|
|
+ /* 222 */ "expr ::= expr in_op LP select RP",
|
|
+ /* 223 */ "expr ::= expr in_op nm dbnm paren_exprlist",
|
|
+ /* 224 */ "expr ::= EXISTS LP select RP",
|
|
+ /* 225 */ "expr ::= CASE case_operand case_exprlist case_else END",
|
|
+ /* 226 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr",
|
|
+ /* 227 */ "case_exprlist ::= WHEN expr THEN expr",
|
|
+ /* 228 */ "case_else ::= ELSE expr",
|
|
+ /* 229 */ "case_else ::=",
|
|
+ /* 230 */ "case_operand ::= expr",
|
|
+ /* 231 */ "case_operand ::=",
|
|
+ /* 232 */ "exprlist ::=",
|
|
+ /* 233 */ "nexprlist ::= nexprlist COMMA expr",
|
|
+ /* 234 */ "nexprlist ::= expr",
|
|
+ /* 235 */ "paren_exprlist ::=",
|
|
+ /* 236 */ "paren_exprlist ::= LP exprlist RP",
|
|
+ /* 237 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt",
|
|
+ /* 238 */ "uniqueflag ::= UNIQUE",
|
|
+ /* 239 */ "uniqueflag ::=",
|
|
+ /* 240 */ "eidlist_opt ::=",
|
|
+ /* 241 */ "eidlist_opt ::= LP eidlist RP",
|
|
+ /* 242 */ "eidlist ::= eidlist COMMA nm collate sortorder",
|
|
+ /* 243 */ "eidlist ::= nm collate sortorder",
|
|
+ /* 244 */ "collate ::=",
|
|
+ /* 245 */ "collate ::= COLLATE ID|STRING",
|
|
+ /* 246 */ "cmd ::= DROP INDEX ifexists fullname",
|
|
+ /* 247 */ "cmd ::= VACUUM vinto",
|
|
+ /* 248 */ "cmd ::= VACUUM nm vinto",
|
|
+ /* 249 */ "vinto ::= INTO expr",
|
|
+ /* 250 */ "vinto ::=",
|
|
+ /* 251 */ "cmd ::= PRAGMA nm dbnm",
|
|
+ /* 252 */ "cmd ::= PRAGMA nm dbnm EQ nmnum",
|
|
+ /* 253 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP",
|
|
+ /* 254 */ "cmd ::= PRAGMA nm dbnm EQ minus_num",
|
|
+ /* 255 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP",
|
|
+ /* 256 */ "plus_num ::= PLUS INTEGER|FLOAT",
|
|
+ /* 257 */ "minus_num ::= MINUS INTEGER|FLOAT",
|
|
+ /* 258 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END",
|
|
+ /* 259 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause",
|
|
+ /* 260 */ "trigger_time ::= BEFORE|AFTER",
|
|
+ /* 261 */ "trigger_time ::= INSTEAD OF",
|
|
+ /* 262 */ "trigger_time ::=",
|
|
+ /* 263 */ "trigger_event ::= DELETE|INSERT",
|
|
+ /* 264 */ "trigger_event ::= UPDATE",
|
|
+ /* 265 */ "trigger_event ::= UPDATE OF idlist",
|
|
+ /* 266 */ "when_clause ::=",
|
|
+ /* 267 */ "when_clause ::= WHEN expr",
|
|
+ /* 268 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI",
|
|
+ /* 269 */ "trigger_cmd_list ::= trigger_cmd SEMI",
|
|
+ /* 270 */ "trnm ::= nm DOT nm",
|
|
+ /* 271 */ "tridxby ::= INDEXED BY nm",
|
|
+ /* 272 */ "tridxby ::= NOT INDEXED",
|
|
+ /* 273 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt",
|
|
+ /* 274 */ "trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt",
|
|
+ /* 275 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt",
|
|
+ /* 276 */ "trigger_cmd ::= scanpt select scanpt",
|
|
+ /* 277 */ "expr ::= RAISE LP IGNORE RP",
|
|
+ /* 278 */ "expr ::= RAISE LP raisetype COMMA nm RP",
|
|
+ /* 279 */ "raisetype ::= ROLLBACK",
|
|
+ /* 280 */ "raisetype ::= ABORT",
|
|
+ /* 281 */ "raisetype ::= FAIL",
|
|
+ /* 282 */ "cmd ::= DROP TRIGGER ifexists fullname",
|
|
+ /* 283 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt",
|
|
+ /* 284 */ "cmd ::= DETACH database_kw_opt expr",
|
|
+ /* 285 */ "key_opt ::=",
|
|
+ /* 286 */ "key_opt ::= KEY expr",
|
|
+ /* 287 */ "cmd ::= REINDEX",
|
|
+ /* 288 */ "cmd ::= REINDEX nm dbnm",
|
|
+ /* 289 */ "cmd ::= ANALYZE",
|
|
+ /* 290 */ "cmd ::= ANALYZE nm dbnm",
|
|
+ /* 291 */ "cmd ::= ALTER TABLE fullname RENAME TO nm",
|
|
+ /* 292 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist",
|
|
+ /* 293 */ "cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm",
|
|
+ /* 294 */ "add_column_fullname ::= fullname",
|
|
+ /* 295 */ "cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm",
|
|
+ /* 296 */ "cmd ::= create_vtab",
|
|
+ /* 297 */ "cmd ::= create_vtab LP vtabarglist RP",
|
|
+ /* 298 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm",
|
|
+ /* 299 */ "vtabarg ::=",
|
|
+ /* 300 */ "vtabargtoken ::= ANY",
|
|
+ /* 301 */ "vtabargtoken ::= lp anylist RP",
|
|
+ /* 302 */ "lp ::= LP",
|
|
+ /* 303 */ "with ::= WITH wqlist",
|
|
+ /* 304 */ "with ::= WITH RECURSIVE wqlist",
|
|
+ /* 305 */ "wqas ::= AS",
|
|
+ /* 306 */ "wqas ::= AS MATERIALIZED",
|
|
+ /* 307 */ "wqas ::= AS NOT MATERIALIZED",
|
|
+ /* 308 */ "wqitem ::= nm eidlist_opt wqas LP select RP",
|
|
+ /* 309 */ "wqlist ::= wqitem",
|
|
+ /* 310 */ "wqlist ::= wqlist COMMA wqitem",
|
|
+ /* 311 */ "windowdefn_list ::= windowdefn",
|
|
+ /* 312 */ "windowdefn_list ::= windowdefn_list COMMA windowdefn",
|
|
+ /* 313 */ "windowdefn ::= nm AS LP window RP",
|
|
+ /* 314 */ "window ::= PARTITION BY nexprlist orderby_opt frame_opt",
|
|
+ /* 315 */ "window ::= nm PARTITION BY nexprlist orderby_opt frame_opt",
|
|
+ /* 316 */ "window ::= ORDER BY sortlist frame_opt",
|
|
+ /* 317 */ "window ::= nm ORDER BY sortlist frame_opt",
|
|
+ /* 318 */ "window ::= frame_opt",
|
|
+ /* 319 */ "window ::= nm frame_opt",
|
|
+ /* 320 */ "frame_opt ::=",
|
|
+ /* 321 */ "frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt",
|
|
+ /* 322 */ "frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt",
|
|
+ /* 323 */ "range_or_rows ::= RANGE|ROWS|GROUPS",
|
|
+ /* 324 */ "frame_bound_s ::= frame_bound",
|
|
+ /* 325 */ "frame_bound_s ::= UNBOUNDED PRECEDING",
|
|
+ /* 326 */ "frame_bound_e ::= frame_bound",
|
|
+ /* 327 */ "frame_bound_e ::= UNBOUNDED FOLLOWING",
|
|
+ /* 328 */ "frame_bound ::= expr PRECEDING|FOLLOWING",
|
|
+ /* 329 */ "frame_bound ::= CURRENT ROW",
|
|
+ /* 330 */ "frame_exclude_opt ::=",
|
|
+ /* 331 */ "frame_exclude_opt ::= EXCLUDE frame_exclude",
|
|
+ /* 332 */ "frame_exclude ::= NO OTHERS",
|
|
+ /* 333 */ "frame_exclude ::= CURRENT ROW",
|
|
+ /* 334 */ "frame_exclude ::= GROUP|TIES",
|
|
+ /* 335 */ "window_clause ::= WINDOW windowdefn_list",
|
|
+ /* 336 */ "filter_over ::= filter_clause over_clause",
|
|
+ /* 337 */ "filter_over ::= over_clause",
|
|
+ /* 338 */ "filter_over ::= filter_clause",
|
|
+ /* 339 */ "over_clause ::= OVER LP window RP",
|
|
+ /* 340 */ "over_clause ::= OVER nm",
|
|
+ /* 341 */ "filter_clause ::= FILTER LP WHERE expr RP",
|
|
+ /* 342 */ "input ::= cmdlist",
|
|
+ /* 343 */ "cmdlist ::= cmdlist ecmd",
|
|
+ /* 344 */ "cmdlist ::= ecmd",
|
|
+ /* 345 */ "ecmd ::= SEMI",
|
|
+ /* 346 */ "ecmd ::= cmdx SEMI",
|
|
+ /* 347 */ "ecmd ::= explain cmdx SEMI",
|
|
+ /* 348 */ "trans_opt ::=",
|
|
+ /* 349 */ "trans_opt ::= TRANSACTION",
|
|
+ /* 350 */ "trans_opt ::= TRANSACTION nm",
|
|
+ /* 351 */ "savepoint_opt ::= SAVEPOINT",
|
|
+ /* 352 */ "savepoint_opt ::=",
|
|
+ /* 353 */ "cmd ::= create_table create_table_args",
|
|
+ /* 354 */ "table_option_set ::= table_option",
|
|
+ /* 355 */ "columnlist ::= columnlist COMMA columnname carglist",
|
|
+ /* 356 */ "columnlist ::= columnname carglist",
|
|
+ /* 357 */ "nm ::= ID|INDEXED",
|
|
+ /* 358 */ "nm ::= STRING",
|
|
+ /* 359 */ "nm ::= JOIN_KW",
|
|
+ /* 360 */ "typetoken ::= typename",
|
|
+ /* 361 */ "typename ::= ID|STRING",
|
|
+ /* 362 */ "signed ::= plus_num",
|
|
+ /* 363 */ "signed ::= minus_num",
|
|
+ /* 364 */ "carglist ::= carglist ccons",
|
|
+ /* 365 */ "carglist ::=",
|
|
+ /* 366 */ "ccons ::= NULL onconf",
|
|
+ /* 367 */ "ccons ::= GENERATED ALWAYS AS generated",
|
|
+ /* 368 */ "ccons ::= AS generated",
|
|
+ /* 369 */ "conslist_opt ::= COMMA conslist",
|
|
+ /* 370 */ "conslist ::= conslist tconscomma tcons",
|
|
+ /* 371 */ "conslist ::= tcons",
|
|
+ /* 372 */ "tconscomma ::=",
|
|
+ /* 373 */ "defer_subclause_opt ::= defer_subclause",
|
|
+ /* 374 */ "resolvetype ::= raisetype",
|
|
+ /* 375 */ "selectnowith ::= oneselect",
|
|
+ /* 376 */ "oneselect ::= values",
|
|
+ /* 377 */ "sclp ::= selcollist COMMA",
|
|
+ /* 378 */ "as ::= ID|STRING",
|
|
+ /* 379 */ "indexed_opt ::= indexed_by",
|
|
+ /* 380 */ "returning ::=",
|
|
+ /* 381 */ "expr ::= term",
|
|
+ /* 382 */ "likeop ::= LIKE_KW|MATCH",
|
|
+ /* 383 */ "exprlist ::= nexprlist",
|
|
+ /* 384 */ "nmnum ::= plus_num",
|
|
+ /* 385 */ "nmnum ::= nm",
|
|
+ /* 386 */ "nmnum ::= ON",
|
|
+ /* 387 */ "nmnum ::= DELETE",
|
|
+ /* 388 */ "nmnum ::= DEFAULT",
|
|
+ /* 389 */ "plus_num ::= INTEGER|FLOAT",
|
|
+ /* 390 */ "foreach_clause ::=",
|
|
+ /* 391 */ "foreach_clause ::= FOR EACH ROW",
|
|
+ /* 392 */ "trnm ::= nm",
|
|
+ /* 393 */ "tridxby ::=",
|
|
+ /* 394 */ "database_kw_opt ::= DATABASE",
|
|
+ /* 395 */ "database_kw_opt ::=",
|
|
+ /* 396 */ "kwcolumn_opt ::=",
|
|
+ /* 397 */ "kwcolumn_opt ::= COLUMNKW",
|
|
+ /* 398 */ "vtabarglist ::= vtabarg",
|
|
+ /* 399 */ "vtabarglist ::= vtabarglist COMMA vtabarg",
|
|
+ /* 400 */ "vtabarg ::= vtabarg vtabargtoken",
|
|
+ /* 401 */ "anylist ::=",
|
|
+ /* 402 */ "anylist ::= anylist LP anylist RP",
|
|
+ /* 403 */ "anylist ::= anylist ANY",
|
|
+ /* 404 */ "with ::=",
|
|
};
|
|
#endif /* NDEBUG */
|
|
|
|
@@ -154269,7 +169067,7 @@ static int yyGrowStack(yyParser *p){
|
|
#endif
|
|
p->yystksz = newSize;
|
|
}
|
|
- return pNew==0;
|
|
+ return pNew==0;
|
|
}
|
|
#endif
|
|
|
|
@@ -154311,7 +169109,7 @@ SQLITE_PRIVATE void sqlite3ParserInit(void *yypRawParser sqlite3ParserCTX_PDECL)
|
|
}
|
|
|
|
#ifndef sqlite3Parser_ENGINEALWAYSONSTACK
|
|
-/*
|
|
+/*
|
|
** This function allocates a new parser.
|
|
** The only argument is a pointer to a function which works like
|
|
** malloc.
|
|
@@ -154338,7 +169136,7 @@ SQLITE_PRIVATE void *sqlite3ParserAlloc(void *(*mallocProc)(YYMALLOCARGTYPE) sql
|
|
/* The following function deletes the "minor type" or semantic value
|
|
** associated with a symbol. The symbol can be either a terminal
|
|
** or nonterminal. "yymajor" is the symbol code, and "yypminor" is
|
|
-** a pointer to the value to be deleted. The code used to do the
|
|
+** a pointer to the value to be deleted. The code used to do the
|
|
** deletions is derived from the %destructor and/or %token_destructor
|
|
** directives of the input grammar.
|
|
*/
|
|
@@ -154353,7 +169151,7 @@ static void yy_destructor(
|
|
/* Here is inserted the actions which take place when a
|
|
** terminal or non-terminal is destroyed. This can happen
|
|
** when the symbol is popped from the stack during a
|
|
- ** reduce or during error processing or when a parser is
|
|
+ ** reduce or during error processing or when a parser is
|
|
** being destroyed before it is finished parsing.
|
|
**
|
|
** Note: during a reduce, the only symbols destroyed are those
|
|
@@ -154361,98 +169159,97 @@ static void yy_destructor(
|
|
** inside the C code.
|
|
*/
|
|
/********* Begin destructor definitions ***************************************/
|
|
- case 200: /* select */
|
|
- case 234: /* selectnowith */
|
|
- case 235: /* oneselect */
|
|
- case 247: /* values */
|
|
+ case 204: /* select */
|
|
+ case 239: /* selectnowith */
|
|
+ case 240: /* oneselect */
|
|
+ case 252: /* values */
|
|
{
|
|
-sqlite3SelectDelete(pParse->db, (yypminor->yy539));
|
|
-}
|
|
- break;
|
|
- case 211: /* term */
|
|
- case 212: /* expr */
|
|
- case 241: /* where_opt */
|
|
- case 243: /* having_opt */
|
|
- case 255: /* on_opt */
|
|
- case 271: /* case_operand */
|
|
- case 273: /* case_else */
|
|
- case 276: /* vinto */
|
|
- case 283: /* when_clause */
|
|
- case 288: /* key_opt */
|
|
- case 302: /* filter_clause */
|
|
+sqlite3SelectDelete(pParse->db, (yypminor->yy47));
|
|
+}
|
|
+ break;
|
|
+ case 216: /* term */
|
|
+ case 217: /* expr */
|
|
+ case 246: /* where_opt */
|
|
+ case 248: /* having_opt */
|
|
+ case 267: /* where_opt_ret */
|
|
+ case 278: /* case_operand */
|
|
+ case 280: /* case_else */
|
|
+ case 283: /* vinto */
|
|
+ case 290: /* when_clause */
|
|
+ case 295: /* key_opt */
|
|
+ case 311: /* filter_clause */
|
|
{
|
|
-sqlite3ExprDelete(pParse->db, (yypminor->yy202));
|
|
-}
|
|
- break;
|
|
- case 216: /* eidlist_opt */
|
|
- case 226: /* sortlist */
|
|
- case 227: /* eidlist */
|
|
- case 239: /* selcollist */
|
|
- case 242: /* groupby_opt */
|
|
- case 244: /* orderby_opt */
|
|
- case 248: /* nexprlist */
|
|
- case 249: /* sclp */
|
|
- case 257: /* exprlist */
|
|
- case 262: /* setlist */
|
|
- case 270: /* paren_exprlist */
|
|
- case 272: /* case_exprlist */
|
|
- case 301: /* part_opt */
|
|
+sqlite3ExprDelete(pParse->db, (yypminor->yy528));
|
|
+}
|
|
+ break;
|
|
+ case 221: /* eidlist_opt */
|
|
+ case 231: /* sortlist */
|
|
+ case 232: /* eidlist */
|
|
+ case 244: /* selcollist */
|
|
+ case 247: /* groupby_opt */
|
|
+ case 249: /* orderby_opt */
|
|
+ case 253: /* nexprlist */
|
|
+ case 254: /* sclp */
|
|
+ case 261: /* exprlist */
|
|
+ case 268: /* setlist */
|
|
+ case 277: /* paren_exprlist */
|
|
+ case 279: /* case_exprlist */
|
|
+ case 310: /* part_opt */
|
|
{
|
|
-sqlite3ExprListDelete(pParse->db, (yypminor->yy242));
|
|
+sqlite3ExprListDelete(pParse->db, (yypminor->yy322));
|
|
}
|
|
break;
|
|
- case 233: /* fullname */
|
|
- case 240: /* from */
|
|
- case 251: /* seltablist */
|
|
- case 252: /* stl_prefix */
|
|
- case 258: /* xfullname */
|
|
+ case 238: /* fullname */
|
|
+ case 245: /* from */
|
|
+ case 256: /* seltablist */
|
|
+ case 257: /* stl_prefix */
|
|
+ case 262: /* xfullname */
|
|
{
|
|
-sqlite3SrcListDelete(pParse->db, (yypminor->yy47));
|
|
+sqlite3SrcListDelete(pParse->db, (yypminor->yy131));
|
|
}
|
|
break;
|
|
- case 236: /* wqlist */
|
|
+ case 241: /* wqlist */
|
|
{
|
|
-sqlite3WithDelete(pParse->db, (yypminor->yy131));
|
|
+sqlite3WithDelete(pParse->db, (yypminor->yy521));
|
|
}
|
|
break;
|
|
- case 246: /* window_clause */
|
|
- case 297: /* windowdefn_list */
|
|
+ case 251: /* window_clause */
|
|
+ case 306: /* windowdefn_list */
|
|
{
|
|
-sqlite3WindowListDelete(pParse->db, (yypminor->yy303));
|
|
+sqlite3WindowListDelete(pParse->db, (yypminor->yy41));
|
|
}
|
|
break;
|
|
- case 256: /* using_opt */
|
|
- case 259: /* idlist */
|
|
- case 264: /* idlist_opt */
|
|
+ case 263: /* idlist */
|
|
+ case 270: /* idlist_opt */
|
|
{
|
|
-sqlite3IdListDelete(pParse->db, (yypminor->yy600));
|
|
+sqlite3IdListDelete(pParse->db, (yypminor->yy254));
|
|
}
|
|
break;
|
|
- case 266: /* filter_over */
|
|
- case 298: /* windowdefn */
|
|
- case 299: /* window */
|
|
- case 300: /* frame_opt */
|
|
- case 303: /* over_clause */
|
|
+ case 273: /* filter_over */
|
|
+ case 307: /* windowdefn */
|
|
+ case 308: /* window */
|
|
+ case 309: /* frame_opt */
|
|
+ case 312: /* over_clause */
|
|
{
|
|
-sqlite3WindowDelete(pParse->db, (yypminor->yy303));
|
|
+sqlite3WindowDelete(pParse->db, (yypminor->yy41));
|
|
}
|
|
break;
|
|
- case 279: /* trigger_cmd_list */
|
|
- case 284: /* trigger_cmd */
|
|
+ case 286: /* trigger_cmd_list */
|
|
+ case 291: /* trigger_cmd */
|
|
{
|
|
-sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy447));
|
|
+sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy33));
|
|
}
|
|
break;
|
|
- case 281: /* trigger_event */
|
|
+ case 288: /* trigger_event */
|
|
{
|
|
-sqlite3IdListDelete(pParse->db, (yypminor->yy230).b);
|
|
+sqlite3IdListDelete(pParse->db, (yypminor->yy180).b);
|
|
}
|
|
break;
|
|
- case 305: /* frame_bound */
|
|
- case 306: /* frame_bound_s */
|
|
- case 307: /* frame_bound_e */
|
|
+ case 314: /* frame_bound */
|
|
+ case 315: /* frame_bound_s */
|
|
+ case 316: /* frame_bound_e */
|
|
{
|
|
-sqlite3ExprDelete(pParse->db, (yypminor->yy77).pExpr);
|
|
+sqlite3ExprDelete(pParse->db, (yypminor->yy595).pExpr);
|
|
}
|
|
break;
|
|
/********* End destructor definitions *****************************************/
|
|
@@ -154493,7 +169290,7 @@ SQLITE_PRIVATE void sqlite3ParserFinalize(void *p){
|
|
}
|
|
|
|
#ifndef sqlite3Parser_ENGINEALWAYSONSTACK
|
|
-/*
|
|
+/*
|
|
** Deallocate and destroy a parser. Destructors are called for
|
|
** all stack elements before shutting the parser down.
|
|
**
|
|
@@ -154619,7 +169416,7 @@ static YYACTIONTYPE yy_find_shift_action(
|
|
#endif /* YYWILDCARD */
|
|
return yy_default[stateno];
|
|
}else{
|
|
- assert( i>=0 && i<sizeof(yy_action)/sizeof(yy_action[0]) );
|
|
+ assert( i>=0 && i<(int)(sizeof(yy_action)/sizeof(yy_action[0])) );
|
|
return yy_action[i];
|
|
}
|
|
}while(1);
|
|
@@ -154715,7 +169512,7 @@ static void yy_shift(
|
|
assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack) );
|
|
}
|
|
#endif
|
|
-#if YYSTACKDEPTH>0
|
|
+#if YYSTACKDEPTH>0
|
|
if( yypParser->yytos>yypParser->yystackEnd ){
|
|
yypParser->yytos--;
|
|
yyStackOverflow(yypParser);
|
|
@@ -154743,391 +169540,411 @@ static void yy_shift(
|
|
/* For rule J, yyRuleInfoLhs[J] contains the symbol on the left-hand side
|
|
** of that rule */
|
|
static const YYCODETYPE yyRuleInfoLhs[] = {
|
|
- 185, /* (0) explain ::= EXPLAIN */
|
|
- 185, /* (1) explain ::= EXPLAIN QUERY PLAN */
|
|
- 184, /* (2) cmdx ::= cmd */
|
|
- 186, /* (3) cmd ::= BEGIN transtype trans_opt */
|
|
- 187, /* (4) transtype ::= */
|
|
- 187, /* (5) transtype ::= DEFERRED */
|
|
- 187, /* (6) transtype ::= IMMEDIATE */
|
|
- 187, /* (7) transtype ::= EXCLUSIVE */
|
|
- 186, /* (8) cmd ::= COMMIT|END trans_opt */
|
|
- 186, /* (9) cmd ::= ROLLBACK trans_opt */
|
|
- 186, /* (10) cmd ::= SAVEPOINT nm */
|
|
- 186, /* (11) cmd ::= RELEASE savepoint_opt nm */
|
|
- 186, /* (12) cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */
|
|
- 191, /* (13) create_table ::= createkw temp TABLE ifnotexists nm dbnm */
|
|
- 193, /* (14) createkw ::= CREATE */
|
|
- 195, /* (15) ifnotexists ::= */
|
|
- 195, /* (16) ifnotexists ::= IF NOT EXISTS */
|
|
- 194, /* (17) temp ::= TEMP */
|
|
- 194, /* (18) temp ::= */
|
|
- 192, /* (19) create_table_args ::= LP columnlist conslist_opt RP table_options */
|
|
- 192, /* (20) create_table_args ::= AS select */
|
|
- 199, /* (21) table_options ::= */
|
|
- 199, /* (22) table_options ::= WITHOUT nm */
|
|
- 201, /* (23) columnname ::= nm typetoken */
|
|
- 203, /* (24) typetoken ::= */
|
|
- 203, /* (25) typetoken ::= typename LP signed RP */
|
|
- 203, /* (26) typetoken ::= typename LP signed COMMA signed RP */
|
|
- 204, /* (27) typename ::= typename ID|STRING */
|
|
- 208, /* (28) scanpt ::= */
|
|
- 209, /* (29) scantok ::= */
|
|
- 210, /* (30) ccons ::= CONSTRAINT nm */
|
|
- 210, /* (31) ccons ::= DEFAULT scantok term */
|
|
- 210, /* (32) ccons ::= DEFAULT LP expr RP */
|
|
- 210, /* (33) ccons ::= DEFAULT PLUS scantok term */
|
|
- 210, /* (34) ccons ::= DEFAULT MINUS scantok term */
|
|
- 210, /* (35) ccons ::= DEFAULT scantok ID|INDEXED */
|
|
- 210, /* (36) ccons ::= NOT NULL onconf */
|
|
- 210, /* (37) ccons ::= PRIMARY KEY sortorder onconf autoinc */
|
|
- 210, /* (38) ccons ::= UNIQUE onconf */
|
|
- 210, /* (39) ccons ::= CHECK LP expr RP */
|
|
- 210, /* (40) ccons ::= REFERENCES nm eidlist_opt refargs */
|
|
- 210, /* (41) ccons ::= defer_subclause */
|
|
- 210, /* (42) ccons ::= COLLATE ID|STRING */
|
|
- 219, /* (43) generated ::= LP expr RP */
|
|
- 219, /* (44) generated ::= LP expr RP ID */
|
|
- 215, /* (45) autoinc ::= */
|
|
- 215, /* (46) autoinc ::= AUTOINCR */
|
|
- 217, /* (47) refargs ::= */
|
|
- 217, /* (48) refargs ::= refargs refarg */
|
|
- 220, /* (49) refarg ::= MATCH nm */
|
|
- 220, /* (50) refarg ::= ON INSERT refact */
|
|
- 220, /* (51) refarg ::= ON DELETE refact */
|
|
- 220, /* (52) refarg ::= ON UPDATE refact */
|
|
- 221, /* (53) refact ::= SET NULL */
|
|
- 221, /* (54) refact ::= SET DEFAULT */
|
|
- 221, /* (55) refact ::= CASCADE */
|
|
- 221, /* (56) refact ::= RESTRICT */
|
|
- 221, /* (57) refact ::= NO ACTION */
|
|
- 218, /* (58) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */
|
|
- 218, /* (59) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
|
|
- 222, /* (60) init_deferred_pred_opt ::= */
|
|
- 222, /* (61) init_deferred_pred_opt ::= INITIALLY DEFERRED */
|
|
- 222, /* (62) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */
|
|
- 198, /* (63) conslist_opt ::= */
|
|
- 224, /* (64) tconscomma ::= COMMA */
|
|
- 225, /* (65) tcons ::= CONSTRAINT nm */
|
|
- 225, /* (66) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */
|
|
- 225, /* (67) tcons ::= UNIQUE LP sortlist RP onconf */
|
|
- 225, /* (68) tcons ::= CHECK LP expr RP onconf */
|
|
- 225, /* (69) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */
|
|
- 228, /* (70) defer_subclause_opt ::= */
|
|
- 213, /* (71) onconf ::= */
|
|
- 213, /* (72) onconf ::= ON CONFLICT resolvetype */
|
|
- 229, /* (73) orconf ::= */
|
|
- 229, /* (74) orconf ::= OR resolvetype */
|
|
- 230, /* (75) resolvetype ::= IGNORE */
|
|
- 230, /* (76) resolvetype ::= REPLACE */
|
|
- 186, /* (77) cmd ::= DROP TABLE ifexists fullname */
|
|
- 232, /* (78) ifexists ::= IF EXISTS */
|
|
- 232, /* (79) ifexists ::= */
|
|
- 186, /* (80) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */
|
|
- 186, /* (81) cmd ::= DROP VIEW ifexists fullname */
|
|
- 186, /* (82) cmd ::= select */
|
|
- 200, /* (83) select ::= WITH wqlist selectnowith */
|
|
- 200, /* (84) select ::= WITH RECURSIVE wqlist selectnowith */
|
|
- 200, /* (85) select ::= selectnowith */
|
|
- 234, /* (86) selectnowith ::= selectnowith multiselect_op oneselect */
|
|
- 237, /* (87) multiselect_op ::= UNION */
|
|
- 237, /* (88) multiselect_op ::= UNION ALL */
|
|
- 237, /* (89) multiselect_op ::= EXCEPT|INTERSECT */
|
|
- 235, /* (90) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
|
|
- 235, /* (91) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */
|
|
- 247, /* (92) values ::= VALUES LP nexprlist RP */
|
|
- 247, /* (93) values ::= values COMMA LP nexprlist RP */
|
|
- 238, /* (94) distinct ::= DISTINCT */
|
|
- 238, /* (95) distinct ::= ALL */
|
|
- 238, /* (96) distinct ::= */
|
|
- 249, /* (97) sclp ::= */
|
|
- 239, /* (98) selcollist ::= sclp scanpt expr scanpt as */
|
|
- 239, /* (99) selcollist ::= sclp scanpt STAR */
|
|
- 239, /* (100) selcollist ::= sclp scanpt nm DOT STAR */
|
|
- 250, /* (101) as ::= AS nm */
|
|
- 250, /* (102) as ::= */
|
|
- 240, /* (103) from ::= */
|
|
- 240, /* (104) from ::= FROM seltablist */
|
|
- 252, /* (105) stl_prefix ::= seltablist joinop */
|
|
- 252, /* (106) stl_prefix ::= */
|
|
- 251, /* (107) seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */
|
|
- 251, /* (108) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */
|
|
- 251, /* (109) seltablist ::= stl_prefix LP select RP as on_opt using_opt */
|
|
- 251, /* (110) seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */
|
|
- 196, /* (111) dbnm ::= */
|
|
- 196, /* (112) dbnm ::= DOT nm */
|
|
- 233, /* (113) fullname ::= nm */
|
|
- 233, /* (114) fullname ::= nm DOT nm */
|
|
- 258, /* (115) xfullname ::= nm */
|
|
- 258, /* (116) xfullname ::= nm DOT nm */
|
|
- 258, /* (117) xfullname ::= nm DOT nm AS nm */
|
|
- 258, /* (118) xfullname ::= nm AS nm */
|
|
- 253, /* (119) joinop ::= COMMA|JOIN */
|
|
- 253, /* (120) joinop ::= JOIN_KW JOIN */
|
|
- 253, /* (121) joinop ::= JOIN_KW nm JOIN */
|
|
- 253, /* (122) joinop ::= JOIN_KW nm nm JOIN */
|
|
- 255, /* (123) on_opt ::= ON expr */
|
|
- 255, /* (124) on_opt ::= */
|
|
- 254, /* (125) indexed_opt ::= */
|
|
- 254, /* (126) indexed_opt ::= INDEXED BY nm */
|
|
- 254, /* (127) indexed_opt ::= NOT INDEXED */
|
|
- 256, /* (128) using_opt ::= USING LP idlist RP */
|
|
- 256, /* (129) using_opt ::= */
|
|
- 244, /* (130) orderby_opt ::= */
|
|
- 244, /* (131) orderby_opt ::= ORDER BY sortlist */
|
|
- 226, /* (132) sortlist ::= sortlist COMMA expr sortorder nulls */
|
|
- 226, /* (133) sortlist ::= expr sortorder nulls */
|
|
- 214, /* (134) sortorder ::= ASC */
|
|
- 214, /* (135) sortorder ::= DESC */
|
|
- 214, /* (136) sortorder ::= */
|
|
- 260, /* (137) nulls ::= NULLS FIRST */
|
|
- 260, /* (138) nulls ::= NULLS LAST */
|
|
- 260, /* (139) nulls ::= */
|
|
- 242, /* (140) groupby_opt ::= */
|
|
- 242, /* (141) groupby_opt ::= GROUP BY nexprlist */
|
|
- 243, /* (142) having_opt ::= */
|
|
- 243, /* (143) having_opt ::= HAVING expr */
|
|
- 245, /* (144) limit_opt ::= */
|
|
- 245, /* (145) limit_opt ::= LIMIT expr */
|
|
- 245, /* (146) limit_opt ::= LIMIT expr OFFSET expr */
|
|
- 245, /* (147) limit_opt ::= LIMIT expr COMMA expr */
|
|
- 186, /* (148) cmd ::= with DELETE FROM xfullname indexed_opt where_opt */
|
|
- 241, /* (149) where_opt ::= */
|
|
- 241, /* (150) where_opt ::= WHERE expr */
|
|
- 186, /* (151) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist where_opt */
|
|
- 262, /* (152) setlist ::= setlist COMMA nm EQ expr */
|
|
- 262, /* (153) setlist ::= setlist COMMA LP idlist RP EQ expr */
|
|
- 262, /* (154) setlist ::= nm EQ expr */
|
|
- 262, /* (155) setlist ::= LP idlist RP EQ expr */
|
|
- 186, /* (156) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */
|
|
- 186, /* (157) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES */
|
|
- 265, /* (158) upsert ::= */
|
|
- 265, /* (159) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt */
|
|
- 265, /* (160) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING */
|
|
- 265, /* (161) upsert ::= ON CONFLICT DO NOTHING */
|
|
- 263, /* (162) insert_cmd ::= INSERT orconf */
|
|
- 263, /* (163) insert_cmd ::= REPLACE */
|
|
- 264, /* (164) idlist_opt ::= */
|
|
- 264, /* (165) idlist_opt ::= LP idlist RP */
|
|
- 259, /* (166) idlist ::= idlist COMMA nm */
|
|
- 259, /* (167) idlist ::= nm */
|
|
- 212, /* (168) expr ::= LP expr RP */
|
|
- 212, /* (169) expr ::= ID|INDEXED */
|
|
- 212, /* (170) expr ::= JOIN_KW */
|
|
- 212, /* (171) expr ::= nm DOT nm */
|
|
- 212, /* (172) expr ::= nm DOT nm DOT nm */
|
|
- 211, /* (173) term ::= NULL|FLOAT|BLOB */
|
|
- 211, /* (174) term ::= STRING */
|
|
- 211, /* (175) term ::= INTEGER */
|
|
- 212, /* (176) expr ::= VARIABLE */
|
|
- 212, /* (177) expr ::= expr COLLATE ID|STRING */
|
|
- 212, /* (178) expr ::= CAST LP expr AS typetoken RP */
|
|
- 212, /* (179) expr ::= ID|INDEXED LP distinct exprlist RP */
|
|
- 212, /* (180) expr ::= ID|INDEXED LP STAR RP */
|
|
- 212, /* (181) expr ::= ID|INDEXED LP distinct exprlist RP filter_over */
|
|
- 212, /* (182) expr ::= ID|INDEXED LP STAR RP filter_over */
|
|
- 211, /* (183) term ::= CTIME_KW */
|
|
- 212, /* (184) expr ::= LP nexprlist COMMA expr RP */
|
|
- 212, /* (185) expr ::= expr AND expr */
|
|
- 212, /* (186) expr ::= expr OR expr */
|
|
- 212, /* (187) expr ::= expr LT|GT|GE|LE expr */
|
|
- 212, /* (188) expr ::= expr EQ|NE expr */
|
|
- 212, /* (189) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */
|
|
- 212, /* (190) expr ::= expr PLUS|MINUS expr */
|
|
- 212, /* (191) expr ::= expr STAR|SLASH|REM expr */
|
|
- 212, /* (192) expr ::= expr CONCAT expr */
|
|
- 267, /* (193) likeop ::= NOT LIKE_KW|MATCH */
|
|
- 212, /* (194) expr ::= expr likeop expr */
|
|
- 212, /* (195) expr ::= expr likeop expr ESCAPE expr */
|
|
- 212, /* (196) expr ::= expr ISNULL|NOTNULL */
|
|
- 212, /* (197) expr ::= expr NOT NULL */
|
|
- 212, /* (198) expr ::= expr IS expr */
|
|
- 212, /* (199) expr ::= expr IS NOT expr */
|
|
- 212, /* (200) expr ::= NOT expr */
|
|
- 212, /* (201) expr ::= BITNOT expr */
|
|
- 212, /* (202) expr ::= PLUS|MINUS expr */
|
|
- 268, /* (203) between_op ::= BETWEEN */
|
|
- 268, /* (204) between_op ::= NOT BETWEEN */
|
|
- 212, /* (205) expr ::= expr between_op expr AND expr */
|
|
- 269, /* (206) in_op ::= IN */
|
|
- 269, /* (207) in_op ::= NOT IN */
|
|
- 212, /* (208) expr ::= expr in_op LP exprlist RP */
|
|
- 212, /* (209) expr ::= LP select RP */
|
|
- 212, /* (210) expr ::= expr in_op LP select RP */
|
|
- 212, /* (211) expr ::= expr in_op nm dbnm paren_exprlist */
|
|
- 212, /* (212) expr ::= EXISTS LP select RP */
|
|
- 212, /* (213) expr ::= CASE case_operand case_exprlist case_else END */
|
|
- 272, /* (214) case_exprlist ::= case_exprlist WHEN expr THEN expr */
|
|
- 272, /* (215) case_exprlist ::= WHEN expr THEN expr */
|
|
- 273, /* (216) case_else ::= ELSE expr */
|
|
- 273, /* (217) case_else ::= */
|
|
- 271, /* (218) case_operand ::= expr */
|
|
- 271, /* (219) case_operand ::= */
|
|
- 257, /* (220) exprlist ::= */
|
|
- 248, /* (221) nexprlist ::= nexprlist COMMA expr */
|
|
- 248, /* (222) nexprlist ::= expr */
|
|
- 270, /* (223) paren_exprlist ::= */
|
|
- 270, /* (224) paren_exprlist ::= LP exprlist RP */
|
|
- 186, /* (225) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
|
|
- 274, /* (226) uniqueflag ::= UNIQUE */
|
|
- 274, /* (227) uniqueflag ::= */
|
|
- 216, /* (228) eidlist_opt ::= */
|
|
- 216, /* (229) eidlist_opt ::= LP eidlist RP */
|
|
- 227, /* (230) eidlist ::= eidlist COMMA nm collate sortorder */
|
|
- 227, /* (231) eidlist ::= nm collate sortorder */
|
|
- 275, /* (232) collate ::= */
|
|
- 275, /* (233) collate ::= COLLATE ID|STRING */
|
|
- 186, /* (234) cmd ::= DROP INDEX ifexists fullname */
|
|
- 186, /* (235) cmd ::= VACUUM vinto */
|
|
- 186, /* (236) cmd ::= VACUUM nm vinto */
|
|
- 276, /* (237) vinto ::= INTO expr */
|
|
- 276, /* (238) vinto ::= */
|
|
- 186, /* (239) cmd ::= PRAGMA nm dbnm */
|
|
- 186, /* (240) cmd ::= PRAGMA nm dbnm EQ nmnum */
|
|
- 186, /* (241) cmd ::= PRAGMA nm dbnm LP nmnum RP */
|
|
- 186, /* (242) cmd ::= PRAGMA nm dbnm EQ minus_num */
|
|
- 186, /* (243) cmd ::= PRAGMA nm dbnm LP minus_num RP */
|
|
- 206, /* (244) plus_num ::= PLUS INTEGER|FLOAT */
|
|
- 207, /* (245) minus_num ::= MINUS INTEGER|FLOAT */
|
|
- 186, /* (246) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
|
|
- 278, /* (247) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
|
|
- 280, /* (248) trigger_time ::= BEFORE|AFTER */
|
|
- 280, /* (249) trigger_time ::= INSTEAD OF */
|
|
- 280, /* (250) trigger_time ::= */
|
|
- 281, /* (251) trigger_event ::= DELETE|INSERT */
|
|
- 281, /* (252) trigger_event ::= UPDATE */
|
|
- 281, /* (253) trigger_event ::= UPDATE OF idlist */
|
|
- 283, /* (254) when_clause ::= */
|
|
- 283, /* (255) when_clause ::= WHEN expr */
|
|
- 279, /* (256) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
|
|
- 279, /* (257) trigger_cmd_list ::= trigger_cmd SEMI */
|
|
- 285, /* (258) trnm ::= nm DOT nm */
|
|
- 286, /* (259) tridxby ::= INDEXED BY nm */
|
|
- 286, /* (260) tridxby ::= NOT INDEXED */
|
|
- 284, /* (261) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt scanpt */
|
|
- 284, /* (262) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */
|
|
- 284, /* (263) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
|
|
- 284, /* (264) trigger_cmd ::= scanpt select scanpt */
|
|
- 212, /* (265) expr ::= RAISE LP IGNORE RP */
|
|
- 212, /* (266) expr ::= RAISE LP raisetype COMMA nm RP */
|
|
- 231, /* (267) raisetype ::= ROLLBACK */
|
|
- 231, /* (268) raisetype ::= ABORT */
|
|
- 231, /* (269) raisetype ::= FAIL */
|
|
- 186, /* (270) cmd ::= DROP TRIGGER ifexists fullname */
|
|
- 186, /* (271) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
|
|
- 186, /* (272) cmd ::= DETACH database_kw_opt expr */
|
|
- 288, /* (273) key_opt ::= */
|
|
- 288, /* (274) key_opt ::= KEY expr */
|
|
- 186, /* (275) cmd ::= REINDEX */
|
|
- 186, /* (276) cmd ::= REINDEX nm dbnm */
|
|
- 186, /* (277) cmd ::= ANALYZE */
|
|
- 186, /* (278) cmd ::= ANALYZE nm dbnm */
|
|
- 186, /* (279) cmd ::= ALTER TABLE fullname RENAME TO nm */
|
|
- 186, /* (280) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
|
|
- 289, /* (281) add_column_fullname ::= fullname */
|
|
- 186, /* (282) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */
|
|
- 186, /* (283) cmd ::= create_vtab */
|
|
- 186, /* (284) cmd ::= create_vtab LP vtabarglist RP */
|
|
- 291, /* (285) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
|
|
- 293, /* (286) vtabarg ::= */
|
|
- 294, /* (287) vtabargtoken ::= ANY */
|
|
- 294, /* (288) vtabargtoken ::= lp anylist RP */
|
|
- 295, /* (289) lp ::= LP */
|
|
- 261, /* (290) with ::= WITH wqlist */
|
|
- 261, /* (291) with ::= WITH RECURSIVE wqlist */
|
|
- 236, /* (292) wqlist ::= nm eidlist_opt AS LP select RP */
|
|
- 236, /* (293) wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP */
|
|
- 297, /* (294) windowdefn_list ::= windowdefn */
|
|
- 297, /* (295) windowdefn_list ::= windowdefn_list COMMA windowdefn */
|
|
- 298, /* (296) windowdefn ::= nm AS LP window RP */
|
|
- 299, /* (297) window ::= PARTITION BY nexprlist orderby_opt frame_opt */
|
|
- 299, /* (298) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */
|
|
- 299, /* (299) window ::= ORDER BY sortlist frame_opt */
|
|
- 299, /* (300) window ::= nm ORDER BY sortlist frame_opt */
|
|
- 299, /* (301) window ::= frame_opt */
|
|
- 299, /* (302) window ::= nm frame_opt */
|
|
- 300, /* (303) frame_opt ::= */
|
|
- 300, /* (304) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */
|
|
- 300, /* (305) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */
|
|
- 304, /* (306) range_or_rows ::= RANGE|ROWS|GROUPS */
|
|
- 306, /* (307) frame_bound_s ::= frame_bound */
|
|
- 306, /* (308) frame_bound_s ::= UNBOUNDED PRECEDING */
|
|
- 307, /* (309) frame_bound_e ::= frame_bound */
|
|
- 307, /* (310) frame_bound_e ::= UNBOUNDED FOLLOWING */
|
|
- 305, /* (311) frame_bound ::= expr PRECEDING|FOLLOWING */
|
|
- 305, /* (312) frame_bound ::= CURRENT ROW */
|
|
- 308, /* (313) frame_exclude_opt ::= */
|
|
- 308, /* (314) frame_exclude_opt ::= EXCLUDE frame_exclude */
|
|
- 309, /* (315) frame_exclude ::= NO OTHERS */
|
|
- 309, /* (316) frame_exclude ::= CURRENT ROW */
|
|
- 309, /* (317) frame_exclude ::= GROUP|TIES */
|
|
- 246, /* (318) window_clause ::= WINDOW windowdefn_list */
|
|
- 266, /* (319) filter_over ::= filter_clause over_clause */
|
|
- 266, /* (320) filter_over ::= over_clause */
|
|
- 266, /* (321) filter_over ::= filter_clause */
|
|
- 303, /* (322) over_clause ::= OVER LP window RP */
|
|
- 303, /* (323) over_clause ::= OVER nm */
|
|
- 302, /* (324) filter_clause ::= FILTER LP WHERE expr RP */
|
|
- 181, /* (325) input ::= cmdlist */
|
|
- 182, /* (326) cmdlist ::= cmdlist ecmd */
|
|
- 182, /* (327) cmdlist ::= ecmd */
|
|
- 183, /* (328) ecmd ::= SEMI */
|
|
- 183, /* (329) ecmd ::= cmdx SEMI */
|
|
- 183, /* (330) ecmd ::= explain cmdx SEMI */
|
|
- 188, /* (331) trans_opt ::= */
|
|
- 188, /* (332) trans_opt ::= TRANSACTION */
|
|
- 188, /* (333) trans_opt ::= TRANSACTION nm */
|
|
- 190, /* (334) savepoint_opt ::= SAVEPOINT */
|
|
- 190, /* (335) savepoint_opt ::= */
|
|
- 186, /* (336) cmd ::= create_table create_table_args */
|
|
- 197, /* (337) columnlist ::= columnlist COMMA columnname carglist */
|
|
- 197, /* (338) columnlist ::= columnname carglist */
|
|
- 189, /* (339) nm ::= ID|INDEXED */
|
|
- 189, /* (340) nm ::= STRING */
|
|
- 189, /* (341) nm ::= JOIN_KW */
|
|
- 203, /* (342) typetoken ::= typename */
|
|
- 204, /* (343) typename ::= ID|STRING */
|
|
- 205, /* (344) signed ::= plus_num */
|
|
- 205, /* (345) signed ::= minus_num */
|
|
- 202, /* (346) carglist ::= carglist ccons */
|
|
- 202, /* (347) carglist ::= */
|
|
- 210, /* (348) ccons ::= NULL onconf */
|
|
- 210, /* (349) ccons ::= GENERATED ALWAYS AS generated */
|
|
- 210, /* (350) ccons ::= AS generated */
|
|
- 198, /* (351) conslist_opt ::= COMMA conslist */
|
|
- 223, /* (352) conslist ::= conslist tconscomma tcons */
|
|
- 223, /* (353) conslist ::= tcons */
|
|
- 224, /* (354) tconscomma ::= */
|
|
- 228, /* (355) defer_subclause_opt ::= defer_subclause */
|
|
- 230, /* (356) resolvetype ::= raisetype */
|
|
- 234, /* (357) selectnowith ::= oneselect */
|
|
- 235, /* (358) oneselect ::= values */
|
|
- 249, /* (359) sclp ::= selcollist COMMA */
|
|
- 250, /* (360) as ::= ID|STRING */
|
|
- 212, /* (361) expr ::= term */
|
|
- 267, /* (362) likeop ::= LIKE_KW|MATCH */
|
|
- 257, /* (363) exprlist ::= nexprlist */
|
|
- 277, /* (364) nmnum ::= plus_num */
|
|
- 277, /* (365) nmnum ::= nm */
|
|
- 277, /* (366) nmnum ::= ON */
|
|
- 277, /* (367) nmnum ::= DELETE */
|
|
- 277, /* (368) nmnum ::= DEFAULT */
|
|
- 206, /* (369) plus_num ::= INTEGER|FLOAT */
|
|
- 282, /* (370) foreach_clause ::= */
|
|
- 282, /* (371) foreach_clause ::= FOR EACH ROW */
|
|
- 285, /* (372) trnm ::= nm */
|
|
- 286, /* (373) tridxby ::= */
|
|
- 287, /* (374) database_kw_opt ::= DATABASE */
|
|
- 287, /* (375) database_kw_opt ::= */
|
|
- 290, /* (376) kwcolumn_opt ::= */
|
|
- 290, /* (377) kwcolumn_opt ::= COLUMNKW */
|
|
- 292, /* (378) vtabarglist ::= vtabarg */
|
|
- 292, /* (379) vtabarglist ::= vtabarglist COMMA vtabarg */
|
|
- 293, /* (380) vtabarg ::= vtabarg vtabargtoken */
|
|
- 296, /* (381) anylist ::= */
|
|
- 296, /* (382) anylist ::= anylist LP anylist RP */
|
|
- 296, /* (383) anylist ::= anylist ANY */
|
|
- 261, /* (384) with ::= */
|
|
+ 189, /* (0) explain ::= EXPLAIN */
|
|
+ 189, /* (1) explain ::= EXPLAIN QUERY PLAN */
|
|
+ 188, /* (2) cmdx ::= cmd */
|
|
+ 190, /* (3) cmd ::= BEGIN transtype trans_opt */
|
|
+ 191, /* (4) transtype ::= */
|
|
+ 191, /* (5) transtype ::= DEFERRED */
|
|
+ 191, /* (6) transtype ::= IMMEDIATE */
|
|
+ 191, /* (7) transtype ::= EXCLUSIVE */
|
|
+ 190, /* (8) cmd ::= COMMIT|END trans_opt */
|
|
+ 190, /* (9) cmd ::= ROLLBACK trans_opt */
|
|
+ 190, /* (10) cmd ::= SAVEPOINT nm */
|
|
+ 190, /* (11) cmd ::= RELEASE savepoint_opt nm */
|
|
+ 190, /* (12) cmd ::= ROLLBACK trans_opt TO savepoint_opt nm */
|
|
+ 195, /* (13) create_table ::= createkw temp TABLE ifnotexists nm dbnm */
|
|
+ 197, /* (14) createkw ::= CREATE */
|
|
+ 199, /* (15) ifnotexists ::= */
|
|
+ 199, /* (16) ifnotexists ::= IF NOT EXISTS */
|
|
+ 198, /* (17) temp ::= TEMP */
|
|
+ 198, /* (18) temp ::= */
|
|
+ 196, /* (19) create_table_args ::= LP columnlist conslist_opt RP table_option_set */
|
|
+ 196, /* (20) create_table_args ::= AS select */
|
|
+ 203, /* (21) table_option_set ::= */
|
|
+ 203, /* (22) table_option_set ::= table_option_set COMMA table_option */
|
|
+ 205, /* (23) table_option ::= WITHOUT nm */
|
|
+ 205, /* (24) table_option ::= nm */
|
|
+ 206, /* (25) columnname ::= nm typetoken */
|
|
+ 208, /* (26) typetoken ::= */
|
|
+ 208, /* (27) typetoken ::= typename LP signed RP */
|
|
+ 208, /* (28) typetoken ::= typename LP signed COMMA signed RP */
|
|
+ 209, /* (29) typename ::= typename ID|STRING */
|
|
+ 213, /* (30) scanpt ::= */
|
|
+ 214, /* (31) scantok ::= */
|
|
+ 215, /* (32) ccons ::= CONSTRAINT nm */
|
|
+ 215, /* (33) ccons ::= DEFAULT scantok term */
|
|
+ 215, /* (34) ccons ::= DEFAULT LP expr RP */
|
|
+ 215, /* (35) ccons ::= DEFAULT PLUS scantok term */
|
|
+ 215, /* (36) ccons ::= DEFAULT MINUS scantok term */
|
|
+ 215, /* (37) ccons ::= DEFAULT scantok ID|INDEXED */
|
|
+ 215, /* (38) ccons ::= NOT NULL onconf */
|
|
+ 215, /* (39) ccons ::= PRIMARY KEY sortorder onconf autoinc */
|
|
+ 215, /* (40) ccons ::= UNIQUE onconf */
|
|
+ 215, /* (41) ccons ::= CHECK LP expr RP */
|
|
+ 215, /* (42) ccons ::= REFERENCES nm eidlist_opt refargs */
|
|
+ 215, /* (43) ccons ::= defer_subclause */
|
|
+ 215, /* (44) ccons ::= COLLATE ID|STRING */
|
|
+ 224, /* (45) generated ::= LP expr RP */
|
|
+ 224, /* (46) generated ::= LP expr RP ID */
|
|
+ 220, /* (47) autoinc ::= */
|
|
+ 220, /* (48) autoinc ::= AUTOINCR */
|
|
+ 222, /* (49) refargs ::= */
|
|
+ 222, /* (50) refargs ::= refargs refarg */
|
|
+ 225, /* (51) refarg ::= MATCH nm */
|
|
+ 225, /* (52) refarg ::= ON INSERT refact */
|
|
+ 225, /* (53) refarg ::= ON DELETE refact */
|
|
+ 225, /* (54) refarg ::= ON UPDATE refact */
|
|
+ 226, /* (55) refact ::= SET NULL */
|
|
+ 226, /* (56) refact ::= SET DEFAULT */
|
|
+ 226, /* (57) refact ::= CASCADE */
|
|
+ 226, /* (58) refact ::= RESTRICT */
|
|
+ 226, /* (59) refact ::= NO ACTION */
|
|
+ 223, /* (60) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */
|
|
+ 223, /* (61) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
|
|
+ 227, /* (62) init_deferred_pred_opt ::= */
|
|
+ 227, /* (63) init_deferred_pred_opt ::= INITIALLY DEFERRED */
|
|
+ 227, /* (64) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */
|
|
+ 202, /* (65) conslist_opt ::= */
|
|
+ 229, /* (66) tconscomma ::= COMMA */
|
|
+ 230, /* (67) tcons ::= CONSTRAINT nm */
|
|
+ 230, /* (68) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */
|
|
+ 230, /* (69) tcons ::= UNIQUE LP sortlist RP onconf */
|
|
+ 230, /* (70) tcons ::= CHECK LP expr RP onconf */
|
|
+ 230, /* (71) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */
|
|
+ 233, /* (72) defer_subclause_opt ::= */
|
|
+ 218, /* (73) onconf ::= */
|
|
+ 218, /* (74) onconf ::= ON CONFLICT resolvetype */
|
|
+ 234, /* (75) orconf ::= */
|
|
+ 234, /* (76) orconf ::= OR resolvetype */
|
|
+ 235, /* (77) resolvetype ::= IGNORE */
|
|
+ 235, /* (78) resolvetype ::= REPLACE */
|
|
+ 190, /* (79) cmd ::= DROP TABLE ifexists fullname */
|
|
+ 237, /* (80) ifexists ::= IF EXISTS */
|
|
+ 237, /* (81) ifexists ::= */
|
|
+ 190, /* (82) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */
|
|
+ 190, /* (83) cmd ::= DROP VIEW ifexists fullname */
|
|
+ 190, /* (84) cmd ::= select */
|
|
+ 204, /* (85) select ::= WITH wqlist selectnowith */
|
|
+ 204, /* (86) select ::= WITH RECURSIVE wqlist selectnowith */
|
|
+ 204, /* (87) select ::= selectnowith */
|
|
+ 239, /* (88) selectnowith ::= selectnowith multiselect_op oneselect */
|
|
+ 242, /* (89) multiselect_op ::= UNION */
|
|
+ 242, /* (90) multiselect_op ::= UNION ALL */
|
|
+ 242, /* (91) multiselect_op ::= EXCEPT|INTERSECT */
|
|
+ 240, /* (92) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
|
|
+ 240, /* (93) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */
|
|
+ 252, /* (94) values ::= VALUES LP nexprlist RP */
|
|
+ 252, /* (95) values ::= values COMMA LP nexprlist RP */
|
|
+ 243, /* (96) distinct ::= DISTINCT */
|
|
+ 243, /* (97) distinct ::= ALL */
|
|
+ 243, /* (98) distinct ::= */
|
|
+ 254, /* (99) sclp ::= */
|
|
+ 244, /* (100) selcollist ::= sclp scanpt expr scanpt as */
|
|
+ 244, /* (101) selcollist ::= sclp scanpt STAR */
|
|
+ 244, /* (102) selcollist ::= sclp scanpt nm DOT STAR */
|
|
+ 255, /* (103) as ::= AS nm */
|
|
+ 255, /* (104) as ::= */
|
|
+ 245, /* (105) from ::= */
|
|
+ 245, /* (106) from ::= FROM seltablist */
|
|
+ 257, /* (107) stl_prefix ::= seltablist joinop */
|
|
+ 257, /* (108) stl_prefix ::= */
|
|
+ 256, /* (109) seltablist ::= stl_prefix nm dbnm as on_using */
|
|
+ 256, /* (110) seltablist ::= stl_prefix nm dbnm as indexed_by on_using */
|
|
+ 256, /* (111) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */
|
|
+ 256, /* (112) seltablist ::= stl_prefix LP select RP as on_using */
|
|
+ 256, /* (113) seltablist ::= stl_prefix LP seltablist RP as on_using */
|
|
+ 200, /* (114) dbnm ::= */
|
|
+ 200, /* (115) dbnm ::= DOT nm */
|
|
+ 238, /* (116) fullname ::= nm */
|
|
+ 238, /* (117) fullname ::= nm DOT nm */
|
|
+ 262, /* (118) xfullname ::= nm */
|
|
+ 262, /* (119) xfullname ::= nm DOT nm */
|
|
+ 262, /* (120) xfullname ::= nm DOT nm AS nm */
|
|
+ 262, /* (121) xfullname ::= nm AS nm */
|
|
+ 258, /* (122) joinop ::= COMMA|JOIN */
|
|
+ 258, /* (123) joinop ::= JOIN_KW JOIN */
|
|
+ 258, /* (124) joinop ::= JOIN_KW nm JOIN */
|
|
+ 258, /* (125) joinop ::= JOIN_KW nm nm JOIN */
|
|
+ 259, /* (126) on_using ::= ON expr */
|
|
+ 259, /* (127) on_using ::= USING LP idlist RP */
|
|
+ 259, /* (128) on_using ::= */
|
|
+ 264, /* (129) indexed_opt ::= */
|
|
+ 260, /* (130) indexed_by ::= INDEXED BY nm */
|
|
+ 260, /* (131) indexed_by ::= NOT INDEXED */
|
|
+ 249, /* (132) orderby_opt ::= */
|
|
+ 249, /* (133) orderby_opt ::= ORDER BY sortlist */
|
|
+ 231, /* (134) sortlist ::= sortlist COMMA expr sortorder nulls */
|
|
+ 231, /* (135) sortlist ::= expr sortorder nulls */
|
|
+ 219, /* (136) sortorder ::= ASC */
|
|
+ 219, /* (137) sortorder ::= DESC */
|
|
+ 219, /* (138) sortorder ::= */
|
|
+ 265, /* (139) nulls ::= NULLS FIRST */
|
|
+ 265, /* (140) nulls ::= NULLS LAST */
|
|
+ 265, /* (141) nulls ::= */
|
|
+ 247, /* (142) groupby_opt ::= */
|
|
+ 247, /* (143) groupby_opt ::= GROUP BY nexprlist */
|
|
+ 248, /* (144) having_opt ::= */
|
|
+ 248, /* (145) having_opt ::= HAVING expr */
|
|
+ 250, /* (146) limit_opt ::= */
|
|
+ 250, /* (147) limit_opt ::= LIMIT expr */
|
|
+ 250, /* (148) limit_opt ::= LIMIT expr OFFSET expr */
|
|
+ 250, /* (149) limit_opt ::= LIMIT expr COMMA expr */
|
|
+ 190, /* (150) cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret */
|
|
+ 246, /* (151) where_opt ::= */
|
|
+ 246, /* (152) where_opt ::= WHERE expr */
|
|
+ 267, /* (153) where_opt_ret ::= */
|
|
+ 267, /* (154) where_opt_ret ::= WHERE expr */
|
|
+ 267, /* (155) where_opt_ret ::= RETURNING selcollist */
|
|
+ 267, /* (156) where_opt_ret ::= WHERE expr RETURNING selcollist */
|
|
+ 190, /* (157) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret */
|
|
+ 268, /* (158) setlist ::= setlist COMMA nm EQ expr */
|
|
+ 268, /* (159) setlist ::= setlist COMMA LP idlist RP EQ expr */
|
|
+ 268, /* (160) setlist ::= nm EQ expr */
|
|
+ 268, /* (161) setlist ::= LP idlist RP EQ expr */
|
|
+ 190, /* (162) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */
|
|
+ 190, /* (163) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */
|
|
+ 271, /* (164) upsert ::= */
|
|
+ 271, /* (165) upsert ::= RETURNING selcollist */
|
|
+ 271, /* (166) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */
|
|
+ 271, /* (167) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */
|
|
+ 271, /* (168) upsert ::= ON CONFLICT DO NOTHING returning */
|
|
+ 271, /* (169) upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */
|
|
+ 272, /* (170) returning ::= RETURNING selcollist */
|
|
+ 269, /* (171) insert_cmd ::= INSERT orconf */
|
|
+ 269, /* (172) insert_cmd ::= REPLACE */
|
|
+ 270, /* (173) idlist_opt ::= */
|
|
+ 270, /* (174) idlist_opt ::= LP idlist RP */
|
|
+ 263, /* (175) idlist ::= idlist COMMA nm */
|
|
+ 263, /* (176) idlist ::= nm */
|
|
+ 217, /* (177) expr ::= LP expr RP */
|
|
+ 217, /* (178) expr ::= ID|INDEXED */
|
|
+ 217, /* (179) expr ::= JOIN_KW */
|
|
+ 217, /* (180) expr ::= nm DOT nm */
|
|
+ 217, /* (181) expr ::= nm DOT nm DOT nm */
|
|
+ 216, /* (182) term ::= NULL|FLOAT|BLOB */
|
|
+ 216, /* (183) term ::= STRING */
|
|
+ 216, /* (184) term ::= INTEGER */
|
|
+ 217, /* (185) expr ::= VARIABLE */
|
|
+ 217, /* (186) expr ::= expr COLLATE ID|STRING */
|
|
+ 217, /* (187) expr ::= CAST LP expr AS typetoken RP */
|
|
+ 217, /* (188) expr ::= ID|INDEXED LP distinct exprlist RP */
|
|
+ 217, /* (189) expr ::= ID|INDEXED LP STAR RP */
|
|
+ 217, /* (190) expr ::= ID|INDEXED LP distinct exprlist RP filter_over */
|
|
+ 217, /* (191) expr ::= ID|INDEXED LP STAR RP filter_over */
|
|
+ 216, /* (192) term ::= CTIME_KW */
|
|
+ 217, /* (193) expr ::= LP nexprlist COMMA expr RP */
|
|
+ 217, /* (194) expr ::= expr AND expr */
|
|
+ 217, /* (195) expr ::= expr OR expr */
|
|
+ 217, /* (196) expr ::= expr LT|GT|GE|LE expr */
|
|
+ 217, /* (197) expr ::= expr EQ|NE expr */
|
|
+ 217, /* (198) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */
|
|
+ 217, /* (199) expr ::= expr PLUS|MINUS expr */
|
|
+ 217, /* (200) expr ::= expr STAR|SLASH|REM expr */
|
|
+ 217, /* (201) expr ::= expr CONCAT expr */
|
|
+ 274, /* (202) likeop ::= NOT LIKE_KW|MATCH */
|
|
+ 217, /* (203) expr ::= expr likeop expr */
|
|
+ 217, /* (204) expr ::= expr likeop expr ESCAPE expr */
|
|
+ 217, /* (205) expr ::= expr ISNULL|NOTNULL */
|
|
+ 217, /* (206) expr ::= expr NOT NULL */
|
|
+ 217, /* (207) expr ::= expr IS expr */
|
|
+ 217, /* (208) expr ::= expr IS NOT expr */
|
|
+ 217, /* (209) expr ::= expr IS NOT DISTINCT FROM expr */
|
|
+ 217, /* (210) expr ::= expr IS DISTINCT FROM expr */
|
|
+ 217, /* (211) expr ::= NOT expr */
|
|
+ 217, /* (212) expr ::= BITNOT expr */
|
|
+ 217, /* (213) expr ::= PLUS|MINUS expr */
|
|
+ 217, /* (214) expr ::= expr PTR expr */
|
|
+ 275, /* (215) between_op ::= BETWEEN */
|
|
+ 275, /* (216) between_op ::= NOT BETWEEN */
|
|
+ 217, /* (217) expr ::= expr between_op expr AND expr */
|
|
+ 276, /* (218) in_op ::= IN */
|
|
+ 276, /* (219) in_op ::= NOT IN */
|
|
+ 217, /* (220) expr ::= expr in_op LP exprlist RP */
|
|
+ 217, /* (221) expr ::= LP select RP */
|
|
+ 217, /* (222) expr ::= expr in_op LP select RP */
|
|
+ 217, /* (223) expr ::= expr in_op nm dbnm paren_exprlist */
|
|
+ 217, /* (224) expr ::= EXISTS LP select RP */
|
|
+ 217, /* (225) expr ::= CASE case_operand case_exprlist case_else END */
|
|
+ 279, /* (226) case_exprlist ::= case_exprlist WHEN expr THEN expr */
|
|
+ 279, /* (227) case_exprlist ::= WHEN expr THEN expr */
|
|
+ 280, /* (228) case_else ::= ELSE expr */
|
|
+ 280, /* (229) case_else ::= */
|
|
+ 278, /* (230) case_operand ::= expr */
|
|
+ 278, /* (231) case_operand ::= */
|
|
+ 261, /* (232) exprlist ::= */
|
|
+ 253, /* (233) nexprlist ::= nexprlist COMMA expr */
|
|
+ 253, /* (234) nexprlist ::= expr */
|
|
+ 277, /* (235) paren_exprlist ::= */
|
|
+ 277, /* (236) paren_exprlist ::= LP exprlist RP */
|
|
+ 190, /* (237) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
|
|
+ 281, /* (238) uniqueflag ::= UNIQUE */
|
|
+ 281, /* (239) uniqueflag ::= */
|
|
+ 221, /* (240) eidlist_opt ::= */
|
|
+ 221, /* (241) eidlist_opt ::= LP eidlist RP */
|
|
+ 232, /* (242) eidlist ::= eidlist COMMA nm collate sortorder */
|
|
+ 232, /* (243) eidlist ::= nm collate sortorder */
|
|
+ 282, /* (244) collate ::= */
|
|
+ 282, /* (245) collate ::= COLLATE ID|STRING */
|
|
+ 190, /* (246) cmd ::= DROP INDEX ifexists fullname */
|
|
+ 190, /* (247) cmd ::= VACUUM vinto */
|
|
+ 190, /* (248) cmd ::= VACUUM nm vinto */
|
|
+ 283, /* (249) vinto ::= INTO expr */
|
|
+ 283, /* (250) vinto ::= */
|
|
+ 190, /* (251) cmd ::= PRAGMA nm dbnm */
|
|
+ 190, /* (252) cmd ::= PRAGMA nm dbnm EQ nmnum */
|
|
+ 190, /* (253) cmd ::= PRAGMA nm dbnm LP nmnum RP */
|
|
+ 190, /* (254) cmd ::= PRAGMA nm dbnm EQ minus_num */
|
|
+ 190, /* (255) cmd ::= PRAGMA nm dbnm LP minus_num RP */
|
|
+ 211, /* (256) plus_num ::= PLUS INTEGER|FLOAT */
|
|
+ 212, /* (257) minus_num ::= MINUS INTEGER|FLOAT */
|
|
+ 190, /* (258) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
|
|
+ 285, /* (259) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
|
|
+ 287, /* (260) trigger_time ::= BEFORE|AFTER */
|
|
+ 287, /* (261) trigger_time ::= INSTEAD OF */
|
|
+ 287, /* (262) trigger_time ::= */
|
|
+ 288, /* (263) trigger_event ::= DELETE|INSERT */
|
|
+ 288, /* (264) trigger_event ::= UPDATE */
|
|
+ 288, /* (265) trigger_event ::= UPDATE OF idlist */
|
|
+ 290, /* (266) when_clause ::= */
|
|
+ 290, /* (267) when_clause ::= WHEN expr */
|
|
+ 286, /* (268) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
|
|
+ 286, /* (269) trigger_cmd_list ::= trigger_cmd SEMI */
|
|
+ 292, /* (270) trnm ::= nm DOT nm */
|
|
+ 293, /* (271) tridxby ::= INDEXED BY nm */
|
|
+ 293, /* (272) tridxby ::= NOT INDEXED */
|
|
+ 291, /* (273) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */
|
|
+ 291, /* (274) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */
|
|
+ 291, /* (275) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
|
|
+ 291, /* (276) trigger_cmd ::= scanpt select scanpt */
|
|
+ 217, /* (277) expr ::= RAISE LP IGNORE RP */
|
|
+ 217, /* (278) expr ::= RAISE LP raisetype COMMA nm RP */
|
|
+ 236, /* (279) raisetype ::= ROLLBACK */
|
|
+ 236, /* (280) raisetype ::= ABORT */
|
|
+ 236, /* (281) raisetype ::= FAIL */
|
|
+ 190, /* (282) cmd ::= DROP TRIGGER ifexists fullname */
|
|
+ 190, /* (283) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
|
|
+ 190, /* (284) cmd ::= DETACH database_kw_opt expr */
|
|
+ 295, /* (285) key_opt ::= */
|
|
+ 295, /* (286) key_opt ::= KEY expr */
|
|
+ 190, /* (287) cmd ::= REINDEX */
|
|
+ 190, /* (288) cmd ::= REINDEX nm dbnm */
|
|
+ 190, /* (289) cmd ::= ANALYZE */
|
|
+ 190, /* (290) cmd ::= ANALYZE nm dbnm */
|
|
+ 190, /* (291) cmd ::= ALTER TABLE fullname RENAME TO nm */
|
|
+ 190, /* (292) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
|
|
+ 190, /* (293) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */
|
|
+ 296, /* (294) add_column_fullname ::= fullname */
|
|
+ 190, /* (295) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */
|
|
+ 190, /* (296) cmd ::= create_vtab */
|
|
+ 190, /* (297) cmd ::= create_vtab LP vtabarglist RP */
|
|
+ 298, /* (298) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
|
|
+ 300, /* (299) vtabarg ::= */
|
|
+ 301, /* (300) vtabargtoken ::= ANY */
|
|
+ 301, /* (301) vtabargtoken ::= lp anylist RP */
|
|
+ 302, /* (302) lp ::= LP */
|
|
+ 266, /* (303) with ::= WITH wqlist */
|
|
+ 266, /* (304) with ::= WITH RECURSIVE wqlist */
|
|
+ 305, /* (305) wqas ::= AS */
|
|
+ 305, /* (306) wqas ::= AS MATERIALIZED */
|
|
+ 305, /* (307) wqas ::= AS NOT MATERIALIZED */
|
|
+ 304, /* (308) wqitem ::= nm eidlist_opt wqas LP select RP */
|
|
+ 241, /* (309) wqlist ::= wqitem */
|
|
+ 241, /* (310) wqlist ::= wqlist COMMA wqitem */
|
|
+ 306, /* (311) windowdefn_list ::= windowdefn */
|
|
+ 306, /* (312) windowdefn_list ::= windowdefn_list COMMA windowdefn */
|
|
+ 307, /* (313) windowdefn ::= nm AS LP window RP */
|
|
+ 308, /* (314) window ::= PARTITION BY nexprlist orderby_opt frame_opt */
|
|
+ 308, /* (315) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */
|
|
+ 308, /* (316) window ::= ORDER BY sortlist frame_opt */
|
|
+ 308, /* (317) window ::= nm ORDER BY sortlist frame_opt */
|
|
+ 308, /* (318) window ::= frame_opt */
|
|
+ 308, /* (319) window ::= nm frame_opt */
|
|
+ 309, /* (320) frame_opt ::= */
|
|
+ 309, /* (321) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */
|
|
+ 309, /* (322) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */
|
|
+ 313, /* (323) range_or_rows ::= RANGE|ROWS|GROUPS */
|
|
+ 315, /* (324) frame_bound_s ::= frame_bound */
|
|
+ 315, /* (325) frame_bound_s ::= UNBOUNDED PRECEDING */
|
|
+ 316, /* (326) frame_bound_e ::= frame_bound */
|
|
+ 316, /* (327) frame_bound_e ::= UNBOUNDED FOLLOWING */
|
|
+ 314, /* (328) frame_bound ::= expr PRECEDING|FOLLOWING */
|
|
+ 314, /* (329) frame_bound ::= CURRENT ROW */
|
|
+ 317, /* (330) frame_exclude_opt ::= */
|
|
+ 317, /* (331) frame_exclude_opt ::= EXCLUDE frame_exclude */
|
|
+ 318, /* (332) frame_exclude ::= NO OTHERS */
|
|
+ 318, /* (333) frame_exclude ::= CURRENT ROW */
|
|
+ 318, /* (334) frame_exclude ::= GROUP|TIES */
|
|
+ 251, /* (335) window_clause ::= WINDOW windowdefn_list */
|
|
+ 273, /* (336) filter_over ::= filter_clause over_clause */
|
|
+ 273, /* (337) filter_over ::= over_clause */
|
|
+ 273, /* (338) filter_over ::= filter_clause */
|
|
+ 312, /* (339) over_clause ::= OVER LP window RP */
|
|
+ 312, /* (340) over_clause ::= OVER nm */
|
|
+ 311, /* (341) filter_clause ::= FILTER LP WHERE expr RP */
|
|
+ 185, /* (342) input ::= cmdlist */
|
|
+ 186, /* (343) cmdlist ::= cmdlist ecmd */
|
|
+ 186, /* (344) cmdlist ::= ecmd */
|
|
+ 187, /* (345) ecmd ::= SEMI */
|
|
+ 187, /* (346) ecmd ::= cmdx SEMI */
|
|
+ 187, /* (347) ecmd ::= explain cmdx SEMI */
|
|
+ 192, /* (348) trans_opt ::= */
|
|
+ 192, /* (349) trans_opt ::= TRANSACTION */
|
|
+ 192, /* (350) trans_opt ::= TRANSACTION nm */
|
|
+ 194, /* (351) savepoint_opt ::= SAVEPOINT */
|
|
+ 194, /* (352) savepoint_opt ::= */
|
|
+ 190, /* (353) cmd ::= create_table create_table_args */
|
|
+ 203, /* (354) table_option_set ::= table_option */
|
|
+ 201, /* (355) columnlist ::= columnlist COMMA columnname carglist */
|
|
+ 201, /* (356) columnlist ::= columnname carglist */
|
|
+ 193, /* (357) nm ::= ID|INDEXED */
|
|
+ 193, /* (358) nm ::= STRING */
|
|
+ 193, /* (359) nm ::= JOIN_KW */
|
|
+ 208, /* (360) typetoken ::= typename */
|
|
+ 209, /* (361) typename ::= ID|STRING */
|
|
+ 210, /* (362) signed ::= plus_num */
|
|
+ 210, /* (363) signed ::= minus_num */
|
|
+ 207, /* (364) carglist ::= carglist ccons */
|
|
+ 207, /* (365) carglist ::= */
|
|
+ 215, /* (366) ccons ::= NULL onconf */
|
|
+ 215, /* (367) ccons ::= GENERATED ALWAYS AS generated */
|
|
+ 215, /* (368) ccons ::= AS generated */
|
|
+ 202, /* (369) conslist_opt ::= COMMA conslist */
|
|
+ 228, /* (370) conslist ::= conslist tconscomma tcons */
|
|
+ 228, /* (371) conslist ::= tcons */
|
|
+ 229, /* (372) tconscomma ::= */
|
|
+ 233, /* (373) defer_subclause_opt ::= defer_subclause */
|
|
+ 235, /* (374) resolvetype ::= raisetype */
|
|
+ 239, /* (375) selectnowith ::= oneselect */
|
|
+ 240, /* (376) oneselect ::= values */
|
|
+ 254, /* (377) sclp ::= selcollist COMMA */
|
|
+ 255, /* (378) as ::= ID|STRING */
|
|
+ 264, /* (379) indexed_opt ::= indexed_by */
|
|
+ 272, /* (380) returning ::= */
|
|
+ 217, /* (381) expr ::= term */
|
|
+ 274, /* (382) likeop ::= LIKE_KW|MATCH */
|
|
+ 261, /* (383) exprlist ::= nexprlist */
|
|
+ 284, /* (384) nmnum ::= plus_num */
|
|
+ 284, /* (385) nmnum ::= nm */
|
|
+ 284, /* (386) nmnum ::= ON */
|
|
+ 284, /* (387) nmnum ::= DELETE */
|
|
+ 284, /* (388) nmnum ::= DEFAULT */
|
|
+ 211, /* (389) plus_num ::= INTEGER|FLOAT */
|
|
+ 289, /* (390) foreach_clause ::= */
|
|
+ 289, /* (391) foreach_clause ::= FOR EACH ROW */
|
|
+ 292, /* (392) trnm ::= nm */
|
|
+ 293, /* (393) tridxby ::= */
|
|
+ 294, /* (394) database_kw_opt ::= DATABASE */
|
|
+ 294, /* (395) database_kw_opt ::= */
|
|
+ 297, /* (396) kwcolumn_opt ::= */
|
|
+ 297, /* (397) kwcolumn_opt ::= COLUMNKW */
|
|
+ 299, /* (398) vtabarglist ::= vtabarg */
|
|
+ 299, /* (399) vtabarglist ::= vtabarglist COMMA vtabarg */
|
|
+ 300, /* (400) vtabarg ::= vtabarg vtabargtoken */
|
|
+ 303, /* (401) anylist ::= */
|
|
+ 303, /* (402) anylist ::= anylist LP anylist RP */
|
|
+ 303, /* (403) anylist ::= anylist ANY */
|
|
+ 266, /* (404) with ::= */
|
|
};
|
|
|
|
/* For rule J, yyRuleInfoNRhs[J] contains the negative of the number
|
|
@@ -155152,372 +169969,392 @@ static const signed char yyRuleInfoNRhs[] = {
|
|
-3, /* (16) ifnotexists ::= IF NOT EXISTS */
|
|
-1, /* (17) temp ::= TEMP */
|
|
0, /* (18) temp ::= */
|
|
- -5, /* (19) create_table_args ::= LP columnlist conslist_opt RP table_options */
|
|
+ -5, /* (19) create_table_args ::= LP columnlist conslist_opt RP table_option_set */
|
|
-2, /* (20) create_table_args ::= AS select */
|
|
- 0, /* (21) table_options ::= */
|
|
- -2, /* (22) table_options ::= WITHOUT nm */
|
|
- -2, /* (23) columnname ::= nm typetoken */
|
|
- 0, /* (24) typetoken ::= */
|
|
- -4, /* (25) typetoken ::= typename LP signed RP */
|
|
- -6, /* (26) typetoken ::= typename LP signed COMMA signed RP */
|
|
- -2, /* (27) typename ::= typename ID|STRING */
|
|
- 0, /* (28) scanpt ::= */
|
|
- 0, /* (29) scantok ::= */
|
|
- -2, /* (30) ccons ::= CONSTRAINT nm */
|
|
- -3, /* (31) ccons ::= DEFAULT scantok term */
|
|
- -4, /* (32) ccons ::= DEFAULT LP expr RP */
|
|
- -4, /* (33) ccons ::= DEFAULT PLUS scantok term */
|
|
- -4, /* (34) ccons ::= DEFAULT MINUS scantok term */
|
|
- -3, /* (35) ccons ::= DEFAULT scantok ID|INDEXED */
|
|
- -3, /* (36) ccons ::= NOT NULL onconf */
|
|
- -5, /* (37) ccons ::= PRIMARY KEY sortorder onconf autoinc */
|
|
- -2, /* (38) ccons ::= UNIQUE onconf */
|
|
- -4, /* (39) ccons ::= CHECK LP expr RP */
|
|
- -4, /* (40) ccons ::= REFERENCES nm eidlist_opt refargs */
|
|
- -1, /* (41) ccons ::= defer_subclause */
|
|
- -2, /* (42) ccons ::= COLLATE ID|STRING */
|
|
- -3, /* (43) generated ::= LP expr RP */
|
|
- -4, /* (44) generated ::= LP expr RP ID */
|
|
- 0, /* (45) autoinc ::= */
|
|
- -1, /* (46) autoinc ::= AUTOINCR */
|
|
- 0, /* (47) refargs ::= */
|
|
- -2, /* (48) refargs ::= refargs refarg */
|
|
- -2, /* (49) refarg ::= MATCH nm */
|
|
- -3, /* (50) refarg ::= ON INSERT refact */
|
|
- -3, /* (51) refarg ::= ON DELETE refact */
|
|
- -3, /* (52) refarg ::= ON UPDATE refact */
|
|
- -2, /* (53) refact ::= SET NULL */
|
|
- -2, /* (54) refact ::= SET DEFAULT */
|
|
- -1, /* (55) refact ::= CASCADE */
|
|
- -1, /* (56) refact ::= RESTRICT */
|
|
- -2, /* (57) refact ::= NO ACTION */
|
|
- -3, /* (58) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */
|
|
- -2, /* (59) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
|
|
- 0, /* (60) init_deferred_pred_opt ::= */
|
|
- -2, /* (61) init_deferred_pred_opt ::= INITIALLY DEFERRED */
|
|
- -2, /* (62) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */
|
|
- 0, /* (63) conslist_opt ::= */
|
|
- -1, /* (64) tconscomma ::= COMMA */
|
|
- -2, /* (65) tcons ::= CONSTRAINT nm */
|
|
- -7, /* (66) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */
|
|
- -5, /* (67) tcons ::= UNIQUE LP sortlist RP onconf */
|
|
- -5, /* (68) tcons ::= CHECK LP expr RP onconf */
|
|
- -10, /* (69) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */
|
|
- 0, /* (70) defer_subclause_opt ::= */
|
|
- 0, /* (71) onconf ::= */
|
|
- -3, /* (72) onconf ::= ON CONFLICT resolvetype */
|
|
- 0, /* (73) orconf ::= */
|
|
- -2, /* (74) orconf ::= OR resolvetype */
|
|
- -1, /* (75) resolvetype ::= IGNORE */
|
|
- -1, /* (76) resolvetype ::= REPLACE */
|
|
- -4, /* (77) cmd ::= DROP TABLE ifexists fullname */
|
|
- -2, /* (78) ifexists ::= IF EXISTS */
|
|
- 0, /* (79) ifexists ::= */
|
|
- -9, /* (80) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */
|
|
- -4, /* (81) cmd ::= DROP VIEW ifexists fullname */
|
|
- -1, /* (82) cmd ::= select */
|
|
- -3, /* (83) select ::= WITH wqlist selectnowith */
|
|
- -4, /* (84) select ::= WITH RECURSIVE wqlist selectnowith */
|
|
- -1, /* (85) select ::= selectnowith */
|
|
- -3, /* (86) selectnowith ::= selectnowith multiselect_op oneselect */
|
|
- -1, /* (87) multiselect_op ::= UNION */
|
|
- -2, /* (88) multiselect_op ::= UNION ALL */
|
|
- -1, /* (89) multiselect_op ::= EXCEPT|INTERSECT */
|
|
- -9, /* (90) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
|
|
- -10, /* (91) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */
|
|
- -4, /* (92) values ::= VALUES LP nexprlist RP */
|
|
- -5, /* (93) values ::= values COMMA LP nexprlist RP */
|
|
- -1, /* (94) distinct ::= DISTINCT */
|
|
- -1, /* (95) distinct ::= ALL */
|
|
- 0, /* (96) distinct ::= */
|
|
- 0, /* (97) sclp ::= */
|
|
- -5, /* (98) selcollist ::= sclp scanpt expr scanpt as */
|
|
- -3, /* (99) selcollist ::= sclp scanpt STAR */
|
|
- -5, /* (100) selcollist ::= sclp scanpt nm DOT STAR */
|
|
- -2, /* (101) as ::= AS nm */
|
|
- 0, /* (102) as ::= */
|
|
- 0, /* (103) from ::= */
|
|
- -2, /* (104) from ::= FROM seltablist */
|
|
- -2, /* (105) stl_prefix ::= seltablist joinop */
|
|
- 0, /* (106) stl_prefix ::= */
|
|
- -7, /* (107) seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */
|
|
- -9, /* (108) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */
|
|
- -7, /* (109) seltablist ::= stl_prefix LP select RP as on_opt using_opt */
|
|
- -7, /* (110) seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */
|
|
- 0, /* (111) dbnm ::= */
|
|
- -2, /* (112) dbnm ::= DOT nm */
|
|
- -1, /* (113) fullname ::= nm */
|
|
- -3, /* (114) fullname ::= nm DOT nm */
|
|
- -1, /* (115) xfullname ::= nm */
|
|
- -3, /* (116) xfullname ::= nm DOT nm */
|
|
- -5, /* (117) xfullname ::= nm DOT nm AS nm */
|
|
- -3, /* (118) xfullname ::= nm AS nm */
|
|
- -1, /* (119) joinop ::= COMMA|JOIN */
|
|
- -2, /* (120) joinop ::= JOIN_KW JOIN */
|
|
- -3, /* (121) joinop ::= JOIN_KW nm JOIN */
|
|
- -4, /* (122) joinop ::= JOIN_KW nm nm JOIN */
|
|
- -2, /* (123) on_opt ::= ON expr */
|
|
- 0, /* (124) on_opt ::= */
|
|
- 0, /* (125) indexed_opt ::= */
|
|
- -3, /* (126) indexed_opt ::= INDEXED BY nm */
|
|
- -2, /* (127) indexed_opt ::= NOT INDEXED */
|
|
- -4, /* (128) using_opt ::= USING LP idlist RP */
|
|
- 0, /* (129) using_opt ::= */
|
|
- 0, /* (130) orderby_opt ::= */
|
|
- -3, /* (131) orderby_opt ::= ORDER BY sortlist */
|
|
- -5, /* (132) sortlist ::= sortlist COMMA expr sortorder nulls */
|
|
- -3, /* (133) sortlist ::= expr sortorder nulls */
|
|
- -1, /* (134) sortorder ::= ASC */
|
|
- -1, /* (135) sortorder ::= DESC */
|
|
- 0, /* (136) sortorder ::= */
|
|
- -2, /* (137) nulls ::= NULLS FIRST */
|
|
- -2, /* (138) nulls ::= NULLS LAST */
|
|
- 0, /* (139) nulls ::= */
|
|
- 0, /* (140) groupby_opt ::= */
|
|
- -3, /* (141) groupby_opt ::= GROUP BY nexprlist */
|
|
- 0, /* (142) having_opt ::= */
|
|
- -2, /* (143) having_opt ::= HAVING expr */
|
|
- 0, /* (144) limit_opt ::= */
|
|
- -2, /* (145) limit_opt ::= LIMIT expr */
|
|
- -4, /* (146) limit_opt ::= LIMIT expr OFFSET expr */
|
|
- -4, /* (147) limit_opt ::= LIMIT expr COMMA expr */
|
|
- -6, /* (148) cmd ::= with DELETE FROM xfullname indexed_opt where_opt */
|
|
- 0, /* (149) where_opt ::= */
|
|
- -2, /* (150) where_opt ::= WHERE expr */
|
|
- -8, /* (151) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist where_opt */
|
|
- -5, /* (152) setlist ::= setlist COMMA nm EQ expr */
|
|
- -7, /* (153) setlist ::= setlist COMMA LP idlist RP EQ expr */
|
|
- -3, /* (154) setlist ::= nm EQ expr */
|
|
- -5, /* (155) setlist ::= LP idlist RP EQ expr */
|
|
- -7, /* (156) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */
|
|
- -7, /* (157) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES */
|
|
- 0, /* (158) upsert ::= */
|
|
- -11, /* (159) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt */
|
|
- -8, /* (160) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING */
|
|
- -4, /* (161) upsert ::= ON CONFLICT DO NOTHING */
|
|
- -2, /* (162) insert_cmd ::= INSERT orconf */
|
|
- -1, /* (163) insert_cmd ::= REPLACE */
|
|
- 0, /* (164) idlist_opt ::= */
|
|
- -3, /* (165) idlist_opt ::= LP idlist RP */
|
|
- -3, /* (166) idlist ::= idlist COMMA nm */
|
|
- -1, /* (167) idlist ::= nm */
|
|
- -3, /* (168) expr ::= LP expr RP */
|
|
- -1, /* (169) expr ::= ID|INDEXED */
|
|
- -1, /* (170) expr ::= JOIN_KW */
|
|
- -3, /* (171) expr ::= nm DOT nm */
|
|
- -5, /* (172) expr ::= nm DOT nm DOT nm */
|
|
- -1, /* (173) term ::= NULL|FLOAT|BLOB */
|
|
- -1, /* (174) term ::= STRING */
|
|
- -1, /* (175) term ::= INTEGER */
|
|
- -1, /* (176) expr ::= VARIABLE */
|
|
- -3, /* (177) expr ::= expr COLLATE ID|STRING */
|
|
- -6, /* (178) expr ::= CAST LP expr AS typetoken RP */
|
|
- -5, /* (179) expr ::= ID|INDEXED LP distinct exprlist RP */
|
|
- -4, /* (180) expr ::= ID|INDEXED LP STAR RP */
|
|
- -6, /* (181) expr ::= ID|INDEXED LP distinct exprlist RP filter_over */
|
|
- -5, /* (182) expr ::= ID|INDEXED LP STAR RP filter_over */
|
|
- -1, /* (183) term ::= CTIME_KW */
|
|
- -5, /* (184) expr ::= LP nexprlist COMMA expr RP */
|
|
- -3, /* (185) expr ::= expr AND expr */
|
|
- -3, /* (186) expr ::= expr OR expr */
|
|
- -3, /* (187) expr ::= expr LT|GT|GE|LE expr */
|
|
- -3, /* (188) expr ::= expr EQ|NE expr */
|
|
- -3, /* (189) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */
|
|
- -3, /* (190) expr ::= expr PLUS|MINUS expr */
|
|
- -3, /* (191) expr ::= expr STAR|SLASH|REM expr */
|
|
- -3, /* (192) expr ::= expr CONCAT expr */
|
|
- -2, /* (193) likeop ::= NOT LIKE_KW|MATCH */
|
|
- -3, /* (194) expr ::= expr likeop expr */
|
|
- -5, /* (195) expr ::= expr likeop expr ESCAPE expr */
|
|
- -2, /* (196) expr ::= expr ISNULL|NOTNULL */
|
|
- -3, /* (197) expr ::= expr NOT NULL */
|
|
- -3, /* (198) expr ::= expr IS expr */
|
|
- -4, /* (199) expr ::= expr IS NOT expr */
|
|
- -2, /* (200) expr ::= NOT expr */
|
|
- -2, /* (201) expr ::= BITNOT expr */
|
|
- -2, /* (202) expr ::= PLUS|MINUS expr */
|
|
- -1, /* (203) between_op ::= BETWEEN */
|
|
- -2, /* (204) between_op ::= NOT BETWEEN */
|
|
- -5, /* (205) expr ::= expr between_op expr AND expr */
|
|
- -1, /* (206) in_op ::= IN */
|
|
- -2, /* (207) in_op ::= NOT IN */
|
|
- -5, /* (208) expr ::= expr in_op LP exprlist RP */
|
|
- -3, /* (209) expr ::= LP select RP */
|
|
- -5, /* (210) expr ::= expr in_op LP select RP */
|
|
- -5, /* (211) expr ::= expr in_op nm dbnm paren_exprlist */
|
|
- -4, /* (212) expr ::= EXISTS LP select RP */
|
|
- -5, /* (213) expr ::= CASE case_operand case_exprlist case_else END */
|
|
- -5, /* (214) case_exprlist ::= case_exprlist WHEN expr THEN expr */
|
|
- -4, /* (215) case_exprlist ::= WHEN expr THEN expr */
|
|
- -2, /* (216) case_else ::= ELSE expr */
|
|
- 0, /* (217) case_else ::= */
|
|
- -1, /* (218) case_operand ::= expr */
|
|
- 0, /* (219) case_operand ::= */
|
|
- 0, /* (220) exprlist ::= */
|
|
- -3, /* (221) nexprlist ::= nexprlist COMMA expr */
|
|
- -1, /* (222) nexprlist ::= expr */
|
|
- 0, /* (223) paren_exprlist ::= */
|
|
- -3, /* (224) paren_exprlist ::= LP exprlist RP */
|
|
- -12, /* (225) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
|
|
- -1, /* (226) uniqueflag ::= UNIQUE */
|
|
- 0, /* (227) uniqueflag ::= */
|
|
- 0, /* (228) eidlist_opt ::= */
|
|
- -3, /* (229) eidlist_opt ::= LP eidlist RP */
|
|
- -5, /* (230) eidlist ::= eidlist COMMA nm collate sortorder */
|
|
- -3, /* (231) eidlist ::= nm collate sortorder */
|
|
- 0, /* (232) collate ::= */
|
|
- -2, /* (233) collate ::= COLLATE ID|STRING */
|
|
- -4, /* (234) cmd ::= DROP INDEX ifexists fullname */
|
|
- -2, /* (235) cmd ::= VACUUM vinto */
|
|
- -3, /* (236) cmd ::= VACUUM nm vinto */
|
|
- -2, /* (237) vinto ::= INTO expr */
|
|
- 0, /* (238) vinto ::= */
|
|
- -3, /* (239) cmd ::= PRAGMA nm dbnm */
|
|
- -5, /* (240) cmd ::= PRAGMA nm dbnm EQ nmnum */
|
|
- -6, /* (241) cmd ::= PRAGMA nm dbnm LP nmnum RP */
|
|
- -5, /* (242) cmd ::= PRAGMA nm dbnm EQ minus_num */
|
|
- -6, /* (243) cmd ::= PRAGMA nm dbnm LP minus_num RP */
|
|
- -2, /* (244) plus_num ::= PLUS INTEGER|FLOAT */
|
|
- -2, /* (245) minus_num ::= MINUS INTEGER|FLOAT */
|
|
- -5, /* (246) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
|
|
- -11, /* (247) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
|
|
- -1, /* (248) trigger_time ::= BEFORE|AFTER */
|
|
- -2, /* (249) trigger_time ::= INSTEAD OF */
|
|
- 0, /* (250) trigger_time ::= */
|
|
- -1, /* (251) trigger_event ::= DELETE|INSERT */
|
|
- -1, /* (252) trigger_event ::= UPDATE */
|
|
- -3, /* (253) trigger_event ::= UPDATE OF idlist */
|
|
- 0, /* (254) when_clause ::= */
|
|
- -2, /* (255) when_clause ::= WHEN expr */
|
|
- -3, /* (256) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
|
|
- -2, /* (257) trigger_cmd_list ::= trigger_cmd SEMI */
|
|
- -3, /* (258) trnm ::= nm DOT nm */
|
|
- -3, /* (259) tridxby ::= INDEXED BY nm */
|
|
- -2, /* (260) tridxby ::= NOT INDEXED */
|
|
- -8, /* (261) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt scanpt */
|
|
- -8, /* (262) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */
|
|
- -6, /* (263) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
|
|
- -3, /* (264) trigger_cmd ::= scanpt select scanpt */
|
|
- -4, /* (265) expr ::= RAISE LP IGNORE RP */
|
|
- -6, /* (266) expr ::= RAISE LP raisetype COMMA nm RP */
|
|
- -1, /* (267) raisetype ::= ROLLBACK */
|
|
- -1, /* (268) raisetype ::= ABORT */
|
|
- -1, /* (269) raisetype ::= FAIL */
|
|
- -4, /* (270) cmd ::= DROP TRIGGER ifexists fullname */
|
|
- -6, /* (271) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
|
|
- -3, /* (272) cmd ::= DETACH database_kw_opt expr */
|
|
- 0, /* (273) key_opt ::= */
|
|
- -2, /* (274) key_opt ::= KEY expr */
|
|
- -1, /* (275) cmd ::= REINDEX */
|
|
- -3, /* (276) cmd ::= REINDEX nm dbnm */
|
|
- -1, /* (277) cmd ::= ANALYZE */
|
|
- -3, /* (278) cmd ::= ANALYZE nm dbnm */
|
|
- -6, /* (279) cmd ::= ALTER TABLE fullname RENAME TO nm */
|
|
- -7, /* (280) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
|
|
- -1, /* (281) add_column_fullname ::= fullname */
|
|
- -8, /* (282) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */
|
|
- -1, /* (283) cmd ::= create_vtab */
|
|
- -4, /* (284) cmd ::= create_vtab LP vtabarglist RP */
|
|
- -8, /* (285) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
|
|
- 0, /* (286) vtabarg ::= */
|
|
- -1, /* (287) vtabargtoken ::= ANY */
|
|
- -3, /* (288) vtabargtoken ::= lp anylist RP */
|
|
- -1, /* (289) lp ::= LP */
|
|
- -2, /* (290) with ::= WITH wqlist */
|
|
- -3, /* (291) with ::= WITH RECURSIVE wqlist */
|
|
- -6, /* (292) wqlist ::= nm eidlist_opt AS LP select RP */
|
|
- -8, /* (293) wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP */
|
|
- -1, /* (294) windowdefn_list ::= windowdefn */
|
|
- -3, /* (295) windowdefn_list ::= windowdefn_list COMMA windowdefn */
|
|
- -5, /* (296) windowdefn ::= nm AS LP window RP */
|
|
- -5, /* (297) window ::= PARTITION BY nexprlist orderby_opt frame_opt */
|
|
- -6, /* (298) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */
|
|
- -4, /* (299) window ::= ORDER BY sortlist frame_opt */
|
|
- -5, /* (300) window ::= nm ORDER BY sortlist frame_opt */
|
|
- -1, /* (301) window ::= frame_opt */
|
|
- -2, /* (302) window ::= nm frame_opt */
|
|
- 0, /* (303) frame_opt ::= */
|
|
- -3, /* (304) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */
|
|
- -6, /* (305) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */
|
|
- -1, /* (306) range_or_rows ::= RANGE|ROWS|GROUPS */
|
|
- -1, /* (307) frame_bound_s ::= frame_bound */
|
|
- -2, /* (308) frame_bound_s ::= UNBOUNDED PRECEDING */
|
|
- -1, /* (309) frame_bound_e ::= frame_bound */
|
|
- -2, /* (310) frame_bound_e ::= UNBOUNDED FOLLOWING */
|
|
- -2, /* (311) frame_bound ::= expr PRECEDING|FOLLOWING */
|
|
- -2, /* (312) frame_bound ::= CURRENT ROW */
|
|
- 0, /* (313) frame_exclude_opt ::= */
|
|
- -2, /* (314) frame_exclude_opt ::= EXCLUDE frame_exclude */
|
|
- -2, /* (315) frame_exclude ::= NO OTHERS */
|
|
- -2, /* (316) frame_exclude ::= CURRENT ROW */
|
|
- -1, /* (317) frame_exclude ::= GROUP|TIES */
|
|
- -2, /* (318) window_clause ::= WINDOW windowdefn_list */
|
|
- -2, /* (319) filter_over ::= filter_clause over_clause */
|
|
- -1, /* (320) filter_over ::= over_clause */
|
|
- -1, /* (321) filter_over ::= filter_clause */
|
|
- -4, /* (322) over_clause ::= OVER LP window RP */
|
|
- -2, /* (323) over_clause ::= OVER nm */
|
|
- -5, /* (324) filter_clause ::= FILTER LP WHERE expr RP */
|
|
- -1, /* (325) input ::= cmdlist */
|
|
- -2, /* (326) cmdlist ::= cmdlist ecmd */
|
|
- -1, /* (327) cmdlist ::= ecmd */
|
|
- -1, /* (328) ecmd ::= SEMI */
|
|
- -2, /* (329) ecmd ::= cmdx SEMI */
|
|
- -3, /* (330) ecmd ::= explain cmdx SEMI */
|
|
- 0, /* (331) trans_opt ::= */
|
|
- -1, /* (332) trans_opt ::= TRANSACTION */
|
|
- -2, /* (333) trans_opt ::= TRANSACTION nm */
|
|
- -1, /* (334) savepoint_opt ::= SAVEPOINT */
|
|
- 0, /* (335) savepoint_opt ::= */
|
|
- -2, /* (336) cmd ::= create_table create_table_args */
|
|
- -4, /* (337) columnlist ::= columnlist COMMA columnname carglist */
|
|
- -2, /* (338) columnlist ::= columnname carglist */
|
|
- -1, /* (339) nm ::= ID|INDEXED */
|
|
- -1, /* (340) nm ::= STRING */
|
|
- -1, /* (341) nm ::= JOIN_KW */
|
|
- -1, /* (342) typetoken ::= typename */
|
|
- -1, /* (343) typename ::= ID|STRING */
|
|
- -1, /* (344) signed ::= plus_num */
|
|
- -1, /* (345) signed ::= minus_num */
|
|
- -2, /* (346) carglist ::= carglist ccons */
|
|
- 0, /* (347) carglist ::= */
|
|
- -2, /* (348) ccons ::= NULL onconf */
|
|
- -4, /* (349) ccons ::= GENERATED ALWAYS AS generated */
|
|
- -2, /* (350) ccons ::= AS generated */
|
|
- -2, /* (351) conslist_opt ::= COMMA conslist */
|
|
- -3, /* (352) conslist ::= conslist tconscomma tcons */
|
|
- -1, /* (353) conslist ::= tcons */
|
|
- 0, /* (354) tconscomma ::= */
|
|
- -1, /* (355) defer_subclause_opt ::= defer_subclause */
|
|
- -1, /* (356) resolvetype ::= raisetype */
|
|
- -1, /* (357) selectnowith ::= oneselect */
|
|
- -1, /* (358) oneselect ::= values */
|
|
- -2, /* (359) sclp ::= selcollist COMMA */
|
|
- -1, /* (360) as ::= ID|STRING */
|
|
- -1, /* (361) expr ::= term */
|
|
- -1, /* (362) likeop ::= LIKE_KW|MATCH */
|
|
- -1, /* (363) exprlist ::= nexprlist */
|
|
- -1, /* (364) nmnum ::= plus_num */
|
|
- -1, /* (365) nmnum ::= nm */
|
|
- -1, /* (366) nmnum ::= ON */
|
|
- -1, /* (367) nmnum ::= DELETE */
|
|
- -1, /* (368) nmnum ::= DEFAULT */
|
|
- -1, /* (369) plus_num ::= INTEGER|FLOAT */
|
|
- 0, /* (370) foreach_clause ::= */
|
|
- -3, /* (371) foreach_clause ::= FOR EACH ROW */
|
|
- -1, /* (372) trnm ::= nm */
|
|
- 0, /* (373) tridxby ::= */
|
|
- -1, /* (374) database_kw_opt ::= DATABASE */
|
|
- 0, /* (375) database_kw_opt ::= */
|
|
- 0, /* (376) kwcolumn_opt ::= */
|
|
- -1, /* (377) kwcolumn_opt ::= COLUMNKW */
|
|
- -1, /* (378) vtabarglist ::= vtabarg */
|
|
- -3, /* (379) vtabarglist ::= vtabarglist COMMA vtabarg */
|
|
- -2, /* (380) vtabarg ::= vtabarg vtabargtoken */
|
|
- 0, /* (381) anylist ::= */
|
|
- -4, /* (382) anylist ::= anylist LP anylist RP */
|
|
- -2, /* (383) anylist ::= anylist ANY */
|
|
- 0, /* (384) with ::= */
|
|
+ 0, /* (21) table_option_set ::= */
|
|
+ -3, /* (22) table_option_set ::= table_option_set COMMA table_option */
|
|
+ -2, /* (23) table_option ::= WITHOUT nm */
|
|
+ -1, /* (24) table_option ::= nm */
|
|
+ -2, /* (25) columnname ::= nm typetoken */
|
|
+ 0, /* (26) typetoken ::= */
|
|
+ -4, /* (27) typetoken ::= typename LP signed RP */
|
|
+ -6, /* (28) typetoken ::= typename LP signed COMMA signed RP */
|
|
+ -2, /* (29) typename ::= typename ID|STRING */
|
|
+ 0, /* (30) scanpt ::= */
|
|
+ 0, /* (31) scantok ::= */
|
|
+ -2, /* (32) ccons ::= CONSTRAINT nm */
|
|
+ -3, /* (33) ccons ::= DEFAULT scantok term */
|
|
+ -4, /* (34) ccons ::= DEFAULT LP expr RP */
|
|
+ -4, /* (35) ccons ::= DEFAULT PLUS scantok term */
|
|
+ -4, /* (36) ccons ::= DEFAULT MINUS scantok term */
|
|
+ -3, /* (37) ccons ::= DEFAULT scantok ID|INDEXED */
|
|
+ -3, /* (38) ccons ::= NOT NULL onconf */
|
|
+ -5, /* (39) ccons ::= PRIMARY KEY sortorder onconf autoinc */
|
|
+ -2, /* (40) ccons ::= UNIQUE onconf */
|
|
+ -4, /* (41) ccons ::= CHECK LP expr RP */
|
|
+ -4, /* (42) ccons ::= REFERENCES nm eidlist_opt refargs */
|
|
+ -1, /* (43) ccons ::= defer_subclause */
|
|
+ -2, /* (44) ccons ::= COLLATE ID|STRING */
|
|
+ -3, /* (45) generated ::= LP expr RP */
|
|
+ -4, /* (46) generated ::= LP expr RP ID */
|
|
+ 0, /* (47) autoinc ::= */
|
|
+ -1, /* (48) autoinc ::= AUTOINCR */
|
|
+ 0, /* (49) refargs ::= */
|
|
+ -2, /* (50) refargs ::= refargs refarg */
|
|
+ -2, /* (51) refarg ::= MATCH nm */
|
|
+ -3, /* (52) refarg ::= ON INSERT refact */
|
|
+ -3, /* (53) refarg ::= ON DELETE refact */
|
|
+ -3, /* (54) refarg ::= ON UPDATE refact */
|
|
+ -2, /* (55) refact ::= SET NULL */
|
|
+ -2, /* (56) refact ::= SET DEFAULT */
|
|
+ -1, /* (57) refact ::= CASCADE */
|
|
+ -1, /* (58) refact ::= RESTRICT */
|
|
+ -2, /* (59) refact ::= NO ACTION */
|
|
+ -3, /* (60) defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */
|
|
+ -2, /* (61) defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
|
|
+ 0, /* (62) init_deferred_pred_opt ::= */
|
|
+ -2, /* (63) init_deferred_pred_opt ::= INITIALLY DEFERRED */
|
|
+ -2, /* (64) init_deferred_pred_opt ::= INITIALLY IMMEDIATE */
|
|
+ 0, /* (65) conslist_opt ::= */
|
|
+ -1, /* (66) tconscomma ::= COMMA */
|
|
+ -2, /* (67) tcons ::= CONSTRAINT nm */
|
|
+ -7, /* (68) tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */
|
|
+ -5, /* (69) tcons ::= UNIQUE LP sortlist RP onconf */
|
|
+ -5, /* (70) tcons ::= CHECK LP expr RP onconf */
|
|
+ -10, /* (71) tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */
|
|
+ 0, /* (72) defer_subclause_opt ::= */
|
|
+ 0, /* (73) onconf ::= */
|
|
+ -3, /* (74) onconf ::= ON CONFLICT resolvetype */
|
|
+ 0, /* (75) orconf ::= */
|
|
+ -2, /* (76) orconf ::= OR resolvetype */
|
|
+ -1, /* (77) resolvetype ::= IGNORE */
|
|
+ -1, /* (78) resolvetype ::= REPLACE */
|
|
+ -4, /* (79) cmd ::= DROP TABLE ifexists fullname */
|
|
+ -2, /* (80) ifexists ::= IF EXISTS */
|
|
+ 0, /* (81) ifexists ::= */
|
|
+ -9, /* (82) cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */
|
|
+ -4, /* (83) cmd ::= DROP VIEW ifexists fullname */
|
|
+ -1, /* (84) cmd ::= select */
|
|
+ -3, /* (85) select ::= WITH wqlist selectnowith */
|
|
+ -4, /* (86) select ::= WITH RECURSIVE wqlist selectnowith */
|
|
+ -1, /* (87) select ::= selectnowith */
|
|
+ -3, /* (88) selectnowith ::= selectnowith multiselect_op oneselect */
|
|
+ -1, /* (89) multiselect_op ::= UNION */
|
|
+ -2, /* (90) multiselect_op ::= UNION ALL */
|
|
+ -1, /* (91) multiselect_op ::= EXCEPT|INTERSECT */
|
|
+ -9, /* (92) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
|
|
+ -10, /* (93) oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */
|
|
+ -4, /* (94) values ::= VALUES LP nexprlist RP */
|
|
+ -5, /* (95) values ::= values COMMA LP nexprlist RP */
|
|
+ -1, /* (96) distinct ::= DISTINCT */
|
|
+ -1, /* (97) distinct ::= ALL */
|
|
+ 0, /* (98) distinct ::= */
|
|
+ 0, /* (99) sclp ::= */
|
|
+ -5, /* (100) selcollist ::= sclp scanpt expr scanpt as */
|
|
+ -3, /* (101) selcollist ::= sclp scanpt STAR */
|
|
+ -5, /* (102) selcollist ::= sclp scanpt nm DOT STAR */
|
|
+ -2, /* (103) as ::= AS nm */
|
|
+ 0, /* (104) as ::= */
|
|
+ 0, /* (105) from ::= */
|
|
+ -2, /* (106) from ::= FROM seltablist */
|
|
+ -2, /* (107) stl_prefix ::= seltablist joinop */
|
|
+ 0, /* (108) stl_prefix ::= */
|
|
+ -5, /* (109) seltablist ::= stl_prefix nm dbnm as on_using */
|
|
+ -6, /* (110) seltablist ::= stl_prefix nm dbnm as indexed_by on_using */
|
|
+ -8, /* (111) seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */
|
|
+ -6, /* (112) seltablist ::= stl_prefix LP select RP as on_using */
|
|
+ -6, /* (113) seltablist ::= stl_prefix LP seltablist RP as on_using */
|
|
+ 0, /* (114) dbnm ::= */
|
|
+ -2, /* (115) dbnm ::= DOT nm */
|
|
+ -1, /* (116) fullname ::= nm */
|
|
+ -3, /* (117) fullname ::= nm DOT nm */
|
|
+ -1, /* (118) xfullname ::= nm */
|
|
+ -3, /* (119) xfullname ::= nm DOT nm */
|
|
+ -5, /* (120) xfullname ::= nm DOT nm AS nm */
|
|
+ -3, /* (121) xfullname ::= nm AS nm */
|
|
+ -1, /* (122) joinop ::= COMMA|JOIN */
|
|
+ -2, /* (123) joinop ::= JOIN_KW JOIN */
|
|
+ -3, /* (124) joinop ::= JOIN_KW nm JOIN */
|
|
+ -4, /* (125) joinop ::= JOIN_KW nm nm JOIN */
|
|
+ -2, /* (126) on_using ::= ON expr */
|
|
+ -4, /* (127) on_using ::= USING LP idlist RP */
|
|
+ 0, /* (128) on_using ::= */
|
|
+ 0, /* (129) indexed_opt ::= */
|
|
+ -3, /* (130) indexed_by ::= INDEXED BY nm */
|
|
+ -2, /* (131) indexed_by ::= NOT INDEXED */
|
|
+ 0, /* (132) orderby_opt ::= */
|
|
+ -3, /* (133) orderby_opt ::= ORDER BY sortlist */
|
|
+ -5, /* (134) sortlist ::= sortlist COMMA expr sortorder nulls */
|
|
+ -3, /* (135) sortlist ::= expr sortorder nulls */
|
|
+ -1, /* (136) sortorder ::= ASC */
|
|
+ -1, /* (137) sortorder ::= DESC */
|
|
+ 0, /* (138) sortorder ::= */
|
|
+ -2, /* (139) nulls ::= NULLS FIRST */
|
|
+ -2, /* (140) nulls ::= NULLS LAST */
|
|
+ 0, /* (141) nulls ::= */
|
|
+ 0, /* (142) groupby_opt ::= */
|
|
+ -3, /* (143) groupby_opt ::= GROUP BY nexprlist */
|
|
+ 0, /* (144) having_opt ::= */
|
|
+ -2, /* (145) having_opt ::= HAVING expr */
|
|
+ 0, /* (146) limit_opt ::= */
|
|
+ -2, /* (147) limit_opt ::= LIMIT expr */
|
|
+ -4, /* (148) limit_opt ::= LIMIT expr OFFSET expr */
|
|
+ -4, /* (149) limit_opt ::= LIMIT expr COMMA expr */
|
|
+ -6, /* (150) cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret */
|
|
+ 0, /* (151) where_opt ::= */
|
|
+ -2, /* (152) where_opt ::= WHERE expr */
|
|
+ 0, /* (153) where_opt_ret ::= */
|
|
+ -2, /* (154) where_opt_ret ::= WHERE expr */
|
|
+ -2, /* (155) where_opt_ret ::= RETURNING selcollist */
|
|
+ -4, /* (156) where_opt_ret ::= WHERE expr RETURNING selcollist */
|
|
+ -9, /* (157) cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret */
|
|
+ -5, /* (158) setlist ::= setlist COMMA nm EQ expr */
|
|
+ -7, /* (159) setlist ::= setlist COMMA LP idlist RP EQ expr */
|
|
+ -3, /* (160) setlist ::= nm EQ expr */
|
|
+ -5, /* (161) setlist ::= LP idlist RP EQ expr */
|
|
+ -7, /* (162) cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */
|
|
+ -8, /* (163) cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */
|
|
+ 0, /* (164) upsert ::= */
|
|
+ -2, /* (165) upsert ::= RETURNING selcollist */
|
|
+ -12, /* (166) upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */
|
|
+ -9, /* (167) upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */
|
|
+ -5, /* (168) upsert ::= ON CONFLICT DO NOTHING returning */
|
|
+ -8, /* (169) upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */
|
|
+ -2, /* (170) returning ::= RETURNING selcollist */
|
|
+ -2, /* (171) insert_cmd ::= INSERT orconf */
|
|
+ -1, /* (172) insert_cmd ::= REPLACE */
|
|
+ 0, /* (173) idlist_opt ::= */
|
|
+ -3, /* (174) idlist_opt ::= LP idlist RP */
|
|
+ -3, /* (175) idlist ::= idlist COMMA nm */
|
|
+ -1, /* (176) idlist ::= nm */
|
|
+ -3, /* (177) expr ::= LP expr RP */
|
|
+ -1, /* (178) expr ::= ID|INDEXED */
|
|
+ -1, /* (179) expr ::= JOIN_KW */
|
|
+ -3, /* (180) expr ::= nm DOT nm */
|
|
+ -5, /* (181) expr ::= nm DOT nm DOT nm */
|
|
+ -1, /* (182) term ::= NULL|FLOAT|BLOB */
|
|
+ -1, /* (183) term ::= STRING */
|
|
+ -1, /* (184) term ::= INTEGER */
|
|
+ -1, /* (185) expr ::= VARIABLE */
|
|
+ -3, /* (186) expr ::= expr COLLATE ID|STRING */
|
|
+ -6, /* (187) expr ::= CAST LP expr AS typetoken RP */
|
|
+ -5, /* (188) expr ::= ID|INDEXED LP distinct exprlist RP */
|
|
+ -4, /* (189) expr ::= ID|INDEXED LP STAR RP */
|
|
+ -6, /* (190) expr ::= ID|INDEXED LP distinct exprlist RP filter_over */
|
|
+ -5, /* (191) expr ::= ID|INDEXED LP STAR RP filter_over */
|
|
+ -1, /* (192) term ::= CTIME_KW */
|
|
+ -5, /* (193) expr ::= LP nexprlist COMMA expr RP */
|
|
+ -3, /* (194) expr ::= expr AND expr */
|
|
+ -3, /* (195) expr ::= expr OR expr */
|
|
+ -3, /* (196) expr ::= expr LT|GT|GE|LE expr */
|
|
+ -3, /* (197) expr ::= expr EQ|NE expr */
|
|
+ -3, /* (198) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */
|
|
+ -3, /* (199) expr ::= expr PLUS|MINUS expr */
|
|
+ -3, /* (200) expr ::= expr STAR|SLASH|REM expr */
|
|
+ -3, /* (201) expr ::= expr CONCAT expr */
|
|
+ -2, /* (202) likeop ::= NOT LIKE_KW|MATCH */
|
|
+ -3, /* (203) expr ::= expr likeop expr */
|
|
+ -5, /* (204) expr ::= expr likeop expr ESCAPE expr */
|
|
+ -2, /* (205) expr ::= expr ISNULL|NOTNULL */
|
|
+ -3, /* (206) expr ::= expr NOT NULL */
|
|
+ -3, /* (207) expr ::= expr IS expr */
|
|
+ -4, /* (208) expr ::= expr IS NOT expr */
|
|
+ -6, /* (209) expr ::= expr IS NOT DISTINCT FROM expr */
|
|
+ -5, /* (210) expr ::= expr IS DISTINCT FROM expr */
|
|
+ -2, /* (211) expr ::= NOT expr */
|
|
+ -2, /* (212) expr ::= BITNOT expr */
|
|
+ -2, /* (213) expr ::= PLUS|MINUS expr */
|
|
+ -3, /* (214) expr ::= expr PTR expr */
|
|
+ -1, /* (215) between_op ::= BETWEEN */
|
|
+ -2, /* (216) between_op ::= NOT BETWEEN */
|
|
+ -5, /* (217) expr ::= expr between_op expr AND expr */
|
|
+ -1, /* (218) in_op ::= IN */
|
|
+ -2, /* (219) in_op ::= NOT IN */
|
|
+ -5, /* (220) expr ::= expr in_op LP exprlist RP */
|
|
+ -3, /* (221) expr ::= LP select RP */
|
|
+ -5, /* (222) expr ::= expr in_op LP select RP */
|
|
+ -5, /* (223) expr ::= expr in_op nm dbnm paren_exprlist */
|
|
+ -4, /* (224) expr ::= EXISTS LP select RP */
|
|
+ -5, /* (225) expr ::= CASE case_operand case_exprlist case_else END */
|
|
+ -5, /* (226) case_exprlist ::= case_exprlist WHEN expr THEN expr */
|
|
+ -4, /* (227) case_exprlist ::= WHEN expr THEN expr */
|
|
+ -2, /* (228) case_else ::= ELSE expr */
|
|
+ 0, /* (229) case_else ::= */
|
|
+ -1, /* (230) case_operand ::= expr */
|
|
+ 0, /* (231) case_operand ::= */
|
|
+ 0, /* (232) exprlist ::= */
|
|
+ -3, /* (233) nexprlist ::= nexprlist COMMA expr */
|
|
+ -1, /* (234) nexprlist ::= expr */
|
|
+ 0, /* (235) paren_exprlist ::= */
|
|
+ -3, /* (236) paren_exprlist ::= LP exprlist RP */
|
|
+ -12, /* (237) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
|
|
+ -1, /* (238) uniqueflag ::= UNIQUE */
|
|
+ 0, /* (239) uniqueflag ::= */
|
|
+ 0, /* (240) eidlist_opt ::= */
|
|
+ -3, /* (241) eidlist_opt ::= LP eidlist RP */
|
|
+ -5, /* (242) eidlist ::= eidlist COMMA nm collate sortorder */
|
|
+ -3, /* (243) eidlist ::= nm collate sortorder */
|
|
+ 0, /* (244) collate ::= */
|
|
+ -2, /* (245) collate ::= COLLATE ID|STRING */
|
|
+ -4, /* (246) cmd ::= DROP INDEX ifexists fullname */
|
|
+ -2, /* (247) cmd ::= VACUUM vinto */
|
|
+ -3, /* (248) cmd ::= VACUUM nm vinto */
|
|
+ -2, /* (249) vinto ::= INTO expr */
|
|
+ 0, /* (250) vinto ::= */
|
|
+ -3, /* (251) cmd ::= PRAGMA nm dbnm */
|
|
+ -5, /* (252) cmd ::= PRAGMA nm dbnm EQ nmnum */
|
|
+ -6, /* (253) cmd ::= PRAGMA nm dbnm LP nmnum RP */
|
|
+ -5, /* (254) cmd ::= PRAGMA nm dbnm EQ minus_num */
|
|
+ -6, /* (255) cmd ::= PRAGMA nm dbnm LP minus_num RP */
|
|
+ -2, /* (256) plus_num ::= PLUS INTEGER|FLOAT */
|
|
+ -2, /* (257) minus_num ::= MINUS INTEGER|FLOAT */
|
|
+ -5, /* (258) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
|
|
+ -11, /* (259) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
|
|
+ -1, /* (260) trigger_time ::= BEFORE|AFTER */
|
|
+ -2, /* (261) trigger_time ::= INSTEAD OF */
|
|
+ 0, /* (262) trigger_time ::= */
|
|
+ -1, /* (263) trigger_event ::= DELETE|INSERT */
|
|
+ -1, /* (264) trigger_event ::= UPDATE */
|
|
+ -3, /* (265) trigger_event ::= UPDATE OF idlist */
|
|
+ 0, /* (266) when_clause ::= */
|
|
+ -2, /* (267) when_clause ::= WHEN expr */
|
|
+ -3, /* (268) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
|
|
+ -2, /* (269) trigger_cmd_list ::= trigger_cmd SEMI */
|
|
+ -3, /* (270) trnm ::= nm DOT nm */
|
|
+ -3, /* (271) tridxby ::= INDEXED BY nm */
|
|
+ -2, /* (272) tridxby ::= NOT INDEXED */
|
|
+ -9, /* (273) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */
|
|
+ -8, /* (274) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */
|
|
+ -6, /* (275) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
|
|
+ -3, /* (276) trigger_cmd ::= scanpt select scanpt */
|
|
+ -4, /* (277) expr ::= RAISE LP IGNORE RP */
|
|
+ -6, /* (278) expr ::= RAISE LP raisetype COMMA nm RP */
|
|
+ -1, /* (279) raisetype ::= ROLLBACK */
|
|
+ -1, /* (280) raisetype ::= ABORT */
|
|
+ -1, /* (281) raisetype ::= FAIL */
|
|
+ -4, /* (282) cmd ::= DROP TRIGGER ifexists fullname */
|
|
+ -6, /* (283) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
|
|
+ -3, /* (284) cmd ::= DETACH database_kw_opt expr */
|
|
+ 0, /* (285) key_opt ::= */
|
|
+ -2, /* (286) key_opt ::= KEY expr */
|
|
+ -1, /* (287) cmd ::= REINDEX */
|
|
+ -3, /* (288) cmd ::= REINDEX nm dbnm */
|
|
+ -1, /* (289) cmd ::= ANALYZE */
|
|
+ -3, /* (290) cmd ::= ANALYZE nm dbnm */
|
|
+ -6, /* (291) cmd ::= ALTER TABLE fullname RENAME TO nm */
|
|
+ -7, /* (292) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
|
|
+ -6, /* (293) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */
|
|
+ -1, /* (294) add_column_fullname ::= fullname */
|
|
+ -8, /* (295) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */
|
|
+ -1, /* (296) cmd ::= create_vtab */
|
|
+ -4, /* (297) cmd ::= create_vtab LP vtabarglist RP */
|
|
+ -8, /* (298) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
|
|
+ 0, /* (299) vtabarg ::= */
|
|
+ -1, /* (300) vtabargtoken ::= ANY */
|
|
+ -3, /* (301) vtabargtoken ::= lp anylist RP */
|
|
+ -1, /* (302) lp ::= LP */
|
|
+ -2, /* (303) with ::= WITH wqlist */
|
|
+ -3, /* (304) with ::= WITH RECURSIVE wqlist */
|
|
+ -1, /* (305) wqas ::= AS */
|
|
+ -2, /* (306) wqas ::= AS MATERIALIZED */
|
|
+ -3, /* (307) wqas ::= AS NOT MATERIALIZED */
|
|
+ -6, /* (308) wqitem ::= nm eidlist_opt wqas LP select RP */
|
|
+ -1, /* (309) wqlist ::= wqitem */
|
|
+ -3, /* (310) wqlist ::= wqlist COMMA wqitem */
|
|
+ -1, /* (311) windowdefn_list ::= windowdefn */
|
|
+ -3, /* (312) windowdefn_list ::= windowdefn_list COMMA windowdefn */
|
|
+ -5, /* (313) windowdefn ::= nm AS LP window RP */
|
|
+ -5, /* (314) window ::= PARTITION BY nexprlist orderby_opt frame_opt */
|
|
+ -6, /* (315) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */
|
|
+ -4, /* (316) window ::= ORDER BY sortlist frame_opt */
|
|
+ -5, /* (317) window ::= nm ORDER BY sortlist frame_opt */
|
|
+ -1, /* (318) window ::= frame_opt */
|
|
+ -2, /* (319) window ::= nm frame_opt */
|
|
+ 0, /* (320) frame_opt ::= */
|
|
+ -3, /* (321) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */
|
|
+ -6, /* (322) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */
|
|
+ -1, /* (323) range_or_rows ::= RANGE|ROWS|GROUPS */
|
|
+ -1, /* (324) frame_bound_s ::= frame_bound */
|
|
+ -2, /* (325) frame_bound_s ::= UNBOUNDED PRECEDING */
|
|
+ -1, /* (326) frame_bound_e ::= frame_bound */
|
|
+ -2, /* (327) frame_bound_e ::= UNBOUNDED FOLLOWING */
|
|
+ -2, /* (328) frame_bound ::= expr PRECEDING|FOLLOWING */
|
|
+ -2, /* (329) frame_bound ::= CURRENT ROW */
|
|
+ 0, /* (330) frame_exclude_opt ::= */
|
|
+ -2, /* (331) frame_exclude_opt ::= EXCLUDE frame_exclude */
|
|
+ -2, /* (332) frame_exclude ::= NO OTHERS */
|
|
+ -2, /* (333) frame_exclude ::= CURRENT ROW */
|
|
+ -1, /* (334) frame_exclude ::= GROUP|TIES */
|
|
+ -2, /* (335) window_clause ::= WINDOW windowdefn_list */
|
|
+ -2, /* (336) filter_over ::= filter_clause over_clause */
|
|
+ -1, /* (337) filter_over ::= over_clause */
|
|
+ -1, /* (338) filter_over ::= filter_clause */
|
|
+ -4, /* (339) over_clause ::= OVER LP window RP */
|
|
+ -2, /* (340) over_clause ::= OVER nm */
|
|
+ -5, /* (341) filter_clause ::= FILTER LP WHERE expr RP */
|
|
+ -1, /* (342) input ::= cmdlist */
|
|
+ -2, /* (343) cmdlist ::= cmdlist ecmd */
|
|
+ -1, /* (344) cmdlist ::= ecmd */
|
|
+ -1, /* (345) ecmd ::= SEMI */
|
|
+ -2, /* (346) ecmd ::= cmdx SEMI */
|
|
+ -3, /* (347) ecmd ::= explain cmdx SEMI */
|
|
+ 0, /* (348) trans_opt ::= */
|
|
+ -1, /* (349) trans_opt ::= TRANSACTION */
|
|
+ -2, /* (350) trans_opt ::= TRANSACTION nm */
|
|
+ -1, /* (351) savepoint_opt ::= SAVEPOINT */
|
|
+ 0, /* (352) savepoint_opt ::= */
|
|
+ -2, /* (353) cmd ::= create_table create_table_args */
|
|
+ -1, /* (354) table_option_set ::= table_option */
|
|
+ -4, /* (355) columnlist ::= columnlist COMMA columnname carglist */
|
|
+ -2, /* (356) columnlist ::= columnname carglist */
|
|
+ -1, /* (357) nm ::= ID|INDEXED */
|
|
+ -1, /* (358) nm ::= STRING */
|
|
+ -1, /* (359) nm ::= JOIN_KW */
|
|
+ -1, /* (360) typetoken ::= typename */
|
|
+ -1, /* (361) typename ::= ID|STRING */
|
|
+ -1, /* (362) signed ::= plus_num */
|
|
+ -1, /* (363) signed ::= minus_num */
|
|
+ -2, /* (364) carglist ::= carglist ccons */
|
|
+ 0, /* (365) carglist ::= */
|
|
+ -2, /* (366) ccons ::= NULL onconf */
|
|
+ -4, /* (367) ccons ::= GENERATED ALWAYS AS generated */
|
|
+ -2, /* (368) ccons ::= AS generated */
|
|
+ -2, /* (369) conslist_opt ::= COMMA conslist */
|
|
+ -3, /* (370) conslist ::= conslist tconscomma tcons */
|
|
+ -1, /* (371) conslist ::= tcons */
|
|
+ 0, /* (372) tconscomma ::= */
|
|
+ -1, /* (373) defer_subclause_opt ::= defer_subclause */
|
|
+ -1, /* (374) resolvetype ::= raisetype */
|
|
+ -1, /* (375) selectnowith ::= oneselect */
|
|
+ -1, /* (376) oneselect ::= values */
|
|
+ -2, /* (377) sclp ::= selcollist COMMA */
|
|
+ -1, /* (378) as ::= ID|STRING */
|
|
+ -1, /* (379) indexed_opt ::= indexed_by */
|
|
+ 0, /* (380) returning ::= */
|
|
+ -1, /* (381) expr ::= term */
|
|
+ -1, /* (382) likeop ::= LIKE_KW|MATCH */
|
|
+ -1, /* (383) exprlist ::= nexprlist */
|
|
+ -1, /* (384) nmnum ::= plus_num */
|
|
+ -1, /* (385) nmnum ::= nm */
|
|
+ -1, /* (386) nmnum ::= ON */
|
|
+ -1, /* (387) nmnum ::= DELETE */
|
|
+ -1, /* (388) nmnum ::= DEFAULT */
|
|
+ -1, /* (389) plus_num ::= INTEGER|FLOAT */
|
|
+ 0, /* (390) foreach_clause ::= */
|
|
+ -3, /* (391) foreach_clause ::= FOR EACH ROW */
|
|
+ -1, /* (392) trnm ::= nm */
|
|
+ 0, /* (393) tridxby ::= */
|
|
+ -1, /* (394) database_kw_opt ::= DATABASE */
|
|
+ 0, /* (395) database_kw_opt ::= */
|
|
+ 0, /* (396) kwcolumn_opt ::= */
|
|
+ -1, /* (397) kwcolumn_opt ::= COLUMNKW */
|
|
+ -1, /* (398) vtabarglist ::= vtabarg */
|
|
+ -3, /* (399) vtabarglist ::= vtabarglist COMMA vtabarg */
|
|
+ -2, /* (400) vtabarg ::= vtabarg vtabargtoken */
|
|
+ 0, /* (401) anylist ::= */
|
|
+ -4, /* (402) anylist ::= anylist LP anylist RP */
|
|
+ -2, /* (403) anylist ::= anylist ANY */
|
|
+ 0, /* (404) with ::= */
|
|
};
|
|
|
|
static void yy_accept(yyParser*); /* Forward Declaration */
|
|
@@ -155547,54 +170384,6 @@ static YYACTIONTYPE yy_reduce(
|
|
(void)yyLookahead;
|
|
(void)yyLookaheadToken;
|
|
yymsp = yypParser->yytos;
|
|
-#ifndef NDEBUG
|
|
- if( yyTraceFILE && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){
|
|
- yysize = yyRuleInfoNRhs[yyruleno];
|
|
- if( yysize ){
|
|
- fprintf(yyTraceFILE, "%sReduce %d [%s]%s, pop back to state %d.\n",
|
|
- yyTracePrompt,
|
|
- yyruleno, yyRuleName[yyruleno],
|
|
- yyruleno<YYNRULE_WITH_ACTION ? "" : " without external action",
|
|
- yymsp[yysize].stateno);
|
|
- }else{
|
|
- fprintf(yyTraceFILE, "%sReduce %d [%s]%s.\n",
|
|
- yyTracePrompt, yyruleno, yyRuleName[yyruleno],
|
|
- yyruleno<YYNRULE_WITH_ACTION ? "" : " without external action");
|
|
- }
|
|
- }
|
|
-#endif /* NDEBUG */
|
|
-
|
|
- /* Check that the stack is large enough to grow by a single entry
|
|
- ** if the RHS of the rule is empty. This ensures that there is room
|
|
- ** enough on the stack to push the LHS value */
|
|
- if( yyRuleInfoNRhs[yyruleno]==0 ){
|
|
-#ifdef YYTRACKMAXSTACKDEPTH
|
|
- if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){
|
|
- yypParser->yyhwm++;
|
|
- assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack));
|
|
- }
|
|
-#endif
|
|
-#if YYSTACKDEPTH>0
|
|
- if( yypParser->yytos>=yypParser->yystackEnd ){
|
|
- yyStackOverflow(yypParser);
|
|
- /* The call to yyStackOverflow() above pops the stack until it is
|
|
- ** empty, causing the main parser loop to exit. So the return value
|
|
- ** is never used and does not matter. */
|
|
- return 0;
|
|
- }
|
|
-#else
|
|
- if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz-1] ){
|
|
- if( yyGrowStack(yypParser) ){
|
|
- yyStackOverflow(yypParser);
|
|
- /* The call to yyStackOverflow() above pops the stack until it is
|
|
- ** empty, causing the main parser loop to exit. So the return value
|
|
- ** is never used and does not matter. */
|
|
- return 0;
|
|
- }
|
|
- yymsp = yypParser->yytos;
|
|
- }
|
|
-#endif
|
|
- }
|
|
|
|
switch( yyruleno ){
|
|
/* Beginning here are the reduction cases. A typical example
|
|
@@ -155617,16 +170406,16 @@ static YYACTIONTYPE yy_reduce(
|
|
{ sqlite3FinishCoding(pParse); }
|
|
break;
|
|
case 3: /* cmd ::= BEGIN transtype trans_opt */
|
|
-{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy192);}
|
|
+{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy394);}
|
|
break;
|
|
case 4: /* transtype ::= */
|
|
-{yymsp[1].minor.yy192 = TK_DEFERRED;}
|
|
+{yymsp[1].minor.yy394 = TK_DEFERRED;}
|
|
break;
|
|
case 5: /* transtype ::= DEFERRED */
|
|
case 6: /* transtype ::= IMMEDIATE */ yytestcase(yyruleno==6);
|
|
case 7: /* transtype ::= EXCLUSIVE */ yytestcase(yyruleno==7);
|
|
- case 306: /* range_or_rows ::= RANGE|ROWS|GROUPS */ yytestcase(yyruleno==306);
|
|
-{yymsp[0].minor.yy192 = yymsp[0].major; /*A-overwrites-X*/}
|
|
+ case 323: /* range_or_rows ::= RANGE|ROWS|GROUPS */ yytestcase(yyruleno==323);
|
|
+{yymsp[0].minor.yy394 = yymsp[0].major; /*A-overwrites-X*/}
|
|
break;
|
|
case 8: /* cmd ::= COMMIT|END trans_opt */
|
|
case 9: /* cmd ::= ROLLBACK trans_opt */ yytestcase(yyruleno==9);
|
|
@@ -155649,7 +170438,7 @@ static YYACTIONTYPE yy_reduce(
|
|
break;
|
|
case 13: /* create_table ::= createkw temp TABLE ifnotexists nm dbnm */
|
|
{
|
|
- sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy192,0,0,yymsp[-2].minor.yy192);
|
|
+ sqlite3StartTable(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,yymsp[-4].minor.yy394,0,0,yymsp[-2].minor.yy394);
|
|
}
|
|
break;
|
|
case 14: /* createkw ::= CREATE */
|
|
@@ -155657,96 +170446,112 @@ static YYACTIONTYPE yy_reduce(
|
|
break;
|
|
case 15: /* ifnotexists ::= */
|
|
case 18: /* temp ::= */ yytestcase(yyruleno==18);
|
|
- case 21: /* table_options ::= */ yytestcase(yyruleno==21);
|
|
- case 45: /* autoinc ::= */ yytestcase(yyruleno==45);
|
|
- case 60: /* init_deferred_pred_opt ::= */ yytestcase(yyruleno==60);
|
|
- case 70: /* defer_subclause_opt ::= */ yytestcase(yyruleno==70);
|
|
- case 79: /* ifexists ::= */ yytestcase(yyruleno==79);
|
|
- case 96: /* distinct ::= */ yytestcase(yyruleno==96);
|
|
- case 232: /* collate ::= */ yytestcase(yyruleno==232);
|
|
-{yymsp[1].minor.yy192 = 0;}
|
|
+ case 47: /* autoinc ::= */ yytestcase(yyruleno==47);
|
|
+ case 62: /* init_deferred_pred_opt ::= */ yytestcase(yyruleno==62);
|
|
+ case 72: /* defer_subclause_opt ::= */ yytestcase(yyruleno==72);
|
|
+ case 81: /* ifexists ::= */ yytestcase(yyruleno==81);
|
|
+ case 98: /* distinct ::= */ yytestcase(yyruleno==98);
|
|
+ case 244: /* collate ::= */ yytestcase(yyruleno==244);
|
|
+{yymsp[1].minor.yy394 = 0;}
|
|
break;
|
|
case 16: /* ifnotexists ::= IF NOT EXISTS */
|
|
-{yymsp[-2].minor.yy192 = 1;}
|
|
+{yymsp[-2].minor.yy394 = 1;}
|
|
break;
|
|
case 17: /* temp ::= TEMP */
|
|
- case 46: /* autoinc ::= AUTOINCR */ yytestcase(yyruleno==46);
|
|
-{yymsp[0].minor.yy192 = 1;}
|
|
+{yymsp[0].minor.yy394 = pParse->db->init.busy==0;}
|
|
break;
|
|
- case 19: /* create_table_args ::= LP columnlist conslist_opt RP table_options */
|
|
+ case 19: /* create_table_args ::= LP columnlist conslist_opt RP table_option_set */
|
|
{
|
|
- sqlite3EndTable(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,yymsp[0].minor.yy192,0);
|
|
+ sqlite3EndTable(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,yymsp[0].minor.yy285,0);
|
|
}
|
|
break;
|
|
case 20: /* create_table_args ::= AS select */
|
|
{
|
|
- sqlite3EndTable(pParse,0,0,0,yymsp[0].minor.yy539);
|
|
- sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy539);
|
|
+ sqlite3EndTable(pParse,0,0,0,yymsp[0].minor.yy47);
|
|
+ sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy47);
|
|
}
|
|
break;
|
|
- case 22: /* table_options ::= WITHOUT nm */
|
|
+ case 21: /* table_option_set ::= */
|
|
+{yymsp[1].minor.yy285 = 0;}
|
|
+ break;
|
|
+ case 22: /* table_option_set ::= table_option_set COMMA table_option */
|
|
+{yylhsminor.yy285 = yymsp[-2].minor.yy285|yymsp[0].minor.yy285;}
|
|
+ yymsp[-2].minor.yy285 = yylhsminor.yy285;
|
|
+ break;
|
|
+ case 23: /* table_option ::= WITHOUT nm */
|
|
{
|
|
if( yymsp[0].minor.yy0.n==5 && sqlite3_strnicmp(yymsp[0].minor.yy0.z,"rowid",5)==0 ){
|
|
- yymsp[-1].minor.yy192 = TF_WithoutRowid | TF_NoVisibleRowid;
|
|
+ yymsp[-1].minor.yy285 = TF_WithoutRowid | TF_NoVisibleRowid;
|
|
}else{
|
|
- yymsp[-1].minor.yy192 = 0;
|
|
+ yymsp[-1].minor.yy285 = 0;
|
|
sqlite3ErrorMsg(pParse, "unknown table option: %.*s", yymsp[0].minor.yy0.n, yymsp[0].minor.yy0.z);
|
|
}
|
|
}
|
|
break;
|
|
- case 23: /* columnname ::= nm typetoken */
|
|
-{sqlite3AddColumn(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0);}
|
|
+ case 24: /* table_option ::= nm */
|
|
+{
|
|
+ if( yymsp[0].minor.yy0.n==6 && sqlite3_strnicmp(yymsp[0].minor.yy0.z,"strict",6)==0 ){
|
|
+ yylhsminor.yy285 = TF_Strict;
|
|
+ }else{
|
|
+ yylhsminor.yy285 = 0;
|
|
+ sqlite3ErrorMsg(pParse, "unknown table option: %.*s", yymsp[0].minor.yy0.n, yymsp[0].minor.yy0.z);
|
|
+ }
|
|
+}
|
|
+ yymsp[0].minor.yy285 = yylhsminor.yy285;
|
|
break;
|
|
- case 24: /* typetoken ::= */
|
|
- case 63: /* conslist_opt ::= */ yytestcase(yyruleno==63);
|
|
- case 102: /* as ::= */ yytestcase(yyruleno==102);
|
|
+ case 25: /* columnname ::= nm typetoken */
|
|
+{sqlite3AddColumn(pParse,yymsp[-1].minor.yy0,yymsp[0].minor.yy0);}
|
|
+ break;
|
|
+ case 26: /* typetoken ::= */
|
|
+ case 65: /* conslist_opt ::= */ yytestcase(yyruleno==65);
|
|
+ case 104: /* as ::= */ yytestcase(yyruleno==104);
|
|
{yymsp[1].minor.yy0.n = 0; yymsp[1].minor.yy0.z = 0;}
|
|
break;
|
|
- case 25: /* typetoken ::= typename LP signed RP */
|
|
+ case 27: /* 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 26: /* typetoken ::= typename LP signed COMMA signed RP */
|
|
+ case 28: /* 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 27: /* typename ::= typename ID|STRING */
|
|
+ case 29: /* 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 28: /* scanpt ::= */
|
|
+ case 30: /* scanpt ::= */
|
|
{
|
|
assert( yyLookahead!=YYNOCODE );
|
|
- yymsp[1].minor.yy436 = yyLookaheadToken.z;
|
|
+ yymsp[1].minor.yy522 = yyLookaheadToken.z;
|
|
}
|
|
break;
|
|
- case 29: /* scantok ::= */
|
|
+ case 31: /* scantok ::= */
|
|
{
|
|
assert( yyLookahead!=YYNOCODE );
|
|
yymsp[1].minor.yy0 = yyLookaheadToken;
|
|
}
|
|
break;
|
|
- case 30: /* ccons ::= CONSTRAINT nm */
|
|
- case 65: /* tcons ::= CONSTRAINT nm */ yytestcase(yyruleno==65);
|
|
+ case 32: /* ccons ::= CONSTRAINT nm */
|
|
+ case 67: /* tcons ::= CONSTRAINT nm */ yytestcase(yyruleno==67);
|
|
{pParse->constraintName = yymsp[0].minor.yy0;}
|
|
break;
|
|
- case 31: /* ccons ::= DEFAULT scantok term */
|
|
-{sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy202,yymsp[-1].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);}
|
|
+ case 33: /* ccons ::= DEFAULT scantok term */
|
|
+{sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy528,yymsp[-1].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);}
|
|
break;
|
|
- case 32: /* ccons ::= DEFAULT LP expr RP */
|
|
-{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy202,yymsp[-2].minor.yy0.z+1,yymsp[0].minor.yy0.z);}
|
|
+ case 34: /* ccons ::= DEFAULT LP expr RP */
|
|
+{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy528,yymsp[-2].minor.yy0.z+1,yymsp[0].minor.yy0.z);}
|
|
break;
|
|
- case 33: /* ccons ::= DEFAULT PLUS scantok term */
|
|
-{sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy202,yymsp[-2].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);}
|
|
+ case 35: /* ccons ::= DEFAULT PLUS scantok term */
|
|
+{sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy528,yymsp[-2].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);}
|
|
break;
|
|
- case 34: /* ccons ::= DEFAULT MINUS scantok term */
|
|
+ case 36: /* ccons ::= DEFAULT MINUS scantok term */
|
|
{
|
|
- Expr *p = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy202, 0);
|
|
+ Expr *p = sqlite3PExpr(pParse, TK_UMINUS, yymsp[0].minor.yy528, 0);
|
|
sqlite3AddDefaultValue(pParse,p,yymsp[-2].minor.yy0.z,&yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n]);
|
|
}
|
|
break;
|
|
- case 35: /* ccons ::= DEFAULT scantok ID|INDEXED */
|
|
+ case 37: /* ccons ::= DEFAULT scantok ID|INDEXED */
|
|
{
|
|
Expr *p = tokenExpr(pParse, TK_STRING, yymsp[0].minor.yy0);
|
|
if( p ){
|
|
@@ -155756,325 +170561,316 @@ static YYACTIONTYPE yy_reduce(
|
|
sqlite3AddDefaultValue(pParse,p,yymsp[0].minor.yy0.z,yymsp[0].minor.yy0.z+yymsp[0].minor.yy0.n);
|
|
}
|
|
break;
|
|
- case 36: /* ccons ::= NOT NULL onconf */
|
|
-{sqlite3AddNotNull(pParse, yymsp[0].minor.yy192);}
|
|
+ case 38: /* ccons ::= NOT NULL onconf */
|
|
+{sqlite3AddNotNull(pParse, yymsp[0].minor.yy394);}
|
|
break;
|
|
- case 37: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */
|
|
-{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy192,yymsp[0].minor.yy192,yymsp[-2].minor.yy192);}
|
|
+ case 39: /* ccons ::= PRIMARY KEY sortorder onconf autoinc */
|
|
+{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy394,yymsp[0].minor.yy394,yymsp[-2].minor.yy394);}
|
|
break;
|
|
- case 38: /* ccons ::= UNIQUE onconf */
|
|
-{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy192,0,0,0,0,
|
|
+ case 40: /* ccons ::= UNIQUE onconf */
|
|
+{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy394,0,0,0,0,
|
|
SQLITE_IDXTYPE_UNIQUE);}
|
|
break;
|
|
- case 39: /* ccons ::= CHECK LP expr RP */
|
|
-{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy202);}
|
|
+ case 41: /* ccons ::= CHECK LP expr RP */
|
|
+{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy528,yymsp[-2].minor.yy0.z,yymsp[0].minor.yy0.z);}
|
|
break;
|
|
- case 40: /* ccons ::= REFERENCES nm eidlist_opt refargs */
|
|
-{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy242,yymsp[0].minor.yy192);}
|
|
+ case 42: /* ccons ::= REFERENCES nm eidlist_opt refargs */
|
|
+{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy0,yymsp[-1].minor.yy322,yymsp[0].minor.yy394);}
|
|
break;
|
|
- case 41: /* ccons ::= defer_subclause */
|
|
-{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy192);}
|
|
+ case 43: /* ccons ::= defer_subclause */
|
|
+{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy394);}
|
|
break;
|
|
- case 42: /* ccons ::= COLLATE ID|STRING */
|
|
+ case 44: /* ccons ::= COLLATE ID|STRING */
|
|
{sqlite3AddCollateType(pParse, &yymsp[0].minor.yy0);}
|
|
break;
|
|
- case 43: /* generated ::= LP expr RP */
|
|
-{sqlite3AddGenerated(pParse,yymsp[-1].minor.yy202,0);}
|
|
+ case 45: /* generated ::= LP expr RP */
|
|
+{sqlite3AddGenerated(pParse,yymsp[-1].minor.yy528,0);}
|
|
+ break;
|
|
+ case 46: /* generated ::= LP expr RP ID */
|
|
+{sqlite3AddGenerated(pParse,yymsp[-2].minor.yy528,&yymsp[0].minor.yy0);}
|
|
break;
|
|
- case 44: /* generated ::= LP expr RP ID */
|
|
-{sqlite3AddGenerated(pParse,yymsp[-2].minor.yy202,&yymsp[0].minor.yy0);}
|
|
+ case 48: /* autoinc ::= AUTOINCR */
|
|
+{yymsp[0].minor.yy394 = 1;}
|
|
break;
|
|
- case 47: /* refargs ::= */
|
|
-{ yymsp[1].minor.yy192 = OE_None*0x0101; /* EV: R-19803-45884 */}
|
|
+ case 49: /* refargs ::= */
|
|
+{ yymsp[1].minor.yy394 = OE_None*0x0101; /* EV: R-19803-45884 */}
|
|
break;
|
|
- case 48: /* refargs ::= refargs refarg */
|
|
-{ yymsp[-1].minor.yy192 = (yymsp[-1].minor.yy192 & ~yymsp[0].minor.yy207.mask) | yymsp[0].minor.yy207.value; }
|
|
+ case 50: /* refargs ::= refargs refarg */
|
|
+{ yymsp[-1].minor.yy394 = (yymsp[-1].minor.yy394 & ~yymsp[0].minor.yy231.mask) | yymsp[0].minor.yy231.value; }
|
|
break;
|
|
- case 49: /* refarg ::= MATCH nm */
|
|
-{ yymsp[-1].minor.yy207.value = 0; yymsp[-1].minor.yy207.mask = 0x000000; }
|
|
+ case 51: /* refarg ::= MATCH nm */
|
|
+{ yymsp[-1].minor.yy231.value = 0; yymsp[-1].minor.yy231.mask = 0x000000; }
|
|
break;
|
|
- case 50: /* refarg ::= ON INSERT refact */
|
|
-{ yymsp[-2].minor.yy207.value = 0; yymsp[-2].minor.yy207.mask = 0x000000; }
|
|
+ case 52: /* refarg ::= ON INSERT refact */
|
|
+{ yymsp[-2].minor.yy231.value = 0; yymsp[-2].minor.yy231.mask = 0x000000; }
|
|
break;
|
|
- case 51: /* refarg ::= ON DELETE refact */
|
|
-{ yymsp[-2].minor.yy207.value = yymsp[0].minor.yy192; yymsp[-2].minor.yy207.mask = 0x0000ff; }
|
|
+ case 53: /* refarg ::= ON DELETE refact */
|
|
+{ yymsp[-2].minor.yy231.value = yymsp[0].minor.yy394; yymsp[-2].minor.yy231.mask = 0x0000ff; }
|
|
break;
|
|
- case 52: /* refarg ::= ON UPDATE refact */
|
|
-{ yymsp[-2].minor.yy207.value = yymsp[0].minor.yy192<<8; yymsp[-2].minor.yy207.mask = 0x00ff00; }
|
|
+ case 54: /* refarg ::= ON UPDATE refact */
|
|
+{ yymsp[-2].minor.yy231.value = yymsp[0].minor.yy394<<8; yymsp[-2].minor.yy231.mask = 0x00ff00; }
|
|
break;
|
|
- case 53: /* refact ::= SET NULL */
|
|
-{ yymsp[-1].minor.yy192 = OE_SetNull; /* EV: R-33326-45252 */}
|
|
+ case 55: /* refact ::= SET NULL */
|
|
+{ yymsp[-1].minor.yy394 = OE_SetNull; /* EV: R-33326-45252 */}
|
|
break;
|
|
- case 54: /* refact ::= SET DEFAULT */
|
|
-{ yymsp[-1].minor.yy192 = OE_SetDflt; /* EV: R-33326-45252 */}
|
|
+ case 56: /* refact ::= SET DEFAULT */
|
|
+{ yymsp[-1].minor.yy394 = OE_SetDflt; /* EV: R-33326-45252 */}
|
|
break;
|
|
- case 55: /* refact ::= CASCADE */
|
|
-{ yymsp[0].minor.yy192 = OE_Cascade; /* EV: R-33326-45252 */}
|
|
+ case 57: /* refact ::= CASCADE */
|
|
+{ yymsp[0].minor.yy394 = OE_Cascade; /* EV: R-33326-45252 */}
|
|
break;
|
|
- case 56: /* refact ::= RESTRICT */
|
|
-{ yymsp[0].minor.yy192 = OE_Restrict; /* EV: R-33326-45252 */}
|
|
+ case 58: /* refact ::= RESTRICT */
|
|
+{ yymsp[0].minor.yy394 = OE_Restrict; /* EV: R-33326-45252 */}
|
|
break;
|
|
- case 57: /* refact ::= NO ACTION */
|
|
-{ yymsp[-1].minor.yy192 = OE_None; /* EV: R-33326-45252 */}
|
|
+ case 59: /* refact ::= NO ACTION */
|
|
+{ yymsp[-1].minor.yy394 = OE_None; /* EV: R-33326-45252 */}
|
|
break;
|
|
- case 58: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */
|
|
-{yymsp[-2].minor.yy192 = 0;}
|
|
+ case 60: /* defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt */
|
|
+{yymsp[-2].minor.yy394 = 0;}
|
|
break;
|
|
- case 59: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
|
|
- case 74: /* orconf ::= OR resolvetype */ yytestcase(yyruleno==74);
|
|
- case 162: /* insert_cmd ::= INSERT orconf */ yytestcase(yyruleno==162);
|
|
-{yymsp[-1].minor.yy192 = yymsp[0].minor.yy192;}
|
|
+ case 61: /* defer_subclause ::= DEFERRABLE init_deferred_pred_opt */
|
|
+ case 76: /* orconf ::= OR resolvetype */ yytestcase(yyruleno==76);
|
|
+ case 171: /* insert_cmd ::= INSERT orconf */ yytestcase(yyruleno==171);
|
|
+{yymsp[-1].minor.yy394 = yymsp[0].minor.yy394;}
|
|
break;
|
|
- case 61: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */
|
|
- case 78: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==78);
|
|
- case 204: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==204);
|
|
- case 207: /* in_op ::= NOT IN */ yytestcase(yyruleno==207);
|
|
- case 233: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==233);
|
|
-{yymsp[-1].minor.yy192 = 1;}
|
|
+ case 63: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */
|
|
+ case 80: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==80);
|
|
+ case 216: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==216);
|
|
+ case 219: /* in_op ::= NOT IN */ yytestcase(yyruleno==219);
|
|
+ case 245: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==245);
|
|
+{yymsp[-1].minor.yy394 = 1;}
|
|
break;
|
|
- case 62: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */
|
|
-{yymsp[-1].minor.yy192 = 0;}
|
|
+ case 64: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */
|
|
+{yymsp[-1].minor.yy394 = 0;}
|
|
break;
|
|
- case 64: /* tconscomma ::= COMMA */
|
|
+ case 66: /* tconscomma ::= COMMA */
|
|
{pParse->constraintName.n = 0;}
|
|
break;
|
|
- case 66: /* tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */
|
|
-{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy242,yymsp[0].minor.yy192,yymsp[-2].minor.yy192,0);}
|
|
+ case 68: /* tcons ::= PRIMARY KEY LP sortlist autoinc RP onconf */
|
|
+{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy322,yymsp[0].minor.yy394,yymsp[-2].minor.yy394,0);}
|
|
break;
|
|
- case 67: /* tcons ::= UNIQUE LP sortlist RP onconf */
|
|
-{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy242,yymsp[0].minor.yy192,0,0,0,0,
|
|
+ case 69: /* tcons ::= UNIQUE LP sortlist RP onconf */
|
|
+{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy322,yymsp[0].minor.yy394,0,0,0,0,
|
|
SQLITE_IDXTYPE_UNIQUE);}
|
|
break;
|
|
- case 68: /* tcons ::= CHECK LP expr RP onconf */
|
|
-{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy202);}
|
|
+ case 70: /* tcons ::= CHECK LP expr RP onconf */
|
|
+{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy528,yymsp[-3].minor.yy0.z,yymsp[-1].minor.yy0.z);}
|
|
break;
|
|
- case 69: /* tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */
|
|
+ case 71: /* tcons ::= FOREIGN KEY LP eidlist RP REFERENCES nm eidlist_opt refargs defer_subclause_opt */
|
|
{
|
|
- sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy242, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy242, yymsp[-1].minor.yy192);
|
|
- sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy192);
|
|
+ sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy322, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy322, yymsp[-1].minor.yy394);
|
|
+ sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy394);
|
|
}
|
|
break;
|
|
- case 71: /* onconf ::= */
|
|
- case 73: /* orconf ::= */ yytestcase(yyruleno==73);
|
|
-{yymsp[1].minor.yy192 = OE_Default;}
|
|
+ case 73: /* onconf ::= */
|
|
+ case 75: /* orconf ::= */ yytestcase(yyruleno==75);
|
|
+{yymsp[1].minor.yy394 = OE_Default;}
|
|
break;
|
|
- case 72: /* onconf ::= ON CONFLICT resolvetype */
|
|
-{yymsp[-2].minor.yy192 = yymsp[0].minor.yy192;}
|
|
+ case 74: /* onconf ::= ON CONFLICT resolvetype */
|
|
+{yymsp[-2].minor.yy394 = yymsp[0].minor.yy394;}
|
|
break;
|
|
- case 75: /* resolvetype ::= IGNORE */
|
|
-{yymsp[0].minor.yy192 = OE_Ignore;}
|
|
+ case 77: /* resolvetype ::= IGNORE */
|
|
+{yymsp[0].minor.yy394 = OE_Ignore;}
|
|
break;
|
|
- case 76: /* resolvetype ::= REPLACE */
|
|
- case 163: /* insert_cmd ::= REPLACE */ yytestcase(yyruleno==163);
|
|
-{yymsp[0].minor.yy192 = OE_Replace;}
|
|
+ case 78: /* resolvetype ::= REPLACE */
|
|
+ case 172: /* insert_cmd ::= REPLACE */ yytestcase(yyruleno==172);
|
|
+{yymsp[0].minor.yy394 = OE_Replace;}
|
|
break;
|
|
- case 77: /* cmd ::= DROP TABLE ifexists fullname */
|
|
+ case 79: /* cmd ::= DROP TABLE ifexists fullname */
|
|
{
|
|
- sqlite3DropTable(pParse, yymsp[0].minor.yy47, 0, yymsp[-1].minor.yy192);
|
|
+ sqlite3DropTable(pParse, yymsp[0].minor.yy131, 0, yymsp[-1].minor.yy394);
|
|
}
|
|
break;
|
|
- case 80: /* cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */
|
|
+ case 82: /* cmd ::= createkw temp VIEW ifnotexists nm dbnm eidlist_opt AS select */
|
|
{
|
|
- sqlite3CreateView(pParse, &yymsp[-8].minor.yy0, &yymsp[-4].minor.yy0, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy242, yymsp[0].minor.yy539, yymsp[-7].minor.yy192, yymsp[-5].minor.yy192);
|
|
+ sqlite3CreateView(pParse, &yymsp[-8].minor.yy0, &yymsp[-4].minor.yy0, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy322, yymsp[0].minor.yy47, yymsp[-7].minor.yy394, yymsp[-5].minor.yy394);
|
|
}
|
|
break;
|
|
- case 81: /* cmd ::= DROP VIEW ifexists fullname */
|
|
+ case 83: /* cmd ::= DROP VIEW ifexists fullname */
|
|
{
|
|
- sqlite3DropTable(pParse, yymsp[0].minor.yy47, 1, yymsp[-1].minor.yy192);
|
|
+ sqlite3DropTable(pParse, yymsp[0].minor.yy131, 1, yymsp[-1].minor.yy394);
|
|
}
|
|
break;
|
|
- case 82: /* cmd ::= select */
|
|
+ case 84: /* cmd ::= select */
|
|
{
|
|
- SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0};
|
|
- sqlite3Select(pParse, yymsp[0].minor.yy539, &dest);
|
|
- sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy539);
|
|
+ SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0, 0};
|
|
+ sqlite3Select(pParse, yymsp[0].minor.yy47, &dest);
|
|
+ sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy47);
|
|
}
|
|
break;
|
|
- case 83: /* select ::= WITH wqlist selectnowith */
|
|
-{
|
|
- Select *p = yymsp[0].minor.yy539;
|
|
- if( p ){
|
|
- p->pWith = yymsp[-1].minor.yy131;
|
|
- parserDoubleLinkSelect(pParse, p);
|
|
- }else{
|
|
- sqlite3WithDelete(pParse->db, yymsp[-1].minor.yy131);
|
|
- }
|
|
- yymsp[-2].minor.yy539 = p;
|
|
-}
|
|
+ case 85: /* select ::= WITH wqlist selectnowith */
|
|
+{yymsp[-2].minor.yy47 = attachWithToSelect(pParse,yymsp[0].minor.yy47,yymsp[-1].minor.yy521);}
|
|
break;
|
|
- case 84: /* select ::= WITH RECURSIVE wqlist selectnowith */
|
|
-{
|
|
- Select *p = yymsp[0].minor.yy539;
|
|
- if( p ){
|
|
- p->pWith = yymsp[-1].minor.yy131;
|
|
- parserDoubleLinkSelect(pParse, p);
|
|
- }else{
|
|
- sqlite3WithDelete(pParse->db, yymsp[-1].minor.yy131);
|
|
- }
|
|
- yymsp[-3].minor.yy539 = p;
|
|
-}
|
|
+ case 86: /* select ::= WITH RECURSIVE wqlist selectnowith */
|
|
+{yymsp[-3].minor.yy47 = attachWithToSelect(pParse,yymsp[0].minor.yy47,yymsp[-1].minor.yy521);}
|
|
break;
|
|
- case 85: /* select ::= selectnowith */
|
|
+ case 87: /* select ::= selectnowith */
|
|
{
|
|
- Select *p = yymsp[0].minor.yy539;
|
|
+ Select *p = yymsp[0].minor.yy47;
|
|
if( p ){
|
|
parserDoubleLinkSelect(pParse, p);
|
|
}
|
|
- yymsp[0].minor.yy539 = p; /*A-overwrites-X*/
|
|
+ yymsp[0].minor.yy47 = p; /*A-overwrites-X*/
|
|
}
|
|
break;
|
|
- case 86: /* selectnowith ::= selectnowith multiselect_op oneselect */
|
|
+ case 88: /* selectnowith ::= selectnowith multiselect_op oneselect */
|
|
{
|
|
- Select *pRhs = yymsp[0].minor.yy539;
|
|
- Select *pLhs = yymsp[-2].minor.yy539;
|
|
+ Select *pRhs = yymsp[0].minor.yy47;
|
|
+ Select *pLhs = yymsp[-2].minor.yy47;
|
|
if( pRhs && pRhs->pPrior ){
|
|
SrcList *pFrom;
|
|
Token x;
|
|
x.n = 0;
|
|
parserDoubleLinkSelect(pParse, pRhs);
|
|
- pFrom = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&x,pRhs,0,0);
|
|
+ pFrom = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&x,pRhs,0);
|
|
pRhs = sqlite3SelectNew(pParse,0,pFrom,0,0,0,0,0,0);
|
|
}
|
|
if( pRhs ){
|
|
- pRhs->op = (u8)yymsp[-1].minor.yy192;
|
|
+ pRhs->op = (u8)yymsp[-1].minor.yy394;
|
|
pRhs->pPrior = pLhs;
|
|
if( ALWAYS(pLhs) ) pLhs->selFlags &= ~SF_MultiValue;
|
|
pRhs->selFlags &= ~SF_MultiValue;
|
|
- if( yymsp[-1].minor.yy192!=TK_ALL ) pParse->hasCompound = 1;
|
|
+ if( yymsp[-1].minor.yy394!=TK_ALL ) pParse->hasCompound = 1;
|
|
}else{
|
|
sqlite3SelectDelete(pParse->db, pLhs);
|
|
}
|
|
- yymsp[-2].minor.yy539 = pRhs;
|
|
+ yymsp[-2].minor.yy47 = pRhs;
|
|
}
|
|
break;
|
|
- case 87: /* multiselect_op ::= UNION */
|
|
- case 89: /* multiselect_op ::= EXCEPT|INTERSECT */ yytestcase(yyruleno==89);
|
|
-{yymsp[0].minor.yy192 = yymsp[0].major; /*A-overwrites-OP*/}
|
|
+ case 89: /* multiselect_op ::= UNION */
|
|
+ case 91: /* multiselect_op ::= EXCEPT|INTERSECT */ yytestcase(yyruleno==91);
|
|
+{yymsp[0].minor.yy394 = yymsp[0].major; /*A-overwrites-OP*/}
|
|
break;
|
|
- case 88: /* multiselect_op ::= UNION ALL */
|
|
-{yymsp[-1].minor.yy192 = TK_ALL;}
|
|
+ case 90: /* multiselect_op ::= UNION ALL */
|
|
+{yymsp[-1].minor.yy394 = TK_ALL;}
|
|
break;
|
|
- case 90: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
|
|
+ case 92: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
|
|
{
|
|
- yymsp[-8].minor.yy539 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy242,yymsp[-5].minor.yy47,yymsp[-4].minor.yy202,yymsp[-3].minor.yy242,yymsp[-2].minor.yy202,yymsp[-1].minor.yy242,yymsp[-7].minor.yy192,yymsp[0].minor.yy202);
|
|
+ yymsp[-8].minor.yy47 = sqlite3SelectNew(pParse,yymsp[-6].minor.yy322,yymsp[-5].minor.yy131,yymsp[-4].minor.yy528,yymsp[-3].minor.yy322,yymsp[-2].minor.yy528,yymsp[-1].minor.yy322,yymsp[-7].minor.yy394,yymsp[0].minor.yy528);
|
|
}
|
|
break;
|
|
- case 91: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */
|
|
+ case 93: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt window_clause orderby_opt limit_opt */
|
|
{
|
|
- yymsp[-9].minor.yy539 = sqlite3SelectNew(pParse,yymsp[-7].minor.yy242,yymsp[-6].minor.yy47,yymsp[-5].minor.yy202,yymsp[-4].minor.yy242,yymsp[-3].minor.yy202,yymsp[-1].minor.yy242,yymsp[-8].minor.yy192,yymsp[0].minor.yy202);
|
|
- if( yymsp[-9].minor.yy539 ){
|
|
- yymsp[-9].minor.yy539->pWinDefn = yymsp[-2].minor.yy303;
|
|
+ yymsp[-9].minor.yy47 = sqlite3SelectNew(pParse,yymsp[-7].minor.yy322,yymsp[-6].minor.yy131,yymsp[-5].minor.yy528,yymsp[-4].minor.yy322,yymsp[-3].minor.yy528,yymsp[-1].minor.yy322,yymsp[-8].minor.yy394,yymsp[0].minor.yy528);
|
|
+ if( yymsp[-9].minor.yy47 ){
|
|
+ yymsp[-9].minor.yy47->pWinDefn = yymsp[-2].minor.yy41;
|
|
}else{
|
|
- sqlite3WindowListDelete(pParse->db, yymsp[-2].minor.yy303);
|
|
+ sqlite3WindowListDelete(pParse->db, yymsp[-2].minor.yy41);
|
|
}
|
|
}
|
|
break;
|
|
- case 92: /* values ::= VALUES LP nexprlist RP */
|
|
+ case 94: /* values ::= VALUES LP nexprlist RP */
|
|
{
|
|
- yymsp[-3].minor.yy539 = sqlite3SelectNew(pParse,yymsp[-1].minor.yy242,0,0,0,0,0,SF_Values,0);
|
|
+ yymsp[-3].minor.yy47 = sqlite3SelectNew(pParse,yymsp[-1].minor.yy322,0,0,0,0,0,SF_Values,0);
|
|
}
|
|
break;
|
|
- case 93: /* values ::= values COMMA LP nexprlist RP */
|
|
+ case 95: /* values ::= values COMMA LP nexprlist RP */
|
|
{
|
|
- Select *pRight, *pLeft = yymsp[-4].minor.yy539;
|
|
- pRight = sqlite3SelectNew(pParse,yymsp[-1].minor.yy242,0,0,0,0,0,SF_Values|SF_MultiValue,0);
|
|
+ Select *pRight, *pLeft = yymsp[-4].minor.yy47;
|
|
+ pRight = sqlite3SelectNew(pParse,yymsp[-1].minor.yy322,0,0,0,0,0,SF_Values|SF_MultiValue,0);
|
|
if( ALWAYS(pLeft) ) pLeft->selFlags &= ~SF_MultiValue;
|
|
if( pRight ){
|
|
pRight->op = TK_ALL;
|
|
pRight->pPrior = pLeft;
|
|
- yymsp[-4].minor.yy539 = pRight;
|
|
+ yymsp[-4].minor.yy47 = pRight;
|
|
}else{
|
|
- yymsp[-4].minor.yy539 = pLeft;
|
|
+ yymsp[-4].minor.yy47 = pLeft;
|
|
}
|
|
}
|
|
break;
|
|
- case 94: /* distinct ::= DISTINCT */
|
|
-{yymsp[0].minor.yy192 = SF_Distinct;}
|
|
+ case 96: /* distinct ::= DISTINCT */
|
|
+{yymsp[0].minor.yy394 = SF_Distinct;}
|
|
break;
|
|
- case 95: /* distinct ::= ALL */
|
|
-{yymsp[0].minor.yy192 = SF_All;}
|
|
+ case 97: /* distinct ::= ALL */
|
|
+{yymsp[0].minor.yy394 = SF_All;}
|
|
break;
|
|
- case 97: /* sclp ::= */
|
|
- case 130: /* orderby_opt ::= */ yytestcase(yyruleno==130);
|
|
- case 140: /* groupby_opt ::= */ yytestcase(yyruleno==140);
|
|
- case 220: /* exprlist ::= */ yytestcase(yyruleno==220);
|
|
- case 223: /* paren_exprlist ::= */ yytestcase(yyruleno==223);
|
|
- case 228: /* eidlist_opt ::= */ yytestcase(yyruleno==228);
|
|
-{yymsp[1].minor.yy242 = 0;}
|
|
+ case 99: /* sclp ::= */
|
|
+ case 132: /* orderby_opt ::= */ yytestcase(yyruleno==132);
|
|
+ case 142: /* groupby_opt ::= */ yytestcase(yyruleno==142);
|
|
+ case 232: /* exprlist ::= */ yytestcase(yyruleno==232);
|
|
+ case 235: /* paren_exprlist ::= */ yytestcase(yyruleno==235);
|
|
+ case 240: /* eidlist_opt ::= */ yytestcase(yyruleno==240);
|
|
+{yymsp[1].minor.yy322 = 0;}
|
|
break;
|
|
- case 98: /* selcollist ::= sclp scanpt expr scanpt as */
|
|
+ case 100: /* selcollist ::= sclp scanpt expr scanpt as */
|
|
{
|
|
- yymsp[-4].minor.yy242 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy242, yymsp[-2].minor.yy202);
|
|
- if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy242, &yymsp[0].minor.yy0, 1);
|
|
- sqlite3ExprListSetSpan(pParse,yymsp[-4].minor.yy242,yymsp[-3].minor.yy436,yymsp[-1].minor.yy436);
|
|
+ yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy322, yymsp[-2].minor.yy528);
|
|
+ if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy322, &yymsp[0].minor.yy0, 1);
|
|
+ sqlite3ExprListSetSpan(pParse,yymsp[-4].minor.yy322,yymsp[-3].minor.yy522,yymsp[-1].minor.yy522);
|
|
}
|
|
break;
|
|
- case 99: /* selcollist ::= sclp scanpt STAR */
|
|
+ case 101: /* selcollist ::= sclp scanpt STAR */
|
|
{
|
|
Expr *p = sqlite3Expr(pParse->db, TK_ASTERISK, 0);
|
|
- yymsp[-2].minor.yy242 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy242, p);
|
|
+ yymsp[-2].minor.yy322 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy322, p);
|
|
}
|
|
break;
|
|
- case 100: /* selcollist ::= sclp scanpt nm DOT STAR */
|
|
+ case 102: /* selcollist ::= sclp scanpt nm DOT STAR */
|
|
{
|
|
Expr *pRight = sqlite3PExpr(pParse, TK_ASTERISK, 0, 0);
|
|
- Expr *pLeft = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1);
|
|
+ Expr *pLeft = tokenExpr(pParse, TK_ID, yymsp[-2].minor.yy0);
|
|
Expr *pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight);
|
|
- yymsp[-4].minor.yy242 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy242, pDot);
|
|
+ yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy322, pDot);
|
|
}
|
|
break;
|
|
- case 101: /* as ::= AS nm */
|
|
- case 112: /* dbnm ::= DOT nm */ yytestcase(yyruleno==112);
|
|
- case 244: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==244);
|
|
- case 245: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==245);
|
|
+ case 103: /* as ::= AS nm */
|
|
+ case 115: /* dbnm ::= DOT nm */ yytestcase(yyruleno==115);
|
|
+ case 256: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==256);
|
|
+ case 257: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==257);
|
|
{yymsp[-1].minor.yy0 = yymsp[0].minor.yy0;}
|
|
break;
|
|
- case 103: /* from ::= */
|
|
-{yymsp[1].minor.yy47 = sqlite3DbMallocZero(pParse->db, sizeof(*yymsp[1].minor.yy47));}
|
|
+ case 105: /* from ::= */
|
|
+ case 108: /* stl_prefix ::= */ yytestcase(yyruleno==108);
|
|
+{yymsp[1].minor.yy131 = 0;}
|
|
break;
|
|
- case 104: /* from ::= FROM seltablist */
|
|
+ case 106: /* from ::= FROM seltablist */
|
|
{
|
|
- yymsp[-1].minor.yy47 = yymsp[0].minor.yy47;
|
|
- sqlite3SrcListShiftJoinType(yymsp[-1].minor.yy47);
|
|
+ yymsp[-1].minor.yy131 = yymsp[0].minor.yy131;
|
|
+ sqlite3SrcListShiftJoinType(pParse,yymsp[-1].minor.yy131);
|
|
}
|
|
break;
|
|
- case 105: /* stl_prefix ::= seltablist joinop */
|
|
+ case 107: /* stl_prefix ::= seltablist joinop */
|
|
{
|
|
- if( ALWAYS(yymsp[-1].minor.yy47 && yymsp[-1].minor.yy47->nSrc>0) ) yymsp[-1].minor.yy47->a[yymsp[-1].minor.yy47->nSrc-1].fg.jointype = (u8)yymsp[0].minor.yy192;
|
|
+ if( ALWAYS(yymsp[-1].minor.yy131 && yymsp[-1].minor.yy131->nSrc>0) ) yymsp[-1].minor.yy131->a[yymsp[-1].minor.yy131->nSrc-1].fg.jointype = (u8)yymsp[0].minor.yy394;
|
|
}
|
|
break;
|
|
- case 106: /* stl_prefix ::= */
|
|
-{yymsp[1].minor.yy47 = 0;}
|
|
+ case 109: /* seltablist ::= stl_prefix nm dbnm as on_using */
|
|
+{
|
|
+ yymsp[-4].minor.yy131 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-4].minor.yy131,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy561);
|
|
+}
|
|
break;
|
|
- case 107: /* seltablist ::= stl_prefix nm dbnm as indexed_opt on_opt using_opt */
|
|
+ case 110: /* seltablist ::= stl_prefix nm dbnm as indexed_by on_using */
|
|
{
|
|
- yymsp[-6].minor.yy47 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy47,&yymsp[-5].minor.yy0,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,0,yymsp[-1].minor.yy202,yymsp[0].minor.yy600);
|
|
- sqlite3SrcListIndexedBy(pParse, yymsp[-6].minor.yy47, &yymsp[-2].minor.yy0);
|
|
+ yymsp[-5].minor.yy131 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy131,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,0,&yymsp[0].minor.yy561);
|
|
+ sqlite3SrcListIndexedBy(pParse, yymsp[-5].minor.yy131, &yymsp[-1].minor.yy0);
|
|
}
|
|
break;
|
|
- case 108: /* seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_opt using_opt */
|
|
+ case 111: /* seltablist ::= stl_prefix nm dbnm LP exprlist RP as on_using */
|
|
{
|
|
- yymsp[-8].minor.yy47 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-8].minor.yy47,&yymsp[-7].minor.yy0,&yymsp[-6].minor.yy0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy202,yymsp[0].minor.yy600);
|
|
- sqlite3SrcListFuncArgs(pParse, yymsp[-8].minor.yy47, yymsp[-4].minor.yy242);
|
|
+ yymsp[-7].minor.yy131 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-7].minor.yy131,&yymsp[-6].minor.yy0,&yymsp[-5].minor.yy0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy561);
|
|
+ sqlite3SrcListFuncArgs(pParse, yymsp[-7].minor.yy131, yymsp[-3].minor.yy322);
|
|
}
|
|
break;
|
|
- case 109: /* seltablist ::= stl_prefix LP select RP as on_opt using_opt */
|
|
+ case 112: /* seltablist ::= stl_prefix LP select RP as on_using */
|
|
{
|
|
- yymsp[-6].minor.yy47 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy47,0,0,&yymsp[-2].minor.yy0,yymsp[-4].minor.yy539,yymsp[-1].minor.yy202,yymsp[0].minor.yy600);
|
|
+ yymsp[-5].minor.yy131 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy131,0,0,&yymsp[-1].minor.yy0,yymsp[-3].minor.yy47,&yymsp[0].minor.yy561);
|
|
}
|
|
break;
|
|
- case 110: /* seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */
|
|
+ case 113: /* seltablist ::= stl_prefix LP seltablist RP as on_using */
|
|
{
|
|
- if( yymsp[-6].minor.yy47==0 && yymsp[-2].minor.yy0.n==0 && yymsp[-1].minor.yy202==0 && yymsp[0].minor.yy600==0 ){
|
|
- yymsp[-6].minor.yy47 = yymsp[-4].minor.yy47;
|
|
- }else if( yymsp[-4].minor.yy47->nSrc==1 ){
|
|
- yymsp[-6].minor.yy47 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy47,0,0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy202,yymsp[0].minor.yy600);
|
|
- if( yymsp[-6].minor.yy47 ){
|
|
- struct SrcList_item *pNew = &yymsp[-6].minor.yy47->a[yymsp[-6].minor.yy47->nSrc-1];
|
|
- struct SrcList_item *pOld = yymsp[-4].minor.yy47->a;
|
|
+ if( yymsp[-5].minor.yy131==0 && yymsp[-1].minor.yy0.n==0 && yymsp[0].minor.yy561.pOn==0 && yymsp[0].minor.yy561.pUsing==0 ){
|
|
+ yymsp[-5].minor.yy131 = yymsp[-3].minor.yy131;
|
|
+ }else if( yymsp[-3].minor.yy131->nSrc==1 ){
|
|
+ yymsp[-5].minor.yy131 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy131,0,0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy561);
|
|
+ if( yymsp[-5].minor.yy131 ){
|
|
+ SrcItem *pNew = &yymsp[-5].minor.yy131->a[yymsp[-5].minor.yy131->nSrc-1];
|
|
+ SrcItem *pOld = yymsp[-3].minor.yy131->a;
|
|
pNew->zName = pOld->zName;
|
|
pNew->zDatabase = pOld->zDatabase;
|
|
pNew->pSelect = pOld->pSelect;
|
|
+ if( pNew->pSelect && (pNew->pSelect->selFlags & SF_NestedFrom)!=0 ){
|
|
+ pNew->fg.isNestedFrom = 1;
|
|
+ }
|
|
if( pOld->fg.isTabFunc ){
|
|
pNew->u1.pFuncArg = pOld->u1.pFuncArg;
|
|
pOld->u1.pFuncArg = 0;
|
|
@@ -156084,249 +170880,277 @@ static YYACTIONTYPE yy_reduce(
|
|
pOld->zName = pOld->zDatabase = 0;
|
|
pOld->pSelect = 0;
|
|
}
|
|
- sqlite3SrcListDelete(pParse->db, yymsp[-4].minor.yy47);
|
|
+ sqlite3SrcListDelete(pParse->db, yymsp[-3].minor.yy131);
|
|
}else{
|
|
Select *pSubquery;
|
|
- sqlite3SrcListShiftJoinType(yymsp[-4].minor.yy47);
|
|
- pSubquery = sqlite3SelectNew(pParse,0,yymsp[-4].minor.yy47,0,0,0,0,SF_NestedFrom,0);
|
|
- yymsp[-6].minor.yy47 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy47,0,0,&yymsp[-2].minor.yy0,pSubquery,yymsp[-1].minor.yy202,yymsp[0].minor.yy600);
|
|
+ sqlite3SrcListShiftJoinType(pParse,yymsp[-3].minor.yy131);
|
|
+ pSubquery = sqlite3SelectNew(pParse,0,yymsp[-3].minor.yy131,0,0,0,0,SF_NestedFrom,0);
|
|
+ yymsp[-5].minor.yy131 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy131,0,0,&yymsp[-1].minor.yy0,pSubquery,&yymsp[0].minor.yy561);
|
|
}
|
|
}
|
|
break;
|
|
- case 111: /* dbnm ::= */
|
|
- case 125: /* indexed_opt ::= */ yytestcase(yyruleno==125);
|
|
+ case 114: /* dbnm ::= */
|
|
+ case 129: /* indexed_opt ::= */ yytestcase(yyruleno==129);
|
|
{yymsp[1].minor.yy0.z=0; yymsp[1].minor.yy0.n=0;}
|
|
break;
|
|
- case 113: /* fullname ::= nm */
|
|
+ case 116: /* fullname ::= nm */
|
|
{
|
|
- yylhsminor.yy47 = sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0);
|
|
- if( IN_RENAME_OBJECT && yylhsminor.yy47 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy47->a[0].zName, &yymsp[0].minor.yy0);
|
|
+ yylhsminor.yy131 = sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0);
|
|
+ if( IN_RENAME_OBJECT && yylhsminor.yy131 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy131->a[0].zName, &yymsp[0].minor.yy0);
|
|
}
|
|
- yymsp[0].minor.yy47 = yylhsminor.yy47;
|
|
+ yymsp[0].minor.yy131 = yylhsminor.yy131;
|
|
break;
|
|
- case 114: /* fullname ::= nm DOT nm */
|
|
+ case 117: /* fullname ::= nm DOT nm */
|
|
{
|
|
- yylhsminor.yy47 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0);
|
|
- if( IN_RENAME_OBJECT && yylhsminor.yy47 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy47->a[0].zName, &yymsp[0].minor.yy0);
|
|
+ yylhsminor.yy131 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0);
|
|
+ if( IN_RENAME_OBJECT && yylhsminor.yy131 ) sqlite3RenameTokenMap(pParse, yylhsminor.yy131->a[0].zName, &yymsp[0].minor.yy0);
|
|
}
|
|
- yymsp[-2].minor.yy47 = yylhsminor.yy47;
|
|
+ yymsp[-2].minor.yy131 = yylhsminor.yy131;
|
|
break;
|
|
- case 115: /* xfullname ::= nm */
|
|
-{yymsp[0].minor.yy47 = sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0); /*A-overwrites-X*/}
|
|
+ case 118: /* xfullname ::= nm */
|
|
+{yymsp[0].minor.yy131 = sqlite3SrcListAppend(pParse,0,&yymsp[0].minor.yy0,0); /*A-overwrites-X*/}
|
|
break;
|
|
- case 116: /* xfullname ::= nm DOT nm */
|
|
-{yymsp[-2].minor.yy47 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/}
|
|
+ case 119: /* xfullname ::= nm DOT nm */
|
|
+{yymsp[-2].minor.yy131 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/}
|
|
break;
|
|
- case 117: /* xfullname ::= nm DOT nm AS nm */
|
|
+ case 120: /* xfullname ::= nm DOT nm AS nm */
|
|
{
|
|
- yymsp[-4].minor.yy47 = sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,&yymsp[-2].minor.yy0); /*A-overwrites-X*/
|
|
- if( yymsp[-4].minor.yy47 ) yymsp[-4].minor.yy47->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0);
|
|
+ yymsp[-4].minor.yy131 = sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,&yymsp[-2].minor.yy0); /*A-overwrites-X*/
|
|
+ if( yymsp[-4].minor.yy131 ) yymsp[-4].minor.yy131->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0);
|
|
}
|
|
break;
|
|
- case 118: /* xfullname ::= nm AS nm */
|
|
-{
|
|
- yymsp[-2].minor.yy47 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,0); /*A-overwrites-X*/
|
|
- if( yymsp[-2].minor.yy47 ) yymsp[-2].minor.yy47->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0);
|
|
+ case 121: /* xfullname ::= nm AS nm */
|
|
+{
|
|
+ yymsp[-2].minor.yy131 = sqlite3SrcListAppend(pParse,0,&yymsp[-2].minor.yy0,0); /*A-overwrites-X*/
|
|
+ if( yymsp[-2].minor.yy131 ) yymsp[-2].minor.yy131->a[0].zAlias = sqlite3NameFromToken(pParse->db, &yymsp[0].minor.yy0);
|
|
}
|
|
break;
|
|
- case 119: /* joinop ::= COMMA|JOIN */
|
|
-{ yymsp[0].minor.yy192 = JT_INNER; }
|
|
+ case 122: /* joinop ::= COMMA|JOIN */
|
|
+{ yymsp[0].minor.yy394 = JT_INNER; }
|
|
+ break;
|
|
+ case 123: /* joinop ::= JOIN_KW JOIN */
|
|
+{yymsp[-1].minor.yy394 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); /*X-overwrites-A*/}
|
|
break;
|
|
- case 120: /* joinop ::= JOIN_KW JOIN */
|
|
-{yymsp[-1].minor.yy192 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); /*X-overwrites-A*/}
|
|
+ case 124: /* joinop ::= JOIN_KW nm JOIN */
|
|
+{yymsp[-2].minor.yy394 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); /*X-overwrites-A*/}
|
|
break;
|
|
- case 121: /* joinop ::= JOIN_KW nm JOIN */
|
|
-{yymsp[-2].minor.yy192 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); /*X-overwrites-A*/}
|
|
+ case 125: /* joinop ::= JOIN_KW nm nm JOIN */
|
|
+{yymsp[-3].minor.yy394 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);/*X-overwrites-A*/}
|
|
break;
|
|
- case 122: /* joinop ::= JOIN_KW nm nm JOIN */
|
|
-{yymsp[-3].minor.yy192 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);/*X-overwrites-A*/}
|
|
+ case 126: /* on_using ::= ON expr */
|
|
+{yymsp[-1].minor.yy561.pOn = yymsp[0].minor.yy528; yymsp[-1].minor.yy561.pUsing = 0;}
|
|
break;
|
|
- case 123: /* on_opt ::= ON expr */
|
|
- case 143: /* having_opt ::= HAVING expr */ yytestcase(yyruleno==143);
|
|
- case 150: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==150);
|
|
- case 216: /* case_else ::= ELSE expr */ yytestcase(yyruleno==216);
|
|
- case 237: /* vinto ::= INTO expr */ yytestcase(yyruleno==237);
|
|
-{yymsp[-1].minor.yy202 = yymsp[0].minor.yy202;}
|
|
+ case 127: /* on_using ::= USING LP idlist RP */
|
|
+{yymsp[-3].minor.yy561.pOn = 0; yymsp[-3].minor.yy561.pUsing = yymsp[-1].minor.yy254;}
|
|
break;
|
|
- case 124: /* on_opt ::= */
|
|
- case 142: /* having_opt ::= */ yytestcase(yyruleno==142);
|
|
- case 144: /* limit_opt ::= */ yytestcase(yyruleno==144);
|
|
- case 149: /* where_opt ::= */ yytestcase(yyruleno==149);
|
|
- case 217: /* case_else ::= */ yytestcase(yyruleno==217);
|
|
- case 219: /* case_operand ::= */ yytestcase(yyruleno==219);
|
|
- case 238: /* vinto ::= */ yytestcase(yyruleno==238);
|
|
-{yymsp[1].minor.yy202 = 0;}
|
|
+ case 128: /* on_using ::= */
|
|
+{yymsp[1].minor.yy561.pOn = 0; yymsp[1].minor.yy561.pUsing = 0;}
|
|
break;
|
|
- case 126: /* indexed_opt ::= INDEXED BY nm */
|
|
+ case 130: /* indexed_by ::= INDEXED BY nm */
|
|
{yymsp[-2].minor.yy0 = yymsp[0].minor.yy0;}
|
|
break;
|
|
- case 127: /* indexed_opt ::= NOT INDEXED */
|
|
+ case 131: /* indexed_by ::= NOT INDEXED */
|
|
{yymsp[-1].minor.yy0.z=0; yymsp[-1].minor.yy0.n=1;}
|
|
break;
|
|
- case 128: /* using_opt ::= USING LP idlist RP */
|
|
-{yymsp[-3].minor.yy600 = yymsp[-1].minor.yy600;}
|
|
+ case 133: /* orderby_opt ::= ORDER BY sortlist */
|
|
+ case 143: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==143);
|
|
+{yymsp[-2].minor.yy322 = yymsp[0].minor.yy322;}
|
|
break;
|
|
- case 129: /* using_opt ::= */
|
|
- case 164: /* idlist_opt ::= */ yytestcase(yyruleno==164);
|
|
-{yymsp[1].minor.yy600 = 0;}
|
|
- break;
|
|
- case 131: /* orderby_opt ::= ORDER BY sortlist */
|
|
- case 141: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==141);
|
|
-{yymsp[-2].minor.yy242 = yymsp[0].minor.yy242;}
|
|
- break;
|
|
- case 132: /* sortlist ::= sortlist COMMA expr sortorder nulls */
|
|
+ case 134: /* sortlist ::= sortlist COMMA expr sortorder nulls */
|
|
{
|
|
- yymsp[-4].minor.yy242 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy242,yymsp[-2].minor.yy202);
|
|
- sqlite3ExprListSetSortOrder(yymsp[-4].minor.yy242,yymsp[-1].minor.yy192,yymsp[0].minor.yy192);
|
|
+ yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy322,yymsp[-2].minor.yy528);
|
|
+ sqlite3ExprListSetSortOrder(yymsp[-4].minor.yy322,yymsp[-1].minor.yy394,yymsp[0].minor.yy394);
|
|
}
|
|
break;
|
|
- case 133: /* sortlist ::= expr sortorder nulls */
|
|
+ case 135: /* sortlist ::= expr sortorder nulls */
|
|
{
|
|
- yymsp[-2].minor.yy242 = sqlite3ExprListAppend(pParse,0,yymsp[-2].minor.yy202); /*A-overwrites-Y*/
|
|
- sqlite3ExprListSetSortOrder(yymsp[-2].minor.yy242,yymsp[-1].minor.yy192,yymsp[0].minor.yy192);
|
|
+ yymsp[-2].minor.yy322 = sqlite3ExprListAppend(pParse,0,yymsp[-2].minor.yy528); /*A-overwrites-Y*/
|
|
+ sqlite3ExprListSetSortOrder(yymsp[-2].minor.yy322,yymsp[-1].minor.yy394,yymsp[0].minor.yy394);
|
|
}
|
|
break;
|
|
- case 134: /* sortorder ::= ASC */
|
|
-{yymsp[0].minor.yy192 = SQLITE_SO_ASC;}
|
|
+ case 136: /* sortorder ::= ASC */
|
|
+{yymsp[0].minor.yy394 = SQLITE_SO_ASC;}
|
|
+ break;
|
|
+ case 137: /* sortorder ::= DESC */
|
|
+{yymsp[0].minor.yy394 = SQLITE_SO_DESC;}
|
|
+ break;
|
|
+ case 138: /* sortorder ::= */
|
|
+ case 141: /* nulls ::= */ yytestcase(yyruleno==141);
|
|
+{yymsp[1].minor.yy394 = SQLITE_SO_UNDEFINED;}
|
|
break;
|
|
- case 135: /* sortorder ::= DESC */
|
|
-{yymsp[0].minor.yy192 = SQLITE_SO_DESC;}
|
|
+ case 139: /* nulls ::= NULLS FIRST */
|
|
+{yymsp[-1].minor.yy394 = SQLITE_SO_ASC;}
|
|
break;
|
|
- case 136: /* sortorder ::= */
|
|
- case 139: /* nulls ::= */ yytestcase(yyruleno==139);
|
|
-{yymsp[1].minor.yy192 = SQLITE_SO_UNDEFINED;}
|
|
+ case 140: /* nulls ::= NULLS LAST */
|
|
+{yymsp[-1].minor.yy394 = SQLITE_SO_DESC;}
|
|
break;
|
|
- case 137: /* nulls ::= NULLS FIRST */
|
|
-{yymsp[-1].minor.yy192 = SQLITE_SO_ASC;}
|
|
+ case 144: /* having_opt ::= */
|
|
+ case 146: /* limit_opt ::= */ yytestcase(yyruleno==146);
|
|
+ case 151: /* where_opt ::= */ yytestcase(yyruleno==151);
|
|
+ case 153: /* where_opt_ret ::= */ yytestcase(yyruleno==153);
|
|
+ case 229: /* case_else ::= */ yytestcase(yyruleno==229);
|
|
+ case 231: /* case_operand ::= */ yytestcase(yyruleno==231);
|
|
+ case 250: /* vinto ::= */ yytestcase(yyruleno==250);
|
|
+{yymsp[1].minor.yy528 = 0;}
|
|
break;
|
|
- case 138: /* nulls ::= NULLS LAST */
|
|
-{yymsp[-1].minor.yy192 = SQLITE_SO_DESC;}
|
|
+ case 145: /* having_opt ::= HAVING expr */
|
|
+ case 152: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==152);
|
|
+ case 154: /* where_opt_ret ::= WHERE expr */ yytestcase(yyruleno==154);
|
|
+ case 228: /* case_else ::= ELSE expr */ yytestcase(yyruleno==228);
|
|
+ case 249: /* vinto ::= INTO expr */ yytestcase(yyruleno==249);
|
|
+{yymsp[-1].minor.yy528 = yymsp[0].minor.yy528;}
|
|
break;
|
|
- case 145: /* limit_opt ::= LIMIT expr */
|
|
-{yymsp[-1].minor.yy202 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy202,0);}
|
|
+ case 147: /* limit_opt ::= LIMIT expr */
|
|
+{yymsp[-1].minor.yy528 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy528,0);}
|
|
break;
|
|
- case 146: /* limit_opt ::= LIMIT expr OFFSET expr */
|
|
-{yymsp[-3].minor.yy202 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[-2].minor.yy202,yymsp[0].minor.yy202);}
|
|
+ case 148: /* limit_opt ::= LIMIT expr OFFSET expr */
|
|
+{yymsp[-3].minor.yy528 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[-2].minor.yy528,yymsp[0].minor.yy528);}
|
|
break;
|
|
- case 147: /* limit_opt ::= LIMIT expr COMMA expr */
|
|
-{yymsp[-3].minor.yy202 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy202,yymsp[-2].minor.yy202);}
|
|
+ case 149: /* limit_opt ::= LIMIT expr COMMA expr */
|
|
+{yymsp[-3].minor.yy528 = sqlite3PExpr(pParse,TK_LIMIT,yymsp[0].minor.yy528,yymsp[-2].minor.yy528);}
|
|
break;
|
|
- case 148: /* cmd ::= with DELETE FROM xfullname indexed_opt where_opt */
|
|
+ case 150: /* cmd ::= with DELETE FROM xfullname indexed_opt where_opt_ret */
|
|
{
|
|
- sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy47, &yymsp[-1].minor.yy0);
|
|
- sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy47,yymsp[0].minor.yy202,0,0);
|
|
+ sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy131, &yymsp[-1].minor.yy0);
|
|
+ sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy131,yymsp[0].minor.yy528,0,0);
|
|
}
|
|
break;
|
|
- case 151: /* cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist where_opt */
|
|
+ case 155: /* where_opt_ret ::= RETURNING selcollist */
|
|
+{sqlite3AddReturning(pParse,yymsp[0].minor.yy322); yymsp[-1].minor.yy528 = 0;}
|
|
+ break;
|
|
+ case 156: /* where_opt_ret ::= WHERE expr RETURNING selcollist */
|
|
+{sqlite3AddReturning(pParse,yymsp[0].minor.yy322); yymsp[-3].minor.yy528 = yymsp[-2].minor.yy528;}
|
|
+ break;
|
|
+ case 157: /* cmd ::= with UPDATE orconf xfullname indexed_opt SET setlist from where_opt_ret */
|
|
{
|
|
- sqlite3SrcListIndexedBy(pParse, yymsp[-4].minor.yy47, &yymsp[-3].minor.yy0);
|
|
- sqlite3ExprListCheckLength(pParse,yymsp[-1].minor.yy242,"set list");
|
|
- sqlite3Update(pParse,yymsp[-4].minor.yy47,yymsp[-1].minor.yy242,yymsp[0].minor.yy202,yymsp[-5].minor.yy192,0,0,0);
|
|
+ sqlite3SrcListIndexedBy(pParse, yymsp[-5].minor.yy131, &yymsp[-4].minor.yy0);
|
|
+ sqlite3ExprListCheckLength(pParse,yymsp[-2].minor.yy322,"set list");
|
|
+ if( yymsp[-1].minor.yy131 ){
|
|
+ SrcList *pFromClause = yymsp[-1].minor.yy131;
|
|
+ if( pFromClause->nSrc>1 ){
|
|
+ Select *pSubquery;
|
|
+ Token as;
|
|
+ pSubquery = sqlite3SelectNew(pParse,0,pFromClause,0,0,0,0,SF_NestedFrom,0);
|
|
+ as.n = 0;
|
|
+ as.z = 0;
|
|
+ pFromClause = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&as,pSubquery,0);
|
|
+ }
|
|
+ yymsp[-5].minor.yy131 = sqlite3SrcListAppendList(pParse, yymsp[-5].minor.yy131, pFromClause);
|
|
+ }
|
|
+ sqlite3Update(pParse,yymsp[-5].minor.yy131,yymsp[-2].minor.yy322,yymsp[0].minor.yy528,yymsp[-6].minor.yy394,0,0,0);
|
|
}
|
|
break;
|
|
- case 152: /* setlist ::= setlist COMMA nm EQ expr */
|
|
+ case 158: /* setlist ::= setlist COMMA nm EQ expr */
|
|
{
|
|
- yymsp[-4].minor.yy242 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy242, yymsp[0].minor.yy202);
|
|
- sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy242, &yymsp[-2].minor.yy0, 1);
|
|
+ yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy322, yymsp[0].minor.yy528);
|
|
+ sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy322, &yymsp[-2].minor.yy0, 1);
|
|
}
|
|
break;
|
|
- case 153: /* setlist ::= setlist COMMA LP idlist RP EQ expr */
|
|
+ case 159: /* setlist ::= setlist COMMA LP idlist RP EQ expr */
|
|
{
|
|
- yymsp[-6].minor.yy242 = sqlite3ExprListAppendVector(pParse, yymsp[-6].minor.yy242, yymsp[-3].minor.yy600, yymsp[0].minor.yy202);
|
|
+ yymsp[-6].minor.yy322 = sqlite3ExprListAppendVector(pParse, yymsp[-6].minor.yy322, yymsp[-3].minor.yy254, yymsp[0].minor.yy528);
|
|
}
|
|
break;
|
|
- case 154: /* setlist ::= nm EQ expr */
|
|
+ case 160: /* setlist ::= nm EQ expr */
|
|
{
|
|
- yylhsminor.yy242 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy202);
|
|
- sqlite3ExprListSetName(pParse, yylhsminor.yy242, &yymsp[-2].minor.yy0, 1);
|
|
+ yylhsminor.yy322 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy528);
|
|
+ sqlite3ExprListSetName(pParse, yylhsminor.yy322, &yymsp[-2].minor.yy0, 1);
|
|
}
|
|
- yymsp[-2].minor.yy242 = yylhsminor.yy242;
|
|
+ yymsp[-2].minor.yy322 = yylhsminor.yy322;
|
|
break;
|
|
- case 155: /* setlist ::= LP idlist RP EQ expr */
|
|
+ case 161: /* setlist ::= LP idlist RP EQ expr */
|
|
{
|
|
- yymsp[-4].minor.yy242 = sqlite3ExprListAppendVector(pParse, 0, yymsp[-3].minor.yy600, yymsp[0].minor.yy202);
|
|
+ yymsp[-4].minor.yy322 = sqlite3ExprListAppendVector(pParse, 0, yymsp[-3].minor.yy254, yymsp[0].minor.yy528);
|
|
}
|
|
break;
|
|
- case 156: /* cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */
|
|
+ case 162: /* cmd ::= with insert_cmd INTO xfullname idlist_opt select upsert */
|
|
{
|
|
- sqlite3Insert(pParse, yymsp[-3].minor.yy47, yymsp[-1].minor.yy539, yymsp[-2].minor.yy600, yymsp[-5].minor.yy192, yymsp[0].minor.yy318);
|
|
+ sqlite3Insert(pParse, yymsp[-3].minor.yy131, yymsp[-1].minor.yy47, yymsp[-2].minor.yy254, yymsp[-5].minor.yy394, yymsp[0].minor.yy444);
|
|
}
|
|
break;
|
|
- case 157: /* cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES */
|
|
+ case 163: /* cmd ::= with insert_cmd INTO xfullname idlist_opt DEFAULT VALUES returning */
|
|
{
|
|
- sqlite3Insert(pParse, yymsp[-3].minor.yy47, 0, yymsp[-2].minor.yy600, yymsp[-5].minor.yy192, 0);
|
|
+ sqlite3Insert(pParse, yymsp[-4].minor.yy131, 0, yymsp[-3].minor.yy254, yymsp[-6].minor.yy394, 0);
|
|
}
|
|
break;
|
|
- case 158: /* upsert ::= */
|
|
-{ yymsp[1].minor.yy318 = 0; }
|
|
+ case 164: /* upsert ::= */
|
|
+{ yymsp[1].minor.yy444 = 0; }
|
|
+ break;
|
|
+ case 165: /* upsert ::= RETURNING selcollist */
|
|
+{ yymsp[-1].minor.yy444 = 0; sqlite3AddReturning(pParse,yymsp[0].minor.yy322); }
|
|
+ break;
|
|
+ case 166: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt upsert */
|
|
+{ yymsp[-11].minor.yy444 = sqlite3UpsertNew(pParse->db,yymsp[-8].minor.yy322,yymsp[-6].minor.yy528,yymsp[-2].minor.yy322,yymsp[-1].minor.yy528,yymsp[0].minor.yy444);}
|
|
+ break;
|
|
+ case 167: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING upsert */
|
|
+{ yymsp[-8].minor.yy444 = sqlite3UpsertNew(pParse->db,yymsp[-5].minor.yy322,yymsp[-3].minor.yy528,0,0,yymsp[0].minor.yy444); }
|
|
+ break;
|
|
+ case 168: /* upsert ::= ON CONFLICT DO NOTHING returning */
|
|
+{ yymsp[-4].minor.yy444 = sqlite3UpsertNew(pParse->db,0,0,0,0,0); }
|
|
break;
|
|
- case 159: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO UPDATE SET setlist where_opt */
|
|
-{ yymsp[-10].minor.yy318 = sqlite3UpsertNew(pParse->db,yymsp[-7].minor.yy242,yymsp[-5].minor.yy202,yymsp[-1].minor.yy242,yymsp[0].minor.yy202);}
|
|
+ case 169: /* upsert ::= ON CONFLICT DO UPDATE SET setlist where_opt returning */
|
|
+{ yymsp[-7].minor.yy444 = sqlite3UpsertNew(pParse->db,0,0,yymsp[-2].minor.yy322,yymsp[-1].minor.yy528,0);}
|
|
break;
|
|
- case 160: /* upsert ::= ON CONFLICT LP sortlist RP where_opt DO NOTHING */
|
|
-{ yymsp[-7].minor.yy318 = sqlite3UpsertNew(pParse->db,yymsp[-4].minor.yy242,yymsp[-2].minor.yy202,0,0); }
|
|
+ case 170: /* returning ::= RETURNING selcollist */
|
|
+{sqlite3AddReturning(pParse,yymsp[0].minor.yy322);}
|
|
break;
|
|
- case 161: /* upsert ::= ON CONFLICT DO NOTHING */
|
|
-{ yymsp[-3].minor.yy318 = sqlite3UpsertNew(pParse->db,0,0,0,0); }
|
|
+ case 173: /* idlist_opt ::= */
|
|
+{yymsp[1].minor.yy254 = 0;}
|
|
break;
|
|
- case 165: /* idlist_opt ::= LP idlist RP */
|
|
-{yymsp[-2].minor.yy600 = yymsp[-1].minor.yy600;}
|
|
+ case 174: /* idlist_opt ::= LP idlist RP */
|
|
+{yymsp[-2].minor.yy254 = yymsp[-1].minor.yy254;}
|
|
break;
|
|
- case 166: /* idlist ::= idlist COMMA nm */
|
|
-{yymsp[-2].minor.yy600 = sqlite3IdListAppend(pParse,yymsp[-2].minor.yy600,&yymsp[0].minor.yy0);}
|
|
+ case 175: /* idlist ::= idlist COMMA nm */
|
|
+{yymsp[-2].minor.yy254 = sqlite3IdListAppend(pParse,yymsp[-2].minor.yy254,&yymsp[0].minor.yy0);}
|
|
break;
|
|
- case 167: /* idlist ::= nm */
|
|
-{yymsp[0].minor.yy600 = sqlite3IdListAppend(pParse,0,&yymsp[0].minor.yy0); /*A-overwrites-Y*/}
|
|
+ case 176: /* idlist ::= nm */
|
|
+{yymsp[0].minor.yy254 = sqlite3IdListAppend(pParse,0,&yymsp[0].minor.yy0); /*A-overwrites-Y*/}
|
|
break;
|
|
- case 168: /* expr ::= LP expr RP */
|
|
-{yymsp[-2].minor.yy202 = yymsp[-1].minor.yy202;}
|
|
+ case 177: /* expr ::= LP expr RP */
|
|
+{yymsp[-2].minor.yy528 = yymsp[-1].minor.yy528;}
|
|
break;
|
|
- case 169: /* expr ::= ID|INDEXED */
|
|
- case 170: /* expr ::= JOIN_KW */ yytestcase(yyruleno==170);
|
|
-{yymsp[0].minor.yy202=tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0); /*A-overwrites-X*/}
|
|
+ case 178: /* expr ::= ID|INDEXED */
|
|
+ case 179: /* expr ::= JOIN_KW */ yytestcase(yyruleno==179);
|
|
+{yymsp[0].minor.yy528=tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0); /*A-overwrites-X*/}
|
|
break;
|
|
- case 171: /* expr ::= nm DOT nm */
|
|
+ case 180: /* expr ::= nm DOT nm */
|
|
{
|
|
- Expr *temp1 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1);
|
|
- Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[0].minor.yy0, 1);
|
|
- if( IN_RENAME_OBJECT ){
|
|
- sqlite3RenameTokenMap(pParse, (void*)temp2, &yymsp[0].minor.yy0);
|
|
- sqlite3RenameTokenMap(pParse, (void*)temp1, &yymsp[-2].minor.yy0);
|
|
- }
|
|
- yylhsminor.yy202 = sqlite3PExpr(pParse, TK_DOT, temp1, temp2);
|
|
+ Expr *temp1 = tokenExpr(pParse,TK_ID,yymsp[-2].minor.yy0);
|
|
+ Expr *temp2 = tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0);
|
|
+ yylhsminor.yy528 = sqlite3PExpr(pParse, TK_DOT, temp1, temp2);
|
|
}
|
|
- yymsp[-2].minor.yy202 = yylhsminor.yy202;
|
|
+ yymsp[-2].minor.yy528 = yylhsminor.yy528;
|
|
break;
|
|
- case 172: /* expr ::= nm DOT nm DOT nm */
|
|
+ case 181: /* expr ::= nm DOT nm DOT nm */
|
|
{
|
|
- Expr *temp1 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-4].minor.yy0, 1);
|
|
- Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1);
|
|
- Expr *temp3 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[0].minor.yy0, 1);
|
|
+ Expr *temp1 = tokenExpr(pParse,TK_ID,yymsp[-4].minor.yy0);
|
|
+ Expr *temp2 = tokenExpr(pParse,TK_ID,yymsp[-2].minor.yy0);
|
|
+ Expr *temp3 = tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0);
|
|
Expr *temp4 = sqlite3PExpr(pParse, TK_DOT, temp2, temp3);
|
|
if( IN_RENAME_OBJECT ){
|
|
- sqlite3RenameTokenMap(pParse, (void*)temp3, &yymsp[0].minor.yy0);
|
|
- sqlite3RenameTokenMap(pParse, (void*)temp2, &yymsp[-2].minor.yy0);
|
|
+ sqlite3RenameTokenRemap(pParse, 0, temp1);
|
|
}
|
|
- yylhsminor.yy202 = sqlite3PExpr(pParse, TK_DOT, temp1, temp4);
|
|
+ yylhsminor.yy528 = sqlite3PExpr(pParse, TK_DOT, temp1, temp4);
|
|
}
|
|
- yymsp[-4].minor.yy202 = yylhsminor.yy202;
|
|
+ yymsp[-4].minor.yy528 = yylhsminor.yy528;
|
|
break;
|
|
- case 173: /* term ::= NULL|FLOAT|BLOB */
|
|
- case 174: /* term ::= STRING */ yytestcase(yyruleno==174);
|
|
-{yymsp[0].minor.yy202=tokenExpr(pParse,yymsp[0].major,yymsp[0].minor.yy0); /*A-overwrites-X*/}
|
|
+ case 182: /* term ::= NULL|FLOAT|BLOB */
|
|
+ case 183: /* term ::= STRING */ yytestcase(yyruleno==183);
|
|
+{yymsp[0].minor.yy528=tokenExpr(pParse,yymsp[0].major,yymsp[0].minor.yy0); /*A-overwrites-X*/}
|
|
break;
|
|
- case 175: /* term ::= INTEGER */
|
|
+ case 184: /* term ::= INTEGER */
|
|
{
|
|
- yylhsminor.yy202 = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &yymsp[0].minor.yy0, 1);
|
|
+ yylhsminor.yy528 = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &yymsp[0].minor.yy0, 1);
|
|
+ if( yylhsminor.yy528 ) yylhsminor.yy528->w.iOfst = (int)(yymsp[0].minor.yy0.z - pParse->zTail);
|
|
}
|
|
- yymsp[0].minor.yy202 = yylhsminor.yy202;
|
|
+ yymsp[0].minor.yy528 = yylhsminor.yy528;
|
|
break;
|
|
- case 176: /* expr ::= VARIABLE */
|
|
+ case 185: /* expr ::= VARIABLE */
|
|
{
|
|
if( !(yymsp[0].minor.yy0.z[0]=='#' && sqlite3Isdigit(yymsp[0].minor.yy0.z[1])) ){
|
|
u32 n = yymsp[0].minor.yy0.n;
|
|
- yymsp[0].minor.yy202 = tokenExpr(pParse, TK_VARIABLE, yymsp[0].minor.yy0);
|
|
- sqlite3ExprAssignVarNumber(pParse, yymsp[0].minor.yy202, n);
|
|
+ yymsp[0].minor.yy528 = tokenExpr(pParse, TK_VARIABLE, yymsp[0].minor.yy0);
|
|
+ sqlite3ExprAssignVarNumber(pParse, yymsp[0].minor.yy528, n);
|
|
}else{
|
|
/* When doing a nested parse, one can include terms in an expression
|
|
** that look like this: #1 #2 ... These terms refer to registers
|
|
@@ -156335,159 +171159,179 @@ static YYACTIONTYPE yy_reduce(
|
|
assert( t.n>=2 );
|
|
if( pParse->nested==0 ){
|
|
sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &t);
|
|
- yymsp[0].minor.yy202 = 0;
|
|
+ yymsp[0].minor.yy528 = 0;
|
|
}else{
|
|
- yymsp[0].minor.yy202 = sqlite3PExpr(pParse, TK_REGISTER, 0, 0);
|
|
- if( yymsp[0].minor.yy202 ) sqlite3GetInt32(&t.z[1], &yymsp[0].minor.yy202->iTable);
|
|
+ yymsp[0].minor.yy528 = sqlite3PExpr(pParse, TK_REGISTER, 0, 0);
|
|
+ if( yymsp[0].minor.yy528 ) sqlite3GetInt32(&t.z[1], &yymsp[0].minor.yy528->iTable);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
- case 177: /* expr ::= expr COLLATE ID|STRING */
|
|
+ case 186: /* expr ::= expr COLLATE ID|STRING */
|
|
{
|
|
- yymsp[-2].minor.yy202 = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy202, &yymsp[0].minor.yy0, 1);
|
|
+ yymsp[-2].minor.yy528 = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy528, &yymsp[0].minor.yy0, 1);
|
|
}
|
|
break;
|
|
- case 178: /* expr ::= CAST LP expr AS typetoken RP */
|
|
+ case 187: /* expr ::= CAST LP expr AS typetoken RP */
|
|
{
|
|
- yymsp[-5].minor.yy202 = sqlite3ExprAlloc(pParse->db, TK_CAST, &yymsp[-1].minor.yy0, 1);
|
|
- sqlite3ExprAttachSubtrees(pParse->db, yymsp[-5].minor.yy202, yymsp[-3].minor.yy202, 0);
|
|
+ yymsp[-5].minor.yy528 = sqlite3ExprAlloc(pParse->db, TK_CAST, &yymsp[-1].minor.yy0, 1);
|
|
+ sqlite3ExprAttachSubtrees(pParse->db, yymsp[-5].minor.yy528, yymsp[-3].minor.yy528, 0);
|
|
}
|
|
break;
|
|
- case 179: /* expr ::= ID|INDEXED LP distinct exprlist RP */
|
|
+ case 188: /* expr ::= ID|INDEXED LP distinct exprlist RP */
|
|
{
|
|
- yylhsminor.yy202 = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy242, &yymsp[-4].minor.yy0, yymsp[-2].minor.yy192);
|
|
+ yylhsminor.yy528 = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy322, &yymsp[-4].minor.yy0, yymsp[-2].minor.yy394);
|
|
}
|
|
- yymsp[-4].minor.yy202 = yylhsminor.yy202;
|
|
+ yymsp[-4].minor.yy528 = yylhsminor.yy528;
|
|
break;
|
|
- case 180: /* expr ::= ID|INDEXED LP STAR RP */
|
|
+ case 189: /* expr ::= ID|INDEXED LP STAR RP */
|
|
{
|
|
- yylhsminor.yy202 = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0, 0);
|
|
+ yylhsminor.yy528 = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0, 0);
|
|
}
|
|
- yymsp[-3].minor.yy202 = yylhsminor.yy202;
|
|
+ yymsp[-3].minor.yy528 = yylhsminor.yy528;
|
|
break;
|
|
- case 181: /* expr ::= ID|INDEXED LP distinct exprlist RP filter_over */
|
|
+ case 190: /* expr ::= ID|INDEXED LP distinct exprlist RP filter_over */
|
|
{
|
|
- yylhsminor.yy202 = sqlite3ExprFunction(pParse, yymsp[-2].minor.yy242, &yymsp[-5].minor.yy0, yymsp[-3].minor.yy192);
|
|
- sqlite3WindowAttach(pParse, yylhsminor.yy202, yymsp[0].minor.yy303);
|
|
+ yylhsminor.yy528 = sqlite3ExprFunction(pParse, yymsp[-2].minor.yy322, &yymsp[-5].minor.yy0, yymsp[-3].minor.yy394);
|
|
+ sqlite3WindowAttach(pParse, yylhsminor.yy528, yymsp[0].minor.yy41);
|
|
}
|
|
- yymsp[-5].minor.yy202 = yylhsminor.yy202;
|
|
+ yymsp[-5].minor.yy528 = yylhsminor.yy528;
|
|
break;
|
|
- case 182: /* expr ::= ID|INDEXED LP STAR RP filter_over */
|
|
+ case 191: /* expr ::= ID|INDEXED LP STAR RP filter_over */
|
|
{
|
|
- yylhsminor.yy202 = sqlite3ExprFunction(pParse, 0, &yymsp[-4].minor.yy0, 0);
|
|
- sqlite3WindowAttach(pParse, yylhsminor.yy202, yymsp[0].minor.yy303);
|
|
+ yylhsminor.yy528 = sqlite3ExprFunction(pParse, 0, &yymsp[-4].minor.yy0, 0);
|
|
+ sqlite3WindowAttach(pParse, yylhsminor.yy528, yymsp[0].minor.yy41);
|
|
}
|
|
- yymsp[-4].minor.yy202 = yylhsminor.yy202;
|
|
+ yymsp[-4].minor.yy528 = yylhsminor.yy528;
|
|
break;
|
|
- case 183: /* term ::= CTIME_KW */
|
|
+ case 192: /* term ::= CTIME_KW */
|
|
{
|
|
- yylhsminor.yy202 = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0, 0);
|
|
+ yylhsminor.yy528 = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0, 0);
|
|
}
|
|
- yymsp[0].minor.yy202 = yylhsminor.yy202;
|
|
+ yymsp[0].minor.yy528 = yylhsminor.yy528;
|
|
break;
|
|
- case 184: /* expr ::= LP nexprlist COMMA expr RP */
|
|
+ case 193: /* expr ::= LP nexprlist COMMA expr RP */
|
|
{
|
|
- ExprList *pList = sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy242, yymsp[-1].minor.yy202);
|
|
- yymsp[-4].minor.yy202 = sqlite3PExpr(pParse, TK_VECTOR, 0, 0);
|
|
- if( yymsp[-4].minor.yy202 ){
|
|
- yymsp[-4].minor.yy202->x.pList = pList;
|
|
+ ExprList *pList = sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy322, yymsp[-1].minor.yy528);
|
|
+ yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_VECTOR, 0, 0);
|
|
+ if( yymsp[-4].minor.yy528 ){
|
|
+ yymsp[-4].minor.yy528->x.pList = pList;
|
|
if( ALWAYS(pList->nExpr) ){
|
|
- yymsp[-4].minor.yy202->flags |= pList->a[0].pExpr->flags & EP_Propagate;
|
|
+ yymsp[-4].minor.yy528->flags |= pList->a[0].pExpr->flags & EP_Propagate;
|
|
}
|
|
}else{
|
|
sqlite3ExprListDelete(pParse->db, pList);
|
|
}
|
|
}
|
|
break;
|
|
- case 185: /* expr ::= expr AND expr */
|
|
-{yymsp[-2].minor.yy202=sqlite3ExprAnd(pParse,yymsp[-2].minor.yy202,yymsp[0].minor.yy202);}
|
|
+ case 194: /* expr ::= expr AND expr */
|
|
+{yymsp[-2].minor.yy528=sqlite3ExprAnd(pParse,yymsp[-2].minor.yy528,yymsp[0].minor.yy528);}
|
|
break;
|
|
- case 186: /* expr ::= expr OR expr */
|
|
- case 187: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==187);
|
|
- case 188: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==188);
|
|
- case 189: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==189);
|
|
- case 190: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==190);
|
|
- case 191: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==191);
|
|
- case 192: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==192);
|
|
-{yymsp[-2].minor.yy202=sqlite3PExpr(pParse,yymsp[-1].major,yymsp[-2].minor.yy202,yymsp[0].minor.yy202);}
|
|
+ case 195: /* expr ::= expr OR expr */
|
|
+ case 196: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==196);
|
|
+ case 197: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==197);
|
|
+ case 198: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==198);
|
|
+ case 199: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==199);
|
|
+ case 200: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==200);
|
|
+ case 201: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==201);
|
|
+{yymsp[-2].minor.yy528=sqlite3PExpr(pParse,yymsp[-1].major,yymsp[-2].minor.yy528,yymsp[0].minor.yy528);}
|
|
break;
|
|
- case 193: /* likeop ::= NOT LIKE_KW|MATCH */
|
|
+ case 202: /* likeop ::= NOT LIKE_KW|MATCH */
|
|
{yymsp[-1].minor.yy0=yymsp[0].minor.yy0; yymsp[-1].minor.yy0.n|=0x80000000; /*yymsp[-1].minor.yy0-overwrite-yymsp[0].minor.yy0*/}
|
|
break;
|
|
- case 194: /* expr ::= expr likeop expr */
|
|
+ case 203: /* expr ::= expr likeop expr */
|
|
{
|
|
ExprList *pList;
|
|
int bNot = yymsp[-1].minor.yy0.n & 0x80000000;
|
|
yymsp[-1].minor.yy0.n &= 0x7fffffff;
|
|
- pList = sqlite3ExprListAppend(pParse,0, yymsp[0].minor.yy202);
|
|
- pList = sqlite3ExprListAppend(pParse,pList, yymsp[-2].minor.yy202);
|
|
- yymsp[-2].minor.yy202 = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0, 0);
|
|
- if( bNot ) yymsp[-2].minor.yy202 = sqlite3PExpr(pParse, TK_NOT, yymsp[-2].minor.yy202, 0);
|
|
- if( yymsp[-2].minor.yy202 ) yymsp[-2].minor.yy202->flags |= EP_InfixFunc;
|
|
+ pList = sqlite3ExprListAppend(pParse,0, yymsp[0].minor.yy528);
|
|
+ pList = sqlite3ExprListAppend(pParse,pList, yymsp[-2].minor.yy528);
|
|
+ yymsp[-2].minor.yy528 = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0, 0);
|
|
+ if( bNot ) yymsp[-2].minor.yy528 = sqlite3PExpr(pParse, TK_NOT, yymsp[-2].minor.yy528, 0);
|
|
+ if( yymsp[-2].minor.yy528 ) yymsp[-2].minor.yy528->flags |= EP_InfixFunc;
|
|
}
|
|
break;
|
|
- case 195: /* expr ::= expr likeop expr ESCAPE expr */
|
|
+ case 204: /* expr ::= expr likeop expr ESCAPE expr */
|
|
{
|
|
ExprList *pList;
|
|
int bNot = yymsp[-3].minor.yy0.n & 0x80000000;
|
|
yymsp[-3].minor.yy0.n &= 0x7fffffff;
|
|
- pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy202);
|
|
- pList = sqlite3ExprListAppend(pParse,pList, yymsp[-4].minor.yy202);
|
|
- pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy202);
|
|
- yymsp[-4].minor.yy202 = sqlite3ExprFunction(pParse, pList, &yymsp[-3].minor.yy0, 0);
|
|
- if( bNot ) yymsp[-4].minor.yy202 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy202, 0);
|
|
- if( yymsp[-4].minor.yy202 ) yymsp[-4].minor.yy202->flags |= EP_InfixFunc;
|
|
+ pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy528);
|
|
+ pList = sqlite3ExprListAppend(pParse,pList, yymsp[-4].minor.yy528);
|
|
+ pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy528);
|
|
+ yymsp[-4].minor.yy528 = sqlite3ExprFunction(pParse, pList, &yymsp[-3].minor.yy0, 0);
|
|
+ if( bNot ) yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy528, 0);
|
|
+ if( yymsp[-4].minor.yy528 ) yymsp[-4].minor.yy528->flags |= EP_InfixFunc;
|
|
}
|
|
break;
|
|
- case 196: /* expr ::= expr ISNULL|NOTNULL */
|
|
-{yymsp[-1].minor.yy202 = sqlite3PExpr(pParse,yymsp[0].major,yymsp[-1].minor.yy202,0);}
|
|
+ case 205: /* expr ::= expr ISNULL|NOTNULL */
|
|
+{yymsp[-1].minor.yy528 = sqlite3PExpr(pParse,yymsp[0].major,yymsp[-1].minor.yy528,0);}
|
|
break;
|
|
- case 197: /* expr ::= expr NOT NULL */
|
|
-{yymsp[-2].minor.yy202 = sqlite3PExpr(pParse,TK_NOTNULL,yymsp[-2].minor.yy202,0);}
|
|
+ case 206: /* expr ::= expr NOT NULL */
|
|
+{yymsp[-2].minor.yy528 = sqlite3PExpr(pParse,TK_NOTNULL,yymsp[-2].minor.yy528,0);}
|
|
break;
|
|
- case 198: /* expr ::= expr IS expr */
|
|
+ case 207: /* expr ::= expr IS expr */
|
|
{
|
|
- yymsp[-2].minor.yy202 = sqlite3PExpr(pParse,TK_IS,yymsp[-2].minor.yy202,yymsp[0].minor.yy202);
|
|
- binaryToUnaryIfNull(pParse, yymsp[0].minor.yy202, yymsp[-2].minor.yy202, TK_ISNULL);
|
|
+ yymsp[-2].minor.yy528 = sqlite3PExpr(pParse,TK_IS,yymsp[-2].minor.yy528,yymsp[0].minor.yy528);
|
|
+ binaryToUnaryIfNull(pParse, yymsp[0].minor.yy528, yymsp[-2].minor.yy528, TK_ISNULL);
|
|
}
|
|
break;
|
|
- case 199: /* expr ::= expr IS NOT expr */
|
|
+ case 208: /* expr ::= expr IS NOT expr */
|
|
{
|
|
- yymsp[-3].minor.yy202 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-3].minor.yy202,yymsp[0].minor.yy202);
|
|
- binaryToUnaryIfNull(pParse, yymsp[0].minor.yy202, yymsp[-3].minor.yy202, TK_NOTNULL);
|
|
+ yymsp[-3].minor.yy528 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-3].minor.yy528,yymsp[0].minor.yy528);
|
|
+ binaryToUnaryIfNull(pParse, yymsp[0].minor.yy528, yymsp[-3].minor.yy528, TK_NOTNULL);
|
|
}
|
|
break;
|
|
- case 200: /* expr ::= NOT expr */
|
|
- case 201: /* expr ::= BITNOT expr */ yytestcase(yyruleno==201);
|
|
-{yymsp[-1].minor.yy202 = sqlite3PExpr(pParse, yymsp[-1].major, yymsp[0].minor.yy202, 0);/*A-overwrites-B*/}
|
|
+ case 209: /* expr ::= expr IS NOT DISTINCT FROM expr */
|
|
+{
|
|
+ yymsp[-5].minor.yy528 = sqlite3PExpr(pParse,TK_IS,yymsp[-5].minor.yy528,yymsp[0].minor.yy528);
|
|
+ binaryToUnaryIfNull(pParse, yymsp[0].minor.yy528, yymsp[-5].minor.yy528, TK_ISNULL);
|
|
+}
|
|
break;
|
|
- case 202: /* expr ::= PLUS|MINUS expr */
|
|
+ case 210: /* expr ::= expr IS DISTINCT FROM expr */
|
|
{
|
|
- yymsp[-1].minor.yy202 = sqlite3PExpr(pParse, yymsp[-1].major==TK_PLUS ? TK_UPLUS : TK_UMINUS, yymsp[0].minor.yy202, 0);
|
|
+ yymsp[-4].minor.yy528 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-4].minor.yy528,yymsp[0].minor.yy528);
|
|
+ binaryToUnaryIfNull(pParse, yymsp[0].minor.yy528, yymsp[-4].minor.yy528, TK_NOTNULL);
|
|
+}
|
|
+ break;
|
|
+ case 211: /* expr ::= NOT expr */
|
|
+ case 212: /* expr ::= BITNOT expr */ yytestcase(yyruleno==212);
|
|
+{yymsp[-1].minor.yy528 = sqlite3PExpr(pParse, yymsp[-1].major, yymsp[0].minor.yy528, 0);/*A-overwrites-B*/}
|
|
+ break;
|
|
+ case 213: /* expr ::= PLUS|MINUS expr */
|
|
+{
|
|
+ yymsp[-1].minor.yy528 = sqlite3PExpr(pParse, yymsp[-1].major==TK_PLUS ? TK_UPLUS : TK_UMINUS, yymsp[0].minor.yy528, 0);
|
|
/*A-overwrites-B*/
|
|
}
|
|
break;
|
|
- case 203: /* between_op ::= BETWEEN */
|
|
- case 206: /* in_op ::= IN */ yytestcase(yyruleno==206);
|
|
-{yymsp[0].minor.yy192 = 0;}
|
|
+ case 214: /* expr ::= expr PTR expr */
|
|
+{
|
|
+ ExprList *pList = sqlite3ExprListAppend(pParse, 0, yymsp[-2].minor.yy528);
|
|
+ pList = sqlite3ExprListAppend(pParse, pList, yymsp[0].minor.yy528);
|
|
+ yylhsminor.yy528 = sqlite3ExprFunction(pParse, pList, &yymsp[-1].minor.yy0, 0);
|
|
+}
|
|
+ yymsp[-2].minor.yy528 = yylhsminor.yy528;
|
|
break;
|
|
- case 205: /* expr ::= expr between_op expr AND expr */
|
|
+ case 215: /* between_op ::= BETWEEN */
|
|
+ case 218: /* in_op ::= IN */ yytestcase(yyruleno==218);
|
|
+{yymsp[0].minor.yy394 = 0;}
|
|
+ break;
|
|
+ case 217: /* expr ::= expr between_op expr AND expr */
|
|
{
|
|
- ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy202);
|
|
- pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy202);
|
|
- yymsp[-4].minor.yy202 = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy202, 0);
|
|
- if( yymsp[-4].minor.yy202 ){
|
|
- yymsp[-4].minor.yy202->x.pList = pList;
|
|
+ ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy528);
|
|
+ pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy528);
|
|
+ yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_BETWEEN, yymsp[-4].minor.yy528, 0);
|
|
+ if( yymsp[-4].minor.yy528 ){
|
|
+ yymsp[-4].minor.yy528->x.pList = pList;
|
|
}else{
|
|
sqlite3ExprListDelete(pParse->db, pList);
|
|
- }
|
|
- if( yymsp[-3].minor.yy192 ) yymsp[-4].minor.yy202 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy202, 0);
|
|
+ }
|
|
+ if( yymsp[-3].minor.yy394 ) yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy528, 0);
|
|
}
|
|
break;
|
|
- case 208: /* expr ::= expr in_op LP exprlist RP */
|
|
+ case 220: /* expr ::= expr in_op LP exprlist RP */
|
|
{
|
|
- if( yymsp[-1].minor.yy242==0 ){
|
|
+ if( yymsp[-1].minor.yy322==0 ){
|
|
/* Expressions of the form
|
|
**
|
|
** expr1 IN ()
|
|
@@ -156496,535 +171340,582 @@ static YYACTIONTYPE yy_reduce(
|
|
** simplify to constants 0 (false) and 1 (true), respectively,
|
|
** regardless of the value of expr1.
|
|
*/
|
|
- sqlite3ExprUnmapAndDelete(pParse, yymsp[-4].minor.yy202);
|
|
- yymsp[-4].minor.yy202 = sqlite3Expr(pParse->db, TK_INTEGER, yymsp[-3].minor.yy192 ? "1" : "0");
|
|
- }else{
|
|
- yymsp[-4].minor.yy202 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy202, 0);
|
|
- if( yymsp[-4].minor.yy202 ){
|
|
- yymsp[-4].minor.yy202->x.pList = yymsp[-1].minor.yy242;
|
|
- sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy202);
|
|
+ sqlite3ExprUnmapAndDelete(pParse, yymsp[-4].minor.yy528);
|
|
+ yymsp[-4].minor.yy528 = sqlite3Expr(pParse->db, TK_STRING, yymsp[-3].minor.yy394 ? "true" : "false");
|
|
+ if( yymsp[-4].minor.yy528 ) sqlite3ExprIdToTrueFalse(yymsp[-4].minor.yy528);
|
|
+ }else{
|
|
+ Expr *pRHS = yymsp[-1].minor.yy322->a[0].pExpr;
|
|
+ if( yymsp[-1].minor.yy322->nExpr==1 && sqlite3ExprIsConstant(pRHS) && yymsp[-4].minor.yy528->op!=TK_VECTOR ){
|
|
+ yymsp[-1].minor.yy322->a[0].pExpr = 0;
|
|
+ sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy322);
|
|
+ pRHS = sqlite3PExpr(pParse, TK_UPLUS, pRHS, 0);
|
|
+ yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_EQ, yymsp[-4].minor.yy528, pRHS);
|
|
+ }else if( yymsp[-1].minor.yy322->nExpr==1 && pRHS->op==TK_SELECT ){
|
|
+ yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy528, 0);
|
|
+ sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy528, pRHS->x.pSelect);
|
|
+ pRHS->x.pSelect = 0;
|
|
+ sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy322);
|
|
}else{
|
|
- sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy242);
|
|
+ yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy528, 0);
|
|
+ if( yymsp[-4].minor.yy528==0 ){
|
|
+ sqlite3ExprListDelete(pParse->db, yymsp[-1].minor.yy322);
|
|
+ }else if( yymsp[-4].minor.yy528->pLeft->op==TK_VECTOR ){
|
|
+ int nExpr = yymsp[-4].minor.yy528->pLeft->x.pList->nExpr;
|
|
+ Select *pSelectRHS = sqlite3ExprListToValues(pParse, nExpr, yymsp[-1].minor.yy322);
|
|
+ if( pSelectRHS ){
|
|
+ parserDoubleLinkSelect(pParse, pSelectRHS);
|
|
+ sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy528, pSelectRHS);
|
|
+ }
|
|
+ }else{
|
|
+ yymsp[-4].minor.yy528->x.pList = yymsp[-1].minor.yy322;
|
|
+ sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy528);
|
|
+ }
|
|
}
|
|
- if( yymsp[-3].minor.yy192 ) yymsp[-4].minor.yy202 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy202, 0);
|
|
+ if( yymsp[-3].minor.yy394 ) yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy528, 0);
|
|
}
|
|
}
|
|
break;
|
|
- case 209: /* expr ::= LP select RP */
|
|
+ case 221: /* expr ::= LP select RP */
|
|
{
|
|
- yymsp[-2].minor.yy202 = sqlite3PExpr(pParse, TK_SELECT, 0, 0);
|
|
- sqlite3PExprAddSelect(pParse, yymsp[-2].minor.yy202, yymsp[-1].minor.yy539);
|
|
+ yymsp[-2].minor.yy528 = sqlite3PExpr(pParse, TK_SELECT, 0, 0);
|
|
+ sqlite3PExprAddSelect(pParse, yymsp[-2].minor.yy528, yymsp[-1].minor.yy47);
|
|
}
|
|
break;
|
|
- case 210: /* expr ::= expr in_op LP select RP */
|
|
+ case 222: /* expr ::= expr in_op LP select RP */
|
|
{
|
|
- yymsp[-4].minor.yy202 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy202, 0);
|
|
- sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy202, yymsp[-1].minor.yy539);
|
|
- if( yymsp[-3].minor.yy192 ) yymsp[-4].minor.yy202 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy202, 0);
|
|
+ yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy528, 0);
|
|
+ sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy528, yymsp[-1].minor.yy47);
|
|
+ if( yymsp[-3].minor.yy394 ) yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy528, 0);
|
|
}
|
|
break;
|
|
- case 211: /* expr ::= expr in_op nm dbnm paren_exprlist */
|
|
+ case 223: /* expr ::= expr in_op nm dbnm paren_exprlist */
|
|
{
|
|
SrcList *pSrc = sqlite3SrcListAppend(pParse, 0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);
|
|
Select *pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0);
|
|
- if( yymsp[0].minor.yy242 ) sqlite3SrcListFuncArgs(pParse, pSelect ? pSrc : 0, yymsp[0].minor.yy242);
|
|
- yymsp[-4].minor.yy202 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy202, 0);
|
|
- sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy202, pSelect);
|
|
- if( yymsp[-3].minor.yy192 ) yymsp[-4].minor.yy202 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy202, 0);
|
|
+ if( yymsp[0].minor.yy322 ) sqlite3SrcListFuncArgs(pParse, pSelect ? pSrc : 0, yymsp[0].minor.yy322);
|
|
+ yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy528, 0);
|
|
+ sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy528, pSelect);
|
|
+ if( yymsp[-3].minor.yy394 ) yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy528, 0);
|
|
}
|
|
break;
|
|
- case 212: /* expr ::= EXISTS LP select RP */
|
|
+ case 224: /* expr ::= EXISTS LP select RP */
|
|
{
|
|
Expr *p;
|
|
- p = yymsp[-3].minor.yy202 = sqlite3PExpr(pParse, TK_EXISTS, 0, 0);
|
|
- sqlite3PExprAddSelect(pParse, p, yymsp[-1].minor.yy539);
|
|
+ p = yymsp[-3].minor.yy528 = sqlite3PExpr(pParse, TK_EXISTS, 0, 0);
|
|
+ sqlite3PExprAddSelect(pParse, p, yymsp[-1].minor.yy47);
|
|
}
|
|
break;
|
|
- case 213: /* expr ::= CASE case_operand case_exprlist case_else END */
|
|
+ case 225: /* expr ::= CASE case_operand case_exprlist case_else END */
|
|
{
|
|
- yymsp[-4].minor.yy202 = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy202, 0);
|
|
- if( yymsp[-4].minor.yy202 ){
|
|
- yymsp[-4].minor.yy202->x.pList = yymsp[-1].minor.yy202 ? sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy242,yymsp[-1].minor.yy202) : yymsp[-2].minor.yy242;
|
|
- sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy202);
|
|
+ yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy528, 0);
|
|
+ if( yymsp[-4].minor.yy528 ){
|
|
+ yymsp[-4].minor.yy528->x.pList = yymsp[-1].minor.yy528 ? sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy322,yymsp[-1].minor.yy528) : yymsp[-2].minor.yy322;
|
|
+ sqlite3ExprSetHeightAndFlags(pParse, yymsp[-4].minor.yy528);
|
|
}else{
|
|
- sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy242);
|
|
- sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy202);
|
|
+ sqlite3ExprListDelete(pParse->db, yymsp[-2].minor.yy322);
|
|
+ sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy528);
|
|
}
|
|
}
|
|
break;
|
|
- case 214: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */
|
|
+ case 226: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */
|
|
{
|
|
- yymsp[-4].minor.yy242 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy242, yymsp[-2].minor.yy202);
|
|
- yymsp[-4].minor.yy242 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy242, yymsp[0].minor.yy202);
|
|
+ yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy322, yymsp[-2].minor.yy528);
|
|
+ yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy322, yymsp[0].minor.yy528);
|
|
}
|
|
break;
|
|
- case 215: /* case_exprlist ::= WHEN expr THEN expr */
|
|
+ case 227: /* case_exprlist ::= WHEN expr THEN expr */
|
|
{
|
|
- yymsp[-3].minor.yy242 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy202);
|
|
- yymsp[-3].minor.yy242 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy242, yymsp[0].minor.yy202);
|
|
+ yymsp[-3].minor.yy322 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy528);
|
|
+ yymsp[-3].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy322, yymsp[0].minor.yy528);
|
|
}
|
|
break;
|
|
- case 218: /* case_operand ::= expr */
|
|
-{yymsp[0].minor.yy202 = yymsp[0].minor.yy202; /*A-overwrites-X*/}
|
|
+ case 230: /* case_operand ::= expr */
|
|
+{yymsp[0].minor.yy528 = yymsp[0].minor.yy528; /*A-overwrites-X*/}
|
|
break;
|
|
- case 221: /* nexprlist ::= nexprlist COMMA expr */
|
|
-{yymsp[-2].minor.yy242 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy242,yymsp[0].minor.yy202);}
|
|
+ case 233: /* nexprlist ::= nexprlist COMMA expr */
|
|
+{yymsp[-2].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy322,yymsp[0].minor.yy528);}
|
|
break;
|
|
- case 222: /* nexprlist ::= expr */
|
|
-{yymsp[0].minor.yy242 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy202); /*A-overwrites-Y*/}
|
|
+ case 234: /* nexprlist ::= expr */
|
|
+{yymsp[0].minor.yy322 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy528); /*A-overwrites-Y*/}
|
|
break;
|
|
- case 224: /* paren_exprlist ::= LP exprlist RP */
|
|
- case 229: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==229);
|
|
-{yymsp[-2].minor.yy242 = yymsp[-1].minor.yy242;}
|
|
+ case 236: /* paren_exprlist ::= LP exprlist RP */
|
|
+ case 241: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==241);
|
|
+{yymsp[-2].minor.yy322 = yymsp[-1].minor.yy322;}
|
|
break;
|
|
- case 225: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
|
|
+ case 237: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
|
|
{
|
|
- sqlite3CreateIndex(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0,
|
|
- sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,0), yymsp[-2].minor.yy242, yymsp[-10].minor.yy192,
|
|
- &yymsp[-11].minor.yy0, yymsp[0].minor.yy202, SQLITE_SO_ASC, yymsp[-8].minor.yy192, SQLITE_IDXTYPE_APPDEF);
|
|
+ sqlite3CreateIndex(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0,
|
|
+ sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,0), yymsp[-2].minor.yy322, yymsp[-10].minor.yy394,
|
|
+ &yymsp[-11].minor.yy0, yymsp[0].minor.yy528, SQLITE_SO_ASC, yymsp[-8].minor.yy394, SQLITE_IDXTYPE_APPDEF);
|
|
if( IN_RENAME_OBJECT && pParse->pNewIndex ){
|
|
sqlite3RenameTokenMap(pParse, pParse->pNewIndex->zName, &yymsp[-4].minor.yy0);
|
|
}
|
|
}
|
|
break;
|
|
- case 226: /* uniqueflag ::= UNIQUE */
|
|
- case 268: /* raisetype ::= ABORT */ yytestcase(yyruleno==268);
|
|
-{yymsp[0].minor.yy192 = OE_Abort;}
|
|
+ case 238: /* uniqueflag ::= UNIQUE */
|
|
+ case 280: /* raisetype ::= ABORT */ yytestcase(yyruleno==280);
|
|
+{yymsp[0].minor.yy394 = OE_Abort;}
|
|
break;
|
|
- case 227: /* uniqueflag ::= */
|
|
-{yymsp[1].minor.yy192 = OE_None;}
|
|
+ case 239: /* uniqueflag ::= */
|
|
+{yymsp[1].minor.yy394 = OE_None;}
|
|
break;
|
|
- case 230: /* eidlist ::= eidlist COMMA nm collate sortorder */
|
|
+ case 242: /* eidlist ::= eidlist COMMA nm collate sortorder */
|
|
{
|
|
- yymsp[-4].minor.yy242 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy242, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy192, yymsp[0].minor.yy192);
|
|
+ yymsp[-4].minor.yy322 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy322, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy394, yymsp[0].minor.yy394);
|
|
}
|
|
break;
|
|
- case 231: /* eidlist ::= nm collate sortorder */
|
|
+ case 243: /* eidlist ::= nm collate sortorder */
|
|
{
|
|
- yymsp[-2].minor.yy242 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy192, yymsp[0].minor.yy192); /*A-overwrites-Y*/
|
|
+ yymsp[-2].minor.yy322 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy394, yymsp[0].minor.yy394); /*A-overwrites-Y*/
|
|
}
|
|
break;
|
|
- case 234: /* cmd ::= DROP INDEX ifexists fullname */
|
|
-{sqlite3DropIndex(pParse, yymsp[0].minor.yy47, yymsp[-1].minor.yy192);}
|
|
+ case 246: /* cmd ::= DROP INDEX ifexists fullname */
|
|
+{sqlite3DropIndex(pParse, yymsp[0].minor.yy131, yymsp[-1].minor.yy394);}
|
|
break;
|
|
- case 235: /* cmd ::= VACUUM vinto */
|
|
-{sqlite3Vacuum(pParse,0,yymsp[0].minor.yy202);}
|
|
+ case 247: /* cmd ::= VACUUM vinto */
|
|
+{sqlite3Vacuum(pParse,0,yymsp[0].minor.yy528);}
|
|
break;
|
|
- case 236: /* cmd ::= VACUUM nm vinto */
|
|
-{sqlite3Vacuum(pParse,&yymsp[-1].minor.yy0,yymsp[0].minor.yy202);}
|
|
+ case 248: /* cmd ::= VACUUM nm vinto */
|
|
+{sqlite3Vacuum(pParse,&yymsp[-1].minor.yy0,yymsp[0].minor.yy528);}
|
|
break;
|
|
- case 239: /* cmd ::= PRAGMA nm dbnm */
|
|
+ case 251: /* cmd ::= PRAGMA nm dbnm */
|
|
{sqlite3Pragma(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,0,0);}
|
|
break;
|
|
- case 240: /* cmd ::= PRAGMA nm dbnm EQ nmnum */
|
|
+ case 252: /* cmd ::= PRAGMA nm dbnm EQ nmnum */
|
|
{sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,0);}
|
|
break;
|
|
- case 241: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */
|
|
+ case 253: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */
|
|
{sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,0);}
|
|
break;
|
|
- case 242: /* cmd ::= PRAGMA nm dbnm EQ minus_num */
|
|
+ case 254: /* cmd ::= PRAGMA nm dbnm EQ minus_num */
|
|
{sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,1);}
|
|
break;
|
|
- case 243: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */
|
|
+ case 255: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */
|
|
{sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,1);}
|
|
break;
|
|
- case 246: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
|
|
+ case 258: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
|
|
{
|
|
Token all;
|
|
all.z = yymsp[-3].minor.yy0.z;
|
|
all.n = (int)(yymsp[0].minor.yy0.z - yymsp[-3].minor.yy0.z) + yymsp[0].minor.yy0.n;
|
|
- sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy447, &all);
|
|
+ sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy33, &all);
|
|
}
|
|
break;
|
|
- case 247: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
|
|
+ case 259: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
|
|
{
|
|
- sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy192, yymsp[-4].minor.yy230.a, yymsp[-4].minor.yy230.b, yymsp[-2].minor.yy47, yymsp[0].minor.yy202, yymsp[-10].minor.yy192, yymsp[-8].minor.yy192);
|
|
+ sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy394, yymsp[-4].minor.yy180.a, yymsp[-4].minor.yy180.b, yymsp[-2].minor.yy131, yymsp[0].minor.yy528, yymsp[-10].minor.yy394, yymsp[-8].minor.yy394);
|
|
yymsp[-10].minor.yy0 = (yymsp[-6].minor.yy0.n==0?yymsp[-7].minor.yy0:yymsp[-6].minor.yy0); /*A-overwrites-T*/
|
|
}
|
|
break;
|
|
- case 248: /* trigger_time ::= BEFORE|AFTER */
|
|
-{ yymsp[0].minor.yy192 = yymsp[0].major; /*A-overwrites-X*/ }
|
|
+ case 260: /* trigger_time ::= BEFORE|AFTER */
|
|
+{ yymsp[0].minor.yy394 = yymsp[0].major; /*A-overwrites-X*/ }
|
|
break;
|
|
- case 249: /* trigger_time ::= INSTEAD OF */
|
|
-{ yymsp[-1].minor.yy192 = TK_INSTEAD;}
|
|
+ case 261: /* trigger_time ::= INSTEAD OF */
|
|
+{ yymsp[-1].minor.yy394 = TK_INSTEAD;}
|
|
break;
|
|
- case 250: /* trigger_time ::= */
|
|
-{ yymsp[1].minor.yy192 = TK_BEFORE; }
|
|
+ case 262: /* trigger_time ::= */
|
|
+{ yymsp[1].minor.yy394 = TK_BEFORE; }
|
|
break;
|
|
- case 251: /* trigger_event ::= DELETE|INSERT */
|
|
- case 252: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==252);
|
|
-{yymsp[0].minor.yy230.a = yymsp[0].major; /*A-overwrites-X*/ yymsp[0].minor.yy230.b = 0;}
|
|
+ case 263: /* trigger_event ::= DELETE|INSERT */
|
|
+ case 264: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==264);
|
|
+{yymsp[0].minor.yy180.a = yymsp[0].major; /*A-overwrites-X*/ yymsp[0].minor.yy180.b = 0;}
|
|
break;
|
|
- case 253: /* trigger_event ::= UPDATE OF idlist */
|
|
-{yymsp[-2].minor.yy230.a = TK_UPDATE; yymsp[-2].minor.yy230.b = yymsp[0].minor.yy600;}
|
|
+ case 265: /* trigger_event ::= UPDATE OF idlist */
|
|
+{yymsp[-2].minor.yy180.a = TK_UPDATE; yymsp[-2].minor.yy180.b = yymsp[0].minor.yy254;}
|
|
break;
|
|
- case 254: /* when_clause ::= */
|
|
- case 273: /* key_opt ::= */ yytestcase(yyruleno==273);
|
|
-{ yymsp[1].minor.yy202 = 0; }
|
|
+ case 266: /* when_clause ::= */
|
|
+ case 285: /* key_opt ::= */ yytestcase(yyruleno==285);
|
|
+{ yymsp[1].minor.yy528 = 0; }
|
|
break;
|
|
- case 255: /* when_clause ::= WHEN expr */
|
|
- case 274: /* key_opt ::= KEY expr */ yytestcase(yyruleno==274);
|
|
-{ yymsp[-1].minor.yy202 = yymsp[0].minor.yy202; }
|
|
+ case 267: /* when_clause ::= WHEN expr */
|
|
+ case 286: /* key_opt ::= KEY expr */ yytestcase(yyruleno==286);
|
|
+{ yymsp[-1].minor.yy528 = yymsp[0].minor.yy528; }
|
|
break;
|
|
- case 256: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
|
|
+ case 268: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
|
|
{
|
|
- assert( yymsp[-2].minor.yy447!=0 );
|
|
- yymsp[-2].minor.yy447->pLast->pNext = yymsp[-1].minor.yy447;
|
|
- yymsp[-2].minor.yy447->pLast = yymsp[-1].minor.yy447;
|
|
+ assert( yymsp[-2].minor.yy33!=0 );
|
|
+ yymsp[-2].minor.yy33->pLast->pNext = yymsp[-1].minor.yy33;
|
|
+ yymsp[-2].minor.yy33->pLast = yymsp[-1].minor.yy33;
|
|
}
|
|
break;
|
|
- case 257: /* trigger_cmd_list ::= trigger_cmd SEMI */
|
|
-{
|
|
- assert( yymsp[-1].minor.yy447!=0 );
|
|
- yymsp[-1].minor.yy447->pLast = yymsp[-1].minor.yy447;
|
|
+ case 269: /* trigger_cmd_list ::= trigger_cmd SEMI */
|
|
+{
|
|
+ assert( yymsp[-1].minor.yy33!=0 );
|
|
+ yymsp[-1].minor.yy33->pLast = yymsp[-1].minor.yy33;
|
|
}
|
|
break;
|
|
- case 258: /* trnm ::= nm DOT nm */
|
|
+ case 270: /* trnm ::= nm DOT nm */
|
|
{
|
|
yymsp[-2].minor.yy0 = yymsp[0].minor.yy0;
|
|
- sqlite3ErrorMsg(pParse,
|
|
+ sqlite3ErrorMsg(pParse,
|
|
"qualified table names are not allowed on INSERT, UPDATE, and DELETE "
|
|
"statements within triggers");
|
|
}
|
|
break;
|
|
- case 259: /* tridxby ::= INDEXED BY nm */
|
|
+ case 271: /* tridxby ::= INDEXED BY nm */
|
|
{
|
|
sqlite3ErrorMsg(pParse,
|
|
"the INDEXED BY clause is not allowed on UPDATE or DELETE statements "
|
|
"within triggers");
|
|
}
|
|
break;
|
|
- case 260: /* tridxby ::= NOT INDEXED */
|
|
+ case 272: /* tridxby ::= NOT INDEXED */
|
|
{
|
|
sqlite3ErrorMsg(pParse,
|
|
"the NOT INDEXED clause is not allowed on UPDATE or DELETE statements "
|
|
"within triggers");
|
|
}
|
|
break;
|
|
- case 261: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt scanpt */
|
|
-{yylhsminor.yy447 = sqlite3TriggerUpdateStep(pParse, &yymsp[-5].minor.yy0, yymsp[-2].minor.yy242, yymsp[-1].minor.yy202, yymsp[-6].minor.yy192, yymsp[-7].minor.yy0.z, yymsp[0].minor.yy436);}
|
|
- yymsp[-7].minor.yy447 = yylhsminor.yy447;
|
|
+ case 273: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */
|
|
+{yylhsminor.yy33 = sqlite3TriggerUpdateStep(pParse, &yymsp[-6].minor.yy0, yymsp[-2].minor.yy131, yymsp[-3].minor.yy322, yymsp[-1].minor.yy528, yymsp[-7].minor.yy394, yymsp[-8].minor.yy0.z, yymsp[0].minor.yy522);}
|
|
+ yymsp[-8].minor.yy33 = yylhsminor.yy33;
|
|
break;
|
|
- case 262: /* trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */
|
|
+ case 274: /* trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */
|
|
{
|
|
- yylhsminor.yy447 = sqlite3TriggerInsertStep(pParse,&yymsp[-4].minor.yy0,yymsp[-3].minor.yy600,yymsp[-2].minor.yy539,yymsp[-6].minor.yy192,yymsp[-1].minor.yy318,yymsp[-7].minor.yy436,yymsp[0].minor.yy436);/*yylhsminor.yy447-overwrites-yymsp[-6].minor.yy192*/
|
|
+ yylhsminor.yy33 = sqlite3TriggerInsertStep(pParse,&yymsp[-4].minor.yy0,yymsp[-3].minor.yy254,yymsp[-2].minor.yy47,yymsp[-6].minor.yy394,yymsp[-1].minor.yy444,yymsp[-7].minor.yy522,yymsp[0].minor.yy522);/*yylhsminor.yy33-overwrites-yymsp[-6].minor.yy394*/
|
|
}
|
|
- yymsp[-7].minor.yy447 = yylhsminor.yy447;
|
|
+ yymsp[-7].minor.yy33 = yylhsminor.yy33;
|
|
break;
|
|
- case 263: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
|
|
-{yylhsminor.yy447 = sqlite3TriggerDeleteStep(pParse, &yymsp[-3].minor.yy0, yymsp[-1].minor.yy202, yymsp[-5].minor.yy0.z, yymsp[0].minor.yy436);}
|
|
- yymsp[-5].minor.yy447 = yylhsminor.yy447;
|
|
+ case 275: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
|
|
+{yylhsminor.yy33 = sqlite3TriggerDeleteStep(pParse, &yymsp[-3].minor.yy0, yymsp[-1].minor.yy528, yymsp[-5].minor.yy0.z, yymsp[0].minor.yy522);}
|
|
+ yymsp[-5].minor.yy33 = yylhsminor.yy33;
|
|
break;
|
|
- case 264: /* trigger_cmd ::= scanpt select scanpt */
|
|
-{yylhsminor.yy447 = sqlite3TriggerSelectStep(pParse->db, yymsp[-1].minor.yy539, yymsp[-2].minor.yy436, yymsp[0].minor.yy436); /*yylhsminor.yy447-overwrites-yymsp[-1].minor.yy539*/}
|
|
- yymsp[-2].minor.yy447 = yylhsminor.yy447;
|
|
+ case 276: /* trigger_cmd ::= scanpt select scanpt */
|
|
+{yylhsminor.yy33 = sqlite3TriggerSelectStep(pParse->db, yymsp[-1].minor.yy47, yymsp[-2].minor.yy522, yymsp[0].minor.yy522); /*yylhsminor.yy33-overwrites-yymsp[-1].minor.yy47*/}
|
|
+ yymsp[-2].minor.yy33 = yylhsminor.yy33;
|
|
break;
|
|
- case 265: /* expr ::= RAISE LP IGNORE RP */
|
|
+ case 277: /* expr ::= RAISE LP IGNORE RP */
|
|
{
|
|
- yymsp[-3].minor.yy202 = sqlite3PExpr(pParse, TK_RAISE, 0, 0);
|
|
- if( yymsp[-3].minor.yy202 ){
|
|
- yymsp[-3].minor.yy202->affExpr = OE_Ignore;
|
|
+ yymsp[-3].minor.yy528 = sqlite3PExpr(pParse, TK_RAISE, 0, 0);
|
|
+ if( yymsp[-3].minor.yy528 ){
|
|
+ yymsp[-3].minor.yy528->affExpr = OE_Ignore;
|
|
}
|
|
}
|
|
break;
|
|
- case 266: /* expr ::= RAISE LP raisetype COMMA nm RP */
|
|
+ case 278: /* expr ::= RAISE LP raisetype COMMA nm RP */
|
|
{
|
|
- yymsp[-5].minor.yy202 = sqlite3ExprAlloc(pParse->db, TK_RAISE, &yymsp[-1].minor.yy0, 1);
|
|
- if( yymsp[-5].minor.yy202 ) {
|
|
- yymsp[-5].minor.yy202->affExpr = (char)yymsp[-3].minor.yy192;
|
|
+ yymsp[-5].minor.yy528 = sqlite3ExprAlloc(pParse->db, TK_RAISE, &yymsp[-1].minor.yy0, 1);
|
|
+ if( yymsp[-5].minor.yy528 ) {
|
|
+ yymsp[-5].minor.yy528->affExpr = (char)yymsp[-3].minor.yy394;
|
|
}
|
|
}
|
|
break;
|
|
- case 267: /* raisetype ::= ROLLBACK */
|
|
-{yymsp[0].minor.yy192 = OE_Rollback;}
|
|
+ case 279: /* raisetype ::= ROLLBACK */
|
|
+{yymsp[0].minor.yy394 = OE_Rollback;}
|
|
break;
|
|
- case 269: /* raisetype ::= FAIL */
|
|
-{yymsp[0].minor.yy192 = OE_Fail;}
|
|
+ case 281: /* raisetype ::= FAIL */
|
|
+{yymsp[0].minor.yy394 = OE_Fail;}
|
|
break;
|
|
- case 270: /* cmd ::= DROP TRIGGER ifexists fullname */
|
|
+ case 282: /* cmd ::= DROP TRIGGER ifexists fullname */
|
|
{
|
|
- sqlite3DropTrigger(pParse,yymsp[0].minor.yy47,yymsp[-1].minor.yy192);
|
|
+ sqlite3DropTrigger(pParse,yymsp[0].minor.yy131,yymsp[-1].minor.yy394);
|
|
}
|
|
break;
|
|
- case 271: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
|
|
+ case 283: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
|
|
{
|
|
- sqlite3Attach(pParse, yymsp[-3].minor.yy202, yymsp[-1].minor.yy202, yymsp[0].minor.yy202);
|
|
+ sqlite3Attach(pParse, yymsp[-3].minor.yy528, yymsp[-1].minor.yy528, yymsp[0].minor.yy528);
|
|
}
|
|
break;
|
|
- case 272: /* cmd ::= DETACH database_kw_opt expr */
|
|
+ case 284: /* cmd ::= DETACH database_kw_opt expr */
|
|
{
|
|
- sqlite3Detach(pParse, yymsp[0].minor.yy202);
|
|
+ sqlite3Detach(pParse, yymsp[0].minor.yy528);
|
|
}
|
|
break;
|
|
- case 275: /* cmd ::= REINDEX */
|
|
+ case 287: /* cmd ::= REINDEX */
|
|
{sqlite3Reindex(pParse, 0, 0);}
|
|
break;
|
|
- case 276: /* cmd ::= REINDEX nm dbnm */
|
|
+ case 288: /* cmd ::= REINDEX nm dbnm */
|
|
{sqlite3Reindex(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);}
|
|
break;
|
|
- case 277: /* cmd ::= ANALYZE */
|
|
+ case 289: /* cmd ::= ANALYZE */
|
|
{sqlite3Analyze(pParse, 0, 0);}
|
|
break;
|
|
- case 278: /* cmd ::= ANALYZE nm dbnm */
|
|
+ case 290: /* cmd ::= ANALYZE nm dbnm */
|
|
{sqlite3Analyze(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);}
|
|
break;
|
|
- case 279: /* cmd ::= ALTER TABLE fullname RENAME TO nm */
|
|
+ case 291: /* cmd ::= ALTER TABLE fullname RENAME TO nm */
|
|
{
|
|
- sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy47,&yymsp[0].minor.yy0);
|
|
+ sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy131,&yymsp[0].minor.yy0);
|
|
}
|
|
break;
|
|
- case 280: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
|
|
+ case 292: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
|
|
{
|
|
yymsp[-1].minor.yy0.n = (int)(pParse->sLastToken.z-yymsp[-1].minor.yy0.z) + pParse->sLastToken.n;
|
|
sqlite3AlterFinishAddColumn(pParse, &yymsp[-1].minor.yy0);
|
|
}
|
|
break;
|
|
- case 281: /* add_column_fullname ::= fullname */
|
|
+ case 293: /* cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */
|
|
+{
|
|
+ sqlite3AlterDropColumn(pParse, yymsp[-3].minor.yy131, &yymsp[0].minor.yy0);
|
|
+}
|
|
+ break;
|
|
+ case 294: /* add_column_fullname ::= fullname */
|
|
{
|
|
disableLookaside(pParse);
|
|
- sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy47);
|
|
+ sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy131);
|
|
}
|
|
break;
|
|
- case 282: /* cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */
|
|
+ case 295: /* cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */
|
|
{
|
|
- sqlite3AlterRenameColumn(pParse, yymsp[-5].minor.yy47, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0);
|
|
+ sqlite3AlterRenameColumn(pParse, yymsp[-5].minor.yy131, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0);
|
|
}
|
|
break;
|
|
- case 283: /* cmd ::= create_vtab */
|
|
+ case 296: /* cmd ::= create_vtab */
|
|
{sqlite3VtabFinishParse(pParse,0);}
|
|
break;
|
|
- case 284: /* cmd ::= create_vtab LP vtabarglist RP */
|
|
+ case 297: /* cmd ::= create_vtab LP vtabarglist RP */
|
|
{sqlite3VtabFinishParse(pParse,&yymsp[0].minor.yy0);}
|
|
break;
|
|
- case 285: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
|
|
+ case 298: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
|
|
{
|
|
- sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy192);
|
|
+ sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy394);
|
|
}
|
|
break;
|
|
- case 286: /* vtabarg ::= */
|
|
+ case 299: /* vtabarg ::= */
|
|
{sqlite3VtabArgInit(pParse);}
|
|
break;
|
|
- case 287: /* vtabargtoken ::= ANY */
|
|
- case 288: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==288);
|
|
- case 289: /* lp ::= LP */ yytestcase(yyruleno==289);
|
|
+ case 300: /* vtabargtoken ::= ANY */
|
|
+ case 301: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==301);
|
|
+ case 302: /* lp ::= LP */ yytestcase(yyruleno==302);
|
|
{sqlite3VtabArgExtend(pParse,&yymsp[0].minor.yy0);}
|
|
break;
|
|
- case 290: /* with ::= WITH wqlist */
|
|
- case 291: /* with ::= WITH RECURSIVE wqlist */ yytestcase(yyruleno==291);
|
|
-{ sqlite3WithPush(pParse, yymsp[0].minor.yy131, 1); }
|
|
+ case 303: /* with ::= WITH wqlist */
|
|
+ case 304: /* with ::= WITH RECURSIVE wqlist */ yytestcase(yyruleno==304);
|
|
+{ sqlite3WithPush(pParse, yymsp[0].minor.yy521, 1); }
|
|
break;
|
|
- case 292: /* wqlist ::= nm eidlist_opt AS LP select RP */
|
|
+ case 305: /* wqas ::= AS */
|
|
+{yymsp[0].minor.yy516 = M10d_Any;}
|
|
+ break;
|
|
+ case 306: /* wqas ::= AS MATERIALIZED */
|
|
+{yymsp[-1].minor.yy516 = M10d_Yes;}
|
|
+ break;
|
|
+ case 307: /* wqas ::= AS NOT MATERIALIZED */
|
|
+{yymsp[-2].minor.yy516 = M10d_No;}
|
|
+ break;
|
|
+ case 308: /* wqitem ::= nm eidlist_opt wqas LP select RP */
|
|
+{
|
|
+ yymsp[-5].minor.yy385 = sqlite3CteNew(pParse, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy322, yymsp[-1].minor.yy47, yymsp[-3].minor.yy516); /*A-overwrites-X*/
|
|
+}
|
|
+ break;
|
|
+ case 309: /* wqlist ::= wqitem */
|
|
{
|
|
- yymsp[-5].minor.yy131 = sqlite3WithAdd(pParse, 0, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy242, yymsp[-1].minor.yy539); /*A-overwrites-X*/
|
|
+ yymsp[0].minor.yy521 = sqlite3WithAdd(pParse, 0, yymsp[0].minor.yy385); /*A-overwrites-X*/
|
|
}
|
|
break;
|
|
- case 293: /* wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP */
|
|
+ case 310: /* wqlist ::= wqlist COMMA wqitem */
|
|
{
|
|
- yymsp[-7].minor.yy131 = sqlite3WithAdd(pParse, yymsp[-7].minor.yy131, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy242, yymsp[-1].minor.yy539);
|
|
+ yymsp[-2].minor.yy521 = sqlite3WithAdd(pParse, yymsp[-2].minor.yy521, yymsp[0].minor.yy385);
|
|
}
|
|
break;
|
|
- case 294: /* windowdefn_list ::= windowdefn */
|
|
-{ yylhsminor.yy303 = yymsp[0].minor.yy303; }
|
|
- yymsp[0].minor.yy303 = yylhsminor.yy303;
|
|
+ case 311: /* windowdefn_list ::= windowdefn */
|
|
+{ yylhsminor.yy41 = yymsp[0].minor.yy41; }
|
|
+ yymsp[0].minor.yy41 = yylhsminor.yy41;
|
|
break;
|
|
- case 295: /* windowdefn_list ::= windowdefn_list COMMA windowdefn */
|
|
+ case 312: /* windowdefn_list ::= windowdefn_list COMMA windowdefn */
|
|
{
|
|
- assert( yymsp[0].minor.yy303!=0 );
|
|
- sqlite3WindowChain(pParse, yymsp[0].minor.yy303, yymsp[-2].minor.yy303);
|
|
- yymsp[0].minor.yy303->pNextWin = yymsp[-2].minor.yy303;
|
|
- yylhsminor.yy303 = yymsp[0].minor.yy303;
|
|
+ assert( yymsp[0].minor.yy41!=0 );
|
|
+ sqlite3WindowChain(pParse, yymsp[0].minor.yy41, yymsp[-2].minor.yy41);
|
|
+ yymsp[0].minor.yy41->pNextWin = yymsp[-2].minor.yy41;
|
|
+ yylhsminor.yy41 = yymsp[0].minor.yy41;
|
|
}
|
|
- yymsp[-2].minor.yy303 = yylhsminor.yy303;
|
|
+ yymsp[-2].minor.yy41 = yylhsminor.yy41;
|
|
break;
|
|
- case 296: /* windowdefn ::= nm AS LP window RP */
|
|
+ case 313: /* windowdefn ::= nm AS LP window RP */
|
|
{
|
|
- if( ALWAYS(yymsp[-1].minor.yy303) ){
|
|
- yymsp[-1].minor.yy303->zName = sqlite3DbStrNDup(pParse->db, yymsp[-4].minor.yy0.z, yymsp[-4].minor.yy0.n);
|
|
+ if( ALWAYS(yymsp[-1].minor.yy41) ){
|
|
+ yymsp[-1].minor.yy41->zName = sqlite3DbStrNDup(pParse->db, yymsp[-4].minor.yy0.z, yymsp[-4].minor.yy0.n);
|
|
}
|
|
- yylhsminor.yy303 = yymsp[-1].minor.yy303;
|
|
+ yylhsminor.yy41 = yymsp[-1].minor.yy41;
|
|
}
|
|
- yymsp[-4].minor.yy303 = yylhsminor.yy303;
|
|
+ yymsp[-4].minor.yy41 = yylhsminor.yy41;
|
|
break;
|
|
- case 297: /* window ::= PARTITION BY nexprlist orderby_opt frame_opt */
|
|
+ case 314: /* window ::= PARTITION BY nexprlist orderby_opt frame_opt */
|
|
{
|
|
- yymsp[-4].minor.yy303 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy303, yymsp[-2].minor.yy242, yymsp[-1].minor.yy242, 0);
|
|
+ yymsp[-4].minor.yy41 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, yymsp[-2].minor.yy322, yymsp[-1].minor.yy322, 0);
|
|
}
|
|
break;
|
|
- case 298: /* window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */
|
|
+ case 315: /* window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */
|
|
{
|
|
- yylhsminor.yy303 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy303, yymsp[-2].minor.yy242, yymsp[-1].minor.yy242, &yymsp[-5].minor.yy0);
|
|
+ yylhsminor.yy41 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, yymsp[-2].minor.yy322, yymsp[-1].minor.yy322, &yymsp[-5].minor.yy0);
|
|
}
|
|
- yymsp[-5].minor.yy303 = yylhsminor.yy303;
|
|
+ yymsp[-5].minor.yy41 = yylhsminor.yy41;
|
|
break;
|
|
- case 299: /* window ::= ORDER BY sortlist frame_opt */
|
|
+ case 316: /* window ::= ORDER BY sortlist frame_opt */
|
|
{
|
|
- yymsp[-3].minor.yy303 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy303, 0, yymsp[-1].minor.yy242, 0);
|
|
+ yymsp[-3].minor.yy41 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, 0, yymsp[-1].minor.yy322, 0);
|
|
}
|
|
break;
|
|
- case 300: /* window ::= nm ORDER BY sortlist frame_opt */
|
|
+ case 317: /* window ::= nm ORDER BY sortlist frame_opt */
|
|
{
|
|
- yylhsminor.yy303 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy303, 0, yymsp[-1].minor.yy242, &yymsp[-4].minor.yy0);
|
|
+ yylhsminor.yy41 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, 0, yymsp[-1].minor.yy322, &yymsp[-4].minor.yy0);
|
|
}
|
|
- yymsp[-4].minor.yy303 = yylhsminor.yy303;
|
|
+ yymsp[-4].minor.yy41 = yylhsminor.yy41;
|
|
break;
|
|
- case 301: /* window ::= frame_opt */
|
|
- case 320: /* filter_over ::= over_clause */ yytestcase(yyruleno==320);
|
|
+ case 318: /* window ::= frame_opt */
|
|
+ case 337: /* filter_over ::= over_clause */ yytestcase(yyruleno==337);
|
|
{
|
|
- yylhsminor.yy303 = yymsp[0].minor.yy303;
|
|
+ yylhsminor.yy41 = yymsp[0].minor.yy41;
|
|
}
|
|
- yymsp[0].minor.yy303 = yylhsminor.yy303;
|
|
+ yymsp[0].minor.yy41 = yylhsminor.yy41;
|
|
break;
|
|
- case 302: /* window ::= nm frame_opt */
|
|
+ case 319: /* window ::= nm frame_opt */
|
|
{
|
|
- yylhsminor.yy303 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy303, 0, 0, &yymsp[-1].minor.yy0);
|
|
+ yylhsminor.yy41 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, 0, 0, &yymsp[-1].minor.yy0);
|
|
}
|
|
- yymsp[-1].minor.yy303 = yylhsminor.yy303;
|
|
+ yymsp[-1].minor.yy41 = yylhsminor.yy41;
|
|
break;
|
|
- case 303: /* frame_opt ::= */
|
|
-{
|
|
- yymsp[1].minor.yy303 = sqlite3WindowAlloc(pParse, 0, TK_UNBOUNDED, 0, TK_CURRENT, 0, 0);
|
|
+ case 320: /* frame_opt ::= */
|
|
+{
|
|
+ yymsp[1].minor.yy41 = sqlite3WindowAlloc(pParse, 0, TK_UNBOUNDED, 0, TK_CURRENT, 0, 0);
|
|
}
|
|
break;
|
|
- case 304: /* frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */
|
|
-{
|
|
- yylhsminor.yy303 = sqlite3WindowAlloc(pParse, yymsp[-2].minor.yy192, yymsp[-1].minor.yy77.eType, yymsp[-1].minor.yy77.pExpr, TK_CURRENT, 0, yymsp[0].minor.yy58);
|
|
+ case 321: /* frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */
|
|
+{
|
|
+ yylhsminor.yy41 = sqlite3WindowAlloc(pParse, yymsp[-2].minor.yy394, yymsp[-1].minor.yy595.eType, yymsp[-1].minor.yy595.pExpr, TK_CURRENT, 0, yymsp[0].minor.yy516);
|
|
}
|
|
- yymsp[-2].minor.yy303 = yylhsminor.yy303;
|
|
+ yymsp[-2].minor.yy41 = yylhsminor.yy41;
|
|
break;
|
|
- case 305: /* frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */
|
|
-{
|
|
- yylhsminor.yy303 = sqlite3WindowAlloc(pParse, yymsp[-5].minor.yy192, yymsp[-3].minor.yy77.eType, yymsp[-3].minor.yy77.pExpr, yymsp[-1].minor.yy77.eType, yymsp[-1].minor.yy77.pExpr, yymsp[0].minor.yy58);
|
|
+ case 322: /* frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */
|
|
+{
|
|
+ yylhsminor.yy41 = sqlite3WindowAlloc(pParse, yymsp[-5].minor.yy394, yymsp[-3].minor.yy595.eType, yymsp[-3].minor.yy595.pExpr, yymsp[-1].minor.yy595.eType, yymsp[-1].minor.yy595.pExpr, yymsp[0].minor.yy516);
|
|
}
|
|
- yymsp[-5].minor.yy303 = yylhsminor.yy303;
|
|
+ yymsp[-5].minor.yy41 = yylhsminor.yy41;
|
|
break;
|
|
- case 307: /* frame_bound_s ::= frame_bound */
|
|
- case 309: /* frame_bound_e ::= frame_bound */ yytestcase(yyruleno==309);
|
|
-{yylhsminor.yy77 = yymsp[0].minor.yy77;}
|
|
- yymsp[0].minor.yy77 = yylhsminor.yy77;
|
|
+ case 324: /* frame_bound_s ::= frame_bound */
|
|
+ case 326: /* frame_bound_e ::= frame_bound */ yytestcase(yyruleno==326);
|
|
+{yylhsminor.yy595 = yymsp[0].minor.yy595;}
|
|
+ yymsp[0].minor.yy595 = yylhsminor.yy595;
|
|
break;
|
|
- case 308: /* frame_bound_s ::= UNBOUNDED PRECEDING */
|
|
- case 310: /* frame_bound_e ::= UNBOUNDED FOLLOWING */ yytestcase(yyruleno==310);
|
|
- case 312: /* frame_bound ::= CURRENT ROW */ yytestcase(yyruleno==312);
|
|
-{yylhsminor.yy77.eType = yymsp[-1].major; yylhsminor.yy77.pExpr = 0;}
|
|
- yymsp[-1].minor.yy77 = yylhsminor.yy77;
|
|
+ case 325: /* frame_bound_s ::= UNBOUNDED PRECEDING */
|
|
+ case 327: /* frame_bound_e ::= UNBOUNDED FOLLOWING */ yytestcase(yyruleno==327);
|
|
+ case 329: /* frame_bound ::= CURRENT ROW */ yytestcase(yyruleno==329);
|
|
+{yylhsminor.yy595.eType = yymsp[-1].major; yylhsminor.yy595.pExpr = 0;}
|
|
+ yymsp[-1].minor.yy595 = yylhsminor.yy595;
|
|
break;
|
|
- case 311: /* frame_bound ::= expr PRECEDING|FOLLOWING */
|
|
-{yylhsminor.yy77.eType = yymsp[0].major; yylhsminor.yy77.pExpr = yymsp[-1].minor.yy202;}
|
|
- yymsp[-1].minor.yy77 = yylhsminor.yy77;
|
|
+ case 328: /* frame_bound ::= expr PRECEDING|FOLLOWING */
|
|
+{yylhsminor.yy595.eType = yymsp[0].major; yylhsminor.yy595.pExpr = yymsp[-1].minor.yy528;}
|
|
+ yymsp[-1].minor.yy595 = yylhsminor.yy595;
|
|
break;
|
|
- case 313: /* frame_exclude_opt ::= */
|
|
-{yymsp[1].minor.yy58 = 0;}
|
|
+ case 330: /* frame_exclude_opt ::= */
|
|
+{yymsp[1].minor.yy516 = 0;}
|
|
break;
|
|
- case 314: /* frame_exclude_opt ::= EXCLUDE frame_exclude */
|
|
-{yymsp[-1].minor.yy58 = yymsp[0].minor.yy58;}
|
|
+ case 331: /* frame_exclude_opt ::= EXCLUDE frame_exclude */
|
|
+{yymsp[-1].minor.yy516 = yymsp[0].minor.yy516;}
|
|
break;
|
|
- case 315: /* frame_exclude ::= NO OTHERS */
|
|
- case 316: /* frame_exclude ::= CURRENT ROW */ yytestcase(yyruleno==316);
|
|
-{yymsp[-1].minor.yy58 = yymsp[-1].major; /*A-overwrites-X*/}
|
|
+ case 332: /* frame_exclude ::= NO OTHERS */
|
|
+ case 333: /* frame_exclude ::= CURRENT ROW */ yytestcase(yyruleno==333);
|
|
+{yymsp[-1].minor.yy516 = yymsp[-1].major; /*A-overwrites-X*/}
|
|
break;
|
|
- case 317: /* frame_exclude ::= GROUP|TIES */
|
|
-{yymsp[0].minor.yy58 = yymsp[0].major; /*A-overwrites-X*/}
|
|
+ case 334: /* frame_exclude ::= GROUP|TIES */
|
|
+{yymsp[0].minor.yy516 = yymsp[0].major; /*A-overwrites-X*/}
|
|
break;
|
|
- case 318: /* window_clause ::= WINDOW windowdefn_list */
|
|
-{ yymsp[-1].minor.yy303 = yymsp[0].minor.yy303; }
|
|
+ case 335: /* window_clause ::= WINDOW windowdefn_list */
|
|
+{ yymsp[-1].minor.yy41 = yymsp[0].minor.yy41; }
|
|
break;
|
|
- case 319: /* filter_over ::= filter_clause over_clause */
|
|
+ case 336: /* filter_over ::= filter_clause over_clause */
|
|
{
|
|
- yymsp[0].minor.yy303->pFilter = yymsp[-1].minor.yy202;
|
|
- yylhsminor.yy303 = yymsp[0].minor.yy303;
|
|
+ if( yymsp[0].minor.yy41 ){
|
|
+ yymsp[0].minor.yy41->pFilter = yymsp[-1].minor.yy528;
|
|
+ }else{
|
|
+ sqlite3ExprDelete(pParse->db, yymsp[-1].minor.yy528);
|
|
+ }
|
|
+ yylhsminor.yy41 = yymsp[0].minor.yy41;
|
|
}
|
|
- yymsp[-1].minor.yy303 = yylhsminor.yy303;
|
|
+ yymsp[-1].minor.yy41 = yylhsminor.yy41;
|
|
break;
|
|
- case 321: /* filter_over ::= filter_clause */
|
|
+ case 338: /* filter_over ::= filter_clause */
|
|
{
|
|
- yylhsminor.yy303 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window));
|
|
- if( yylhsminor.yy303 ){
|
|
- yylhsminor.yy303->eFrmType = TK_FILTER;
|
|
- yylhsminor.yy303->pFilter = yymsp[0].minor.yy202;
|
|
+ yylhsminor.yy41 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window));
|
|
+ if( yylhsminor.yy41 ){
|
|
+ yylhsminor.yy41->eFrmType = TK_FILTER;
|
|
+ yylhsminor.yy41->pFilter = yymsp[0].minor.yy528;
|
|
}else{
|
|
- sqlite3ExprDelete(pParse->db, yymsp[0].minor.yy202);
|
|
+ sqlite3ExprDelete(pParse->db, yymsp[0].minor.yy528);
|
|
}
|
|
}
|
|
- yymsp[0].minor.yy303 = yylhsminor.yy303;
|
|
+ yymsp[0].minor.yy41 = yylhsminor.yy41;
|
|
break;
|
|
- case 322: /* over_clause ::= OVER LP window RP */
|
|
+ case 339: /* over_clause ::= OVER LP window RP */
|
|
{
|
|
- yymsp[-3].minor.yy303 = yymsp[-1].minor.yy303;
|
|
- assert( yymsp[-3].minor.yy303!=0 );
|
|
+ yymsp[-3].minor.yy41 = yymsp[-1].minor.yy41;
|
|
+ assert( yymsp[-3].minor.yy41!=0 );
|
|
}
|
|
break;
|
|
- case 323: /* over_clause ::= OVER nm */
|
|
+ case 340: /* over_clause ::= OVER nm */
|
|
{
|
|
- yymsp[-1].minor.yy303 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window));
|
|
- if( yymsp[-1].minor.yy303 ){
|
|
- yymsp[-1].minor.yy303->zName = sqlite3DbStrNDup(pParse->db, yymsp[0].minor.yy0.z, yymsp[0].minor.yy0.n);
|
|
+ yymsp[-1].minor.yy41 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window));
|
|
+ if( yymsp[-1].minor.yy41 ){
|
|
+ yymsp[-1].minor.yy41->zName = sqlite3DbStrNDup(pParse->db, yymsp[0].minor.yy0.z, yymsp[0].minor.yy0.n);
|
|
}
|
|
}
|
|
break;
|
|
- case 324: /* filter_clause ::= FILTER LP WHERE expr RP */
|
|
-{ yymsp[-4].minor.yy202 = yymsp[-1].minor.yy202; }
|
|
+ case 341: /* filter_clause ::= FILTER LP WHERE expr RP */
|
|
+{ yymsp[-4].minor.yy528 = yymsp[-1].minor.yy528; }
|
|
break;
|
|
default:
|
|
- /* (325) input ::= cmdlist */ yytestcase(yyruleno==325);
|
|
- /* (326) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==326);
|
|
- /* (327) cmdlist ::= ecmd (OPTIMIZED OUT) */ assert(yyruleno!=327);
|
|
- /* (328) ecmd ::= SEMI */ yytestcase(yyruleno==328);
|
|
- /* (329) ecmd ::= cmdx SEMI */ yytestcase(yyruleno==329);
|
|
- /* (330) ecmd ::= explain cmdx SEMI (NEVER REDUCES) */ assert(yyruleno!=330);
|
|
- /* (331) trans_opt ::= */ yytestcase(yyruleno==331);
|
|
- /* (332) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==332);
|
|
- /* (333) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==333);
|
|
- /* (334) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==334);
|
|
- /* (335) savepoint_opt ::= */ yytestcase(yyruleno==335);
|
|
- /* (336) cmd ::= create_table create_table_args */ yytestcase(yyruleno==336);
|
|
- /* (337) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==337);
|
|
- /* (338) columnlist ::= columnname carglist */ yytestcase(yyruleno==338);
|
|
- /* (339) nm ::= ID|INDEXED */ yytestcase(yyruleno==339);
|
|
- /* (340) nm ::= STRING */ yytestcase(yyruleno==340);
|
|
- /* (341) nm ::= JOIN_KW */ yytestcase(yyruleno==341);
|
|
- /* (342) typetoken ::= typename */ yytestcase(yyruleno==342);
|
|
- /* (343) typename ::= ID|STRING */ yytestcase(yyruleno==343);
|
|
- /* (344) signed ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=344);
|
|
- /* (345) signed ::= minus_num (OPTIMIZED OUT) */ assert(yyruleno!=345);
|
|
- /* (346) carglist ::= carglist ccons */ yytestcase(yyruleno==346);
|
|
- /* (347) carglist ::= */ yytestcase(yyruleno==347);
|
|
- /* (348) ccons ::= NULL onconf */ yytestcase(yyruleno==348);
|
|
- /* (349) ccons ::= GENERATED ALWAYS AS generated */ yytestcase(yyruleno==349);
|
|
- /* (350) ccons ::= AS generated */ yytestcase(yyruleno==350);
|
|
- /* (351) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==351);
|
|
- /* (352) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==352);
|
|
- /* (353) conslist ::= tcons (OPTIMIZED OUT) */ assert(yyruleno!=353);
|
|
- /* (354) tconscomma ::= */ yytestcase(yyruleno==354);
|
|
- /* (355) defer_subclause_opt ::= defer_subclause (OPTIMIZED OUT) */ assert(yyruleno!=355);
|
|
- /* (356) resolvetype ::= raisetype (OPTIMIZED OUT) */ assert(yyruleno!=356);
|
|
- /* (357) selectnowith ::= oneselect (OPTIMIZED OUT) */ assert(yyruleno!=357);
|
|
- /* (358) oneselect ::= values */ yytestcase(yyruleno==358);
|
|
- /* (359) sclp ::= selcollist COMMA */ yytestcase(yyruleno==359);
|
|
- /* (360) as ::= ID|STRING */ yytestcase(yyruleno==360);
|
|
- /* (361) expr ::= term (OPTIMIZED OUT) */ assert(yyruleno!=361);
|
|
- /* (362) likeop ::= LIKE_KW|MATCH */ yytestcase(yyruleno==362);
|
|
- /* (363) exprlist ::= nexprlist */ yytestcase(yyruleno==363);
|
|
- /* (364) nmnum ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=364);
|
|
- /* (365) nmnum ::= nm (OPTIMIZED OUT) */ assert(yyruleno!=365);
|
|
- /* (366) nmnum ::= ON */ yytestcase(yyruleno==366);
|
|
- /* (367) nmnum ::= DELETE */ yytestcase(yyruleno==367);
|
|
- /* (368) nmnum ::= DEFAULT */ yytestcase(yyruleno==368);
|
|
- /* (369) plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==369);
|
|
- /* (370) foreach_clause ::= */ yytestcase(yyruleno==370);
|
|
- /* (371) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==371);
|
|
- /* (372) trnm ::= nm */ yytestcase(yyruleno==372);
|
|
- /* (373) tridxby ::= */ yytestcase(yyruleno==373);
|
|
- /* (374) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==374);
|
|
- /* (375) database_kw_opt ::= */ yytestcase(yyruleno==375);
|
|
- /* (376) kwcolumn_opt ::= */ yytestcase(yyruleno==376);
|
|
- /* (377) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==377);
|
|
- /* (378) vtabarglist ::= vtabarg */ yytestcase(yyruleno==378);
|
|
- /* (379) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==379);
|
|
- /* (380) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==380);
|
|
- /* (381) anylist ::= */ yytestcase(yyruleno==381);
|
|
- /* (382) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==382);
|
|
- /* (383) anylist ::= anylist ANY */ yytestcase(yyruleno==383);
|
|
- /* (384) with ::= */ yytestcase(yyruleno==384);
|
|
+ /* (342) input ::= cmdlist */ yytestcase(yyruleno==342);
|
|
+ /* (343) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==343);
|
|
+ /* (344) cmdlist ::= ecmd (OPTIMIZED OUT) */ assert(yyruleno!=344);
|
|
+ /* (345) ecmd ::= SEMI */ yytestcase(yyruleno==345);
|
|
+ /* (346) ecmd ::= cmdx SEMI */ yytestcase(yyruleno==346);
|
|
+ /* (347) ecmd ::= explain cmdx SEMI (NEVER REDUCES) */ assert(yyruleno!=347);
|
|
+ /* (348) trans_opt ::= */ yytestcase(yyruleno==348);
|
|
+ /* (349) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==349);
|
|
+ /* (350) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==350);
|
|
+ /* (351) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==351);
|
|
+ /* (352) savepoint_opt ::= */ yytestcase(yyruleno==352);
|
|
+ /* (353) cmd ::= create_table create_table_args */ yytestcase(yyruleno==353);
|
|
+ /* (354) table_option_set ::= table_option (OPTIMIZED OUT) */ assert(yyruleno!=354);
|
|
+ /* (355) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==355);
|
|
+ /* (356) columnlist ::= columnname carglist */ yytestcase(yyruleno==356);
|
|
+ /* (357) nm ::= ID|INDEXED */ yytestcase(yyruleno==357);
|
|
+ /* (358) nm ::= STRING */ yytestcase(yyruleno==358);
|
|
+ /* (359) nm ::= JOIN_KW */ yytestcase(yyruleno==359);
|
|
+ /* (360) typetoken ::= typename */ yytestcase(yyruleno==360);
|
|
+ /* (361) typename ::= ID|STRING */ yytestcase(yyruleno==361);
|
|
+ /* (362) signed ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=362);
|
|
+ /* (363) signed ::= minus_num (OPTIMIZED OUT) */ assert(yyruleno!=363);
|
|
+ /* (364) carglist ::= carglist ccons */ yytestcase(yyruleno==364);
|
|
+ /* (365) carglist ::= */ yytestcase(yyruleno==365);
|
|
+ /* (366) ccons ::= NULL onconf */ yytestcase(yyruleno==366);
|
|
+ /* (367) ccons ::= GENERATED ALWAYS AS generated */ yytestcase(yyruleno==367);
|
|
+ /* (368) ccons ::= AS generated */ yytestcase(yyruleno==368);
|
|
+ /* (369) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==369);
|
|
+ /* (370) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==370);
|
|
+ /* (371) conslist ::= tcons (OPTIMIZED OUT) */ assert(yyruleno!=371);
|
|
+ /* (372) tconscomma ::= */ yytestcase(yyruleno==372);
|
|
+ /* (373) defer_subclause_opt ::= defer_subclause (OPTIMIZED OUT) */ assert(yyruleno!=373);
|
|
+ /* (374) resolvetype ::= raisetype (OPTIMIZED OUT) */ assert(yyruleno!=374);
|
|
+ /* (375) selectnowith ::= oneselect (OPTIMIZED OUT) */ assert(yyruleno!=375);
|
|
+ /* (376) oneselect ::= values */ yytestcase(yyruleno==376);
|
|
+ /* (377) sclp ::= selcollist COMMA */ yytestcase(yyruleno==377);
|
|
+ /* (378) as ::= ID|STRING */ yytestcase(yyruleno==378);
|
|
+ /* (379) indexed_opt ::= indexed_by (OPTIMIZED OUT) */ assert(yyruleno!=379);
|
|
+ /* (380) returning ::= */ yytestcase(yyruleno==380);
|
|
+ /* (381) expr ::= term (OPTIMIZED OUT) */ assert(yyruleno!=381);
|
|
+ /* (382) likeop ::= LIKE_KW|MATCH */ yytestcase(yyruleno==382);
|
|
+ /* (383) exprlist ::= nexprlist */ yytestcase(yyruleno==383);
|
|
+ /* (384) nmnum ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=384);
|
|
+ /* (385) nmnum ::= nm (OPTIMIZED OUT) */ assert(yyruleno!=385);
|
|
+ /* (386) nmnum ::= ON */ yytestcase(yyruleno==386);
|
|
+ /* (387) nmnum ::= DELETE */ yytestcase(yyruleno==387);
|
|
+ /* (388) nmnum ::= DEFAULT */ yytestcase(yyruleno==388);
|
|
+ /* (389) plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==389);
|
|
+ /* (390) foreach_clause ::= */ yytestcase(yyruleno==390);
|
|
+ /* (391) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==391);
|
|
+ /* (392) trnm ::= nm */ yytestcase(yyruleno==392);
|
|
+ /* (393) tridxby ::= */ yytestcase(yyruleno==393);
|
|
+ /* (394) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==394);
|
|
+ /* (395) database_kw_opt ::= */ yytestcase(yyruleno==395);
|
|
+ /* (396) kwcolumn_opt ::= */ yytestcase(yyruleno==396);
|
|
+ /* (397) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==397);
|
|
+ /* (398) vtabarglist ::= vtabarg */ yytestcase(yyruleno==398);
|
|
+ /* (399) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==399);
|
|
+ /* (400) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==400);
|
|
+ /* (401) anylist ::= */ yytestcase(yyruleno==401);
|
|
+ /* (402) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==402);
|
|
+ /* (403) anylist ::= anylist ANY */ yytestcase(yyruleno==403);
|
|
+ /* (404) with ::= */ yytestcase(yyruleno==404);
|
|
break;
|
|
/********** End reduce actions ************************************************/
|
|
};
|
|
@@ -157176,12 +172067,56 @@ SQLITE_PRIVATE void sqlite3Parser(
|
|
}
|
|
#endif
|
|
|
|
- do{
|
|
+ while(1){ /* Exit by "break" */
|
|
+ assert( yypParser->yytos>=yypParser->yystack );
|
|
assert( yyact==yypParser->yytos->stateno );
|
|
yyact = yy_find_shift_action((YYCODETYPE)yymajor,yyact);
|
|
if( yyact >= YY_MIN_REDUCE ){
|
|
- yyact = yy_reduce(yypParser,yyact-YY_MIN_REDUCE,yymajor,
|
|
- yyminor sqlite3ParserCTX_PARAM);
|
|
+ unsigned int yyruleno = yyact - YY_MIN_REDUCE; /* Reduce by this rule */
|
|
+#ifndef NDEBUG
|
|
+ assert( yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) );
|
|
+ if( yyTraceFILE ){
|
|
+ int yysize = yyRuleInfoNRhs[yyruleno];
|
|
+ if( yysize ){
|
|
+ fprintf(yyTraceFILE, "%sReduce %d [%s]%s, pop back to state %d.\n",
|
|
+ yyTracePrompt,
|
|
+ yyruleno, yyRuleName[yyruleno],
|
|
+ yyruleno<YYNRULE_WITH_ACTION ? "" : " without external action",
|
|
+ yypParser->yytos[yysize].stateno);
|
|
+ }else{
|
|
+ fprintf(yyTraceFILE, "%sReduce %d [%s]%s.\n",
|
|
+ yyTracePrompt, yyruleno, yyRuleName[yyruleno],
|
|
+ yyruleno<YYNRULE_WITH_ACTION ? "" : " without external action");
|
|
+ }
|
|
+ }
|
|
+#endif /* NDEBUG */
|
|
+
|
|
+ /* Check that the stack is large enough to grow by a single entry
|
|
+ ** if the RHS of the rule is empty. This ensures that there is room
|
|
+ ** enough on the stack to push the LHS value */
|
|
+ if( yyRuleInfoNRhs[yyruleno]==0 ){
|
|
+#ifdef YYTRACKMAXSTACKDEPTH
|
|
+ if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){
|
|
+ yypParser->yyhwm++;
|
|
+ assert( yypParser->yyhwm ==
|
|
+ (int)(yypParser->yytos - yypParser->yystack));
|
|
+ }
|
|
+#endif
|
|
+#if YYSTACKDEPTH>0
|
|
+ if( yypParser->yytos>=yypParser->yystackEnd ){
|
|
+ yyStackOverflow(yypParser);
|
|
+ break;
|
|
+ }
|
|
+#else
|
|
+ if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz-1] ){
|
|
+ if( yyGrowStack(yypParser) ){
|
|
+ yyStackOverflow(yypParser);
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+#endif
|
|
+ }
|
|
+ yyact = yy_reduce(yypParser,yyruleno,yymajor,yyminor sqlite3ParserCTX_PARAM);
|
|
}else if( yyact <= YY_MAX_SHIFTREDUCE ){
|
|
yy_shift(yypParser,yyact,(YYCODETYPE)yymajor,yyminor);
|
|
#ifndef YYNOERRORRECOVERY
|
|
@@ -157206,7 +172141,7 @@ SQLITE_PRIVATE void sqlite3Parser(
|
|
#ifdef YYERRORSYMBOL
|
|
/* A syntax error has occurred.
|
|
** The response to an error depends upon whether or not the
|
|
- ** grammar defines an error token "ERROR".
|
|
+ ** grammar defines an error token "ERROR".
|
|
**
|
|
** This is what we do if the grammar does define ERROR:
|
|
**
|
|
@@ -157237,14 +172172,13 @@ SQLITE_PRIVATE void sqlite3Parser(
|
|
yy_destructor(yypParser, (YYCODETYPE)yymajor, &yyminorunion);
|
|
yymajor = YYNOCODE;
|
|
}else{
|
|
- while( yypParser->yytos >= yypParser->yystack
|
|
- && (yyact = yy_find_reduce_action(
|
|
- yypParser->yytos->stateno,
|
|
- YYERRORSYMBOL)) > YY_MAX_SHIFTREDUCE
|
|
- ){
|
|
+ while( yypParser->yytos > yypParser->yystack ){
|
|
+ yyact = yy_find_reduce_action(yypParser->yytos->stateno,
|
|
+ YYERRORSYMBOL);
|
|
+ if( yyact<=YY_MAX_SHIFTREDUCE ) break;
|
|
yy_pop_parser_stack(yypParser);
|
|
}
|
|
- if( yypParser->yytos < yypParser->yystack || yymajor==0 ){
|
|
+ if( yypParser->yytos <= yypParser->yystack || yymajor==0 ){
|
|
yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
|
|
yy_parse_failed(yypParser);
|
|
#ifndef YYNOERRORRECOVERY
|
|
@@ -157294,7 +172228,7 @@ SQLITE_PRIVATE void sqlite3Parser(
|
|
break;
|
|
#endif
|
|
}
|
|
- }while( yypParser->yytos>yypParser->yystack );
|
|
+ }
|
|
#ifndef NDEBUG
|
|
if( yyTraceFILE ){
|
|
yyStackEntry *i;
|
|
@@ -157355,8 +172289,8 @@ SQLITE_PRIVATE int sqlite3ParserFallback(int iToken){
|
|
** all of them need to be used within the switch.
|
|
*/
|
|
#define CC_X 0 /* The letter 'x', or start of BLOB literal */
|
|
-#define CC_KYWD 1 /* Alphabetics or '_'. Usable in a keyword */
|
|
-#define CC_ID 2 /* unicode characters usable in IDs */
|
|
+#define CC_KYWD0 1 /* First letter of a keyword */
|
|
+#define CC_KYWD 2 /* Alphabetics or '_'. Usable in a keyword */
|
|
#define CC_DIGIT 3 /* Digits */
|
|
#define CC_DOLLAR 4 /* '$' */
|
|
#define CC_VARALPHA 5 /* '@', '#', ':'. Alphabetic SQL variables */
|
|
@@ -157381,47 +172315,49 @@ SQLITE_PRIVATE int sqlite3ParserFallback(int iToken){
|
|
#define CC_AND 24 /* '&' */
|
|
#define CC_TILDA 25 /* '~' */
|
|
#define CC_DOT 26 /* '.' */
|
|
-#define CC_ILLEGAL 27 /* Illegal character */
|
|
-#define CC_NUL 28 /* 0x00 */
|
|
+#define CC_ID 27 /* unicode characters usable in IDs */
|
|
+#define CC_ILLEGAL 28 /* Illegal character */
|
|
+#define CC_NUL 29 /* 0x00 */
|
|
+#define CC_BOM 30 /* First byte of UTF8 BOM: 0xEF 0xBB 0xBF */
|
|
|
|
static const unsigned char aiClass[] = {
|
|
#ifdef SQLITE_ASCII
|
|
/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xa xb xc xd xe xf */
|
|
-/* 0x */ 28, 27, 27, 27, 27, 27, 27, 27, 27, 7, 7, 27, 7, 7, 27, 27,
|
|
-/* 1x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
|
|
+/* 0x */ 29, 28, 28, 28, 28, 28, 28, 28, 28, 7, 7, 28, 7, 7, 28, 28,
|
|
+/* 1x */ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
|
|
/* 2x */ 7, 15, 8, 5, 4, 22, 24, 8, 17, 18, 21, 20, 23, 11, 26, 16,
|
|
/* 3x */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 19, 12, 14, 13, 6,
|
|
/* 4x */ 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
-/* 5x */ 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 9, 27, 27, 27, 1,
|
|
+/* 5x */ 1, 1, 1, 1, 1, 1, 1, 1, 0, 2, 2, 9, 28, 28, 28, 2,
|
|
/* 6x */ 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
-/* 7x */ 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 27, 10, 27, 25, 27,
|
|
-/* 8x */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
-/* 9x */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
-/* Ax */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
-/* Bx */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
-/* Cx */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
-/* Dx */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
-/* Ex */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
-/* Fx */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2
|
|
+/* 7x */ 1, 1, 1, 1, 1, 1, 1, 1, 0, 2, 2, 28, 10, 28, 25, 28,
|
|
+/* 8x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
|
|
+/* 9x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
|
|
+/* Ax */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
|
|
+/* Bx */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
|
|
+/* Cx */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
|
|
+/* Dx */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
|
|
+/* Ex */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 30,
|
|
+/* Fx */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27
|
|
#endif
|
|
#ifdef SQLITE_EBCDIC
|
|
/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xa xb xc xd xe xf */
|
|
-/* 0x */ 27, 27, 27, 27, 27, 7, 27, 27, 27, 27, 27, 27, 7, 7, 27, 27,
|
|
-/* 1x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
|
|
-/* 2x */ 27, 27, 27, 27, 27, 7, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
|
|
-/* 3x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
|
|
-/* 4x */ 7, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 26, 12, 17, 20, 10,
|
|
-/* 5x */ 24, 27, 27, 27, 27, 27, 27, 27, 27, 27, 15, 4, 21, 18, 19, 27,
|
|
-/* 6x */ 11, 16, 27, 27, 27, 27, 27, 27, 27, 27, 27, 23, 22, 1, 13, 6,
|
|
-/* 7x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 8, 5, 5, 5, 8, 14, 8,
|
|
-/* 8x */ 27, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 27, 27, 27, 27, 27,
|
|
-/* 9x */ 27, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 27, 27, 27, 27, 27,
|
|
-/* Ax */ 27, 25, 1, 1, 1, 1, 1, 0, 1, 1, 27, 27, 27, 27, 27, 27,
|
|
-/* Bx */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 9, 27, 27, 27, 27, 27,
|
|
-/* Cx */ 27, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 27, 27, 27, 27, 27,
|
|
-/* Dx */ 27, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 27, 27, 27, 27, 27,
|
|
-/* Ex */ 27, 27, 1, 1, 1, 1, 1, 0, 1, 1, 27, 27, 27, 27, 27, 27,
|
|
-/* Fx */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 27, 27, 27, 27, 27, 27,
|
|
+/* 0x */ 29, 28, 28, 28, 28, 7, 28, 28, 28, 28, 28, 28, 7, 7, 28, 28,
|
|
+/* 1x */ 28, 28, 28, 28, 28, 7, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
|
|
+/* 2x */ 28, 28, 28, 28, 28, 7, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
|
|
+/* 3x */ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
|
|
+/* 4x */ 7, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 26, 12, 17, 20, 10,
|
|
+/* 5x */ 24, 28, 28, 28, 28, 28, 28, 28, 28, 28, 15, 4, 21, 18, 19, 28,
|
|
+/* 6x */ 11, 16, 28, 28, 28, 28, 28, 28, 28, 28, 28, 23, 22, 2, 13, 6,
|
|
+/* 7x */ 28, 28, 28, 28, 28, 28, 28, 28, 28, 8, 5, 5, 5, 8, 14, 8,
|
|
+/* 8x */ 28, 1, 1, 1, 1, 1, 1, 1, 1, 1, 28, 28, 28, 28, 28, 28,
|
|
+/* 9x */ 28, 1, 1, 1, 1, 1, 1, 1, 1, 1, 28, 28, 28, 28, 28, 28,
|
|
+/* Ax */ 28, 25, 1, 1, 1, 1, 1, 0, 2, 2, 28, 28, 28, 28, 28, 28,
|
|
+/* Bx */ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 9, 28, 28, 28, 28, 28,
|
|
+/* Cx */ 28, 1, 1, 1, 1, 1, 1, 1, 1, 1, 28, 28, 28, 28, 28, 28,
|
|
+/* Dx */ 28, 1, 1, 1, 1, 1, 1, 1, 1, 1, 28, 28, 28, 28, 28, 28,
|
|
+/* Ex */ 28, 28, 1, 1, 1, 1, 1, 0, 2, 2, 28, 28, 28, 28, 28, 28,
|
|
+/* Fx */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 28, 28, 28, 28, 28, 28,
|
|
#endif
|
|
};
|
|
|
|
@@ -157430,7 +172366,7 @@ static const unsigned char aiClass[] = {
|
|
** lower-case ASCII equivalent. On ASCII machines, this is just
|
|
** an upper-to-lower case map. On EBCDIC machines we also need
|
|
** to adjust the encoding. The mapping is only valid for alphabetics
|
|
-** which are the only characters for which this feature is used.
|
|
+** which are the only characters for which this feature is used.
|
|
**
|
|
** Used by keywordhash.h
|
|
*/
|
|
@@ -157462,7 +172398,7 @@ const unsigned char ebcdicToAscii[] = {
|
|
|
|
/*
|
|
** The sqlite3KeywordCode function looks up an identifier to determine if
|
|
-** it is a keyword. If it is a keyword, the token code of that keyword is
|
|
+** it is a keyword. If it is a keyword, the token code of that keyword is
|
|
** returned. If the input is not a keyword, TK_ID is returned.
|
|
**
|
|
** The implementation of this routine was generated by a program,
|
|
@@ -157486,20 +172422,21 @@ const unsigned char ebcdicToAscii[] = {
|
|
** is substantially reduced. This is important for embedded applications
|
|
** on platforms with limited memory.
|
|
*/
|
|
-/* Hash score: 227 */
|
|
-/* zKWText[] encodes 984 bytes of keyword text in 648 bytes */
|
|
+/* Hash score: 231 */
|
|
+/* zKWText[] encodes 1007 bytes of keyword text in 667 bytes */
|
|
/* REINDEXEDESCAPEACHECKEYBEFOREIGNOREGEXPLAINSTEADDATABASELECT */
|
|
/* ABLEFTHENDEFERRABLELSEXCLUDELETEMPORARYISNULLSAVEPOINTERSECT */
|
|
/* IESNOTNULLIKEXCEPTRANSACTIONATURALTERAISEXCLUSIVEXISTS */
|
|
/* CONSTRAINTOFFSETRIGGERANGENERATEDETACHAVINGLOBEGINNEREFERENCES */
|
|
/* UNIQUERYWITHOUTERELEASEATTACHBETWEENOTHINGROUPSCASCADEFAULT */
|
|
/* CASECOLLATECREATECURRENT_DATEIMMEDIATEJOINSERTMATCHPLANALYZE */
|
|
-/* PRAGMABORTUPDATEVALUESVIRTUALWAYSWHENWHERECURSIVEAFTERENAMEAND */
|
|
-/* EFERREDISTINCTAUTOINCREMENTCASTCOLUMNCOMMITCONFLICTCROSS */
|
|
-/* CURRENT_TIMESTAMPARTITIONDROPRECEDINGFAILASTFILTEREPLACEFIRST */
|
|
-/* FOLLOWINGFROMFULLIMITIFORDERESTRICTOTHERSOVERIGHTROLLBACKROWS */
|
|
-/* UNBOUNDEDUNIONUSINGVACUUMVIEWINDOWBYINITIALLYPRIMARY */
|
|
-static const char zKWText[647] = {
|
|
+/* PRAGMATERIALIZEDEFERREDISTINCTUPDATEVALUESVIRTUALWAYSWHENWHERE */
|
|
+/* CURSIVEABORTAFTERENAMEANDROPARTITIONAUTOINCREMENTCASTCOLUMN */
|
|
+/* COMMITCONFLICTCROSSCURRENT_TIMESTAMPRECEDINGFAILASTFILTER */
|
|
+/* EPLACEFIRSTFOLLOWINGFROMFULLIMITIFORDERESTRICTOTHERSOVER */
|
|
+/* ETURNINGRIGHTROLLBACKROWSUNBOUNDEDUNIONUSINGVACUUMVIEWINDOWBY */
|
|
+/* INITIALLYPRIMARY */
|
|
+static const char zKWText[666] = {
|
|
'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',
|
|
@@ -157520,115 +172457,117 @@ static const char zKWText[647] = {
|
|
'C','R','E','A','T','E','C','U','R','R','E','N','T','_','D','A','T','E',
|
|
'I','M','M','E','D','I','A','T','E','J','O','I','N','S','E','R','T','M',
|
|
'A','T','C','H','P','L','A','N','A','L','Y','Z','E','P','R','A','G','M',
|
|
- 'A','B','O','R','T','U','P','D','A','T','E','V','A','L','U','E','S','V',
|
|
- 'I','R','T','U','A','L','W','A','Y','S','W','H','E','N','W','H','E','R',
|
|
- 'E','C','U','R','S','I','V','E','A','F','T','E','R','E','N','A','M','E',
|
|
- 'A','N','D','E','F','E','R','R','E','D','I','S','T','I','N','C','T','A',
|
|
- 'U','T','O','I','N','C','R','E','M','E','N','T','C','A','S','T','C','O',
|
|
- 'L','U','M','N','C','O','M','M','I','T','C','O','N','F','L','I','C','T',
|
|
- 'C','R','O','S','S','C','U','R','R','E','N','T','_','T','I','M','E','S',
|
|
- 'T','A','M','P','A','R','T','I','T','I','O','N','D','R','O','P','R','E',
|
|
- 'C','E','D','I','N','G','F','A','I','L','A','S','T','F','I','L','T','E',
|
|
- 'R','E','P','L','A','C','E','F','I','R','S','T','F','O','L','L','O','W',
|
|
- 'I','N','G','F','R','O','M','F','U','L','L','I','M','I','T','I','F','O',
|
|
- 'R','D','E','R','E','S','T','R','I','C','T','O','T','H','E','R','S','O',
|
|
- 'V','E','R','I','G','H','T','R','O','L','L','B','A','C','K','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',
|
|
+ 'A','T','E','R','I','A','L','I','Z','E','D','E','F','E','R','R','E','D',
|
|
+ 'I','S','T','I','N','C','T','U','P','D','A','T','E','V','A','L','U','E',
|
|
+ 'S','V','I','R','T','U','A','L','W','A','Y','S','W','H','E','N','W','H',
|
|
+ 'E','R','E','C','U','R','S','I','V','E','A','B','O','R','T','A','F','T',
|
|
+ 'E','R','E','N','A','M','E','A','N','D','R','O','P','A','R','T','I','T',
|
|
+ 'I','O','N','A','U','T','O','I','N','C','R','E','M','E','N','T','C','A',
|
|
+ 'S','T','C','O','L','U','M','N','C','O','M','M','I','T','C','O','N','F',
|
|
+ 'L','I','C','T','C','R','O','S','S','C','U','R','R','E','N','T','_','T',
|
|
+ 'I','M','E','S','T','A','M','P','R','E','C','E','D','I','N','G','F','A',
|
|
+ 'I','L','A','S','T','F','I','L','T','E','R','E','P','L','A','C','E','F',
|
|
+ 'I','R','S','T','F','O','L','L','O','W','I','N','G','F','R','O','M','F',
|
|
+ 'U','L','L','I','M','I','T','I','F','O','R','D','E','R','E','S','T','R',
|
|
+ 'I','C','T','O','T','H','E','R','S','O','V','E','R','E','T','U','R','N',
|
|
+ 'I','N','G','R','I','G','H','T','R','O','L','L','B','A','C','K','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',
|
|
};
|
|
/* aKWHash[i] is the hash value for the i-th keyword */
|
|
static const unsigned char aKWHash[127] = {
|
|
- 84, 102, 132, 82, 114, 29, 0, 0, 91, 0, 85, 72, 0,
|
|
- 53, 35, 86, 15, 0, 42, 94, 54, 126, 133, 19, 0, 0,
|
|
- 138, 0, 40, 128, 0, 22, 104, 0, 9, 0, 0, 122, 80,
|
|
- 0, 78, 6, 0, 65, 99, 145, 0, 134, 112, 0, 0, 48,
|
|
- 0, 100, 24, 0, 17, 0, 27, 70, 23, 26, 5, 60, 140,
|
|
- 107, 121, 0, 73, 101, 71, 143, 61, 119, 74, 0, 49, 0,
|
|
- 11, 41, 0, 110, 0, 0, 0, 106, 10, 108, 113, 124, 14,
|
|
- 50, 123, 0, 89, 0, 18, 120, 142, 56, 129, 137, 88, 83,
|
|
- 37, 30, 125, 0, 0, 105, 51, 130, 127, 0, 34, 0, 0,
|
|
- 44, 0, 95, 38, 39, 0, 20, 45, 116, 90,
|
|
+ 84, 92, 134, 82, 105, 29, 0, 0, 94, 0, 85, 72, 0,
|
|
+ 53, 35, 86, 15, 0, 42, 97, 54, 89, 135, 19, 0, 0,
|
|
+ 140, 0, 40, 129, 0, 22, 107, 0, 9, 0, 0, 123, 80,
|
|
+ 0, 78, 6, 0, 65, 103, 147, 0, 136, 115, 0, 0, 48,
|
|
+ 0, 90, 24, 0, 17, 0, 27, 70, 23, 26, 5, 60, 142,
|
|
+ 110, 122, 0, 73, 91, 71, 145, 61, 120, 74, 0, 49, 0,
|
|
+ 11, 41, 0, 113, 0, 0, 0, 109, 10, 111, 116, 125, 14,
|
|
+ 50, 124, 0, 100, 0, 18, 121, 144, 56, 130, 139, 88, 83,
|
|
+ 37, 30, 126, 0, 0, 108, 51, 131, 128, 0, 34, 0, 0,
|
|
+ 132, 0, 98, 38, 39, 0, 20, 45, 117, 93,
|
|
};
|
|
/* 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[145] = {
|
|
- 0, 0, 0, 0, 4, 0, 43, 0, 0, 103, 111, 0, 0,
|
|
- 0, 2, 0, 0, 141, 0, 0, 0, 13, 0, 0, 0, 0,
|
|
- 139, 0, 0, 118, 52, 0, 0, 135, 12, 0, 0, 62, 0,
|
|
- 136, 0, 131, 0, 0, 36, 0, 0, 28, 77, 0, 0, 0,
|
|
+static const unsigned char aKWNext[147] = {
|
|
+ 0, 0, 0, 0, 4, 0, 43, 0, 0, 106, 114, 0, 0,
|
|
+ 0, 2, 0, 0, 143, 0, 0, 0, 13, 0, 0, 0, 0,
|
|
+ 141, 0, 0, 119, 52, 0, 0, 137, 12, 0, 0, 62, 0,
|
|
+ 138, 0, 133, 0, 0, 36, 0, 0, 28, 77, 0, 0, 0,
|
|
0, 59, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
- 0, 69, 0, 0, 0, 0, 0, 144, 3, 0, 58, 0, 1,
|
|
- 75, 0, 0, 0, 31, 0, 0, 0, 0, 0, 0, 64, 66,
|
|
- 63, 0, 0, 0, 0, 46, 0, 16, 0, 115, 0, 0, 0,
|
|
- 0, 0, 0, 0, 0, 0, 0, 81, 97, 0, 8, 0, 109,
|
|
- 21, 7, 67, 0, 79, 93, 117, 0, 0, 68, 0, 0, 96,
|
|
- 0, 55, 0, 76, 0, 92, 32, 33, 57, 25, 0, 98, 0,
|
|
- 0, 87,
|
|
+ 0, 69, 0, 0, 0, 0, 0, 146, 3, 0, 58, 0, 1,
|
|
+ 75, 0, 0, 0, 31, 0, 0, 0, 0, 0, 127, 0, 104,
|
|
+ 0, 64, 66, 63, 0, 0, 0, 0, 0, 46, 0, 16, 8,
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 81, 101, 0,
|
|
+ 112, 21, 7, 67, 0, 79, 96, 118, 0, 0, 68, 0, 0,
|
|
+ 99, 44, 0, 55, 0, 76, 0, 95, 32, 33, 57, 25, 0,
|
|
+ 102, 0, 0, 87,
|
|
};
|
|
/* aKWLen[i] is the length (in bytes) of the i-th keyword */
|
|
-static const unsigned char aKWLen[145] = {
|
|
+static const unsigned char aKWLen[147] = {
|
|
7, 7, 5, 4, 6, 4, 5, 3, 6, 7, 3, 6, 6,
|
|
7, 7, 3, 8, 2, 6, 5, 4, 4, 3, 10, 4, 7,
|
|
6, 9, 4, 2, 6, 5, 9, 9, 4, 7, 3, 2, 4,
|
|
4, 6, 11, 6, 2, 7, 5, 5, 9, 6, 10, 4, 6,
|
|
2, 3, 7, 5, 9, 6, 6, 4, 5, 5, 10, 6, 5,
|
|
7, 4, 5, 7, 6, 7, 7, 6, 5, 7, 3, 7, 4,
|
|
- 7, 6, 12, 9, 4, 6, 5, 4, 7, 6, 5, 6, 6,
|
|
- 7, 6, 4, 5, 9, 5, 6, 3, 8, 8, 2, 13, 2,
|
|
- 2, 4, 6, 6, 8, 5, 17, 12, 7, 9, 4, 9, 4,
|
|
- 4, 6, 7, 5, 9, 4, 4, 5, 2, 5, 8, 6, 4,
|
|
- 5, 8, 4, 3, 9, 5, 5, 6, 4, 6, 2, 2, 9,
|
|
- 3, 7,
|
|
+ 7, 6, 12, 9, 4, 6, 5, 4, 7, 6, 12, 8, 8,
|
|
+ 2, 6, 6, 7, 6, 4, 5, 9, 5, 5, 6, 3, 4,
|
|
+ 9, 13, 2, 2, 4, 6, 6, 8, 5, 17, 12, 7, 9,
|
|
+ 4, 4, 6, 7, 5, 9, 4, 4, 5, 2, 5, 8, 6,
|
|
+ 4, 9, 5, 8, 4, 3, 9, 5, 5, 6, 4, 6, 2,
|
|
+ 2, 9, 3, 7,
|
|
};
|
|
/* aKWOffset[i] is the index into zKWText[] of the start of
|
|
** the text for the i-th keyword. */
|
|
-static const unsigned short int aKWOffset[145] = {
|
|
+static const unsigned short int aKWOffset[147] = {
|
|
0, 2, 2, 8, 9, 14, 16, 20, 23, 25, 25, 29, 33,
|
|
36, 41, 46, 48, 53, 54, 59, 62, 65, 67, 69, 78, 81,
|
|
86, 90, 90, 94, 99, 101, 105, 111, 119, 123, 123, 123, 126,
|
|
129, 132, 137, 142, 146, 147, 152, 156, 160, 168, 174, 181, 184,
|
|
184, 187, 189, 195, 198, 206, 211, 216, 219, 222, 226, 236, 239,
|
|
244, 244, 248, 252, 259, 265, 271, 277, 277, 283, 284, 288, 295,
|
|
- 299, 306, 312, 324, 333, 335, 341, 346, 348, 355, 360, 365, 371,
|
|
- 377, 382, 388, 392, 395, 404, 408, 414, 416, 423, 424, 431, 433,
|
|
- 435, 444, 448, 454, 460, 468, 473, 473, 473, 489, 498, 501, 510,
|
|
- 513, 517, 522, 529, 534, 543, 547, 550, 555, 557, 561, 569, 575,
|
|
- 578, 583, 591, 591, 595, 604, 609, 614, 620, 623, 626, 629, 631,
|
|
- 636, 640,
|
|
+ 299, 306, 312, 324, 333, 335, 341, 346, 348, 355, 359, 370, 377,
|
|
+ 378, 385, 391, 397, 402, 408, 412, 415, 424, 429, 433, 439, 441,
|
|
+ 444, 453, 455, 457, 466, 470, 476, 482, 490, 495, 495, 495, 511,
|
|
+ 520, 523, 527, 532, 539, 544, 553, 557, 560, 565, 567, 571, 579,
|
|
+ 585, 588, 597, 602, 610, 610, 614, 623, 628, 633, 639, 642, 645,
|
|
+ 648, 650, 655, 659,
|
|
};
|
|
/* aKWCode[i] is the parser symbol code for the i-th keyword */
|
|
-static const unsigned char aKWCode[145] = {
|
|
- 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,
|
|
- TK_ADD, TK_DATABASE, TK_AS, TK_SELECT, TK_TABLE,
|
|
- TK_JOIN_KW, TK_THEN, TK_END, TK_DEFERRABLE, TK_ELSE,
|
|
- TK_EXCLUDE, TK_DELETE, TK_TEMP, TK_TEMP, TK_OR,
|
|
- TK_ISNULL, TK_NULLS, TK_SAVEPOINT, TK_INTERSECT, TK_TIES,
|
|
- TK_NOTNULL, TK_NOT, TK_NO, TK_NULL, TK_LIKE_KW,
|
|
- TK_EXCEPT, TK_TRANSACTION,TK_ACTION, TK_ON, TK_JOIN_KW,
|
|
- TK_ALTER, TK_RAISE, TK_EXCLUSIVE, TK_EXISTS, TK_CONSTRAINT,
|
|
- TK_INTO, TK_OFFSET, TK_OF, TK_SET, TK_TRIGGER,
|
|
- TK_RANGE, TK_GENERATED, TK_DETACH, TK_HAVING, TK_LIKE_KW,
|
|
- TK_BEGIN, TK_JOIN_KW, TK_REFERENCES, TK_UNIQUE, TK_QUERY,
|
|
- TK_WITHOUT, TK_WITH, TK_JOIN_KW, TK_RELEASE, TK_ATTACH,
|
|
- TK_BETWEEN, TK_NOTHING, TK_GROUPS, TK_GROUP, TK_CASCADE,
|
|
- TK_ASC, TK_DEFAULT, TK_CASE, TK_COLLATE, TK_CREATE,
|
|
- TK_CTIME_KW, TK_IMMEDIATE, TK_JOIN, TK_INSERT, TK_MATCH,
|
|
- TK_PLAN, TK_ANALYZE, TK_PRAGMA, TK_ABORT, TK_UPDATE,
|
|
- TK_VALUES, TK_VIRTUAL, TK_ALWAYS, TK_WHEN, TK_WHERE,
|
|
- TK_RECURSIVE, TK_AFTER, TK_RENAME, TK_AND, TK_DEFERRED,
|
|
- TK_DISTINCT, TK_IS, TK_AUTOINCR, TK_TO, TK_IN,
|
|
- TK_CAST, TK_COLUMNKW, TK_COMMIT, TK_CONFLICT, TK_JOIN_KW,
|
|
- TK_CTIME_KW, TK_CTIME_KW, TK_CURRENT, TK_PARTITION, TK_DROP,
|
|
- TK_PRECEDING, TK_FAIL, TK_LAST, TK_FILTER, TK_REPLACE,
|
|
- TK_FIRST, TK_FOLLOWING, TK_FROM, TK_JOIN_KW, TK_LIMIT,
|
|
- TK_IF, TK_ORDER, TK_RESTRICT, TK_OTHERS, TK_OVER,
|
|
- 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,
|
|
+static const unsigned char aKWCode[147] = {
|
|
+ TK_REINDEX, TK_INDEXED, TK_INDEX, TK_DESC, TK_ESCAPE,
|
|
+ TK_EACH, TK_CHECK, TK_KEY, TK_BEFORE, TK_FOREIGN,
|
|
+ TK_FOR, TK_IGNORE, TK_LIKE_KW, TK_EXPLAIN, TK_INSTEAD,
|
|
+ TK_ADD, TK_DATABASE, TK_AS, TK_SELECT, TK_TABLE,
|
|
+ TK_JOIN_KW, TK_THEN, TK_END, TK_DEFERRABLE, TK_ELSE,
|
|
+ TK_EXCLUDE, TK_DELETE, TK_TEMP, TK_TEMP, TK_OR,
|
|
+ TK_ISNULL, TK_NULLS, TK_SAVEPOINT, TK_INTERSECT, TK_TIES,
|
|
+ TK_NOTNULL, TK_NOT, TK_NO, TK_NULL, TK_LIKE_KW,
|
|
+ TK_EXCEPT, TK_TRANSACTION,TK_ACTION, TK_ON, TK_JOIN_KW,
|
|
+ TK_ALTER, TK_RAISE, TK_EXCLUSIVE, TK_EXISTS, TK_CONSTRAINT,
|
|
+ TK_INTO, TK_OFFSET, TK_OF, TK_SET, TK_TRIGGER,
|
|
+ TK_RANGE, TK_GENERATED, TK_DETACH, TK_HAVING, TK_LIKE_KW,
|
|
+ TK_BEGIN, TK_JOIN_KW, TK_REFERENCES, TK_UNIQUE, TK_QUERY,
|
|
+ TK_WITHOUT, TK_WITH, TK_JOIN_KW, TK_RELEASE, TK_ATTACH,
|
|
+ TK_BETWEEN, TK_NOTHING, TK_GROUPS, TK_GROUP, TK_CASCADE,
|
|
+ TK_ASC, TK_DEFAULT, TK_CASE, TK_COLLATE, TK_CREATE,
|
|
+ TK_CTIME_KW, TK_IMMEDIATE, TK_JOIN, TK_INSERT, TK_MATCH,
|
|
+ TK_PLAN, TK_ANALYZE, TK_PRAGMA, TK_MATERIALIZED, TK_DEFERRED,
|
|
+ TK_DISTINCT, TK_IS, TK_UPDATE, TK_VALUES, TK_VIRTUAL,
|
|
+ TK_ALWAYS, TK_WHEN, TK_WHERE, TK_RECURSIVE, TK_ABORT,
|
|
+ TK_AFTER, TK_RENAME, TK_AND, TK_DROP, TK_PARTITION,
|
|
+ TK_AUTOINCR, TK_TO, TK_IN, TK_CAST, TK_COLUMNKW,
|
|
+ TK_COMMIT, TK_CONFLICT, TK_JOIN_KW, TK_CTIME_KW, TK_CTIME_KW,
|
|
+ TK_CURRENT, TK_PRECEDING, TK_FAIL, TK_LAST, TK_FILTER,
|
|
+ TK_REPLACE, TK_FIRST, TK_FOLLOWING, TK_FROM, TK_JOIN_KW,
|
|
+ TK_LIMIT, TK_IF, TK_ORDER, TK_RESTRICT, TK_OTHERS,
|
|
+ TK_OVER, 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,
|
|
};
|
|
/* Hash table decoded:
|
|
** 0: INSERT
|
|
@@ -157652,7 +172591,7 @@ static const unsigned char aKWCode[145] = {
|
|
** 18: TRANSACTION RIGHT
|
|
** 19: WHEN
|
|
** 20: SET HAVING
|
|
-** 21: IF
|
|
+** 21: MATERIALIZED IF
|
|
** 22: ROWS
|
|
** 23: SELECT
|
|
** 24:
|
|
@@ -157748,7 +172687,7 @@ static const unsigned char aKWCode[145] = {
|
|
** 114: INTERSECT UNBOUNDED
|
|
** 115:
|
|
** 116:
|
|
-** 117: ON
|
|
+** 117: RETURNING ON
|
|
** 118:
|
|
** 119: WHERE
|
|
** 120: NO INNER
|
|
@@ -157766,15 +172705,20 @@ 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) % 127;
|
|
+ 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;
|
|
- j = 0;
|
|
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<n && (z[j]&~0x20)==zKW[j] ){ j++; }
|
|
#endif
|
|
#ifdef SQLITE_EBCDIC
|
|
+ if( toupper(z[0])!=zKW[0] ) continue;
|
|
+ if( toupper(z[1])!=zKW[1] ) continue;
|
|
+ j = 2;
|
|
while( j<n && toupper(z[j])==zKW[j] ){ j++; }
|
|
#endif
|
|
if( j<n ) continue;
|
|
@@ -157866,63 +172810,65 @@ static int keywordCode(const char *z, int n, int *pType){
|
|
testcase( i==85 ); /* PLAN */
|
|
testcase( i==86 ); /* ANALYZE */
|
|
testcase( i==87 ); /* PRAGMA */
|
|
- testcase( i==88 ); /* ABORT */
|
|
- testcase( i==89 ); /* UPDATE */
|
|
- testcase( i==90 ); /* VALUES */
|
|
- testcase( i==91 ); /* VIRTUAL */
|
|
- testcase( i==92 ); /* ALWAYS */
|
|
- testcase( i==93 ); /* WHEN */
|
|
- testcase( i==94 ); /* WHERE */
|
|
- testcase( i==95 ); /* RECURSIVE */
|
|
- testcase( i==96 ); /* AFTER */
|
|
- testcase( i==97 ); /* RENAME */
|
|
- testcase( i==98 ); /* AND */
|
|
- testcase( i==99 ); /* DEFERRED */
|
|
- testcase( i==100 ); /* DISTINCT */
|
|
- testcase( i==101 ); /* IS */
|
|
- testcase( i==102 ); /* AUTOINCREMENT */
|
|
- testcase( i==103 ); /* TO */
|
|
- testcase( i==104 ); /* IN */
|
|
- testcase( i==105 ); /* CAST */
|
|
- testcase( i==106 ); /* COLUMN */
|
|
- testcase( i==107 ); /* COMMIT */
|
|
- testcase( i==108 ); /* CONFLICT */
|
|
- testcase( i==109 ); /* CROSS */
|
|
- testcase( i==110 ); /* CURRENT_TIMESTAMP */
|
|
- testcase( i==111 ); /* CURRENT_TIME */
|
|
- testcase( i==112 ); /* CURRENT */
|
|
- testcase( i==113 ); /* PARTITION */
|
|
- testcase( i==114 ); /* DROP */
|
|
- testcase( i==115 ); /* PRECEDING */
|
|
- testcase( i==116 ); /* FAIL */
|
|
- testcase( i==117 ); /* LAST */
|
|
- testcase( i==118 ); /* FILTER */
|
|
- testcase( i==119 ); /* REPLACE */
|
|
- testcase( i==120 ); /* FIRST */
|
|
- testcase( i==121 ); /* FOLLOWING */
|
|
- testcase( i==122 ); /* FROM */
|
|
- testcase( i==123 ); /* FULL */
|
|
- testcase( i==124 ); /* LIMIT */
|
|
- testcase( i==125 ); /* IF */
|
|
- testcase( i==126 ); /* ORDER */
|
|
- testcase( i==127 ); /* RESTRICT */
|
|
- testcase( i==128 ); /* OTHERS */
|
|
- testcase( i==129 ); /* OVER */
|
|
- testcase( i==130 ); /* RIGHT */
|
|
- testcase( i==131 ); /* ROLLBACK */
|
|
- testcase( i==132 ); /* ROWS */
|
|
- testcase( i==133 ); /* ROW */
|
|
- testcase( i==134 ); /* UNBOUNDED */
|
|
- testcase( i==135 ); /* UNION */
|
|
- testcase( i==136 ); /* USING */
|
|
- testcase( i==137 ); /* VACUUM */
|
|
- testcase( i==138 ); /* VIEW */
|
|
- testcase( i==139 ); /* WINDOW */
|
|
- testcase( i==140 ); /* DO */
|
|
- testcase( i==141 ); /* BY */
|
|
- testcase( i==142 ); /* INITIALLY */
|
|
- testcase( i==143 ); /* ALL */
|
|
- testcase( i==144 ); /* PRIMARY */
|
|
+ testcase( i==88 ); /* MATERIALIZED */
|
|
+ testcase( i==89 ); /* DEFERRED */
|
|
+ testcase( i==90 ); /* DISTINCT */
|
|
+ testcase( i==91 ); /* IS */
|
|
+ testcase( i==92 ); /* UPDATE */
|
|
+ testcase( i==93 ); /* VALUES */
|
|
+ testcase( i==94 ); /* VIRTUAL */
|
|
+ testcase( i==95 ); /* ALWAYS */
|
|
+ testcase( i==96 ); /* WHEN */
|
|
+ testcase( i==97 ); /* WHERE */
|
|
+ testcase( i==98 ); /* RECURSIVE */
|
|
+ testcase( i==99 ); /* ABORT */
|
|
+ testcase( i==100 ); /* AFTER */
|
|
+ testcase( i==101 ); /* RENAME */
|
|
+ testcase( i==102 ); /* AND */
|
|
+ testcase( i==103 ); /* DROP */
|
|
+ testcase( i==104 ); /* PARTITION */
|
|
+ testcase( i==105 ); /* AUTOINCREMENT */
|
|
+ testcase( i==106 ); /* TO */
|
|
+ testcase( i==107 ); /* IN */
|
|
+ testcase( i==108 ); /* CAST */
|
|
+ testcase( i==109 ); /* COLUMN */
|
|
+ testcase( i==110 ); /* COMMIT */
|
|
+ testcase( i==111 ); /* CONFLICT */
|
|
+ testcase( i==112 ); /* CROSS */
|
|
+ testcase( i==113 ); /* CURRENT_TIMESTAMP */
|
|
+ testcase( i==114 ); /* CURRENT_TIME */
|
|
+ testcase( i==115 ); /* CURRENT */
|
|
+ testcase( i==116 ); /* PRECEDING */
|
|
+ testcase( i==117 ); /* FAIL */
|
|
+ testcase( i==118 ); /* LAST */
|
|
+ testcase( i==119 ); /* FILTER */
|
|
+ testcase( i==120 ); /* REPLACE */
|
|
+ testcase( i==121 ); /* FIRST */
|
|
+ testcase( i==122 ); /* FOLLOWING */
|
|
+ testcase( i==123 ); /* FROM */
|
|
+ testcase( i==124 ); /* FULL */
|
|
+ testcase( i==125 ); /* LIMIT */
|
|
+ testcase( i==126 ); /* IF */
|
|
+ testcase( i==127 ); /* ORDER */
|
|
+ testcase( i==128 ); /* RESTRICT */
|
|
+ testcase( i==129 ); /* OTHERS */
|
|
+ testcase( i==130 ); /* OVER */
|
|
+ testcase( i==131 ); /* RETURNING */
|
|
+ testcase( i==132 ); /* RIGHT */
|
|
+ testcase( i==133 ); /* ROLLBACK */
|
|
+ testcase( i==134 ); /* ROWS */
|
|
+ testcase( i==135 ); /* ROW */
|
|
+ testcase( i==136 ); /* UNBOUNDED */
|
|
+ testcase( i==137 ); /* UNION */
|
|
+ testcase( i==138 ); /* USING */
|
|
+ testcase( i==139 ); /* VACUUM */
|
|
+ testcase( i==140 ); /* VIEW */
|
|
+ testcase( i==141 ); /* WINDOW */
|
|
+ testcase( i==142 ); /* DO */
|
|
+ testcase( i==143 ); /* BY */
|
|
+ testcase( i==144 ); /* INITIALLY */
|
|
+ testcase( i==145 ); /* ALL */
|
|
+ testcase( i==146 ); /* PRIMARY */
|
|
*pType = aKWCode[i];
|
|
break;
|
|
}
|
|
@@ -157934,7 +172880,7 @@ SQLITE_PRIVATE int sqlite3KeywordCode(const unsigned char *z, int n){
|
|
keywordCode((char*)z, n, &id);
|
|
return id;
|
|
}
|
|
-#define SQLITE_N_KEYWORD 145
|
|
+#define SQLITE_N_KEYWORD 147
|
|
SQLITE_API int sqlite3_keyword_name(int i,const char **pzName,int *pnName){
|
|
if( i<0 || i>=SQLITE_N_KEYWORD ) return SQLITE_ERROR;
|
|
*pzName = zKWText + aKWOffset[i];
|
|
@@ -157955,14 +172901,14 @@ SQLITE_API int sqlite3_keyword_check(const char *zName, int nName){
|
|
** IdChar(X) will be true. Otherwise it is false.
|
|
**
|
|
** For ASCII, any character with the high-order bit set is
|
|
-** allowed in an identifier. For 7-bit characters,
|
|
+** allowed in an identifier. For 7-bit characters,
|
|
** sqlite3IsIdChar[X] must be 1.
|
|
**
|
|
** For EBCDIC, the rules are more complex but have the same
|
|
** end result.
|
|
**
|
|
** Ticket #1066. the SQL standard does not allow '$' in the
|
|
-** middle of identifiers. But many SQL implementations do.
|
|
+** middle of identifiers. But many SQL implementations do.
|
|
** SQLite will allow '$' in identifiers for compatibility.
|
|
** But the feature is undocumented.
|
|
*/
|
|
@@ -158002,12 +172948,12 @@ static int getToken(const unsigned char **pz){
|
|
do {
|
|
z += sqlite3GetToken(z, &t);
|
|
}while( t==TK_SPACE );
|
|
- if( t==TK_ID
|
|
- || t==TK_STRING
|
|
- || t==TK_JOIN_KW
|
|
- || t==TK_WINDOW
|
|
- || t==TK_OVER
|
|
- || sqlite3ParserFallback(t)==TK_ID
|
|
+ if( t==TK_ID
|
|
+ || t==TK_STRING
|
|
+ || t==TK_JOIN_KW
|
|
+ || t==TK_WINDOW
|
|
+ || t==TK_OVER
|
|
+ || sqlite3ParserFallback(t)==TK_ID
|
|
){
|
|
t = TK_ID;
|
|
}
|
|
@@ -158024,8 +172970,8 @@ static int getToken(const unsigned char **pz){
|
|
**
|
|
** SELECT sum(x) OVER ...
|
|
**
|
|
-** In the above, "OVER" might be a keyword, or it might be an alias for the
|
|
-** sum(x) expression. If a "%fallback ID OVER" directive were added to
|
|
+** In the above, "OVER" might be a keyword, or it might be an alias for the
|
|
+** sum(x) expression. If a "%fallback ID OVER" directive were added to
|
|
** grammar, then SQLite would always treat "OVER" as an alias, making it
|
|
** impossible to call a window-function without a FILTER clause.
|
|
**
|
|
@@ -158069,7 +173015,7 @@ static int analyzeFilterKeyword(const unsigned char *z, int lastToken){
|
|
#endif /* SQLITE_OMIT_WINDOWFUNC */
|
|
|
|
/*
|
|
-** Return the length (in bytes) of the token that begins at z[0].
|
|
+** Return the length (in bytes) of the token that begins at z[0].
|
|
** Store the token type in *tokenType before returning.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
|
|
@@ -158092,6 +173038,9 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
|
|
for(i=2; (c=z[i])!=0 && c!='\n'; i++){}
|
|
*tokenType = TK_SPACE; /* IMP: R-22934-25134 */
|
|
return i;
|
|
+ }else if( z[1]=='>' ){
|
|
+ *tokenType = TK_PTR;
|
|
+ return 2 + (z[2]=='>');
|
|
}
|
|
*tokenType = TK_MINUS;
|
|
return 1;
|
|
@@ -158226,6 +173175,7 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
|
|
}
|
|
/* If the next character is a digit, this is a floating point
|
|
** number that begins with ".". Fall thru into the next case */
|
|
+ /* no break */ deliberate_fall_through
|
|
}
|
|
case CC_DIGIT: {
|
|
testcase( z[0]=='0' ); testcase( z[0]=='1' ); testcase( z[0]=='2' );
|
|
@@ -158247,7 +173197,7 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
|
|
*tokenType = TK_FLOAT;
|
|
}
|
|
if( (z[i]=='e' || z[i]=='E') &&
|
|
- ( sqlite3Isdigit(z[i+1])
|
|
+ ( sqlite3Isdigit(z[i+1])
|
|
|| ((z[i+1]=='+' || z[i+1]=='-') && sqlite3Isdigit(z[i+2]))
|
|
)
|
|
){
|
|
@@ -158302,7 +173252,7 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
|
|
if( n==0 ) *tokenType = TK_ILLEGAL;
|
|
return i;
|
|
}
|
|
- case CC_KYWD: {
|
|
+ case CC_KYWD0: {
|
|
for(i=1; aiClass[z[i]]<=CC_KYWD; i++){}
|
|
if( IdChar(z[i]) ){
|
|
/* This token started out using characters that can appear in keywords,
|
|
@@ -158330,11 +173280,21 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
|
|
#endif
|
|
/* If it is not a BLOB literal, then it must be an ID, since no
|
|
** SQL keywords start with the letter 'x'. Fall through */
|
|
+ /* no break */ deliberate_fall_through
|
|
}
|
|
+ case CC_KYWD:
|
|
case CC_ID: {
|
|
i = 1;
|
|
break;
|
|
}
|
|
+ case CC_BOM: {
|
|
+ if( z[1]==0xbb && z[2]==0xbf ){
|
|
+ *tokenType = TK_SPACE;
|
|
+ return 3;
|
|
+ }
|
|
+ i = 1;
|
|
+ break;
|
|
+ }
|
|
case CC_NUL: {
|
|
*tokenType = TK_ILLEGAL;
|
|
return 0;
|
|
@@ -158350,13 +173310,9 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
|
|
}
|
|
|
|
/*
|
|
-** Run the parser on the given SQL string. The parser structure is
|
|
-** passed in. An SQLITE_ status code is returned. If an error occurs
|
|
-** then an and attempt is made to write an error message into
|
|
-** memory obtained from sqlite3_malloc() and to make *pzErrMsg point to that
|
|
-** error message.
|
|
+** Run the parser on the given SQL string.
|
|
*/
|
|
-SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
|
|
+SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql){
|
|
int nErr = 0; /* Number of errors encountered */
|
|
void *pEngine; /* The LEMON-generated LALR(1) parser */
|
|
int n = 0; /* Length of the next token token */
|
|
@@ -158364,6 +173320,7 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzEr
|
|
int lastTokenParsed = -1; /* type of the previous token */
|
|
sqlite3 *db = pParse->db; /* The database connection */
|
|
int mxSqlLen; /* Max length of an SQL string */
|
|
+ Parse *pParentParse = 0; /* Outer parse context, if any */
|
|
#ifdef sqlite3Parser_ENGINEALWAYSONSTACK
|
|
yyParser sEngine; /* Space to hold the Lemon-generated Parser object */
|
|
#endif
|
|
@@ -158372,11 +173329,10 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzEr
|
|
assert( zSql!=0 );
|
|
mxSqlLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH];
|
|
if( db->nVdbeActive==0 ){
|
|
- db->u1.isInterrupted = 0;
|
|
+ AtomicStore(&db->u1.isInterrupted, 0);
|
|
}
|
|
pParse->rc = SQLITE_OK;
|
|
pParse->zTail = zSql;
|
|
- assert( pzErrMsg!=0 );
|
|
#ifdef SQLITE_DEBUG
|
|
if( db->flags & SQLITE_ParserTrace ){
|
|
printf("parser: [[[%s]]]\n", zSql);
|
|
@@ -158399,26 +173355,28 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzEr
|
|
assert( pParse->pNewTrigger==0 );
|
|
assert( pParse->nVar==0 );
|
|
assert( pParse->pVList==0 );
|
|
- pParse->pParentParse = db->pParse;
|
|
+ pParentParse = db->pParse;
|
|
db->pParse = pParse;
|
|
while( 1 ){
|
|
n = sqlite3GetToken((u8*)zSql, &tokenType);
|
|
mxSqlLen -= n;
|
|
if( mxSqlLen<0 ){
|
|
pParse->rc = SQLITE_TOOBIG;
|
|
+ pParse->nErr++;
|
|
break;
|
|
}
|
|
#ifndef SQLITE_OMIT_WINDOWFUNC
|
|
if( tokenType>=TK_WINDOW ){
|
|
assert( tokenType==TK_SPACE || tokenType==TK_OVER || tokenType==TK_FILTER
|
|
- || tokenType==TK_ILLEGAL || tokenType==TK_WINDOW
|
|
+ || tokenType==TK_ILLEGAL || tokenType==TK_WINDOW
|
|
);
|
|
#else
|
|
if( tokenType>=TK_SPACE ){
|
|
assert( tokenType==TK_SPACE || tokenType==TK_ILLEGAL );
|
|
#endif /* SQLITE_OMIT_WINDOWFUNC */
|
|
- if( db->u1.isInterrupted ){
|
|
+ if( AtomicLoad(&db->u1.isInterrupted) ){
|
|
pParse->rc = SQLITE_INTERRUPT;
|
|
+ pParse->nErr++;
|
|
break;
|
|
}
|
|
if( tokenType==TK_SPACE ){
|
|
@@ -158448,7 +173406,10 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzEr
|
|
tokenType = analyzeFilterKeyword((const u8*)&zSql[6], lastTokenParsed);
|
|
#endif /* SQLITE_OMIT_WINDOWFUNC */
|
|
}else{
|
|
- sqlite3ErrorMsg(pParse, "unrecognized token: \"%.*s\"", n, zSql);
|
|
+ Token x;
|
|
+ x.z = zSql;
|
|
+ x.n = n;
|
|
+ sqlite3ErrorMsg(pParse, "unrecognized token: \"%T\"", &x);
|
|
break;
|
|
}
|
|
}
|
|
@@ -158476,58 +173437,30 @@ SQLITE_PRIVATE int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzEr
|
|
if( db->mallocFailed ){
|
|
pParse->rc = SQLITE_NOMEM_BKPT;
|
|
}
|
|
- if( pParse->rc!=SQLITE_OK && pParse->rc!=SQLITE_DONE && pParse->zErrMsg==0 ){
|
|
- pParse->zErrMsg = sqlite3MPrintf(db, "%s", sqlite3ErrStr(pParse->rc));
|
|
- }
|
|
- assert( pzErrMsg!=0 );
|
|
- if( pParse->zErrMsg ){
|
|
- *pzErrMsg = pParse->zErrMsg;
|
|
- sqlite3_log(pParse->rc, "%s in \"%s\"",
|
|
- *pzErrMsg, pParse->zTail);
|
|
- pParse->zErrMsg = 0;
|
|
+ if( pParse->zErrMsg || (pParse->rc!=SQLITE_OK && pParse->rc!=SQLITE_DONE) ){
|
|
+ if( pParse->zErrMsg==0 ){
|
|
+ pParse->zErrMsg = sqlite3MPrintf(db, "%s", sqlite3ErrStr(pParse->rc));
|
|
+ }
|
|
+ sqlite3_log(pParse->rc, "%s in \"%s\"", pParse->zErrMsg, pParse->zTail);
|
|
nErr++;
|
|
}
|
|
pParse->zTail = zSql;
|
|
- if( pParse->pVdbe && pParse->nErr>0 && pParse->nested==0 ){
|
|
- sqlite3VdbeDelete(pParse->pVdbe);
|
|
- pParse->pVdbe = 0;
|
|
- }
|
|
-#ifndef SQLITE_OMIT_SHARED_CACHE
|
|
- if( pParse->nested==0 ){
|
|
- sqlite3DbFree(db, pParse->aTableLock);
|
|
- pParse->aTableLock = 0;
|
|
- pParse->nTableLock = 0;
|
|
- }
|
|
-#endif
|
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
|
sqlite3_free(pParse->apVtabLock);
|
|
#endif
|
|
|
|
- if( !IN_SPECIAL_PARSE ){
|
|
- /* If the pParse->declareVtab flag is set, do not delete any table
|
|
+ if( pParse->pNewTable && !IN_SPECIAL_PARSE ){
|
|
+ /* If the pParse->declareVtab flag is set, do not delete any table
|
|
** structure built up in pParse->pNewTable. The calling code (see vtab.c)
|
|
** will take responsibility for freeing the Table structure.
|
|
*/
|
|
sqlite3DeleteTable(db, pParse->pNewTable);
|
|
}
|
|
- if( !IN_RENAME_OBJECT ){
|
|
+ if( pParse->pNewTrigger && !IN_RENAME_OBJECT ){
|
|
sqlite3DeleteTrigger(db, pParse->pNewTrigger);
|
|
}
|
|
-
|
|
- if( pParse->pWithToFree ) sqlite3WithDelete(db, pParse->pWithToFree);
|
|
- sqlite3DbFree(db, pParse->pVList);
|
|
- while( pParse->pAinc ){
|
|
- AutoincInfo *p = pParse->pAinc;
|
|
- pParse->pAinc = p->pNext;
|
|
- sqlite3DbFreeNN(db, p);
|
|
- }
|
|
- while( pParse->pZombieTab ){
|
|
- Table *p = pParse->pZombieTab;
|
|
- pParse->pZombieTab = p->pNextZombie;
|
|
- sqlite3DeleteTable(db, p);
|
|
- }
|
|
- db->pParse = pParse->pParentParse;
|
|
- pParse->pParentParse = 0;
|
|
+ if( pParse->pVList ) sqlite3DbNNFreeNN(db, pParse->pVList);
|
|
+ db->pParse = pParentParse;
|
|
assert( nErr==0 || pParse->rc!=SQLITE_OK );
|
|
return nErr;
|
|
}
|
|
@@ -158737,7 +173670,7 @@ SQLITE_PRIVATE const char sqlite3IsEbcdicIdChar[];
|
|
** (2) NORMAL We are in the middle of statement which ends with a single
|
|
** semicolon.
|
|
**
|
|
-** (3) EXPLAIN The keyword EXPLAIN has been seen at the beginning of
|
|
+** (3) EXPLAIN The keyword EXPLAIN has been seen at the beginning of
|
|
** a statement.
|
|
**
|
|
** (4) CREATE The keyword CREATE has been seen at the beginning of a
|
|
@@ -159080,29 +174013,88 @@ SQLITE_PRIVATE int sqlite3IcuInit(sqlite3 *db);
|
|
} /* extern "C" */
|
|
#endif /* __cplusplus */
|
|
|
|
-
|
|
/************** End of sqliteicu.h *******************************************/
|
|
/************** Continuing where we left off in main.c ***********************/
|
|
#endif
|
|
-#ifdef SQLITE_ENABLE_JSON1
|
|
-SQLITE_PRIVATE int sqlite3Json1Init(sqlite3*);
|
|
+
|
|
+/*
|
|
+** This is an extension initializer that is a no-op and always
|
|
+** succeeds, except that it fails if the fault-simulation is set
|
|
+** to 500.
|
|
+*/
|
|
+static int sqlite3TestExtInit(sqlite3 *db){
|
|
+ (void)db;
|
|
+ return sqlite3FaultSim(500);
|
|
+}
|
|
+
|
|
+
|
|
+/*
|
|
+** 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
|
|
+
|
|
+/*
|
|
+** 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
|
|
#ifdef SQLITE_ENABLE_FTS5
|
|
-SQLITE_PRIVATE int sqlite3Fts5Init(sqlite3*);
|
|
+ sqlite3Fts5Init,
|
|
#endif
|
|
+#if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS)
|
|
+ sqlite3IcuInit,
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_RTREE
|
|
+ sqlite3RtreeInit,
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_DBPAGE_VTAB
|
|
+ sqlite3DbpageRegister,
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_DBSTAT_VTAB
|
|
+ sqlite3DbstatRegister,
|
|
+#endif
|
|
+ sqlite3TestExtInit,
|
|
+#if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_JSON)
|
|
+ sqlite3JsonTableFunctions,
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_STMTVTAB
|
|
+ sqlite3StmtVtabInit,
|
|
+#endif
|
|
+#ifdef SQLITE_ENABLE_BYTECODE_VTAB
|
|
+ sqlite3VdbeBytecodeVtabInit,
|
|
+#endif
|
|
+};
|
|
|
|
#ifndef SQLITE_AMALGAMATION
|
|
/* IMPLEMENTATION-OF: R-46656-45156 The sqlite3_version[] string constant
|
|
-** contains the text of SQLITE_VERSION macro.
|
|
+** contains the text of SQLITE_VERSION macro.
|
|
*/
|
|
SQLITE_API const char sqlite3_version[] = SQLITE_VERSION;
|
|
#endif
|
|
|
|
/* IMPLEMENTATION-OF: R-53536-42575 The sqlite3_libversion() function returns
|
|
-** a pointer to the to the sqlite3_version[] string constant.
|
|
+** a pointer to the to the sqlite3_version[] string constant.
|
|
*/
|
|
SQLITE_API const char *sqlite3_libversion(void){ return sqlite3_version; }
|
|
|
|
@@ -159166,13 +174158,13 @@ SQLITE_API char *sqlite3_temp_directory = 0;
|
|
SQLITE_API char *sqlite3_data_directory = 0;
|
|
|
|
/*
|
|
-** Initialize SQLite.
|
|
+** Initialize SQLite.
|
|
**
|
|
** This routine must be called to initialize the memory allocation,
|
|
** VFS, and mutex subsystems prior to doing any serious work with
|
|
** SQLite. But as long as you do not compile with SQLITE_OMIT_AUTOINIT
|
|
** this routine will be called automatically by key routines such as
|
|
-** sqlite3_open().
|
|
+** sqlite3_open().
|
|
**
|
|
** This routine is a no-op except on its very first call for the process,
|
|
** or for the first call after a call to sqlite3_shutdown.
|
|
@@ -159197,7 +174189,7 @@ SQLITE_API char *sqlite3_data_directory = 0;
|
|
** without blocking.
|
|
*/
|
|
SQLITE_API int sqlite3_initialize(void){
|
|
- MUTEX_LOGIC( sqlite3_mutex *pMaster; ) /* The main static mutex */
|
|
+ MUTEX_LOGIC( sqlite3_mutex *pMainMtx; ) /* The main static mutex */
|
|
int rc; /* Result code */
|
|
#ifdef SQLITE_EXTRA_INIT
|
|
int bRunExtraInit = 0; /* Extra initialization needed */
|
|
@@ -159220,9 +174212,12 @@ SQLITE_API int sqlite3_initialize(void){
|
|
** must be complete. So isInit must not be set until the very end
|
|
** of this routine.
|
|
*/
|
|
- if( sqlite3GlobalConfig.isInit ) return SQLITE_OK;
|
|
+ if( sqlite3GlobalConfig.isInit ){
|
|
+ sqlite3MemoryBarrier();
|
|
+ return SQLITE_OK;
|
|
+ }
|
|
|
|
- /* Make sure the mutex subsystem is initialized. If unable to
|
|
+ /* Make sure the mutex subsystem is initialized. If unable to
|
|
** initialize the mutex subsystem, return early with the error.
|
|
** If the system is so sick that we are unable to allocate a mutex,
|
|
** there is not much SQLite is going to be able to do.
|
|
@@ -159234,13 +174229,13 @@ SQLITE_API int sqlite3_initialize(void){
|
|
if( rc ) return rc;
|
|
|
|
/* Initialize the malloc() system and the recursive pInitMutex mutex.
|
|
- ** This operation is protected by the STATIC_MASTER mutex. Note that
|
|
+ ** This operation is protected by the STATIC_MAIN mutex. Note that
|
|
** MutexAlloc() is called for a static mutex prior to initializing the
|
|
** malloc subsystem - this implies that the allocation of a static
|
|
** mutex must not require support from the malloc subsystem.
|
|
*/
|
|
- MUTEX_LOGIC( pMaster = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER); )
|
|
- sqlite3_mutex_enter(pMaster);
|
|
+ MUTEX_LOGIC( pMainMtx = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN); )
|
|
+ sqlite3_mutex_enter(pMainMtx);
|
|
sqlite3GlobalConfig.isMutexInit = 1;
|
|
if( !sqlite3GlobalConfig.isMallocInit ){
|
|
rc = sqlite3MallocInit();
|
|
@@ -159258,7 +174253,7 @@ SQLITE_API int sqlite3_initialize(void){
|
|
if( rc==SQLITE_OK ){
|
|
sqlite3GlobalConfig.nRefInitMutex++;
|
|
}
|
|
- sqlite3_mutex_leave(pMaster);
|
|
+ sqlite3_mutex_leave(pMainMtx);
|
|
|
|
/* If rc is not SQLITE_OK at this point, then either the malloc
|
|
** subsystem could not be initialized or the system failed to allocate
|
|
@@ -159298,14 +174293,15 @@ SQLITE_API int sqlite3_initialize(void){
|
|
sqlite3GlobalConfig.isPCacheInit = 1;
|
|
rc = sqlite3OsInit();
|
|
}
|
|
-#ifdef SQLITE_ENABLE_DESERIALIZE
|
|
+#ifndef SQLITE_OMIT_DESERIALIZE
|
|
if( rc==SQLITE_OK ){
|
|
rc = sqlite3MemdbInit();
|
|
}
|
|
#endif
|
|
if( rc==SQLITE_OK ){
|
|
- sqlite3PCacheBufferSetup( sqlite3GlobalConfig.pPage,
|
|
+ sqlite3PCacheBufferSetup( sqlite3GlobalConfig.pPage,
|
|
sqlite3GlobalConfig.szPage, sqlite3GlobalConfig.nPage);
|
|
+ sqlite3MemoryBarrier();
|
|
sqlite3GlobalConfig.isInit = 1;
|
|
#ifdef SQLITE_EXTRA_INIT
|
|
bRunExtraInit = 1;
|
|
@@ -159318,14 +174314,14 @@ SQLITE_API int sqlite3_initialize(void){
|
|
/* Go back under the static mutex and clean up the recursive
|
|
** mutex to prevent a resource leak.
|
|
*/
|
|
- sqlite3_mutex_enter(pMaster);
|
|
+ sqlite3_mutex_enter(pMainMtx);
|
|
sqlite3GlobalConfig.nRefInitMutex--;
|
|
if( sqlite3GlobalConfig.nRefInitMutex<=0 ){
|
|
assert( sqlite3GlobalConfig.nRefInitMutex==0 );
|
|
sqlite3_mutex_free(sqlite3GlobalConfig.pInitMutex);
|
|
sqlite3GlobalConfig.pInitMutex = 0;
|
|
}
|
|
- sqlite3_mutex_leave(pMaster);
|
|
+ sqlite3_mutex_leave(pMainMtx);
|
|
|
|
/* The following is just a sanity check to make sure SQLite has
|
|
** been compiled correctly. It is important to run this code, but
|
|
@@ -159521,7 +174517,7 @@ SQLITE_API int sqlite3_config(int op, ...){
|
|
** a single parameter which is a pointer to an integer and writes into
|
|
** that integer the number of extra bytes per page required for each page
|
|
** in SQLITE_CONFIG_PAGECACHE. */
|
|
- *va_arg(ap, int*) =
|
|
+ *va_arg(ap, int*) =
|
|
sqlite3HeaderSizeBtree() +
|
|
sqlite3HeaderSizePcache() +
|
|
sqlite3HeaderSizePcache1();
|
|
@@ -159608,7 +174604,7 @@ SQLITE_API int sqlite3_config(int op, ...){
|
|
sqlite3GlobalConfig.nLookaside = va_arg(ap, int);
|
|
break;
|
|
}
|
|
-
|
|
+
|
|
/* Record a pointer to the logger function and its first argument.
|
|
** The default is NULL. Logging is disabled if the function pointer is
|
|
** NULL.
|
|
@@ -159712,12 +174708,12 @@ SQLITE_API int sqlite3_config(int op, ...){
|
|
}
|
|
#endif /* SQLITE_ENABLE_SORTER_REFERENCES */
|
|
|
|
-#ifdef SQLITE_ENABLE_DESERIALIZE
|
|
+#ifndef SQLITE_OMIT_DESERIALIZE
|
|
case SQLITE_CONFIG_MEMDB_MAXSIZE: {
|
|
sqlite3GlobalConfig.mxMemdbSize = va_arg(ap, sqlite3_int64);
|
|
break;
|
|
}
|
|
-#endif /* SQLITE_ENABLE_DESERIALIZE */
|
|
+#endif /* SQLITE_OMIT_DESERIALIZE */
|
|
|
|
default: {
|
|
rc = SQLITE_ERROR;
|
|
@@ -159730,7 +174726,7 @@ SQLITE_API int sqlite3_config(int op, ...){
|
|
|
|
/*
|
|
** Set up the lookaside buffers for a database connection.
|
|
-** Return SQLITE_OK on success.
|
|
+** Return SQLITE_OK on success.
|
|
** If lookaside is already active, return SQLITE_BUSY.
|
|
**
|
|
** The sz parameter is the number of bytes in each lookaside slot.
|
|
@@ -159745,12 +174741,12 @@ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
|
|
sqlite3_int64 szAlloc = sz*(sqlite3_int64)cnt;
|
|
int nBig; /* Number of full-size slots */
|
|
int nSm; /* Number smaller LOOKASIDE_SMALL-byte slots */
|
|
-
|
|
+
|
|
if( sqlite3LookasideUsed(db,0)>0 ){
|
|
return SQLITE_BUSY;
|
|
}
|
|
/* Free any existing lookaside buffer for this handle before
|
|
- ** allocating a new one so we don't have to have space for
|
|
+ ** allocating a new one so we don't have to have space for
|
|
** both at the same time.
|
|
*/
|
|
if( db->lookaside.bMalloced ){
|
|
@@ -159819,18 +174815,19 @@ static int setupLookaside(sqlite3 *db, void *pBuf, int sz, int cnt){
|
|
db->lookaside.bMalloced = pBuf==0 ?1:0;
|
|
db->lookaside.nSlot = nBig+nSm;
|
|
}else{
|
|
- db->lookaside.pStart = db;
|
|
+ db->lookaside.pStart = 0;
|
|
#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
|
|
db->lookaside.pSmallInit = 0;
|
|
db->lookaside.pSmallFree = 0;
|
|
- db->lookaside.pMiddle = db;
|
|
+ db->lookaside.pMiddle = 0;
|
|
#endif /* SQLITE_OMIT_TWOSIZE_LOOKASIDE */
|
|
- db->lookaside.pEnd = db;
|
|
+ db->lookaside.pEnd = 0;
|
|
db->lookaside.bDisable = 1;
|
|
db->lookaside.sz = 0;
|
|
db->lookaside.bMalloced = 0;
|
|
db->lookaside.nSlot = 0;
|
|
}
|
|
+ db->lookaside.pTrueEnd = db->lookaside.pEnd;
|
|
assert( sqlite3LookasideUsed(db,0)==0 );
|
|
#endif /* SQLITE_OMIT_LOOKASIDE */
|
|
return SQLITE_OK;
|
|
@@ -159889,7 +174886,7 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3 *db){
|
|
sqlite3BtreeEnterAll(db);
|
|
for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
|
|
Btree *pBt = db->aDb[i].pBt;
|
|
- if( pBt && sqlite3BtreeIsInTrans(pBt) ){
|
|
+ if( pBt && sqlite3BtreeTxnState(pBt)==SQLITE_TXN_WRITE ){
|
|
Pager *pPager = sqlite3BtreePager(pBt);
|
|
rc = sqlite3PagerFlush(pPager);
|
|
if( rc==SQLITE_BUSY ){
|
|
@@ -159909,6 +174906,7 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3 *db){
|
|
SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){
|
|
va_list ap;
|
|
int rc;
|
|
+ sqlite3_mutex_enter(db->mutex);
|
|
va_start(ap, op);
|
|
switch( op ){
|
|
case SQLITE_DBCONFIG_MAINDBNAME: {
|
|
@@ -159974,6 +174972,7 @@ SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){
|
|
}
|
|
}
|
|
va_end(ap);
|
|
+ sqlite3_mutex_leave(db->mutex);
|
|
return rc;
|
|
}
|
|
|
|
@@ -160025,7 +175024,7 @@ SQLITE_PRIVATE int sqlite3IsBinary(const CollSeq *p){
|
|
}
|
|
|
|
/*
|
|
-** Another built-in collating sequence: NOCASE.
|
|
+** Another built-in collating sequence: NOCASE.
|
|
**
|
|
** This collating sequence is intended to be used for "case independent
|
|
** comparison". SQLite's knowledge of upper and lower case equivalents
|
|
@@ -160078,7 +175077,7 @@ SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3 *db, sqlite3_int64 iRowid)
|
|
/*
|
|
** Return the number of changes in the most recent call to sqlite3_exec().
|
|
*/
|
|
-SQLITE_API int sqlite3_changes(sqlite3 *db){
|
|
+SQLITE_API sqlite3_int64 sqlite3_changes64(sqlite3 *db){
|
|
#ifdef SQLITE_ENABLE_API_ARMOR
|
|
if( !sqlite3SafetyCheckOk(db) ){
|
|
(void)SQLITE_MISUSE_BKPT;
|
|
@@ -160087,11 +175086,14 @@ SQLITE_API int sqlite3_changes(sqlite3 *db){
|
|
#endif
|
|
return db->nChange;
|
|
}
|
|
+SQLITE_API int sqlite3_changes(sqlite3 *db){
|
|
+ return (int)sqlite3_changes64(db);
|
|
+}
|
|
|
|
/*
|
|
** Return the number of changes since the database handle was opened.
|
|
*/
|
|
-SQLITE_API int sqlite3_total_changes(sqlite3 *db){
|
|
+SQLITE_API sqlite3_int64 sqlite3_total_changes64(sqlite3 *db){
|
|
#ifdef SQLITE_ENABLE_API_ARMOR
|
|
if( !sqlite3SafetyCheckOk(db) ){
|
|
(void)SQLITE_MISUSE_BKPT;
|
|
@@ -160100,6 +175102,9 @@ SQLITE_API int sqlite3_total_changes(sqlite3 *db){
|
|
#endif
|
|
return db->nTotalChange;
|
|
}
|
|
+SQLITE_API int sqlite3_total_changes(sqlite3 *db){
|
|
+ return (int)sqlite3_total_changes64(db);
|
|
+}
|
|
|
|
/*
|
|
** Close all open savepoints. This function only manipulates fields of the
|
|
@@ -160124,7 +175129,9 @@ SQLITE_PRIVATE void sqlite3CloseSavepoints(sqlite3 *db){
|
|
** with SQLITE_ANY as the encoding.
|
|
*/
|
|
static void functionDestroy(sqlite3 *db, FuncDef *p){
|
|
- FuncDestructor *pDestructor = p->u.pDestructor;
|
|
+ FuncDestructor *pDestructor;
|
|
+ assert( (p->funcFlags & SQLITE_FUNC_BUILTIN)==0 );
|
|
+ pDestructor = p->u.pDestructor;
|
|
if( pDestructor ){
|
|
pDestructor->nRef--;
|
|
if( pDestructor->nRef==0 ){
|
|
@@ -160167,7 +175174,7 @@ static void disconnectAllVtab(sqlite3 *db){
|
|
|
|
/*
|
|
** Return TRUE if database connection db has unfinalized prepared
|
|
-** statements or unfinished sqlite3_backup objects.
|
|
+** statements or unfinished sqlite3_backup objects.
|
|
*/
|
|
static int connectionIsBusy(sqlite3 *db){
|
|
int j;
|
|
@@ -160194,7 +175201,7 @@ static int sqlite3Close(sqlite3 *db, int forceZombie){
|
|
}
|
|
sqlite3_mutex_enter(db->mutex);
|
|
if( db->mTrace & SQLITE_TRACE_CLOSE ){
|
|
- db->xTrace(SQLITE_TRACE_CLOSE, db->pTraceArg, db, 0);
|
|
+ db->trace.xV2(SQLITE_TRACE_CLOSE, db->pTraceArg, db, 0);
|
|
}
|
|
|
|
/* Force xDisconnect calls on all virtual tables */
|
|
@@ -160228,15 +175235,45 @@ static int sqlite3Close(sqlite3 *db, int forceZombie){
|
|
|
|
/* Convert the connection into a zombie and then close it.
|
|
*/
|
|
- db->magic = SQLITE_MAGIC_ZOMBIE;
|
|
+ db->eOpenState = SQLITE_STATE_ZOMBIE;
|
|
sqlite3LeaveMutexAndCloseZombie(db);
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
+/*
|
|
+** Return the transaction state for a single databse, or the maximum
|
|
+** transaction state over all attached databases if zSchema is null.
|
|
+*/
|
|
+SQLITE_API int sqlite3_txn_state(sqlite3 *db, const char *zSchema){
|
|
+ int iDb, nDb;
|
|
+ int iTxn = -1;
|
|
+#ifdef SQLITE_ENABLE_API_ARMOR
|
|
+ if( !sqlite3SafetyCheckOk(db) ){
|
|
+ (void)SQLITE_MISUSE_BKPT;
|
|
+ return -1;
|
|
+ }
|
|
+#endif
|
|
+ sqlite3_mutex_enter(db->mutex);
|
|
+ if( zSchema ){
|
|
+ nDb = iDb = sqlite3FindDbName(db, zSchema);
|
|
+ if( iDb<0 ) nDb--;
|
|
+ }else{
|
|
+ iDb = 0;
|
|
+ nDb = db->nDb-1;
|
|
+ }
|
|
+ for(; iDb<=nDb; iDb++){
|
|
+ Btree *pBt = db->aDb[iDb].pBt;
|
|
+ int x = pBt!=0 ? sqlite3BtreeTxnState(pBt) : SQLITE_TXN_NONE;
|
|
+ if( x>iTxn ) iTxn = x;
|
|
+ }
|
|
+ sqlite3_mutex_leave(db->mutex);
|
|
+ return iTxn;
|
|
+}
|
|
+
|
|
/*
|
|
** Two variations on the public interface for closing a database
|
|
** connection. The sqlite3_close() version returns SQLITE_BUSY and
|
|
-** leaves the connection option if there are unfinalized prepared
|
|
+** leaves the connection open if there are unfinalized prepared
|
|
** statements or unfinished sqlite3_backups. The sqlite3_close_v2()
|
|
** version forces the connection to become a zombie if there are
|
|
** unclosed resources, and arranges for deallocation when the last
|
|
@@ -160262,7 +175299,7 @@ SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){
|
|
** or if the connection has not yet been closed by sqlite3_close_v2(),
|
|
** then just leave the mutex and return.
|
|
*/
|
|
- if( db->magic!=SQLITE_MAGIC_ZOMBIE || connectionIsBusy(db) ){
|
|
+ if( db->eOpenState!=SQLITE_STATE_ZOMBIE || connectionIsBusy(db) ){
|
|
sqlite3_mutex_leave(db->mutex);
|
|
return;
|
|
}
|
|
@@ -160348,17 +175385,20 @@ SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){
|
|
sqlite3_free(db->auth.zAuthPW);
|
|
#endif
|
|
|
|
- db->magic = SQLITE_MAGIC_ERROR;
|
|
+ db->eOpenState = SQLITE_STATE_ERROR;
|
|
|
|
/* The temp-database schema is allocated differently from the other schema
|
|
** objects (using sqliteMalloc() directly, instead of sqlite3BtreeSchema()).
|
|
** So it needs to be freed here. Todo: Why not roll the temp schema into
|
|
- ** the same sqliteMalloc() as the one that allocates the database
|
|
+ ** the same sqliteMalloc() as the one that allocates the database
|
|
** structure?
|
|
*/
|
|
sqlite3DbFree(db, db->aDb[1].pSchema);
|
|
+ if( db->xAutovacDestr ){
|
|
+ db->xAutovacDestr(db->pAutovacPagesArg);
|
|
+ }
|
|
sqlite3_mutex_leave(db->mutex);
|
|
- db->magic = SQLITE_MAGIC_CLOSED;
|
|
+ db->eOpenState = SQLITE_STATE_CLOSED;
|
|
sqlite3_mutex_free(db->mutex);
|
|
assert( sqlite3LookasideUsed(db,0)==0 );
|
|
if( db->lookaside.bMalloced ){
|
|
@@ -160381,7 +175421,7 @@ SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3 *db, int tripCode){
|
|
assert( sqlite3_mutex_held(db->mutex) );
|
|
sqlite3BeginBenignMalloc();
|
|
|
|
- /* Obtain all b-tree mutexes before making any calls to BtreeRollback().
|
|
+ /* Obtain all b-tree mutexes before making any calls to BtreeRollback().
|
|
** This is important in case the transaction being rolled back has
|
|
** modified the database schema. If the b-tree mutexes are not taken
|
|
** here, then another shared-cache connection might sneak in between
|
|
@@ -160393,7 +175433,7 @@ SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3 *db, int tripCode){
|
|
for(i=0; i<db->nDb; i++){
|
|
Btree *p = db->aDb[i].pBt;
|
|
if( p ){
|
|
- if( sqlite3BtreeIsInTrans(p) ){
|
|
+ if( sqlite3BtreeTxnState(p)==SQLITE_TXN_WRITE ){
|
|
inTrans = 1;
|
|
}
|
|
sqlite3BtreeRollback(p, tripCode, !schemaChange);
|
|
@@ -160411,7 +175451,7 @@ SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3 *db, int tripCode){
|
|
/* Any deferred constraint violations have now been resolved. */
|
|
db->nDeferredCons = 0;
|
|
db->nDeferredImmCons = 0;
|
|
- db->flags &= ~(u64)SQLITE_DeferFKs;
|
|
+ db->flags &= ~(u64)(SQLITE_DeferFKs|SQLITE_CorruptRdOnly);
|
|
|
|
/* If one has been configured, invoke the rollback-hook callback */
|
|
if( db->xRollbackCallback && (inTrans || !db->autoCommit) ){
|
|
@@ -160517,6 +175557,7 @@ SQLITE_PRIVATE const char *sqlite3ErrName(int rc){
|
|
case SQLITE_NOTICE_RECOVER_WAL: zName = "SQLITE_NOTICE_RECOVER_WAL";break;
|
|
case SQLITE_NOTICE_RECOVER_ROLLBACK:
|
|
zName = "SQLITE_NOTICE_RECOVER_ROLLBACK"; break;
|
|
+ case SQLITE_NOTICE_RBU: zName = "SQLITE_NOTICE_RBU"; break;
|
|
case SQLITE_WARNING: zName = "SQLITE_WARNING"; break;
|
|
case SQLITE_WARNING_AUTOINDEX: zName = "SQLITE_WARNING_AUTOINDEX"; break;
|
|
case SQLITE_DONE: zName = "SQLITE_DONE"; break;
|
|
@@ -160607,8 +175648,7 @@ SQLITE_PRIVATE const char *sqlite3ErrStr(int rc){
|
|
*/
|
|
static int sqliteDefaultBusyCallback(
|
|
void *ptr, /* Database connection */
|
|
- int count, /* Number of times table has been busy */
|
|
- sqlite3_file *pFile /* The file on which the lock occurred */
|
|
+ int count /* Number of times table has been busy */
|
|
){
|
|
#if SQLITE_OS_WIN || HAVE_USLEEP
|
|
/* This case is for systems that have support for sleeping for fractions of
|
|
@@ -160622,19 +175662,6 @@ static int sqliteDefaultBusyCallback(
|
|
int tmout = db->busyTimeout;
|
|
int delay, prior;
|
|
|
|
-#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
|
- if( sqlite3OsFileControl(pFile,SQLITE_FCNTL_LOCK_TIMEOUT,&tmout)==SQLITE_OK ){
|
|
- if( count ){
|
|
- tmout = 0;
|
|
- sqlite3OsFileControl(pFile, SQLITE_FCNTL_LOCK_TIMEOUT, &tmout);
|
|
- return 0;
|
|
- }else{
|
|
- return 1;
|
|
- }
|
|
- }
|
|
-#else
|
|
- UNUSED_PARAMETER(pFile);
|
|
-#endif
|
|
assert( count>=0 );
|
|
if( count < NDELAY ){
|
|
delay = delays[count];
|
|
@@ -160654,7 +175681,6 @@ static int sqliteDefaultBusyCallback(
|
|
** must be done in increments of whole seconds */
|
|
sqlite3 *db = (sqlite3 *)ptr;
|
|
int tmout = ((sqlite3 *)ptr)->busyTimeout;
|
|
- UNUSED_PARAMETER(pFile);
|
|
if( (count+1)*1000 > tmout ){
|
|
return 0;
|
|
}
|
|
@@ -160672,25 +175698,16 @@ static int sqliteDefaultBusyCallback(
|
|
** If this routine returns non-zero, the lock is retried. If it
|
|
** returns 0, the operation aborts with an SQLITE_BUSY error.
|
|
*/
|
|
-SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler *p, sqlite3_file *pFile){
|
|
+SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler *p){
|
|
int rc;
|
|
if( p->xBusyHandler==0 || p->nBusy<0 ) return 0;
|
|
- if( p->bExtraFileArg ){
|
|
- /* Add an extra parameter with the pFile pointer to the end of the
|
|
- ** callback argument list */
|
|
- int (*xTra)(void*,int,sqlite3_file*);
|
|
- xTra = (int(*)(void*,int,sqlite3_file*))p->xBusyHandler;
|
|
- rc = xTra(p->pBusyArg, p->nBusy, pFile);
|
|
- }else{
|
|
- /* Legacy style busy handler callback */
|
|
- rc = p->xBusyHandler(p->pBusyArg, p->nBusy);
|
|
- }
|
|
+ rc = p->xBusyHandler(p->pBusyArg, p->nBusy);
|
|
if( rc==0 ){
|
|
p->nBusy = -1;
|
|
}else{
|
|
p->nBusy++;
|
|
}
|
|
- return rc;
|
|
+ return rc;
|
|
}
|
|
|
|
/*
|
|
@@ -160709,7 +175726,6 @@ SQLITE_API int sqlite3_busy_handler(
|
|
db->busyHandler.xBusyHandler = xBusy;
|
|
db->busyHandler.pBusyArg = pArg;
|
|
db->busyHandler.nBusy = 0;
|
|
- db->busyHandler.bExtraFileArg = 0;
|
|
db->busyTimeout = 0;
|
|
sqlite3_mutex_leave(db->mutex);
|
|
return SQLITE_OK;
|
|
@@ -160722,9 +175738,9 @@ SQLITE_API int sqlite3_busy_handler(
|
|
** be invoked every nOps opcodes.
|
|
*/
|
|
SQLITE_API void sqlite3_progress_handler(
|
|
- sqlite3 *db,
|
|
+ sqlite3 *db,
|
|
int nOps,
|
|
- int (*xProgress)(void*),
|
|
+ int (*xProgress)(void*),
|
|
void *pArg
|
|
){
|
|
#ifdef SQLITE_ENABLE_API_ARMOR
|
|
@@ -160760,7 +175776,6 @@ SQLITE_API int sqlite3_busy_timeout(sqlite3 *db, int ms){
|
|
sqlite3_busy_handler(db, (int(*)(void*,int))sqliteDefaultBusyCallback,
|
|
(void*)db);
|
|
db->busyTimeout = ms;
|
|
- db->busyHandler.bExtraFileArg = 1;
|
|
}else{
|
|
sqlite3_busy_handler(db, 0, 0);
|
|
}
|
|
@@ -160772,20 +175787,37 @@ SQLITE_API int sqlite3_busy_timeout(sqlite3 *db, int ms){
|
|
*/
|
|
SQLITE_API void sqlite3_interrupt(sqlite3 *db){
|
|
#ifdef SQLITE_ENABLE_API_ARMOR
|
|
- if( !sqlite3SafetyCheckOk(db) && (db==0 || db->magic!=SQLITE_MAGIC_ZOMBIE) ){
|
|
+ if( !sqlite3SafetyCheckOk(db)
|
|
+ && (db==0 || db->eOpenState!=SQLITE_STATE_ZOMBIE)
|
|
+ ){
|
|
(void)SQLITE_MISUSE_BKPT;
|
|
return;
|
|
}
|
|
#endif
|
|
- db->u1.isInterrupted = 1;
|
|
+ AtomicStore(&db->u1.isInterrupted, 1);
|
|
}
|
|
|
|
+/*
|
|
+** Return true or false depending on whether or not an interrupt is
|
|
+** pending on connection db.
|
|
+*/
|
|
+SQLITE_API int sqlite3_is_interrupted(sqlite3 *db){
|
|
+#ifdef SQLITE_ENABLE_API_ARMOR
|
|
+ if( !sqlite3SafetyCheckOk(db)
|
|
+ && (db==0 || db->eOpenState!=SQLITE_STATE_ZOMBIE)
|
|
+ ){
|
|
+ (void)SQLITE_MISUSE_BKPT;
|
|
+ return 0;
|
|
+ }
|
|
+#endif
|
|
+ return AtomicLoad(&db->u1.isInterrupted)!=0;
|
|
+}
|
|
|
|
/*
|
|
** This function is exactly the same as sqlite3_create_function(), except
|
|
** that it is designed to be called by internal code. The difference is
|
|
** that if a malloc() fails in sqlite3_create_function(), an error code
|
|
-** is returned and the mallocFailed flag cleared.
|
|
+** is returned and the mallocFailed flag cleared.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3CreateFunc(
|
|
sqlite3 *db,
|
|
@@ -160801,7 +175833,6 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
|
|
FuncDestructor *pDestructor
|
|
){
|
|
FuncDef *p;
|
|
- int nName;
|
|
int extraFlags;
|
|
|
|
assert( sqlite3_mutex_held(db->mutex) );
|
|
@@ -160811,7 +175842,7 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
|
|
|| ((xFinal==0)!=(xStep==0)) /* Both or neither of xFinal and xStep */
|
|
|| ((xValue==0)!=(xInverse==0)) /* Both or neither of xValue, xInverse */
|
|
|| (nArg<-1 || nArg>SQLITE_MAX_FUNCTION_ARG)
|
|
- || (255<(nName = sqlite3Strlen30( zFunctionName)))
|
|
+ || (255<sqlite3Strlen30(zFunctionName))
|
|
){
|
|
return SQLITE_MISUSE_BKPT;
|
|
}
|
|
@@ -160825,9 +175856,9 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
|
|
/* The SQLITE_INNOCUOUS flag is the same bit as SQLITE_FUNC_UNSAFE. But
|
|
** the meaning is inverted. So flip the bit. */
|
|
assert( SQLITE_FUNC_UNSAFE==SQLITE_INNOCUOUS );
|
|
- extraFlags ^= SQLITE_FUNC_UNSAFE;
|
|
+ extraFlags ^= SQLITE_FUNC_UNSAFE; /* tag-20230109-1 */
|
|
+
|
|
|
|
-
|
|
#ifndef SQLITE_OMIT_UTF16
|
|
/* If SQLITE_UTF16 is specified as the encoding type, transform this
|
|
** to one of SQLITE_UTF16LE or SQLITE_UTF16BE using the
|
|
@@ -160836,27 +175867,38 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
|
|
** If SQLITE_ANY is specified, add three versions of the function
|
|
** to the hash table.
|
|
*/
|
|
- if( enc==SQLITE_UTF16 ){
|
|
- enc = SQLITE_UTF16NATIVE;
|
|
- }else if( enc==SQLITE_ANY ){
|
|
- int rc;
|
|
- rc = sqlite3CreateFunc(db, zFunctionName, nArg,
|
|
- (SQLITE_UTF8|extraFlags)^SQLITE_FUNC_UNSAFE,
|
|
- pUserData, xSFunc, xStep, xFinal, xValue, xInverse, pDestructor);
|
|
- if( rc==SQLITE_OK ){
|
|
+ switch( enc ){
|
|
+ case SQLITE_UTF16:
|
|
+ enc = SQLITE_UTF16NATIVE;
|
|
+ break;
|
|
+ case SQLITE_ANY: {
|
|
+ int rc;
|
|
rc = sqlite3CreateFunc(db, zFunctionName, nArg,
|
|
- (SQLITE_UTF16LE|extraFlags)^SQLITE_FUNC_UNSAFE,
|
|
+ (SQLITE_UTF8|extraFlags)^SQLITE_FUNC_UNSAFE, /* tag-20230109-1 */
|
|
pUserData, xSFunc, xStep, xFinal, xValue, xInverse, pDestructor);
|
|
+ if( rc==SQLITE_OK ){
|
|
+ rc = sqlite3CreateFunc(db, zFunctionName, nArg,
|
|
+ (SQLITE_UTF16LE|extraFlags)^SQLITE_FUNC_UNSAFE, /* tag-20230109-1*/
|
|
+ pUserData, xSFunc, xStep, xFinal, xValue, xInverse, pDestructor);
|
|
+ }
|
|
+ if( rc!=SQLITE_OK ){
|
|
+ return rc;
|
|
+ }
|
|
+ enc = SQLITE_UTF16BE;
|
|
+ break;
|
|
}
|
|
- if( rc!=SQLITE_OK ){
|
|
- return rc;
|
|
- }
|
|
- enc = SQLITE_UTF16BE;
|
|
+ case SQLITE_UTF8:
|
|
+ case SQLITE_UTF16LE:
|
|
+ case SQLITE_UTF16BE:
|
|
+ break;
|
|
+ default:
|
|
+ enc = SQLITE_UTF8;
|
|
+ break;
|
|
}
|
|
#else
|
|
enc = SQLITE_UTF8;
|
|
#endif
|
|
-
|
|
+
|
|
/* Check if an existing function is being overridden or deleted. If so,
|
|
** and there are active VMs, then return SQLITE_BUSY. If a function
|
|
** is being overridden/deleted but there are no active VMs, allow the
|
|
@@ -160865,13 +175907,17 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
|
|
p = sqlite3FindFunction(db, zFunctionName, nArg, (u8)enc, 0);
|
|
if( p && (p->funcFlags & SQLITE_FUNC_ENCMASK)==(u32)enc && p->nArg==nArg ){
|
|
if( db->nVdbeActive ){
|
|
- sqlite3ErrorWithMsg(db, SQLITE_BUSY,
|
|
+ sqlite3ErrorWithMsg(db, SQLITE_BUSY,
|
|
"unable to delete/modify user-function due to active statements");
|
|
assert( !db->mallocFailed );
|
|
return SQLITE_BUSY;
|
|
}else{
|
|
sqlite3ExpirePreparedStatements(db, 0);
|
|
}
|
|
+ }else if( xSFunc==0 && xFinal==0 ){
|
|
+ /* Trying to delete a function that does not exist. This is a no-op.
|
|
+ ** https://sqlite.org/forum/forumpost/726219164b */
|
|
+ return SQLITE_OK;
|
|
}
|
|
|
|
p = sqlite3FindFunction(db, zFunctionName, nArg, (u8)enc, 1);
|
|
@@ -160940,11 +175986,11 @@ static int createFunctionApi(
|
|
pArg->xDestroy = xDestroy;
|
|
pArg->pUserData = p;
|
|
}
|
|
- rc = sqlite3CreateFunc(db, zFunc, nArg, enc, p,
|
|
+ rc = sqlite3CreateFunc(db, zFunc, nArg, enc, p,
|
|
xSFunc, xStep, xFinal, xValue, xInverse, pArg
|
|
);
|
|
if( pArg && pArg->nRef==0 ){
|
|
- assert( rc!=SQLITE_OK );
|
|
+ assert( rc!=SQLITE_OK || (xStep==0 && xFinal==0) );
|
|
xDestroy(p);
|
|
sqlite3_free(pArg);
|
|
}
|
|
@@ -161057,7 +176103,7 @@ static void sqlite3InvalidFunction(
|
|
**
|
|
** If the function already exists as a regular global function, then
|
|
** this routine is a no-op. If the function does not exist, then create
|
|
-** a new one that always throws a run-time error.
|
|
+** a new one that always throws a run-time error.
|
|
**
|
|
** When virtual tables intend to provide an overloaded function, they
|
|
** should call this routine to make sure the global function exists.
|
|
@@ -161081,7 +176127,7 @@ SQLITE_API int sqlite3_overload_function(
|
|
rc = sqlite3FindFunction(db, zName, nArg, SQLITE_UTF8, 0)!=0;
|
|
sqlite3_mutex_leave(db->mutex);
|
|
if( rc ) return SQLITE_OK;
|
|
- zCopy = sqlite3_mprintf(zName);
|
|
+ zCopy = sqlite3_mprintf("%s", zName);
|
|
if( zCopy==0 ) return SQLITE_NOMEM;
|
|
return sqlite3_create_function_v2(db, zName, nArg, SQLITE_UTF8,
|
|
zCopy, sqlite3InvalidFunction, 0, 0, sqlite3_free);
|
|
@@ -161090,7 +176136,7 @@ SQLITE_API int sqlite3_overload_function(
|
|
#ifndef SQLITE_OMIT_TRACE
|
|
/*
|
|
** Register a trace function. The pArg from the previously registered trace
|
|
-** is returned.
|
|
+** is returned.
|
|
**
|
|
** A NULL trace function means that no tracing is executes. A non-NULL
|
|
** trace is a pointer to a function that is invoked at the start of each
|
|
@@ -161109,7 +176155,7 @@ SQLITE_API void *sqlite3_trace(sqlite3 *db, void(*xTrace)(void*,const char*), vo
|
|
sqlite3_mutex_enter(db->mutex);
|
|
pOld = db->pTraceArg;
|
|
db->mTrace = xTrace ? SQLITE_TRACE_LEGACY : 0;
|
|
- db->xTrace = (int(*)(u32,void*,void*,void*))xTrace;
|
|
+ db->trace.xLegacy = xTrace;
|
|
db->pTraceArg = pArg;
|
|
sqlite3_mutex_leave(db->mutex);
|
|
return pOld;
|
|
@@ -161133,7 +176179,7 @@ SQLITE_API int sqlite3_trace_v2(
|
|
if( mTrace==0 ) xTrace = 0;
|
|
if( xTrace==0 ) mTrace = 0;
|
|
db->mTrace = mTrace;
|
|
- db->xTrace = xTrace;
|
|
+ db->trace.xV2 = xTrace;
|
|
db->pTraceArg = pArg;
|
|
sqlite3_mutex_leave(db->mutex);
|
|
return SQLITE_OK;
|
|
@@ -161141,8 +176187,8 @@ SQLITE_API int sqlite3_trace_v2(
|
|
|
|
#ifndef SQLITE_OMIT_DEPRECATED
|
|
/*
|
|
-** Register a profile function. The pArg from the previously registered
|
|
-** profile function is returned.
|
|
+** Register a profile function. The pArg from the previously registered
|
|
+** profile function is returned.
|
|
**
|
|
** A NULL profile function means that no profiling is executes. A non-NULL
|
|
** profile is a pointer to a function that is invoked at the conclusion of
|
|
@@ -161270,13 +176316,41 @@ SQLITE_API void *sqlite3_preupdate_hook(
|
|
}
|
|
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
|
|
|
|
+/*
|
|
+** Register a function to be invoked prior to each autovacuum that
|
|
+** determines the number of pages to vacuum.
|
|
+*/
|
|
+SQLITE_API int sqlite3_autovacuum_pages(
|
|
+ sqlite3 *db, /* Attach the hook to this database */
|
|
+ unsigned int (*xCallback)(void*,const char*,u32,u32,u32),
|
|
+ void *pArg, /* Argument to the function */
|
|
+ void (*xDestructor)(void*) /* Destructor for pArg */
|
|
+){
|
|
+#ifdef SQLITE_ENABLE_API_ARMOR
|
|
+ if( !sqlite3SafetyCheckOk(db) ){
|
|
+ if( xDestructor ) xDestructor(pArg);
|
|
+ return SQLITE_MISUSE_BKPT;
|
|
+ }
|
|
+#endif
|
|
+ sqlite3_mutex_enter(db->mutex);
|
|
+ if( db->xAutovacDestr ){
|
|
+ db->xAutovacDestr(db->pAutovacPagesArg);
|
|
+ }
|
|
+ db->xAutovacPages = xCallback;
|
|
+ db->pAutovacPagesArg = pArg;
|
|
+ db->xAutovacDestr = xDestructor;
|
|
+ sqlite3_mutex_leave(db->mutex);
|
|
+ return SQLITE_OK;
|
|
+}
|
|
+
|
|
+
|
|
#ifndef SQLITE_OMIT_WAL
|
|
/*
|
|
** The sqlite3_wal_hook() callback registered by sqlite3_wal_autocheckpoint().
|
|
** Invoke sqlite3_wal_checkpoint if the number of frames in the log file
|
|
** is greater than sqlite3.pWalArg cast to an integer (the value configured by
|
|
** wal_autocheckpoint()).
|
|
-*/
|
|
+*/
|
|
SQLITE_PRIVATE int sqlite3WalDefaultHook(
|
|
void *pClientData, /* Argument */
|
|
sqlite3 *db, /* Connection */
|
|
@@ -161362,7 +176436,7 @@ SQLITE_API int sqlite3_wal_checkpoint_v2(
|
|
return SQLITE_OK;
|
|
#else
|
|
int rc; /* Return code */
|
|
- int iDb = SQLITE_MAX_ATTACHED; /* sqlite3.aDb[] index of db to checkpoint */
|
|
+ int iDb; /* Schema to checkpoint */
|
|
|
|
#ifdef SQLITE_ENABLE_API_ARMOR
|
|
if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
|
|
@@ -161385,6 +176459,8 @@ SQLITE_API int sqlite3_wal_checkpoint_v2(
|
|
sqlite3_mutex_enter(db->mutex);
|
|
if( zDb && zDb[0] ){
|
|
iDb = sqlite3FindDbName(db, zDb);
|
|
+ }else{
|
|
+ iDb = SQLITE_MAX_DB; /* This means process all schemas */
|
|
}
|
|
if( iDb<0 ){
|
|
rc = SQLITE_ERROR;
|
|
@@ -161399,7 +176475,7 @@ SQLITE_API int sqlite3_wal_checkpoint_v2(
|
|
/* If there are no active statements, clear the interrupt flag at this
|
|
** point. */
|
|
if( db->nVdbeActive==0 ){
|
|
- db->u1.isInterrupted = 0;
|
|
+ AtomicStore(&db->u1.isInterrupted, 0);
|
|
}
|
|
|
|
sqlite3_mutex_leave(db->mutex);
|
|
@@ -161410,7 +176486,7 @@ SQLITE_API int sqlite3_wal_checkpoint_v2(
|
|
|
|
/*
|
|
** Checkpoint database zDb. If zDb is NULL, or if the buffer zDb points
|
|
-** to contains a zero-length string, all attached databases are
|
|
+** to contains a zero-length string, all attached databases are
|
|
** checkpointed.
|
|
*/
|
|
SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb){
|
|
@@ -161424,16 +176500,16 @@ SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb){
|
|
** Run a checkpoint on database iDb. This is a no-op if database iDb is
|
|
** not currently open in WAL mode.
|
|
**
|
|
-** If a transaction is open on the database being checkpointed, this
|
|
-** function returns SQLITE_LOCKED and a checkpoint is not attempted. If
|
|
-** an error occurs while running the checkpoint, an SQLite error code is
|
|
+** If a transaction is open on the database being checkpointed, this
|
|
+** function returns SQLITE_LOCKED and a checkpoint is not attempted. If
|
|
+** an error occurs while running the checkpoint, an SQLite error code is
|
|
** returned (i.e. SQLITE_IOERR). Otherwise, SQLITE_OK.
|
|
**
|
|
** The mutex on database handle db should be held by the caller. The mutex
|
|
** associated with the specific b-tree being checkpointed is taken by
|
|
** this function while the checkpoint is running.
|
|
**
|
|
-** If iDb is passed SQLITE_MAX_ATTACHED, then all attached databases are
|
|
+** If iDb is passed SQLITE_MAX_DB then all attached databases are
|
|
** checkpointed. If an error is encountered it is returned immediately -
|
|
** no attempt is made to checkpoint any remaining databases.
|
|
**
|
|
@@ -161448,9 +176524,11 @@ SQLITE_PRIVATE int sqlite3Checkpoint(sqlite3 *db, int iDb, int eMode, int *pnLog
|
|
assert( sqlite3_mutex_held(db->mutex) );
|
|
assert( !pnLog || *pnLog==-1 );
|
|
assert( !pnCkpt || *pnCkpt==-1 );
|
|
+ testcase( iDb==SQLITE_MAX_ATTACHED ); /* See forum post a006d86f72 */
|
|
+ testcase( iDb==SQLITE_MAX_DB );
|
|
|
|
for(i=0; i<db->nDb && rc==SQLITE_OK; i++){
|
|
- if( i==iDb || iDb==SQLITE_MAX_ATTACHED ){
|
|
+ if( i==iDb || iDb==SQLITE_MAX_DB ){
|
|
rc = sqlite3BtreeCheckpoint(db->aDb[i].pBt, eMode, pnLog, pnCkpt);
|
|
pnLog = 0;
|
|
pnCkpt = 0;
|
|
@@ -161528,6 +176606,19 @@ SQLITE_API const char *sqlite3_errmsg(sqlite3 *db){
|
|
return z;
|
|
}
|
|
|
|
+/*
|
|
+** Return the byte offset of the most recent error
|
|
+*/
|
|
+SQLITE_API int sqlite3_error_offset(sqlite3 *db){
|
|
+ int iOffset = -1;
|
|
+ if( db && sqlite3SafetyCheckSickOrOk(db) && db->errCode ){
|
|
+ sqlite3_mutex_enter(db->mutex);
|
|
+ iOffset = db->errByteOffset;
|
|
+ sqlite3_mutex_leave(db->mutex);
|
|
+ }
|
|
+ return iOffset;
|
|
+}
|
|
+
|
|
#ifndef SQLITE_OMIT_UTF16
|
|
/*
|
|
** Return UTF-16 encoded English language explanation of the most recent
|
|
@@ -161595,7 +176686,7 @@ SQLITE_API int sqlite3_extended_errcode(sqlite3 *db){
|
|
}
|
|
SQLITE_API int sqlite3_system_errno(sqlite3 *db){
|
|
return db ? db->iSysErrno : 0;
|
|
-}
|
|
+}
|
|
|
|
/*
|
|
** Return a string that describes the kind of error specified in the
|
|
@@ -161612,7 +176703,7 @@ SQLITE_API const char *sqlite3_errstr(int rc){
|
|
*/
|
|
static int createCollation(
|
|
sqlite3* db,
|
|
- const char *zName,
|
|
+ const char *zName,
|
|
u8 enc,
|
|
void* pCtx,
|
|
int(*xCompare)(void*,int,const void*,int,const void*),
|
|
@@ -161620,7 +176711,7 @@ static int createCollation(
|
|
){
|
|
CollSeq *pColl;
|
|
int enc2;
|
|
-
|
|
+
|
|
assert( sqlite3_mutex_held(db->mutex) );
|
|
|
|
/* If SQLITE_UTF16 is specified as the encoding type, transform this
|
|
@@ -161637,14 +176728,14 @@ static int createCollation(
|
|
return SQLITE_MISUSE_BKPT;
|
|
}
|
|
|
|
- /* Check if this call is removing or replacing an existing collation
|
|
+ /* Check if this call is removing or replacing an existing collation
|
|
** sequence. If so, and there are active VMs, return busy. If there
|
|
** are no active VMs, invalidate any pre-compiled statements.
|
|
*/
|
|
pColl = sqlite3FindCollSeq(db, (u8)enc2, zName, 0);
|
|
if( pColl && pColl->xCmp ){
|
|
if( db->nVdbeActive ){
|
|
- sqlite3ErrorWithMsg(db, SQLITE_BUSY,
|
|
+ sqlite3ErrorWithMsg(db, SQLITE_BUSY,
|
|
"unable to delete/modify collation sequence due to active statements");
|
|
return SQLITE_BUSY;
|
|
}
|
|
@@ -161655,7 +176746,7 @@ static int createCollation(
|
|
** then any copies made by synthCollSeq() need to be invalidated.
|
|
** Also, collation destructor - CollSeq.xDel() - function may need
|
|
** to be called.
|
|
- */
|
|
+ */
|
|
if( (pColl->enc & ~SQLITE_UTF16_ALIGNED)==enc2 ){
|
|
CollSeq *aColl = sqlite3HashFind(&db->aCollSeq, zName);
|
|
int j;
|
|
@@ -161788,6 +176879,8 @@ SQLITE_API int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){
|
|
if( newLimit>=0 ){ /* IMP: R-52476-28732 */
|
|
if( newLimit>aHardLimit[limitId] ){
|
|
newLimit = aHardLimit[limitId]; /* IMP: R-51463-25634 */
|
|
+ }else if( newLimit<1 && limitId==SQLITE_LIMIT_LENGTH ){
|
|
+ newLimit = 1;
|
|
}
|
|
db->aLimit[limitId] = newLimit;
|
|
}
|
|
@@ -161804,17 +176897,19 @@ SQLITE_API int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){
|
|
** query parameter. The second argument contains the URI (or non-URI filename)
|
|
** itself. When this function is called the *pFlags variable should contain
|
|
** the default flags to open the database handle with. The value stored in
|
|
-** *pFlags may be updated before returning if the URI filename contains
|
|
+** *pFlags may be updated before returning if the URI filename contains
|
|
** "cache=xxx" or "mode=xxx" query parameters.
|
|
**
|
|
** If successful, SQLITE_OK is returned. In this case *ppVfs is set to point to
|
|
** the VFS that should be used to open the database file. *pzFile is set to
|
|
-** point to a buffer containing the name of the file to open. It is the
|
|
-** responsibility of the caller to eventually call sqlite3_free() to release
|
|
-** this buffer.
|
|
+** point to a buffer containing the name of the file to open. The value
|
|
+** stored in *pzFile is a database name acceptable to sqlite3_uri_parameter()
|
|
+** and is in the same format as names created using sqlite3_create_filename().
|
|
+** The caller must invoke sqlite3_free_filename() (not sqlite3_free()!) on
|
|
+** the value returned in *pzFile to avoid a memory leak.
|
|
**
|
|
** If an error occurs, then an SQLite error code is returned and *pzErrMsg
|
|
-** may be set to point to a buffer containing an English language error
|
|
+** may be set to point to a buffer containing an English language error
|
|
** message. It is the responsibility of the caller to eventually release
|
|
** this buffer by calling sqlite3_free().
|
|
*/
|
|
@@ -161822,7 +176917,7 @@ SQLITE_PRIVATE int sqlite3ParseUri(
|
|
const char *zDefaultVfs, /* VFS to use if no "vfs=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 */
|
|
+ sqlite3_vfs **ppVfs, /* OUT: VFS to use */
|
|
char **pzFile, /* OUT: Filename component of URI */
|
|
char **pzErrMsg /* OUT: Error message (if rc!=SQLITE_OK) */
|
|
){
|
|
@@ -161843,9 +176938,9 @@ SQLITE_PRIVATE int sqlite3ParseUri(
|
|
int eState; /* Parser state when parsing URI */
|
|
int iIn; /* Input character index */
|
|
int iOut = 0; /* Output character index */
|
|
- u64 nByte = nUri+2; /* Bytes of space to allocate */
|
|
+ u64 nByte = nUri+8; /* Bytes of space to allocate */
|
|
|
|
- /* Make sure the SQLITE_OPEN_URI flag is set to indicate to the VFS xOpen
|
|
+ /* Make sure the SQLITE_OPEN_URI flag is set to indicate to the VFS xOpen
|
|
** method that there may be extra parameters following the file-name. */
|
|
flags |= SQLITE_OPEN_URI;
|
|
|
|
@@ -161853,6 +176948,9 @@ SQLITE_PRIVATE int sqlite3ParseUri(
|
|
zFile = sqlite3_malloc64(nByte);
|
|
if( !zFile ) return SQLITE_NOMEM_BKPT;
|
|
|
|
+ memset(zFile, 0, 4); /* 4-byte of 0x00 is the start of DB name marker */
|
|
+ zFile += 4;
|
|
+
|
|
iIn = 5;
|
|
#ifdef SQLITE_ALLOW_URI_AUTHORITY
|
|
if( strncmp(zUri+5, "///", 3)==0 ){
|
|
@@ -161860,7 +176958,7 @@ SQLITE_PRIVATE int sqlite3ParseUri(
|
|
/* The following condition causes URIs with five leading / characters
|
|
** like file://///host/path to be converted into UNCs like //host/path.
|
|
** The correct URI for that UNC has only two or four leading / characters
|
|
- ** file://host/path or file:////host/path. But 5 leading slashes is a
|
|
+ ** file://host/path or file:////host/path. But 5 leading slashes is a
|
|
** common error, we are told, so we handle it as a special case. */
|
|
if( strncmp(zUri+7, "///", 3)==0 ){ iIn++; }
|
|
}else if( strncmp(zUri+5, "//localhost/", 12)==0 ){
|
|
@@ -161872,7 +176970,7 @@ SQLITE_PRIVATE int sqlite3ParseUri(
|
|
iIn = 7;
|
|
while( zUri[iIn] && zUri[iIn]!='/' ) iIn++;
|
|
if( iIn!=7 && (iIn!=16 || memcmp("localhost", &zUri[7], 9)) ){
|
|
- *pzErrMsg = sqlite3_mprintf("invalid uri authority: %.*s",
|
|
+ *pzErrMsg = sqlite3_mprintf("invalid uri authority: %.*s",
|
|
iIn-7, &zUri[7]);
|
|
rc = SQLITE_ERROR;
|
|
goto parse_uri_out;
|
|
@@ -161880,8 +176978,8 @@ SQLITE_PRIVATE int sqlite3ParseUri(
|
|
}
|
|
#endif
|
|
|
|
- /* Copy the filename and any query parameters into the zFile buffer.
|
|
- ** Decode %HH escape codes along the way.
|
|
+ /* Copy the filename and any query parameters into the zFile buffer.
|
|
+ ** Decode %HH escape codes along the way.
|
|
**
|
|
** Within this loop, variable eState may be set to 0, 1 or 2, depending
|
|
** on the parsing context. As follows:
|
|
@@ -161893,9 +176991,9 @@ SQLITE_PRIVATE int sqlite3ParseUri(
|
|
eState = 0;
|
|
while( (c = zUri[iIn])!=0 && c!='#' ){
|
|
iIn++;
|
|
- if( c=='%'
|
|
- && sqlite3Isxdigit(zUri[iIn])
|
|
- && sqlite3Isxdigit(zUri[iIn+1])
|
|
+ if( c=='%'
|
|
+ && sqlite3Isxdigit(zUri[iIn])
|
|
+ && sqlite3Isxdigit(zUri[iIn+1])
|
|
){
|
|
int octet = (sqlite3HexToInt(zUri[iIn++]) << 4);
|
|
octet += sqlite3HexToInt(zUri[iIn++]);
|
|
@@ -161907,7 +177005,7 @@ SQLITE_PRIVATE int sqlite3ParseUri(
|
|
** case we ignore all text in the remainder of the path, name or
|
|
** value currently being parsed. So ignore the current character
|
|
** and skip to the next "?", "=" or "&", as appropriate. */
|
|
- while( (c = zUri[iIn])!=0 && c!='#'
|
|
+ while( (c = zUri[iIn])!=0 && c!='#'
|
|
&& (eState!=0 || c!='?')
|
|
&& (eState!=1 || (c!='=' && c!='&'))
|
|
&& (eState!=2 || c!='&')
|
|
@@ -161942,10 +177040,9 @@ SQLITE_PRIVATE int sqlite3ParseUri(
|
|
zFile[iOut++] = c;
|
|
}
|
|
if( eState==1 ) zFile[iOut++] = '\0';
|
|
- zFile[iOut++] = '\0';
|
|
- zFile[iOut++] = '\0';
|
|
+ memset(zFile+iOut, 0, 4); /* end-of-options + empty journal filenames */
|
|
|
|
- /* Check if there were any options specified that should be interpreted
|
|
+ /* Check if there were any options specified that should be interpreted
|
|
** here. Options that are interpreted here include "vfs" and those that
|
|
** correspond to flags that may be passed to the sqlite3_open_v2()
|
|
** method. */
|
|
@@ -161981,7 +177078,7 @@ SQLITE_PRIVATE int sqlite3ParseUri(
|
|
if( nOpt==4 && memcmp("mode", zOpt, 4)==0 ){
|
|
static struct OpenMode aOpenMode[] = {
|
|
{ "ro", SQLITE_OPEN_READONLY },
|
|
- { "rw", SQLITE_OPEN_READWRITE },
|
|
+ { "rw", SQLITE_OPEN_READWRITE },
|
|
{ "rwc", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE },
|
|
{ "memory", SQLITE_OPEN_MEMORY },
|
|
{ 0, 0 }
|
|
@@ -162023,13 +177120,14 @@ SQLITE_PRIVATE int sqlite3ParseUri(
|
|
}
|
|
|
|
}else{
|
|
- zFile = sqlite3_malloc64(nUri+2);
|
|
+ zFile = sqlite3_malloc64(nUri+8);
|
|
if( !zFile ) return SQLITE_NOMEM_BKPT;
|
|
+ memset(zFile, 0, 4);
|
|
+ zFile += 4;
|
|
if( nUri ){
|
|
memcpy(zFile, zUri, nUri);
|
|
}
|
|
- zFile[nUri] = '\0';
|
|
- zFile[nUri+1] = '\0';
|
|
+ memset(zFile+nUri, 0, 4);
|
|
flags &= ~SQLITE_OPEN_URI;
|
|
}
|
|
|
|
@@ -162040,7 +177138,7 @@ SQLITE_PRIVATE int sqlite3ParseUri(
|
|
}
|
|
parse_uri_out:
|
|
if( rc!=SQLITE_OK ){
|
|
- sqlite3_free(zFile);
|
|
+ sqlite3_free_filename(zFile);
|
|
zFile = 0;
|
|
}
|
|
*pFlags = flags;
|
|
@@ -162048,44 +177146,26 @@ SQLITE_PRIVATE int sqlite3ParseUri(
|
|
return rc;
|
|
}
|
|
|
|
-#if defined(SQLITE_HAS_CODEC)
|
|
/*
|
|
-** Process URI filename query parameters relevant to the SQLite Encryption
|
|
-** Extension. Return true if any of the relevant query parameters are
|
|
-** seen and return false if not.
|
|
+** This routine does the core work of extracting URI parameters from a
|
|
+** database filename for the sqlite3_uri_parameter() interface.
|
|
*/
|
|
-SQLITE_PRIVATE int sqlite3CodecQueryParameters(
|
|
- sqlite3 *db, /* Database connection */
|
|
- const char *zDb, /* Which schema is being created/attached */
|
|
- const char *zUri /* URI filename */
|
|
-){
|
|
- const char *zKey;
|
|
- if( (zKey = sqlite3_uri_parameter(zUri, "hexkey"))!=0 && zKey[0] ){
|
|
- u8 iByte;
|
|
- int i;
|
|
- char zDecoded[40];
|
|
- for(i=0, iByte=0; i<sizeof(zDecoded)*2 && sqlite3Isxdigit(zKey[i]); i++){
|
|
- iByte = (iByte<<4) + sqlite3HexToInt(zKey[i]);
|
|
- if( (i&1)!=0 ) zDecoded[i/2] = iByte;
|
|
- }
|
|
- sqlite3_key_v2(db, zDb, zDecoded, i/2);
|
|
- return 1;
|
|
- }else if( (zKey = sqlite3_uri_parameter(zUri, "key"))!=0 ){
|
|
- sqlite3_key_v2(db, zDb, zKey, sqlite3Strlen30(zKey));
|
|
- return 1;
|
|
- }else if( (zKey = sqlite3_uri_parameter(zUri, "textkey"))!=0 ){
|
|
- sqlite3_key_v2(db, zDb, zKey, -1);
|
|
- return 1;
|
|
- }else{
|
|
- return 0;
|
|
+static const char *uriParameter(const char *zFilename, const char *zParam){
|
|
+ zFilename += sqlite3Strlen30(zFilename) + 1;
|
|
+ while( ALWAYS(zFilename!=0) && zFilename[0] ){
|
|
+ int x = strcmp(zFilename, zParam);
|
|
+ zFilename += sqlite3Strlen30(zFilename) + 1;
|
|
+ if( x==0 ) return zFilename;
|
|
+ zFilename += sqlite3Strlen30(zFilename) + 1;
|
|
}
|
|
+ return 0;
|
|
}
|
|
-#endif
|
|
+
|
|
|
|
|
|
/*
|
|
** This routine does the work of opening a database on behalf of
|
|
-** sqlite3_open() and sqlite3_open16(). The database filename "zFilename"
|
|
+** sqlite3_open() and sqlite3_open16(). The database filename "zFilename"
|
|
** is UTF-8 encoded.
|
|
*/
|
|
static int openDatabase(
|
|
@@ -162099,6 +177179,7 @@ static int openDatabase(
|
|
int isThreadsafe; /* True for threadsafe connections */
|
|
char *zOpen = 0; /* Filename argument to pass to BtreeOpen() */
|
|
char *zErrMsg = 0; /* Error message from sqlite3ParseUri() */
|
|
+ int i; /* Loop counter */
|
|
|
|
#ifdef SQLITE_ENABLE_API_ARMOR
|
|
if( ppDb==0 ) return SQLITE_MISUSE_BKPT;
|
|
@@ -162131,18 +177212,18 @@ static int openDatabase(
|
|
** dealt with in the previous code block. Besides these, the only
|
|
** valid input flags for sqlite3_open_v2() are SQLITE_OPEN_READONLY,
|
|
** SQLITE_OPEN_READWRITE, SQLITE_OPEN_CREATE, SQLITE_OPEN_SHAREDCACHE,
|
|
- ** SQLITE_OPEN_PRIVATECACHE, and some reserved bits. Silently mask
|
|
- ** off all other flags.
|
|
+ ** SQLITE_OPEN_PRIVATECACHE, SQLITE_OPEN_EXRESCODE, and some reserved
|
|
+ ** bits. Silently mask off all other flags.
|
|
*/
|
|
flags &= ~( SQLITE_OPEN_DELETEONCLOSE |
|
|
SQLITE_OPEN_EXCLUSIVE |
|
|
SQLITE_OPEN_MAIN_DB |
|
|
- SQLITE_OPEN_TEMP_DB |
|
|
- SQLITE_OPEN_TRANSIENT_DB |
|
|
- SQLITE_OPEN_MAIN_JOURNAL |
|
|
- SQLITE_OPEN_TEMP_JOURNAL |
|
|
- SQLITE_OPEN_SUBJOURNAL |
|
|
- SQLITE_OPEN_MASTER_JOURNAL |
|
|
+ SQLITE_OPEN_TEMP_DB |
|
|
+ SQLITE_OPEN_TRANSIENT_DB |
|
|
+ SQLITE_OPEN_MAIN_JOURNAL |
|
|
+ SQLITE_OPEN_TEMP_JOURNAL |
|
|
+ SQLITE_OPEN_SUBJOURNAL |
|
|
+ SQLITE_OPEN_SUPER_JOURNAL |
|
|
SQLITE_OPEN_NOMUTEX |
|
|
SQLITE_OPEN_FULLMUTEX |
|
|
SQLITE_OPEN_WAL
|
|
@@ -162151,7 +177232,7 @@ static int openDatabase(
|
|
/* Allocate the sqlite data structure */
|
|
db = sqlite3MallocZero( sizeof(sqlite3) );
|
|
if( db==0 ) goto opendb_out;
|
|
- if( isThreadsafe
|
|
+ if( isThreadsafe
|
|
#ifdef SQLITE_ENABLE_MULTITHREADED_CHECKS
|
|
|| sqlite3GlobalConfig.bCoreMutex
|
|
#endif
|
|
@@ -162167,9 +177248,9 @@ static int openDatabase(
|
|
}
|
|
}
|
|
sqlite3_mutex_enter(db->mutex);
|
|
- db->errMask = 0xff;
|
|
+ db->errMask = (flags & SQLITE_OPEN_EXRESCODE)!=0 ? 0xffffffff : 0xff;
|
|
db->nDb = 2;
|
|
- db->magic = SQLITE_MAGIC_BUSY;
|
|
+ db->eOpenState = SQLITE_STATE_BUSY;
|
|
db->aDb = db->aDbStatic;
|
|
db->lookaside.bDisable = 1;
|
|
db->lookaside.sz = 0;
|
|
@@ -162181,7 +177262,15 @@ static int openDatabase(
|
|
db->nextAutovac = -1;
|
|
db->szMmap = sqlite3GlobalConfig.szMmap;
|
|
db->nextPagesize = 0;
|
|
+ db->init.azInit = sqlite3StdType; /* Any array of string ptrs will do */
|
|
+#ifdef SQLITE_ENABLE_SORTER_MMAP
|
|
+ /* Beginning with version 3.37.0, using the VFS xFetch() API to memory-map
|
|
+ ** the temporary files used to do external sorts (see code in vdbesort.c)
|
|
+ ** is disabled. It can still be used either by defining
|
|
+ ** SQLITE_ENABLE_SORTER_MMAP at compile time or by using the
|
|
+ ** SQLITE_TESTCTRL_SORTER_MMAP test-control at runtime. */
|
|
db->nMaxSorterMmap = 0x7FFFFFFF;
|
|
+#endif
|
|
db->flags |= SQLITE_ShortColNames
|
|
| SQLITE_EnableTrigger
|
|
| SQLITE_EnableView
|
|
@@ -162194,7 +177283,7 @@ static int openDatabase(
|
|
**
|
|
** SQLITE_DQS SQLITE_DBCONFIG_DQS_DDL SQLITE_DBCONFIG_DQS_DML
|
|
** ---------- ----------------------- -----------------------
|
|
-** undefined on on
|
|
+** undefined on on
|
|
** 3 on on
|
|
** 2 on off
|
|
** 1 off on
|
|
@@ -162246,6 +177335,9 @@ static int openDatabase(
|
|
#endif
|
|
#if defined(SQLITE_DEFAULT_DEFENSIVE)
|
|
| SQLITE_Defensive
|
|
+#endif
|
|
+#if defined(SQLITE_DEFAULT_LEGACY_ALTER_TABLE)
|
|
+ | SQLITE_LegacyAlter
|
|
#endif
|
|
;
|
|
sqlite3HashInit(&db->aCollSeq);
|
|
@@ -162268,15 +177360,23 @@ static int openDatabase(
|
|
if( db->mallocFailed ){
|
|
goto opendb_out;
|
|
}
|
|
- /* EVIDENCE-OF: R-08308-17224 The default collating function for all
|
|
- ** strings is BINARY.
|
|
- */
|
|
- db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, sqlite3StrBINARY, 0);
|
|
- assert( db->pDfltColl!=0 );
|
|
+
|
|
+#if SQLITE_OS_UNIX && defined(SQLITE_OS_KV_OPTIONAL)
|
|
+ /* Process magic filenames ":localStorage:" and ":sessionStorage:" */
|
|
+ if( zFilename && zFilename[0]==':' ){
|
|
+ if( strcmp(zFilename, ":localStorage:")==0 ){
|
|
+ zFilename = "file:local?vfs=kvvfs";
|
|
+ flags |= SQLITE_OPEN_URI;
|
|
+ }else if( strcmp(zFilename, ":sessionStorage:")==0 ){
|
|
+ zFilename = "file:session?vfs=kvvfs";
|
|
+ flags |= SQLITE_OPEN_URI;
|
|
+ }
|
|
+ }
|
|
+#endif /* SQLITE_OS_UNIX && defined(SQLITE_OS_KV_OPTIONAL) */
|
|
|
|
/* Parse the filename/URI argument
|
|
**
|
|
- ** Only allow sensible combinations of bits in the flags argument.
|
|
+ ** Only allow sensible combinations of bits in the flags argument.
|
|
** Throw an error if any non-sense combination is used. If we
|
|
** do not block illegal combinations here, it could trigger
|
|
** assert() statements in deeper layers. Sensible combinations
|
|
@@ -162294,7 +177394,7 @@ static int openDatabase(
|
|
testcase( (1<<(flags&7))==0x04 ); /* READWRITE */
|
|
testcase( (1<<(flags&7))==0x40 ); /* READWRITE | CREATE */
|
|
if( ((1<<(flags&7)) & 0x46)==0 ){
|
|
- rc = SQLITE_MISUSE_BKPT; /* IMP: R-65497-44594 */
|
|
+ rc = SQLITE_MISUSE_BKPT; /* IMP: R-18321-05872 */
|
|
}else{
|
|
rc = sqlite3ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg);
|
|
}
|
|
@@ -162304,6 +177404,12 @@ static int openDatabase(
|
|
sqlite3_free(zErrMsg);
|
|
goto opendb_out;
|
|
}
|
|
+ assert( db->pVfs!=0 );
|
|
+#if SQLITE_OS_KV || defined(SQLITE_OS_KV_OPTIONAL)
|
|
+ if( sqlite3_stricmp(db->pVfs->zName, "kvvfs")==0 ){
|
|
+ db->temp_store = 2;
|
|
+ }
|
|
+#endif
|
|
|
|
/* Open the backend database driver */
|
|
rc = sqlite3BtreeOpen(db->pVfs, zOpen, db, &db->aDb[0].pBt, 0,
|
|
@@ -162317,19 +177423,21 @@ static int openDatabase(
|
|
}
|
|
sqlite3BtreeEnter(db->aDb[0].pBt);
|
|
db->aDb[0].pSchema = sqlite3SchemaGet(db, db->aDb[0].pBt);
|
|
- if( !db->mallocFailed ) ENC(db) = SCHEMA_ENC(db);
|
|
+ if( !db->mallocFailed ){
|
|
+ sqlite3SetTextEncoding(db, SCHEMA_ENC(db));
|
|
+ }
|
|
sqlite3BtreeLeave(db->aDb[0].pBt);
|
|
db->aDb[1].pSchema = sqlite3SchemaGet(db, 0);
|
|
|
|
/* The default safety_level for the main database is FULL; for the temp
|
|
- ** database it is OFF. This matches the pager layer defaults.
|
|
+ ** database it is OFF. This matches the pager layer defaults.
|
|
*/
|
|
db->aDb[0].zDbSName = "main";
|
|
db->aDb[0].safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1;
|
|
db->aDb[1].zDbSName = "temp";
|
|
db->aDb[1].safety_level = PAGER_SYNCHRONOUS_OFF;
|
|
|
|
- db->magic = SQLITE_MAGIC_OPEN;
|
|
+ db->eOpenState = SQLITE_STATE_OPEN;
|
|
if( db->mallocFailed ){
|
|
goto opendb_out;
|
|
}
|
|
@@ -162342,14 +177450,11 @@ static int openDatabase(
|
|
sqlite3RegisterPerConnectionBuiltinFunctions(db);
|
|
rc = sqlite3_errcode(db);
|
|
|
|
-#ifdef SQLITE_ENABLE_FTS5
|
|
- /* Register any built-in FTS5 module before loading the automatic
|
|
- ** extensions. This allows automatic extensions to register FTS5
|
|
- ** tokenizers and auxiliary functions. */
|
|
- if( !db->mallocFailed && rc==SQLITE_OK ){
|
|
- rc = sqlite3Fts5Init(db);
|
|
+
|
|
+ /* Load compiled-in extensions */
|
|
+ for(i=0; rc==SQLITE_OK && i<ArraySize(sqlite3BuiltinExtensions); i++){
|
|
+ rc = sqlite3BuiltinExtensions[i](db);
|
|
}
|
|
-#endif
|
|
|
|
/* Load automatic extensions - extensions that have been registered
|
|
** using the sqlite3_automatic_extension() API.
|
|
@@ -162362,65 +177467,9 @@ static int openDatabase(
|
|
}
|
|
}
|
|
|
|
-#ifdef SQLITE_ENABLE_FTS1
|
|
- if( !db->mallocFailed ){
|
|
- extern int sqlite3Fts1Init(sqlite3*);
|
|
- rc = sqlite3Fts1Init(db);
|
|
- }
|
|
-#endif
|
|
-
|
|
-#ifdef SQLITE_ENABLE_FTS2
|
|
- if( !db->mallocFailed && rc==SQLITE_OK ){
|
|
- extern int sqlite3Fts2Init(sqlite3*);
|
|
- rc = sqlite3Fts2Init(db);
|
|
- }
|
|
-#endif
|
|
-
|
|
-#ifdef SQLITE_ENABLE_FTS3 /* automatically defined by SQLITE_ENABLE_FTS4 */
|
|
- if( !db->mallocFailed && rc==SQLITE_OK ){
|
|
- rc = sqlite3Fts3Init(db);
|
|
- }
|
|
-#endif
|
|
-
|
|
-#if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS)
|
|
- if( !db->mallocFailed && rc==SQLITE_OK ){
|
|
- rc = sqlite3IcuInit(db);
|
|
- }
|
|
-#endif
|
|
-
|
|
-#ifdef SQLITE_ENABLE_RTREE
|
|
- if( !db->mallocFailed && rc==SQLITE_OK){
|
|
- rc = sqlite3RtreeInit(db);
|
|
- }
|
|
-#endif
|
|
-
|
|
-#ifdef SQLITE_ENABLE_DBPAGE_VTAB
|
|
- if( !db->mallocFailed && rc==SQLITE_OK){
|
|
- rc = sqlite3DbpageRegister(db);
|
|
- }
|
|
-#endif
|
|
-
|
|
-#ifdef SQLITE_ENABLE_DBSTAT_VTAB
|
|
- if( !db->mallocFailed && rc==SQLITE_OK){
|
|
- rc = sqlite3DbstatRegister(db);
|
|
- }
|
|
-#endif
|
|
-
|
|
-#ifdef SQLITE_ENABLE_JSON1
|
|
- if( !db->mallocFailed && rc==SQLITE_OK){
|
|
- rc = sqlite3Json1Init(db);
|
|
- }
|
|
-#endif
|
|
-
|
|
-#ifdef SQLITE_ENABLE_STMTVTAB
|
|
- if( !db->mallocFailed && rc==SQLITE_OK){
|
|
- rc = sqlite3StmtVtabInit(db);
|
|
- }
|
|
-#endif
|
|
-
|
|
#ifdef SQLITE_ENABLE_INTERNAL_FUNCTIONS
|
|
/* Testing use only!!! The -DSQLITE_ENABLE_INTERNAL_FUNCTIONS=1 compile-time
|
|
- ** option gives access to internal functions by default.
|
|
+ ** option gives access to internal functions by default.
|
|
** Testing use only!!! */
|
|
db->mDbFlags |= DBFLAG_InternalFunc;
|
|
#endif
|
|
@@ -162450,12 +177499,12 @@ static int openDatabase(
|
|
sqlite3_mutex_leave(db->mutex);
|
|
}
|
|
rc = sqlite3_errcode(db);
|
|
- assert( db!=0 || rc==SQLITE_NOMEM );
|
|
- if( rc==SQLITE_NOMEM ){
|
|
+ assert( db!=0 || (rc&0xff)==SQLITE_NOMEM );
|
|
+ if( (rc&0xff)==SQLITE_NOMEM ){
|
|
sqlite3_close(db);
|
|
db = 0;
|
|
}else if( rc!=SQLITE_OK ){
|
|
- db->magic = SQLITE_MAGIC_SICK;
|
|
+ db->eOpenState = SQLITE_STATE_SICK;
|
|
}
|
|
*ppDb = db;
|
|
#ifdef SQLITE_ENABLE_SQLLOG
|
|
@@ -162465,11 +177514,8 @@ static int openDatabase(
|
|
sqlite3GlobalConfig.xSqllog(pArg, db, zFilename, 0);
|
|
}
|
|
#endif
|
|
-#if defined(SQLITE_HAS_CODEC)
|
|
- if( rc==SQLITE_OK ) sqlite3CodecQueryParameters(db, 0, zOpen);
|
|
-#endif
|
|
- sqlite3_free(zOpen);
|
|
- return rc & 0xff;
|
|
+ sqlite3_free_filename(zOpen);
|
|
+ return rc;
|
|
}
|
|
|
|
|
|
@@ -162477,8 +177523,8 @@ static int openDatabase(
|
|
** Open a new database handle.
|
|
*/
|
|
SQLITE_API int sqlite3_open(
|
|
- const char *zFilename,
|
|
- sqlite3 **ppDb
|
|
+ const char *zFilename,
|
|
+ sqlite3 **ppDb
|
|
){
|
|
return openDatabase(zFilename, ppDb,
|
|
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0);
|
|
@@ -162497,7 +177543,7 @@ SQLITE_API int sqlite3_open_v2(
|
|
** Open a new database handle.
|
|
*/
|
|
SQLITE_API int sqlite3_open16(
|
|
- const void *zFilename,
|
|
+ const void *zFilename,
|
|
sqlite3 **ppDb
|
|
){
|
|
char const *zFilename8; /* zFilename encoded in UTF-8 instead of UTF-16 */
|
|
@@ -162536,9 +177582,9 @@ SQLITE_API int sqlite3_open16(
|
|
** Register a new collation sequence with the database handle db.
|
|
*/
|
|
SQLITE_API int sqlite3_create_collation(
|
|
- sqlite3* db,
|
|
- const char *zName,
|
|
- int enc,
|
|
+ sqlite3* db,
|
|
+ const char *zName,
|
|
+ int enc,
|
|
void* pCtx,
|
|
int(*xCompare)(void*,int,const void*,int,const void*)
|
|
){
|
|
@@ -162549,9 +177595,9 @@ SQLITE_API int sqlite3_create_collation(
|
|
** Register a new collation sequence with the database handle db.
|
|
*/
|
|
SQLITE_API int sqlite3_create_collation_v2(
|
|
- sqlite3* db,
|
|
- const char *zName,
|
|
- int enc,
|
|
+ sqlite3* db,
|
|
+ const char *zName,
|
|
+ int enc,
|
|
void* pCtx,
|
|
int(*xCompare)(void*,int,const void*,int,const void*),
|
|
void(*xDel)(void*)
|
|
@@ -162574,9 +177620,9 @@ SQLITE_API int sqlite3_create_collation_v2(
|
|
** Register a new collation sequence with the database handle db.
|
|
*/
|
|
SQLITE_API int sqlite3_create_collation16(
|
|
- sqlite3* db,
|
|
+ sqlite3* db,
|
|
const void *zName,
|
|
- int enc,
|
|
+ int enc,
|
|
void* pCtx,
|
|
int(*xCompare)(void*,int,const void*,int,const void*)
|
|
){
|
|
@@ -162604,8 +177650,8 @@ SQLITE_API int sqlite3_create_collation16(
|
|
** db. Replace any previously installed collation sequence factory.
|
|
*/
|
|
SQLITE_API int sqlite3_collation_needed(
|
|
- sqlite3 *db,
|
|
- void *pCollNeededArg,
|
|
+ sqlite3 *db,
|
|
+ void *pCollNeededArg,
|
|
void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*)
|
|
){
|
|
#ifdef SQLITE_ENABLE_API_ARMOR
|
|
@@ -162625,8 +177671,8 @@ SQLITE_API int sqlite3_collation_needed(
|
|
** db. Replace any previously installed collation sequence factory.
|
|
*/
|
|
SQLITE_API int sqlite3_collation_needed16(
|
|
- sqlite3 *db,
|
|
- void *pCollNeededArg,
|
|
+ sqlite3 *db,
|
|
+ void *pCollNeededArg,
|
|
void(*xCollNeeded16)(void*,sqlite3*,int eTextRep,const void*)
|
|
){
|
|
#ifdef SQLITE_ENABLE_API_ARMOR
|
|
@@ -162695,13 +177741,15 @@ SQLITE_PRIVATE int sqlite3CantopenError(int lineno){
|
|
testcase( sqlite3GlobalConfig.xLog!=0 );
|
|
return sqlite3ReportError(SQLITE_CANTOPEN, lineno, "cannot open file");
|
|
}
|
|
-#ifdef SQLITE_DEBUG
|
|
+#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_CORRUPT_PGNO)
|
|
SQLITE_PRIVATE int sqlite3CorruptPgnoError(int lineno, Pgno pgno){
|
|
char zMsg[100];
|
|
sqlite3_snprintf(sizeof(zMsg), zMsg, "database corruption page %d", pgno);
|
|
testcase( sqlite3GlobalConfig.xLog!=0 );
|
|
return sqlite3ReportError(SQLITE_CORRUPT, lineno, zMsg);
|
|
}
|
|
+#endif
|
|
+#ifdef SQLITE_DEBUG
|
|
SQLITE_PRIVATE int sqlite3NomemError(int lineno){
|
|
testcase( sqlite3GlobalConfig.xLog!=0 );
|
|
return sqlite3ReportError(SQLITE_NOMEM, lineno, "OOM");
|
|
@@ -162767,7 +177815,7 @@ SQLITE_API int sqlite3_table_column_metadata(
|
|
|
|
/* Locate the table in question */
|
|
pTab = sqlite3FindTable(db, zTableName, zDbName);
|
|
- if( !pTab || pTab->pSelect ){
|
|
+ if( !pTab || IsView(pTab) ){
|
|
pTab = 0;
|
|
goto error_out;
|
|
}
|
|
@@ -162778,7 +177826,7 @@ SQLITE_API int sqlite3_table_column_metadata(
|
|
}else{
|
|
for(iCol=0; iCol<pTab->nCol; iCol++){
|
|
pCol = &pTab->aCol[iCol];
|
|
- if( 0==sqlite3StrICmp(pCol->zName, zColumnName) ){
|
|
+ if( 0==sqlite3StrICmp(pCol->zCnName, zColumnName) ){
|
|
break;
|
|
}
|
|
}
|
|
@@ -162796,16 +177844,16 @@ SQLITE_API int sqlite3_table_column_metadata(
|
|
/* The following block stores the meta information that will be returned
|
|
** to the caller in local variables zDataType, zCollSeq, notnull, primarykey
|
|
** and autoinc. At this point there are two possibilities:
|
|
- **
|
|
- ** 1. The specified column name was rowid", "oid" or "_rowid_"
|
|
- ** and there is no explicitly declared IPK column.
|
|
**
|
|
- ** 2. The table is not a view and the column name identified an
|
|
+ ** 1. The specified column name was rowid", "oid" or "_rowid_"
|
|
+ ** and there is no explicitly declared IPK column.
|
|
+ **
|
|
+ ** 2. The table is not a view and the column name identified an
|
|
** explicitly declared column. Copy meta information from *pCol.
|
|
- */
|
|
+ */
|
|
if( pCol ){
|
|
zDataType = sqlite3ColumnType(pCol,0);
|
|
- zCollSeq = pCol->zColl;
|
|
+ zCollSeq = sqlite3ColumnColl(pCol);
|
|
notnull = pCol->notNull!=0;
|
|
primarykey = (pCol->colFlags & COLFLAG_PRIMKEY)!=0;
|
|
autoinc = pTab->iPKey==iCol && (pTab->tabFlags & TF_Autoincrement)!=0;
|
|
@@ -162852,7 +177900,7 @@ SQLITE_API int sqlite3_sleep(int ms){
|
|
pVfs = sqlite3_vfs_find(0);
|
|
if( pVfs==0 ) return 0;
|
|
|
|
- /* This function works in milliseconds, but the underlying OsSleep()
|
|
+ /* This function works in milliseconds, but the underlying OsSleep()
|
|
** API uses microseconds. Hence the 1000's.
|
|
*/
|
|
rc = (sqlite3OsSleep(pVfs, 1000*ms)/1000);
|
|
@@ -162904,8 +177952,20 @@ SQLITE_API int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, vo
|
|
}else if( op==SQLITE_FCNTL_DATA_VERSION ){
|
|
*(unsigned int*)pArg = sqlite3PagerDataVersion(pPager);
|
|
rc = SQLITE_OK;
|
|
+ }else if( op==SQLITE_FCNTL_RESERVE_BYTES ){
|
|
+ int iNew = *(int*)pArg;
|
|
+ *(int*)pArg = sqlite3BtreeGetRequestedReserve(pBtree);
|
|
+ if( iNew>=0 && iNew<=255 ){
|
|
+ sqlite3BtreeSetPageSize(pBtree, 0, iNew, 0);
|
|
+ }
|
|
+ rc = SQLITE_OK;
|
|
+ }else if( op==SQLITE_FCNTL_RESET_CACHE ){
|
|
+ sqlite3BtreeClearCache(pBtree);
|
|
+ rc = SQLITE_OK;
|
|
}else{
|
|
+ int nSave = db->busyHandler.nBusy;
|
|
rc = sqlite3OsFileControl(fd, op, pArg);
|
|
+ db->busyHandler.nBusy = nSave;
|
|
}
|
|
sqlite3BtreeLeave(pBtree);
|
|
}
|
|
@@ -163003,12 +178063,16 @@ SQLITE_API int sqlite3_test_control(int op, ...){
|
|
** sqlite3_test_control().
|
|
*/
|
|
case SQLITE_TESTCTRL_FAULT_INSTALL: {
|
|
- /* MSVC is picky about pulling func ptrs from va lists.
|
|
- ** http://support.microsoft.com/kb/47961
|
|
+ /* A bug in MSVC prevents it from understanding pointers to functions
|
|
+ ** types in the second argument to va_arg(). Work around the problem
|
|
+ ** using a typedef.
|
|
+ ** http://support.microsoft.com/kb/47961 <-- dead hyperlink
|
|
+ ** Search at http://web.archive.org/ to find the 2015-03-16 archive
|
|
+ ** of the link above to see the original text.
|
|
** sqlite3GlobalConfig.xTestCallback = va_arg(ap, int(*)(int));
|
|
*/
|
|
- typedef int(*TESTCALLBACKFUNC_t)(int);
|
|
- sqlite3GlobalConfig.xTestCallback = va_arg(ap, TESTCALLBACKFUNC_t);
|
|
+ typedef int(*sqlite3FaultFuncType)(int);
|
|
+ sqlite3GlobalConfig.xTestCallback = va_arg(ap, sqlite3FaultFuncType);
|
|
rc = sqlite3FaultSim(0);
|
|
break;
|
|
}
|
|
@@ -163016,7 +178080,7 @@ SQLITE_API int sqlite3_test_control(int op, ...){
|
|
/*
|
|
** sqlite3_test_control(BENIGN_MALLOC_HOOKS, xBegin, xEnd)
|
|
**
|
|
- ** Register hooks to call to indicate which malloc() failures
|
|
+ ** Register hooks to call to indicate which malloc() failures
|
|
** are benign.
|
|
*/
|
|
case SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS: {
|
|
@@ -163067,6 +178131,28 @@ SQLITE_API int sqlite3_test_control(int op, ...){
|
|
volatile int x = 0;
|
|
assert( /*side-effects-ok*/ (x = va_arg(ap,int))!=0 );
|
|
rc = x;
|
|
+#if defined(SQLITE_DEBUG)
|
|
+ /* Invoke these debugging routines so that the compiler does not
|
|
+ ** issue "defined but not used" warnings. */
|
|
+ if( x==9999 ){
|
|
+ sqlite3ShowExpr(0);
|
|
+ sqlite3ShowExpr(0);
|
|
+ sqlite3ShowExprList(0);
|
|
+ sqlite3ShowIdList(0);
|
|
+ sqlite3ShowSrcList(0);
|
|
+ sqlite3ShowWith(0);
|
|
+ sqlite3ShowUpsert(0);
|
|
+ sqlite3ShowTriggerStep(0);
|
|
+ sqlite3ShowTriggerStepList(0);
|
|
+ sqlite3ShowTrigger(0);
|
|
+ sqlite3ShowTriggerList(0);
|
|
+#ifndef SQLITE_OMIT_WINDOWFUNC
|
|
+ sqlite3ShowWindow(0);
|
|
+ sqlite3ShowWinFunc(0);
|
|
+#endif
|
|
+ sqlite3ShowSelect(0);
|
|
+ }
|
|
+#endif
|
|
break;
|
|
}
|
|
|
|
@@ -163114,29 +178200,15 @@ SQLITE_API int sqlite3_test_control(int op, ...){
|
|
** 10 little-endian, determined at run-time
|
|
** 432101 big-endian, determined at compile-time
|
|
** 123410 little-endian, determined at compile-time
|
|
- */
|
|
+ */
|
|
case SQLITE_TESTCTRL_BYTEORDER: {
|
|
rc = SQLITE_BYTEORDER*100 + SQLITE_LITTLEENDIAN*10 + SQLITE_BIGENDIAN;
|
|
break;
|
|
}
|
|
|
|
- /* sqlite3_test_control(SQLITE_TESTCTRL_RESERVE, sqlite3 *db, int N)
|
|
- **
|
|
- ** Set the nReserve size to N for the main database on the database
|
|
- ** connection db.
|
|
- */
|
|
- case SQLITE_TESTCTRL_RESERVE: {
|
|
- sqlite3 *db = va_arg(ap, sqlite3*);
|
|
- int x = va_arg(ap,int);
|
|
- sqlite3_mutex_enter(db->mutex);
|
|
- sqlite3BtreeSetPageSize(db->aDb[0].pBt, 0, x, 0);
|
|
- sqlite3_mutex_leave(db->mutex);
|
|
- break;
|
|
- }
|
|
-
|
|
/* sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS, sqlite3 *db, int N)
|
|
**
|
|
- ** Enable or disable various optimizations for testing purposes. The
|
|
+ ** Enable or disable various optimizations for testing purposes. The
|
|
** argument N is a bitmask of optimizations to be disabled. For normal
|
|
** operation N should be 0. The idea is that a test program (like the
|
|
** SQL Logic Test or SLT test module) can run the same SQL multiple times
|
|
@@ -163145,17 +178217,31 @@ SQLITE_API int sqlite3_test_control(int op, ...){
|
|
*/
|
|
case SQLITE_TESTCTRL_OPTIMIZATIONS: {
|
|
sqlite3 *db = va_arg(ap, sqlite3*);
|
|
- db->dbOptFlags = (u16)(va_arg(ap, int) & 0xffff);
|
|
+ db->dbOptFlags = va_arg(ap, u32);
|
|
break;
|
|
}
|
|
|
|
- /* sqlite3_test_control(SQLITE_TESTCTRL_LOCALTIME_FAULT, int onoff);
|
|
+ /* sqlite3_test_control(SQLITE_TESTCTRL_LOCALTIME_FAULT, onoff, xAlt);
|
|
**
|
|
- ** If parameter onoff is non-zero, subsequent calls to localtime()
|
|
- ** and its variants fail. If onoff is zero, undo this setting.
|
|
+ ** If parameter onoff is 1, subsequent calls to localtime() fail.
|
|
+ ** If 2, then invoke xAlt() instead of localtime(). If 0, normal
|
|
+ ** processing.
|
|
+ **
|
|
+ ** xAlt arguments are void pointers, but they really want to be:
|
|
+ **
|
|
+ ** int xAlt(const time_t*, struct tm*);
|
|
+ **
|
|
+ ** xAlt should write results in to struct tm object of its 2nd argument
|
|
+ ** and return zero on success, or return non-zero on failure.
|
|
*/
|
|
case SQLITE_TESTCTRL_LOCALTIME_FAULT: {
|
|
sqlite3GlobalConfig.bLocaltimeFault = va_arg(ap, int);
|
|
+ if( sqlite3GlobalConfig.bLocaltimeFault==2 ){
|
|
+ typedef int(*sqlite3LocaltimeType)(const void*,void*);
|
|
+ sqlite3GlobalConfig.xAltLocaltime = va_arg(ap, sqlite3LocaltimeType);
|
|
+ }else{
|
|
+ sqlite3GlobalConfig.xAltLocaltime = 0;
|
|
+ }
|
|
break;
|
|
}
|
|
|
|
@@ -163186,8 +178272,14 @@ SQLITE_API int sqlite3_test_control(int op, ...){
|
|
/* sqlite3_test_control(SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS, int);
|
|
**
|
|
** Set or clear a flag that causes SQLite to verify that type, name,
|
|
- ** and tbl_name fields of the sqlite_master table. This is normally
|
|
+ ** and tbl_name fields of the sqlite_schema table. This is normally
|
|
** on, but it is sometimes useful to turn it off for testing.
|
|
+ **
|
|
+ ** 2020-07-22: Disabling EXTRA_SCHEMA_CHECKS also disables the
|
|
+ ** verification of rootpage numbers when parsing the schema. This
|
|
+ ** is useful to make it easier to reach strange internal error states
|
|
+ ** during testing. The EXTRA_SCHEMA_CHECKS setting is always enabled
|
|
+ ** in production.
|
|
*/
|
|
case SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS: {
|
|
sqlite3GlobalConfig.bExtraSchemaChecks = va_arg(ap, int);
|
|
@@ -163206,7 +178298,7 @@ SQLITE_API int sqlite3_test_control(int op, ...){
|
|
|
|
/* sqlite3_test_control(SQLITE_TESTCTRL_VDBE_COVERAGE, xCallback, ptr);
|
|
**
|
|
- ** Set the VDBE coverage callback function to xCallback with context
|
|
+ ** Set the VDBE coverage callback function to xCallback with context
|
|
** pointer ptr.
|
|
*/
|
|
case SQLITE_TESTCTRL_VDBE_COVERAGE: {
|
|
@@ -163254,12 +178346,16 @@ SQLITE_API int sqlite3_test_control(int op, ...){
|
|
*/
|
|
case SQLITE_TESTCTRL_IMPOSTER: {
|
|
sqlite3 *db = va_arg(ap, sqlite3*);
|
|
+ int iDb;
|
|
sqlite3_mutex_enter(db->mutex);
|
|
- db->init.iDb = sqlite3FindDbName(db, va_arg(ap,const char*));
|
|
- db->init.busy = db->init.imposterTable = va_arg(ap,int);
|
|
- db->init.newTnum = va_arg(ap,int);
|
|
- if( db->init.busy==0 && db->init.newTnum>0 ){
|
|
- sqlite3ResetAllSchemasOfConnection(db);
|
|
+ iDb = sqlite3FindDbName(db, va_arg(ap,const char*));
|
|
+ if( iDb>=0 ){
|
|
+ db->init.iDb = iDb;
|
|
+ db->init.busy = db->init.imposterTable = va_arg(ap,int);
|
|
+ db->init.newTnum = va_arg(ap,int);
|
|
+ if( db->init.busy==0 && db->init.newTnum>0 ){
|
|
+ sqlite3ResetAllSchemasOfConnection(db);
|
|
+ }
|
|
}
|
|
sqlite3_mutex_leave(db->mutex);
|
|
break;
|
|
@@ -163296,6 +178392,96 @@ SQLITE_API int sqlite3_test_control(int op, ...){
|
|
sqlite3ResultIntReal(pCtx);
|
|
break;
|
|
}
|
|
+
|
|
+ /* sqlite3_test_control(SQLITE_TESTCTRL_SEEK_COUNT,
|
|
+ ** sqlite3 *db, // Database connection
|
|
+ ** u64 *pnSeek // Write seek count here
|
|
+ ** );
|
|
+ **
|
|
+ ** This test-control queries the seek-counter on the "main" database
|
|
+ ** file. The seek-counter is written into *pnSeek and is then reset.
|
|
+ ** The seek-count is only available if compiled with SQLITE_DEBUG.
|
|
+ */
|
|
+ case SQLITE_TESTCTRL_SEEK_COUNT: {
|
|
+ sqlite3 *db = va_arg(ap, sqlite3*);
|
|
+ u64 *pn = va_arg(ap, sqlite3_uint64*);
|
|
+ *pn = sqlite3BtreeSeekCount(db->aDb->pBt);
|
|
+ (void)db; /* Silence harmless unused variable warning */
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ /* sqlite3_test_control(SQLITE_TESTCTRL_TRACEFLAGS, op, ptr)
|
|
+ **
|
|
+ ** "ptr" is a pointer to a u32.
|
|
+ **
|
|
+ ** 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==3 Set sqlite3WhereTrace to the value *ptr
|
|
+ */
|
|
+ case SQLITE_TESTCTRL_TRACEFLAGS: {
|
|
+ int opTrace = va_arg(ap, int);
|
|
+ u32 *ptr = va_arg(ap, u32*);
|
|
+ switch( opTrace ){
|
|
+ case 0: *ptr = sqlite3TreeTrace; break;
|
|
+ case 1: sqlite3TreeTrace = *ptr; break;
|
|
+ case 2: *ptr = sqlite3WhereTrace; break;
|
|
+ case 3: sqlite3WhereTrace = *ptr; break;
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ /* sqlite3_test_control(SQLITE_TESTCTRL_LOGEST,
|
|
+ ** double fIn, // Input value
|
|
+ ** int *pLogEst, // sqlite3LogEstFromDouble(fIn)
|
|
+ ** u64 *pInt, // sqlite3LogEstToInt(*pLogEst)
|
|
+ ** int *pLogEst2 // sqlite3LogEst(*pInt)
|
|
+ ** );
|
|
+ **
|
|
+ ** Test access for the LogEst conversion routines.
|
|
+ */
|
|
+ case SQLITE_TESTCTRL_LOGEST: {
|
|
+ double rIn = va_arg(ap, double);
|
|
+ LogEst rLogEst = sqlite3LogEstFromDouble(rIn);
|
|
+ int *pI1 = va_arg(ap,int*);
|
|
+ u64 *pU64 = va_arg(ap,u64*);
|
|
+ int *pI2 = va_arg(ap,int*);
|
|
+ *pI1 = rLogEst;
|
|
+ *pU64 = sqlite3LogEstToInt(rLogEst);
|
|
+ *pI2 = sqlite3LogEst(*pU64);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+
|
|
+#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_WSD)
|
|
+ /* sqlite3_test_control(SQLITE_TESTCTRL_TUNE, id, *piValue)
|
|
+ **
|
|
+ ** If "id" is an integer between 1 and SQLITE_NTUNE then set the value
|
|
+ ** of the id-th tuning parameter to *piValue. If "id" is between -1
|
|
+ ** and -SQLITE_NTUNE, then write the current value of the (-id)-th
|
|
+ ** tuning parameter into *piValue.
|
|
+ **
|
|
+ ** Tuning parameters are for use during transient development builds,
|
|
+ ** to help find the best values for constants in the query planner.
|
|
+ ** Access tuning parameters using the Tuning(ID) macro. Set the
|
|
+ ** parameters in the CLI using ".testctrl tune ID VALUE".
|
|
+ **
|
|
+ ** Transient use only. Tuning parameters should not be used in
|
|
+ ** checked-in code.
|
|
+ */
|
|
+ case SQLITE_TESTCTRL_TUNE: {
|
|
+ int id = va_arg(ap, int);
|
|
+ int *piValue = va_arg(ap, int*);
|
|
+ if( id>0 && id<=SQLITE_NTUNE ){
|
|
+ Tuning(id) = *piValue;
|
|
+ }else if( id<0 && id>=-SQLITE_NTUNE ){
|
|
+ *piValue = Tuning(-id);
|
|
+ }else{
|
|
+ rc = SQLITE_NOTFOUND;
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+#endif
|
|
}
|
|
va_end(ap);
|
|
#endif /* SQLITE_UNTESTABLE */
|
|
@@ -163317,9 +178503,71 @@ static const char *databaseName(const char *zName){
|
|
return zName;
|
|
}
|
|
|
|
+/*
|
|
+** Append text z[] to the end of p[]. Return a pointer to the first
|
|
+** character after then zero terminator on the new text in p[].
|
|
+*/
|
|
+static char *appendText(char *p, const char *z){
|
|
+ size_t n = strlen(z);
|
|
+ memcpy(p, z, n+1);
|
|
+ return p+n+1;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Allocate memory to hold names for a database, journal file, WAL file,
|
|
+** and query parameters. The pointer returned is valid for use by
|
|
+** sqlite3_filename_database() and sqlite3_uri_parameter() and related
|
|
+** functions.
|
|
+**
|
|
+** Memory layout must be compatible with that generated by the pager
|
|
+** and expected by sqlite3_uri_parameter() and databaseName().
|
|
+*/
|
|
+SQLITE_API const char *sqlite3_create_filename(
|
|
+ const char *zDatabase,
|
|
+ const char *zJournal,
|
|
+ const char *zWal,
|
|
+ int nParam,
|
|
+ const char **azParam
|
|
+){
|
|
+ sqlite3_int64 nByte;
|
|
+ int i;
|
|
+ char *pResult, *p;
|
|
+ nByte = strlen(zDatabase) + strlen(zJournal) + strlen(zWal) + 10;
|
|
+ for(i=0; i<nParam*2; i++){
|
|
+ nByte += strlen(azParam[i])+1;
|
|
+ }
|
|
+ pResult = p = sqlite3_malloc64( nByte );
|
|
+ if( p==0 ) return 0;
|
|
+ memset(p, 0, 4);
|
|
+ p += 4;
|
|
+ p = appendText(p, zDatabase);
|
|
+ for(i=0; i<nParam*2; i++){
|
|
+ p = appendText(p, azParam[i]);
|
|
+ }
|
|
+ *(p++) = 0;
|
|
+ p = appendText(p, zJournal);
|
|
+ p = appendText(p, zWal);
|
|
+ *(p++) = 0;
|
|
+ *(p++) = 0;
|
|
+ assert( (sqlite3_int64)(p - pResult)==nByte );
|
|
+ return pResult + 4;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Free memory obtained from sqlite3_create_filename(). It is a severe
|
|
+** error to call this routine with any parameter other than a pointer
|
|
+** previously obtained from sqlite3_create_filename() or a NULL pointer.
|
|
+*/
|
|
+SQLITE_API void sqlite3_free_filename(const char *p){
|
|
+ if( p==0 ) return;
|
|
+ p = databaseName(p);
|
|
+ sqlite3_free((char*)p - 4);
|
|
+}
|
|
+
|
|
+
|
|
/*
|
|
** This is a utility routine, useful to VFS implementations, that checks
|
|
-** to see if a database file was a URI that contained a specific query
|
|
+** to see if a database file was a URI that contained a specific query
|
|
** parameter, and if so obtains the value of the query parameter.
|
|
**
|
|
** The zFilename argument is the filename pointer passed into the xOpen()
|
|
@@ -163331,14 +178579,7 @@ static const char *databaseName(const char *zName){
|
|
SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam){
|
|
if( zFilename==0 || zParam==0 ) return 0;
|
|
zFilename = databaseName(zFilename);
|
|
- zFilename += sqlite3Strlen30(zFilename) + 1;
|
|
- while( zFilename[0] ){
|
|
- int x = strcmp(zFilename, zParam);
|
|
- zFilename += sqlite3Strlen30(zFilename) + 1;
|
|
- if( x==0 ) return zFilename;
|
|
- zFilename += sqlite3Strlen30(zFilename) + 1;
|
|
- }
|
|
- return 0;
|
|
+ return uriParameter(zFilename, zParam);
|
|
}
|
|
|
|
/*
|
|
@@ -163348,7 +178589,7 @@ SQLITE_API const char *sqlite3_uri_key(const char *zFilename, int N){
|
|
if( zFilename==0 || N<0 ) return 0;
|
|
zFilename = databaseName(zFilename);
|
|
zFilename += sqlite3Strlen30(zFilename) + 1;
|
|
- while( zFilename[0] && (N--)>0 ){
|
|
+ while( ALWAYS(zFilename) && zFilename[0] && (N--)>0 ){
|
|
zFilename += sqlite3Strlen30(zFilename) + 1;
|
|
zFilename += sqlite3Strlen30(zFilename) + 1;
|
|
}
|
|
@@ -163391,13 +178632,14 @@ SQLITE_API sqlite3_int64 sqlite3_uri_int64(
|
|
** corruption.
|
|
*/
|
|
SQLITE_API const char *sqlite3_filename_database(const char *zFilename){
|
|
+ if( zFilename==0 ) return 0;
|
|
return databaseName(zFilename);
|
|
- return sqlite3_uri_parameter(zFilename - 3, "\003");
|
|
}
|
|
SQLITE_API const char *sqlite3_filename_journal(const char *zFilename){
|
|
+ if( zFilename==0 ) return 0;
|
|
zFilename = databaseName(zFilename);
|
|
zFilename += sqlite3Strlen30(zFilename) + 1;
|
|
- while( zFilename[0] ){
|
|
+ while( ALWAYS(zFilename) && zFilename[0] ){
|
|
zFilename += sqlite3Strlen30(zFilename) + 1;
|
|
zFilename += sqlite3Strlen30(zFilename) + 1;
|
|
}
|
|
@@ -163408,7 +178650,7 @@ SQLITE_API const char *sqlite3_filename_wal(const char *zFilename){
|
|
return 0;
|
|
#else
|
|
zFilename = sqlite3_filename_journal(zFilename);
|
|
- zFilename += sqlite3Strlen30(zFilename) + 1;
|
|
+ if( zFilename ) zFilename += sqlite3Strlen30(zFilename) + 1;
|
|
return zFilename;
|
|
#endif
|
|
}
|
|
@@ -163421,6 +178663,24 @@ SQLITE_PRIVATE Btree *sqlite3DbNameToBtree(sqlite3 *db, const char *zDbName){
|
|
return iDb<0 ? 0 : db->aDb[iDb].pBt;
|
|
}
|
|
|
|
+/*
|
|
+** Return the name of the N-th database schema. Return NULL if N is out
|
|
+** of range.
|
|
+*/
|
|
+SQLITE_API const char *sqlite3_db_name(sqlite3 *db, int N){
|
|
+#ifdef SQLITE_ENABLE_API_ARMOR
|
|
+ if( !sqlite3SafetyCheckOk(db) ){
|
|
+ (void)SQLITE_MISUSE_BKPT;
|
|
+ return 0;
|
|
+ }
|
|
+#endif
|
|
+ if( N<0 || N>=db->nDb ){
|
|
+ return 0;
|
|
+ }else{
|
|
+ return db->aDb[N].zDbSName;
|
|
+ }
|
|
+}
|
|
+
|
|
/*
|
|
** Return the filename of the database associated with a database
|
|
** connection.
|
|
@@ -163455,11 +178715,11 @@ SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName){
|
|
|
|
#ifdef SQLITE_ENABLE_SNAPSHOT
|
|
/*
|
|
-** Obtain a snapshot handle for the snapshot of database zDb currently
|
|
+** Obtain a snapshot handle for the snapshot of database zDb currently
|
|
** being read by handle db.
|
|
*/
|
|
SQLITE_API int sqlite3_snapshot_get(
|
|
- sqlite3 *db,
|
|
+ sqlite3 *db,
|
|
const char *zDb,
|
|
sqlite3_snapshot **ppSnapshot
|
|
){
|
|
@@ -163477,7 +178737,7 @@ SQLITE_API int sqlite3_snapshot_get(
|
|
int iDb = sqlite3FindDbName(db, zDb);
|
|
if( iDb==0 || iDb>1 ){
|
|
Btree *pBt = db->aDb[iDb].pBt;
|
|
- if( 0==sqlite3BtreeIsInTrans(pBt) ){
|
|
+ if( SQLITE_TXN_WRITE!=sqlite3BtreeTxnState(pBt) ){
|
|
rc = sqlite3BtreeBeginTrans(pBt, 0, 0);
|
|
if( rc==SQLITE_OK ){
|
|
rc = sqlite3PagerSnapshotGet(sqlite3BtreePager(pBt), ppSnapshot);
|
|
@@ -163495,8 +178755,8 @@ SQLITE_API int sqlite3_snapshot_get(
|
|
** Open a read-transaction on the snapshot idendified by pSnapshot.
|
|
*/
|
|
SQLITE_API int sqlite3_snapshot_open(
|
|
- sqlite3 *db,
|
|
- const char *zDb,
|
|
+ sqlite3 *db,
|
|
+ const char *zDb,
|
|
sqlite3_snapshot *pSnapshot
|
|
){
|
|
int rc = SQLITE_ERROR;
|
|
@@ -163513,10 +178773,10 @@ SQLITE_API int sqlite3_snapshot_open(
|
|
iDb = sqlite3FindDbName(db, zDb);
|
|
if( iDb==0 || iDb>1 ){
|
|
Btree *pBt = db->aDb[iDb].pBt;
|
|
- if( sqlite3BtreeIsInTrans(pBt)==0 ){
|
|
+ if( sqlite3BtreeTxnState(pBt)!=SQLITE_TXN_WRITE ){
|
|
Pager *pPager = sqlite3BtreePager(pBt);
|
|
int bUnlock = 0;
|
|
- if( sqlite3BtreeIsInReadTrans(pBt) ){
|
|
+ if( sqlite3BtreeTxnState(pBt)!=SQLITE_TXN_NONE ){
|
|
if( db->nVdbeActive==0 ){
|
|
rc = sqlite3PagerSnapshotCheck(pPager, pSnapshot);
|
|
if( rc==SQLITE_OK ){
|
|
@@ -163552,8 +178812,8 @@ SQLITE_API int sqlite3_snapshot_open(
|
|
*/
|
|
SQLITE_API int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb){
|
|
int rc = SQLITE_ERROR;
|
|
- int iDb;
|
|
#ifndef SQLITE_OMIT_WAL
|
|
+ int iDb;
|
|
|
|
#ifdef SQLITE_ENABLE_API_ARMOR
|
|
if( !sqlite3SafetyCheckOk(db) ){
|
|
@@ -163565,7 +178825,7 @@ SQLITE_API int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb){
|
|
iDb = sqlite3FindDbName(db, zDb);
|
|
if( iDb==0 || iDb>1 ){
|
|
Btree *pBt = db->aDb[iDb].pBt;
|
|
- if( 0==sqlite3BtreeIsInReadTrans(pBt) ){
|
|
+ if( SQLITE_TXN_NONE==sqlite3BtreeTxnState(pBt) ){
|
|
rc = sqlite3BtreeBeginTrans(pBt, 0, 0);
|
|
if( rc==SQLITE_OK ){
|
|
rc = sqlite3PagerSnapshotRecover(sqlite3BtreePager(pBt));
|
|
@@ -163598,7 +178858,7 @@ SQLITE_API int sqlite3_compileoption_used(const char *zOptName){
|
|
int i, n;
|
|
int nOpt;
|
|
const char **azCompileOpt;
|
|
-
|
|
+
|
|
#if SQLITE_ENABLE_API_ARMOR
|
|
if( zOptName==0 ){
|
|
(void)SQLITE_MISUSE_BKPT;
|
|
@@ -163611,7 +178871,7 @@ SQLITE_API int sqlite3_compileoption_used(const char *zOptName){
|
|
if( sqlite3StrNICmp(zOptName, "SQLITE_", 7)==0 ) zOptName += 7;
|
|
n = sqlite3Strlen30(zOptName);
|
|
|
|
- /* Since nOpt is normally in single digits, a linear search is
|
|
+ /* Since nOpt is normally in single digits, a linear search is
|
|
** adequate. No need for a binary search. */
|
|
for(i=0; i<nOpt; i++){
|
|
if( sqlite3StrNICmp(zOptName, azCompileOpt[i], n)==0
|
|
@@ -163671,25 +178931,25 @@ SQLITE_API const char *sqlite3_compileoption_get(int N){
|
|
*/
|
|
|
|
#define assertMutexHeld() \
|
|
- assert( sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)) )
|
|
+ assert( sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN)) )
|
|
|
|
/*
|
|
** Head of a linked list of all sqlite3 objects created by this process
|
|
** for which either sqlite3.pBlockingConnection or sqlite3.pUnlockConnection
|
|
-** is not NULL. This variable may only accessed while the STATIC_MASTER
|
|
+** is not NULL. This variable may only accessed while the STATIC_MAIN
|
|
** mutex is held.
|
|
*/
|
|
static sqlite3 *SQLITE_WSD sqlite3BlockedList = 0;
|
|
|
|
#ifndef NDEBUG
|
|
/*
|
|
-** This function is a complex assert() that verifies the following
|
|
+** This function is a complex assert() that verifies the following
|
|
** properties of the blocked connections list:
|
|
**
|
|
-** 1) Each entry in the list has a non-NULL value for either
|
|
+** 1) Each entry in the list has a non-NULL value for either
|
|
** pUnlockConnection or pBlockingConnection, or both.
|
|
**
|
|
-** 2) All entries in the list that share a common value for
|
|
+** 2) All entries in the list that share a common value for
|
|
** xUnlockNotify are grouped together.
|
|
**
|
|
** 3) If the argument db is not NULL, then none of the entries in the
|
|
@@ -163741,8 +179001,8 @@ static void addToBlockedList(sqlite3 *db){
|
|
sqlite3 **pp;
|
|
assertMutexHeld();
|
|
for(
|
|
- pp=&sqlite3BlockedList;
|
|
- *pp && (*pp)->xUnlockNotify!=db->xUnlockNotify;
|
|
+ pp=&sqlite3BlockedList;
|
|
+ *pp && (*pp)->xUnlockNotify!=db->xUnlockNotify;
|
|
pp=&(*pp)->pNextBlocked
|
|
);
|
|
db->pNextBlocked = *pp;
|
|
@@ -163750,20 +179010,20 @@ static void addToBlockedList(sqlite3 *db){
|
|
}
|
|
|
|
/*
|
|
-** Obtain the STATIC_MASTER mutex.
|
|
+** Obtain the STATIC_MAIN mutex.
|
|
*/
|
|
static void enterMutex(void){
|
|
- sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
|
|
+ sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN));
|
|
checkListProperties(0);
|
|
}
|
|
|
|
/*
|
|
-** Release the STATIC_MASTER mutex.
|
|
+** Release the STATIC_MAIN mutex.
|
|
*/
|
|
static void leaveMutex(void){
|
|
assertMutexHeld();
|
|
checkListProperties(0);
|
|
- sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER));
|
|
+ sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MAIN));
|
|
}
|
|
|
|
/*
|
|
@@ -163804,9 +179064,9 @@ SQLITE_API int sqlite3_unlock_notify(
|
|
db->xUnlockNotify = 0;
|
|
db->pUnlockArg = 0;
|
|
}else if( 0==db->pBlockingConnection ){
|
|
- /* The blocking transaction has been concluded. Or there never was a
|
|
+ /* The blocking transaction has been concluded. Or there never was a
|
|
** blocking transaction. In either case, invoke the notify callback
|
|
- ** immediately.
|
|
+ ** immediately.
|
|
*/
|
|
xNotify(&pArg, 1);
|
|
}else{
|
|
@@ -163832,7 +179092,7 @@ SQLITE_API int sqlite3_unlock_notify(
|
|
}
|
|
|
|
/*
|
|
-** This function is called while stepping or preparing a statement
|
|
+** This function is called while stepping or preparing a statement
|
|
** associated with connection db. The operation will return SQLITE_LOCKED
|
|
** to the user because it requires a lock that will not be available
|
|
** until connection pBlocker concludes its current transaction.
|
|
@@ -163848,7 +179108,7 @@ SQLITE_PRIVATE void sqlite3ConnectionBlocked(sqlite3 *db, sqlite3 *pBlocker){
|
|
|
|
/*
|
|
** This function is called when
|
|
-** the transaction opened by database db has just finished. Locks held
|
|
+** the transaction opened by database db has just finished. Locks held
|
|
** by database connection db have been released.
|
|
**
|
|
** This function loops through each entry in the blocked connections
|
|
@@ -163874,7 +179134,7 @@ SQLITE_PRIVATE void sqlite3ConnectionUnlocked(sqlite3 *db){
|
|
void *aStatic[16]; /* Starter space for aArg[]. No malloc required */
|
|
|
|
aArg = aStatic;
|
|
- enterMutex(); /* Enter STATIC_MASTER mutex */
|
|
+ enterMutex(); /* Enter STATIC_MAIN mutex */
|
|
|
|
/* This loop runs once for each entry in the blocked-connections list. */
|
|
for(pp=&sqlite3BlockedList; *pp; /* no-op */ ){
|
|
@@ -163908,7 +179168,7 @@ SQLITE_PRIVATE void sqlite3ConnectionUnlocked(sqlite3 *db){
|
|
}else{
|
|
/* This occurs when the array of context pointers that need to
|
|
** be passed to the unlock-notify callback is larger than the
|
|
- ** aStatic[] array allocated on the stack and the attempt to
|
|
+ ** aStatic[] array allocated on the stack and the attempt to
|
|
** allocate a larger array from the heap has failed.
|
|
**
|
|
** This is a difficult situation to handle. Returning an error
|
|
@@ -163916,17 +179176,17 @@ SQLITE_PRIVATE void sqlite3ConnectionUnlocked(sqlite3 *db){
|
|
** is returned the transaction on connection db will still be
|
|
** closed and the unlock-notify callbacks on blocked connections
|
|
** will go unissued. This might cause the application to wait
|
|
- ** indefinitely for an unlock-notify callback that will never
|
|
+ ** indefinitely for an unlock-notify callback that will never
|
|
** arrive.
|
|
**
|
|
** Instead, invoke the unlock-notify callback with the context
|
|
** array already accumulated. We can then clear the array and
|
|
- ** begin accumulating any further context pointers without
|
|
+ ** begin accumulating any further context pointers without
|
|
** requiring any dynamic allocation. This is sub-optimal because
|
|
** it means that instead of one callback with a large array of
|
|
** context pointers the application will receive two or more
|
|
** callbacks with smaller arrays of context pointers, which will
|
|
- ** reduce the applications ability to prioritize multiple
|
|
+ ** reduce the applications ability to prioritize multiple
|
|
** connections. But it is the best that can be done under the
|
|
** circumstances.
|
|
*/
|
|
@@ -163957,11 +179217,11 @@ SQLITE_PRIVATE void sqlite3ConnectionUnlocked(sqlite3 *db){
|
|
xUnlockNotify(aArg, nArg);
|
|
}
|
|
sqlite3_free(aDyn);
|
|
- leaveMutex(); /* Leave STATIC_MASTER mutex */
|
|
+ leaveMutex(); /* Leave STATIC_MAIN mutex */
|
|
}
|
|
|
|
/*
|
|
-** This is called when the database connection passed as an argument is
|
|
+** This is called when the database connection passed as an argument is
|
|
** being closed. The connection is removed from the blocked list.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3ConnectionClosed(sqlite3 *db){
|
|
@@ -164038,7 +179298,7 @@ SQLITE_PRIVATE void sqlite3ConnectionClosed(sqlite3 *db){
|
|
** A doclist (document list) holds a docid-sorted list of hits for a
|
|
** given term. Doclists hold docids and associated token positions.
|
|
** A docid is the unique integer identifier for a single document.
|
|
-** A position is the index of a word within the document. The first
|
|
+** A position is the index of a word within the document. The first
|
|
** word of the document has a position of 0.
|
|
**
|
|
** FTS3 used to optionally store character offsets using a compile-time
|
|
@@ -164063,7 +179323,7 @@ SQLITE_PRIVATE void sqlite3ConnectionClosed(sqlite3 *db){
|
|
**
|
|
** Here, array { X } means zero or more occurrences of X, adjacent in
|
|
** memory. A "position" is an index of a token in the token stream
|
|
-** generated by the tokenizer. Note that POS_END and POS_COLUMN occur
|
|
+** generated by the tokenizer. Note that POS_END and POS_COLUMN occur
|
|
** in the same logical place as the position element, and act as sentinals
|
|
** ending a position list array. POS_END is 0. POS_COLUMN is 1.
|
|
** The positions numbers are not stored literally but rather as two more
|
|
@@ -164087,7 +179347,7 @@ SQLITE_PRIVATE void sqlite3ConnectionClosed(sqlite3 *db){
|
|
** a document record consists of a docid followed by a position-list and
|
|
** a doclist consists of one or more document records.
|
|
**
|
|
-** A bare doclist omits the position information, becoming an
|
|
+** A bare doclist omits the position information, becoming an
|
|
** array of varint-encoded docids.
|
|
**
|
|
**** Segment leaf nodes ****
|
|
@@ -164283,7 +179543,7 @@ SQLITE_PRIVATE void sqlite3ConnectionClosed(sqlite3 *db){
|
|
#ifndef _FTSINT_H
|
|
#define _FTSINT_H
|
|
|
|
-#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
|
|
+#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
|
|
# define NDEBUG 1
|
|
#endif
|
|
|
|
@@ -164306,7 +179566,7 @@ SQLITE_PRIVATE void sqlite3ConnectionClosed(sqlite3 *db){
|
|
|
|
/* If not building as part of the core, include sqlite3ext.h. */
|
|
#ifndef SQLITE_CORE
|
|
-/* # include "sqlite3ext.h" */
|
|
+/* # include "sqlite3ext.h" */
|
|
SQLITE_EXTENSION_INIT3
|
|
#endif
|
|
|
|
@@ -164350,7 +179610,7 @@ SQLITE_EXTENSION_INIT3
|
|
** When an fts3 table is created, it passes any arguments passed to
|
|
** the tokenizer clause of the CREATE VIRTUAL TABLE statement to the
|
|
** sqlite3_tokenizer_module.xCreate() function of the requested tokenizer
|
|
-** implementation. The xCreate() function in turn returns an
|
|
+** implementation. The xCreate() function in turn returns an
|
|
** sqlite3_tokenizer structure representing the specific tokenizer to
|
|
** be used for the fts3 table (customized by the tokenizer clause arguments).
|
|
**
|
|
@@ -164382,7 +179642,7 @@ struct sqlite3_tokenizer_module {
|
|
** then argc is set to 2, and the argv[] array contains pointers
|
|
** to the strings "arg1" and "arg2".
|
|
**
|
|
- ** This method should return either SQLITE_OK (0), or an SQLite error
|
|
+ ** This method should return either SQLITE_OK (0), or an SQLite error
|
|
** code. If SQLITE_OK is returned, then *ppTokenizer should be set
|
|
** to point at the newly created tokenizer structure. The generic
|
|
** sqlite3_tokenizer.pModule variable should not be initialized by
|
|
@@ -164403,7 +179663,7 @@ struct sqlite3_tokenizer_module {
|
|
/*
|
|
** Create a tokenizer cursor to tokenize an input buffer. The caller
|
|
** is responsible for ensuring that the input buffer remains valid
|
|
- ** until the cursor is closed (using the xClose() method).
|
|
+ ** until the cursor is closed (using the xClose() method).
|
|
*/
|
|
int (*xOpen)(
|
|
sqlite3_tokenizer *pTokenizer, /* Tokenizer object */
|
|
@@ -164412,7 +179672,7 @@ struct sqlite3_tokenizer_module {
|
|
);
|
|
|
|
/*
|
|
- ** Destroy an existing tokenizer cursor. The fts3 module calls this
|
|
+ ** Destroy an existing tokenizer cursor. The fts3 module calls this
|
|
** method exactly once for each successful call to xOpen().
|
|
*/
|
|
int (*xClose)(sqlite3_tokenizer_cursor *pCursor);
|
|
@@ -164423,7 +179683,7 @@ struct sqlite3_tokenizer_module {
|
|
** "OUT" variables identified below, or SQLITE_DONE to indicate that
|
|
** the end of the buffer has been reached, or an SQLite error code.
|
|
**
|
|
- ** *ppToken should be set to point at a buffer containing the
|
|
+ ** *ppToken should be set to point at a buffer containing the
|
|
** normalized version of the token (i.e. after any case-folding and/or
|
|
** stemming has been performed). *pnBytes should be set to the length
|
|
** of this buffer in bytes. The input text that generated the token is
|
|
@@ -164435,7 +179695,7 @@ struct sqlite3_tokenizer_module {
|
|
**
|
|
** The buffer *ppToken is set to point at is managed by the tokenizer
|
|
** implementation. It is only required to be valid until the next call
|
|
- ** to xNext() or xClose().
|
|
+ ** to xNext() or xClose().
|
|
*/
|
|
/* TODO(shess) current implementation requires pInput to be
|
|
** nul-terminated. This should either be fixed, or pInput/nBytes
|
|
@@ -164453,7 +179713,7 @@ struct sqlite3_tokenizer_module {
|
|
** Methods below this point are only available if iVersion>=1.
|
|
*/
|
|
|
|
- /*
|
|
+ /*
|
|
** Configure the language id of a tokenizer cursor.
|
|
*/
|
|
int (*xLanguageid)(sqlite3_tokenizer_cursor *pCsr, int iLangid);
|
|
@@ -164522,7 +179782,7 @@ struct Fts3Hash {
|
|
} *ht;
|
|
};
|
|
|
|
-/* Each element in the hash table is an instance of the following
|
|
+/* Each element in the hash table is an instance of the following
|
|
** structure. All elements are stored on a single doubly-linked list.
|
|
**
|
|
** Again, this structure is intended to be opaque, but it can't really
|
|
@@ -164541,10 +179801,10 @@ struct Fts3HashElem {
|
|
** (including the null-terminator, if any). Case
|
|
** is respected in comparisons.
|
|
**
|
|
-** FTS3_HASH_BINARY pKey points to binary data nKey bytes long.
|
|
+** FTS3_HASH_BINARY pKey points to binary data nKey bytes long.
|
|
** memcmp() is used to compare keys.
|
|
**
|
|
-** A copy of the key is made if the copyKey parameter to fts3HashInit is 1.
|
|
+** A copy of the key is made if the copyKey parameter to fts3HashInit is 1.
|
|
*/
|
|
#define FTS3_HASH_STRING 1
|
|
#define FTS3_HASH_BINARY 2
|
|
@@ -164597,7 +179857,7 @@ SQLITE_PRIVATE Fts3HashElem *sqlite3Fts3HashFindElem(const Fts3Hash *, const voi
|
|
|
|
/*
|
|
** This constant determines the maximum depth of an FTS expression tree
|
|
-** that the library will create and use. FTS uses recursion to perform
|
|
+** that the library will create and use. FTS uses recursion to perform
|
|
** various operations on the query tree, so the disadvantage of a large
|
|
** limit is that it may allow very large queries to use large amounts
|
|
** of stack space (perhaps causing a stack overflow).
|
|
@@ -164615,11 +179875,11 @@ SQLITE_PRIVATE Fts3HashElem *sqlite3Fts3HashFindElem(const Fts3Hash *, const voi
|
|
#define FTS3_MERGE_COUNT 16
|
|
|
|
/*
|
|
-** This is the maximum amount of data (in bytes) to store in the
|
|
+** This is the maximum amount of data (in bytes) to store in the
|
|
** Fts3Table.pendingTerms hash table. Normally, the hash table is
|
|
** populated as documents are inserted/updated/deleted in a transaction
|
|
** and used to create a new segment when the transaction is committed.
|
|
-** However if this limit is reached midway through a transaction, a new
|
|
+** However if this limit is reached midway through a transaction, a new
|
|
** segment is created and the hash table cleared immediately.
|
|
*/
|
|
#define FTS3_MAX_PENDING_DATA (1*1024*1024)
|
|
@@ -164650,7 +179910,7 @@ SQLITE_PRIVATE Fts3HashElem *sqlite3Fts3HashFindElem(const Fts3Hash *, const voi
|
|
/*
|
|
** FTS4 virtual tables may maintain multiple indexes - one index of all terms
|
|
** in the document set and zero or more prefix indexes. All indexes are stored
|
|
-** as one or more b+-trees in the %_segments and %_segdir tables.
|
|
+** as one or more b+-trees in the %_segments and %_segdir tables.
|
|
**
|
|
** It is possible to determine which index a b+-tree belongs to based on the
|
|
** value stored in the "%_segdir.level" column. Given this value L, the index
|
|
@@ -164658,8 +179918,8 @@ SQLITE_PRIVATE Fts3HashElem *sqlite3Fts3HashFindElem(const Fts3Hash *, const voi
|
|
** level values between 0 and 1023 (inclusive) belong to index 0, all levels
|
|
** between 1024 and 2047 to index 1, and so on.
|
|
**
|
|
-** It is considered impossible for an index to use more than 1024 levels. In
|
|
-** theory though this may happen, but only after at least
|
|
+** It is considered impossible for an index to use more than 1024 levels. In
|
|
+** theory though this may happen, but only after at least
|
|
** (FTS3_MERGE_COUNT^1024) separate flushes of the pending-terms tables.
|
|
*/
|
|
#define FTS3_SEGDIR_MAXLEVEL 1024
|
|
@@ -164677,14 +179937,14 @@ SQLITE_PRIVATE Fts3HashElem *sqlite3Fts3HashFindElem(const Fts3Hash *, const voi
|
|
** Terminator values for position-lists and column-lists.
|
|
*/
|
|
#define POS_COLUMN (1) /* Column-list terminator */
|
|
-#define POS_END (0) /* Position-list terminator */
|
|
+#define POS_END (0) /* Position-list terminator */
|
|
|
|
/*
|
|
** The assert_fts3_nc() macro is similar to the assert() macro, except that it
|
|
-** is used for assert() conditions that are true only if it can be
|
|
+** is used for assert() conditions that are true only if it can be
|
|
** guranteed that the database is not corrupt.
|
|
*/
|
|
-#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
|
|
+#ifdef SQLITE_DEBUG
|
|
SQLITE_API extern int sqlite3_fts3_may_be_corrupt;
|
|
# define assert_fts3_nc(x) assert(sqlite3_fts3_may_be_corrupt || (x))
|
|
#else
|
|
@@ -164693,7 +179953,7 @@ SQLITE_API extern int sqlite3_fts3_may_be_corrupt;
|
|
|
|
/*
|
|
** This section provides definitions to allow the
|
|
-** FTS3 extension to be compiled outside of the
|
|
+** FTS3 extension to be compiled outside of the
|
|
** amalgamation.
|
|
*/
|
|
#ifndef SQLITE_AMALGAMATION
|
|
@@ -164701,17 +179961,18 @@ SQLITE_API extern int sqlite3_fts3_may_be_corrupt;
|
|
** Macros indicating that conditional expressions are always true or
|
|
** false.
|
|
*/
|
|
-#ifdef SQLITE_COVERAGE_TEST
|
|
-# define ALWAYS(x) (1)
|
|
-# define NEVER(X) (0)
|
|
-#elif defined(SQLITE_DEBUG)
|
|
-# define ALWAYS(x) sqlite3Fts3Always((x)!=0)
|
|
-# define NEVER(x) sqlite3Fts3Never((x)!=0)
|
|
-SQLITE_PRIVATE int sqlite3Fts3Always(int b);
|
|
-SQLITE_PRIVATE int sqlite3Fts3Never(int b);
|
|
+#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST)
|
|
+# define SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS 1
|
|
+#endif
|
|
+#if defined(SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS)
|
|
+# define ALWAYS(X) (1)
|
|
+# define NEVER(X) (0)
|
|
+#elif !defined(NDEBUG)
|
|
+# define ALWAYS(X) ((X)?1:(assert(0),0))
|
|
+# define NEVER(X) ((X)?(assert(0),1):0)
|
|
#else
|
|
-# define ALWAYS(x) (x)
|
|
-# define NEVER(x) (x)
|
|
+# define ALWAYS(X) (X)
|
|
+# define NEVER(X) (X)
|
|
#endif
|
|
|
|
/*
|
|
@@ -164731,7 +179992,7 @@ typedef sqlite3_int64 i64; /* 8-byte signed integer */
|
|
/*
|
|
** Activate assert() only if SQLITE_TEST is enabled.
|
|
*/
|
|
-#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
|
|
+#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
|
|
# define NDEBUG 1
|
|
#endif
|
|
|
|
@@ -164749,6 +180010,8 @@ typedef sqlite3_int64 i64; /* 8-byte signed integer */
|
|
#define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32))
|
|
#define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64)
|
|
|
|
+#define deliberate_fall_through
|
|
+
|
|
#endif /* SQLITE_AMALGAMATION */
|
|
|
|
#ifdef SQLITE_DEBUG
|
|
@@ -164794,8 +180057,8 @@ struct Fts3Table {
|
|
u32 nLeafAdd; /* Number of leaf blocks added this trans */
|
|
int bLock; /* Used to prevent recursive content= tbls */
|
|
|
|
- /* Precompiled statements used by the implementation. Each of these
|
|
- ** statements is run and reset within a single virtual table API call.
|
|
+ /* Precompiled statements used by the implementation. Each of these
|
|
+ ** statements is run and reset within a single virtual table API call.
|
|
*/
|
|
sqlite3_stmt *aStmt[40];
|
|
sqlite3_stmt *pSeekStmt; /* Cache for fts3CursorSeekStmt() */
|
|
@@ -164813,8 +180076,8 @@ struct Fts3Table {
|
|
char *zSegmentsTbl; /* Name of %_segments table */
|
|
sqlite3_blob *pSegments; /* Blob handle open on %_segments table */
|
|
|
|
- /*
|
|
- ** The following array of hash tables is used to buffer pending index
|
|
+ /*
|
|
+ ** The following array of hash tables is used to buffer pending index
|
|
** updates during transactions. All pending updates buffered at any one
|
|
** time must share a common language-id (see the FTS4 langid= feature).
|
|
** The current language id is stored in variable iPrevLangid.
|
|
@@ -164824,10 +180087,10 @@ struct Fts3Table {
|
|
** terms that appear in the document set. Each subsequent index in aIndex[]
|
|
** is an index of prefixes of a specific length.
|
|
**
|
|
- ** Variable nPendingData contains an estimate the memory consumed by the
|
|
+ ** Variable nPendingData contains an estimate the memory consumed by the
|
|
** pending data structures, including hash table overhead, but not including
|
|
** malloc overhead. When nPendingData exceeds nMaxPendingData, all hash
|
|
- ** tables are flushed to disk. Variable iPrevDocid is the docid of the most
|
|
+ ** tables are flushed to disk. Variable iPrevDocid is the docid of the most
|
|
** recently inserted record.
|
|
*/
|
|
int nIndex; /* Size of aIndex[] */
|
|
@@ -164910,10 +180173,10 @@ struct Fts3Cursor {
|
|
**
|
|
** CREATE VIRTUAL TABLE ex1 USING fts3(a,b,c,d);
|
|
** SELECT docid FROM ex1 WHERE b MATCH 'one two three';
|
|
-**
|
|
+**
|
|
** Because the LHS of the MATCH operator is 2nd column "b",
|
|
** Fts3Cursor.eSearch will be set to FTS3_FULLTEXT_SEARCH+1. (+0 for a,
|
|
-** +1 for b, +2 for c, +3 for d.) If the LHS of MATCH were "ex1"
|
|
+** +1 for b, +2 for c, +3 for d.) If the LHS of MATCH were "ex1"
|
|
** indicating that all columns should be searched,
|
|
** then eSearch would be set to FTS3_FULLTEXT_SEARCH+4.
|
|
*/
|
|
@@ -164972,8 +180235,8 @@ struct Fts3Phrase {
|
|
char *pOrPoslist;
|
|
i64 iOrDocid;
|
|
|
|
- /* Variables below this point are populated by fts3_expr.c when parsing
|
|
- ** a MATCH expression. Everything above is part of the evaluation phase.
|
|
+ /* Variables below this point are populated by fts3_expr.c when parsing
|
|
+ ** a MATCH expression. Everything above is part of the evaluation phase.
|
|
*/
|
|
int nToken; /* Number of tokens in the phrase */
|
|
int iColumn; /* Index of column this phrase must match */
|
|
@@ -164983,10 +180246,10 @@ struct Fts3Phrase {
|
|
/*
|
|
** A tree of these objects forms the RHS of a MATCH operator.
|
|
**
|
|
-** If Fts3Expr.eType is FTSQUERY_PHRASE and isLoaded is true, then aDoclist
|
|
-** points to a malloced buffer, size nDoclist bytes, containing the results
|
|
-** of this phrase query in FTS3 doclist format. As usual, the initial
|
|
-** "Length" field found in doclists stored on disk is omitted from this
|
|
+** If Fts3Expr.eType is FTSQUERY_PHRASE and isLoaded is true, then aDoclist
|
|
+** points to a malloced buffer, size nDoclist bytes, containing the results
|
|
+** of this phrase query in FTS3 doclist format. As usual, the initial
|
|
+** "Length" field found in doclists stored on disk is omitted from this
|
|
** buffer.
|
|
**
|
|
** Variable aMI is used only for FTSQUERY_NEAR nodes to store the global
|
|
@@ -164998,7 +180261,7 @@ struct Fts3Phrase {
|
|
** aMI[iCol*3 + 1] = Number of occurrences
|
|
** aMI[iCol*3 + 2] = Number of rows containing at least one instance
|
|
**
|
|
-** The aMI array is allocated using sqlite3_malloc(). It should be freed
|
|
+** The aMI array is allocated using sqlite3_malloc(). It should be freed
|
|
** when the expression node is.
|
|
*/
|
|
struct Fts3Expr {
|
|
@@ -165022,7 +180285,7 @@ struct Fts3Expr {
|
|
|
|
/*
|
|
** Candidate values for Fts3Query.eType. Note that the order of the first
|
|
-** four values is in order of precedence when parsing expressions. For
|
|
+** four values is in order of precedence when parsing expressions. For
|
|
** example, the following:
|
|
**
|
|
** "a OR b AND c NOT d NEAR e"
|
|
@@ -165079,7 +180342,7 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderStart(Fts3Table*, Fts3MultiSegReader*, Ft
|
|
SQLITE_PRIVATE int sqlite3Fts3SegReaderStep(Fts3Table *, Fts3MultiSegReader *);
|
|
SQLITE_PRIVATE void sqlite3Fts3SegReaderFinish(Fts3MultiSegReader *);
|
|
|
|
-SQLITE_PRIVATE int sqlite3Fts3SegReaderCursor(Fts3Table *,
|
|
+SQLITE_PRIVATE int sqlite3Fts3SegReaderCursor(Fts3Table *,
|
|
int, int, int, const char *, int, int, int, Fts3MultiSegReader *);
|
|
|
|
/* Flags allowed as part of the 4th argument to SegmentReaderIterate() */
|
|
@@ -165105,7 +180368,7 @@ struct Fts3MultiSegReader {
|
|
int nAdvance; /* How many seg-readers to advance */
|
|
Fts3SegFilter *pFilter; /* Pointer to filter object */
|
|
char *aBuffer; /* Buffer to merge doclists in */
|
|
- int nBuffer; /* Allocated size of aBuffer[] in bytes */
|
|
+ i64 nBuffer; /* Allocated size of aBuffer[] in bytes */
|
|
|
|
int iColFilter; /* If >=0, filter for this column */
|
|
int bRestart;
|
|
@@ -165141,11 +180404,12 @@ SQLITE_PRIVATE int sqlite3Fts3EvalPhraseStats(Fts3Cursor *, Fts3Expr *, u32 *);
|
|
SQLITE_PRIVATE int sqlite3Fts3FirstFilter(sqlite3_int64, char *, int, char *);
|
|
SQLITE_PRIVATE void sqlite3Fts3CreateStatTable(int*, Fts3Table*);
|
|
SQLITE_PRIVATE int sqlite3Fts3EvalTestDeferred(Fts3Cursor *pCsr, int *pRc);
|
|
+SQLITE_PRIVATE int sqlite3Fts3ReadInt(const char *z, int *pnOut);
|
|
|
|
/* fts3_tokenizer.c */
|
|
SQLITE_PRIVATE const char *sqlite3Fts3NextToken(const char *, int *);
|
|
SQLITE_PRIVATE int sqlite3Fts3InitHashTable(sqlite3 *, Fts3Hash *, const char *);
|
|
-SQLITE_PRIVATE int sqlite3Fts3InitTokenizer(Fts3Hash *pHash, const char *,
|
|
+SQLITE_PRIVATE int sqlite3Fts3InitTokenizer(Fts3Hash *pHash, const char *,
|
|
sqlite3_tokenizer **, char **
|
|
);
|
|
SQLITE_PRIVATE int sqlite3Fts3IsIdChar(char);
|
|
@@ -165167,6 +180431,7 @@ SQLITE_PRIVATE void sqlite3Fts3ExprFree(Fts3Expr *);
|
|
SQLITE_PRIVATE int sqlite3Fts3ExprInitTestInterface(sqlite3 *db, Fts3Hash*);
|
|
SQLITE_PRIVATE int sqlite3Fts3InitTerm(sqlite3 *db);
|
|
#endif
|
|
+SQLITE_PRIVATE void *sqlite3Fts3MallocZero(i64 nByte);
|
|
|
|
SQLITE_PRIVATE int sqlite3Fts3OpenTokenizer(sqlite3_tokenizer *, int, const char *, int,
|
|
sqlite3_tokenizer_cursor **
|
|
@@ -165181,12 +180446,12 @@ SQLITE_PRIVATE int sqlite3Fts3MsrIncrStart(
|
|
Fts3Table*, Fts3MultiSegReader*, int, const char*, int);
|
|
SQLITE_PRIVATE int sqlite3Fts3MsrIncrNext(
|
|
Fts3Table *, Fts3MultiSegReader *, sqlite3_int64 *, char **, int *);
|
|
-SQLITE_PRIVATE int sqlite3Fts3EvalPhrasePoslist(Fts3Cursor *, Fts3Expr *, int iCol, char **);
|
|
+SQLITE_PRIVATE int sqlite3Fts3EvalPhrasePoslist(Fts3Cursor *, Fts3Expr *, int iCol, char **);
|
|
SQLITE_PRIVATE int sqlite3Fts3MsrOvfl(Fts3Cursor *, Fts3MultiSegReader *, int *);
|
|
SQLITE_PRIVATE int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr);
|
|
|
|
/* fts3_tokenize_vtab.c */
|
|
-SQLITE_PRIVATE int sqlite3Fts3InitTok(sqlite3*, Fts3Hash *);
|
|
+SQLITE_PRIVATE int sqlite3Fts3InitTok(sqlite3*, Fts3Hash *, void(*xDestroy)(void*));
|
|
|
|
/* fts3_unicode2.c (functions generated by parsing unicode text files) */
|
|
#ifndef SQLITE_DISABLE_FTS3_UNICODE
|
|
@@ -165195,6 +180460,8 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeIsalnum(int);
|
|
SQLITE_PRIVATE int sqlite3FtsUnicodeIsdiacritic(int);
|
|
#endif
|
|
|
|
+SQLITE_PRIVATE int sqlite3Fts3ExprIterate(Fts3Expr*, int (*x)(Fts3Expr*,int,void*), void*);
|
|
+
|
|
#endif /* !SQLITE_CORE || SQLITE_ENABLE_FTS3 */
|
|
#endif /* _FTSINT_H */
|
|
|
|
@@ -165214,32 +180481,33 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeIsdiacritic(int);
|
|
/* #include <stdarg.h> */
|
|
|
|
/* #include "fts3.h" */
|
|
-#ifndef SQLITE_CORE
|
|
+#ifndef SQLITE_CORE
|
|
/* # include "sqlite3ext.h" */
|
|
SQLITE_EXTENSION_INIT1
|
|
#endif
|
|
|
|
+typedef struct Fts3HashWrapper Fts3HashWrapper;
|
|
+struct Fts3HashWrapper {
|
|
+ Fts3Hash hash; /* Hash table */
|
|
+ int nRef; /* Number of pointers to this object */
|
|
+};
|
|
+
|
|
static int fts3EvalNext(Fts3Cursor *pCsr);
|
|
static int fts3EvalStart(Fts3Cursor *pCsr);
|
|
static int fts3TermSegReaderCursor(
|
|
Fts3Cursor *, const char *, int, int, Fts3MultiSegReader **);
|
|
|
|
-#ifndef SQLITE_AMALGAMATION
|
|
-# if defined(SQLITE_DEBUG)
|
|
-SQLITE_PRIVATE int sqlite3Fts3Always(int b) { assert( b ); return b; }
|
|
-SQLITE_PRIVATE int sqlite3Fts3Never(int b) { assert( !b ); return b; }
|
|
-# endif
|
|
-#endif
|
|
-
|
|
/*
|
|
** This variable is set to false when running tests for which the on disk
|
|
** structures should not be corrupt. Otherwise, true. If it is false, extra
|
|
** assert() conditions in the fts3 code are activated - conditions that are
|
|
** only true if it is guaranteed that the fts3 database is not corrupt.
|
|
*/
|
|
+#ifdef SQLITE_DEBUG
|
|
SQLITE_API int sqlite3_fts3_may_be_corrupt = 1;
|
|
+#endif
|
|
|
|
-/*
|
|
+/*
|
|
** Write a 64-bit variable-length integer to memory starting at p[0].
|
|
** The length of data written will be between 1 and FTS3_VARINT_MAX bytes.
|
|
** The number of bytes written is returned.
|
|
@@ -165285,7 +180553,7 @@ SQLITE_PRIVATE int sqlite3Fts3GetVarintU(const char *pBuf, sqlite_uint64 *v){
|
|
return (int)(p - pStart);
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** Read a 64-bit variable-length integer from memory starting at p[0].
|
|
** Return the number of bytes read, or 0 on error.
|
|
** The value is stored in *v.
|
|
@@ -165294,7 +180562,7 @@ SQLITE_PRIVATE int sqlite3Fts3GetVarint(const char *pBuf, sqlite_int64 *v){
|
|
return sqlite3Fts3GetVarintU(pBuf, (sqlite3_uint64*)v);
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** Read a 64-bit variable-length integer from memory starting at p[0] and
|
|
** not extending past pEnd[-1].
|
|
** Return the number of bytes read, or 0 on error.
|
|
@@ -165321,7 +180589,7 @@ SQLITE_PRIVATE int sqlite3Fts3GetVarintBounded(
|
|
}
|
|
|
|
/*
|
|
-** Similar to sqlite3Fts3GetVarint(), except that the output is truncated to
|
|
+** Similar to sqlite3Fts3GetVarint(), except that the output is truncated to
|
|
** a non-negative 32-bit integer before it is returned.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3Fts3GetVarint32(const char *p, int *pi){
|
|
@@ -165380,7 +180648,7 @@ SQLITE_PRIVATE void sqlite3Fts3Dequote(char *z){
|
|
int iOut = 0; /* Index of next byte to write to output */
|
|
|
|
/* If the first byte was a '[', then the close-quote character is a ']' */
|
|
- if( quote=='[' ) quote = ']';
|
|
+ if( quote=='[' ) quote = ']';
|
|
|
|
while( z[iIn] ){
|
|
if( z[iIn]==quote ){
|
|
@@ -165416,14 +180684,14 @@ static void fts3GetDeltaVarint(char **pp, sqlite3_int64 *pVal){
|
|
** varint is part of.
|
|
*/
|
|
static void fts3GetReverseVarint(
|
|
- char **pp,
|
|
- char *pStart,
|
|
+ char **pp,
|
|
+ char *pStart,
|
|
sqlite3_int64 *pVal
|
|
){
|
|
sqlite3_int64 iVal;
|
|
char *p;
|
|
|
|
- /* Pointer p now points at the first byte past the varint we are
|
|
+ /* Pointer p now points at the first byte past the varint we are
|
|
** interested in. So, unless the doclist is corrupt, the 0x80 bit is
|
|
** clear on character p[-1]. */
|
|
for(p = (*pp)-2; p>=pStart && *p&0x80; p--);
|
|
@@ -165510,7 +180778,7 @@ static int fts3DestroyMethod(sqlite3_vtab *pVtab){
|
|
sqlite3 *db = p->db; /* Database handle */
|
|
|
|
/* Drop the shadow tables */
|
|
- fts3DbExec(&rc, db,
|
|
+ fts3DbExec(&rc, db,
|
|
"DROP TABLE IF EXISTS %Q.'%q_segments';"
|
|
"DROP TABLE IF EXISTS %Q.'%q_segdir';"
|
|
"DROP TABLE IF EXISTS %Q.'%q_docsize';"
|
|
@@ -165536,7 +180804,7 @@ static int fts3DestroyMethod(sqlite3_vtab *pVtab){
|
|
** passed as the first argument. This is done as part of the xConnect()
|
|
** and xCreate() methods.
|
|
**
|
|
-** If *pRc is non-zero when this function is called, it is a no-op.
|
|
+** If *pRc is non-zero when this function is called, it is a no-op.
|
|
** Otherwise, if an error occurs, an SQLite error code is stored in *pRc
|
|
** before returning.
|
|
*/
|
|
@@ -165559,7 +180827,7 @@ static void fts3DeclareVtab(int *pRc, Fts3Table *p){
|
|
|
|
/* Create the whole "CREATE TABLE" statement to pass to SQLite */
|
|
zSql = sqlite3_mprintf(
|
|
- "CREATE TABLE x(%s %Q HIDDEN, docid HIDDEN, %Q HIDDEN)",
|
|
+ "CREATE TABLE x(%s %Q HIDDEN, docid HIDDEN, %Q HIDDEN)",
|
|
zCols, p->zName, zLanguageid
|
|
);
|
|
if( !zCols || !zSql ){
|
|
@@ -165578,7 +180846,7 @@ static void fts3DeclareVtab(int *pRc, Fts3Table *p){
|
|
** Create the %_stat table if it does not already exist.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3Fts3CreateStatTable(int *pRc, Fts3Table *p){
|
|
- fts3DbExec(pRc, p->db,
|
|
+ fts3DbExec(pRc, p->db,
|
|
"CREATE TABLE IF NOT EXISTS %Q.'%q_stat'"
|
|
"(id INTEGER PRIMARY KEY, value BLOB);",
|
|
p->zDb, p->zName
|
|
@@ -165614,9 +180882,9 @@ static int fts3CreateTables(Fts3Table *p){
|
|
zContentCols = sqlite3_mprintf("%z, langid", zContentCols, zLanguageid);
|
|
}
|
|
if( zContentCols==0 ) rc = SQLITE_NOMEM;
|
|
-
|
|
+
|
|
/* Create the content table */
|
|
- fts3DbExec(&rc, db,
|
|
+ fts3DbExec(&rc, db,
|
|
"CREATE TABLE %Q.'%q_content'(%s)",
|
|
p->zDb, p->zName, zContentCols
|
|
);
|
|
@@ -165624,11 +180892,11 @@ static int fts3CreateTables(Fts3Table *p){
|
|
}
|
|
|
|
/* Create other tables */
|
|
- fts3DbExec(&rc, db,
|
|
+ fts3DbExec(&rc, db,
|
|
"CREATE TABLE %Q.'%q_segments'(blockid INTEGER PRIMARY KEY, block BLOB);",
|
|
p->zDb, p->zName
|
|
);
|
|
- fts3DbExec(&rc, db,
|
|
+ fts3DbExec(&rc, db,
|
|
"CREATE TABLE %Q.'%q_segdir'("
|
|
"level INTEGER,"
|
|
"idx INTEGER,"
|
|
@@ -165641,7 +180909,7 @@ static int fts3CreateTables(Fts3Table *p){
|
|
p->zDb, p->zName
|
|
);
|
|
if( p->bHasDocsize ){
|
|
- fts3DbExec(&rc, db,
|
|
+ fts3DbExec(&rc, db,
|
|
"CREATE TABLE %Q.'%q_docsize'(docid INTEGER PRIMARY KEY, size BLOB);",
|
|
p->zDb, p->zName
|
|
);
|
|
@@ -165656,7 +180924,7 @@ static int fts3CreateTables(Fts3Table *p){
|
|
/*
|
|
** Store the current database page-size in bytes in p->nPgsz.
|
|
**
|
|
-** If *pRc is non-zero when this function is called, it is a no-op.
|
|
+** If *pRc is non-zero when this function is called, it is a no-op.
|
|
** Otherwise, if an error occurs, an SQLite error code is stored in *pRc
|
|
** before returning.
|
|
*/
|
|
@@ -165665,7 +180933,7 @@ static void fts3DatabasePageSize(int *pRc, Fts3Table *p){
|
|
int rc; /* Return code */
|
|
char *zSql; /* SQL text "PRAGMA %Q.page_size" */
|
|
sqlite3_stmt *pStmt; /* Compiled "PRAGMA %Q.page_size" statement */
|
|
-
|
|
+
|
|
zSql = sqlite3_mprintf("PRAGMA %Q.page_size", p->zDb);
|
|
if( !zSql ){
|
|
rc = SQLITE_NOMEM;
|
|
@@ -165691,11 +180959,11 @@ static void fts3DatabasePageSize(int *pRc, Fts3Table *p){
|
|
**
|
|
** <key> = <value>
|
|
**
|
|
-** There may not be whitespace surrounding the "=" character. The <value>
|
|
+** There may not be whitespace surrounding the "=" character. The <value>
|
|
** term may be quoted, but the <key> may not.
|
|
*/
|
|
static int fts3IsSpecialColumn(
|
|
- const char *z,
|
|
+ const char *z,
|
|
int *pnKey,
|
|
char **pzValue
|
|
){
|
|
@@ -165772,7 +181040,7 @@ static char *fts3QuoteId(char const *zInput){
|
|
}
|
|
|
|
/*
|
|
-** Return a list of comma separated SQL expressions and a FROM clause that
|
|
+** Return a list of comma separated SQL expressions and a FROM clause that
|
|
** could be used in a SELECT statement such as the following:
|
|
**
|
|
** SELECT <list of expressions> FROM %_content AS x ...
|
|
@@ -165823,7 +181091,7 @@ static char *fts3ReadExprList(Fts3Table *p, const char *zFunc, int *pRc){
|
|
fts3Appendf(pRc, &zRet, ", x.%Q", p->zLanguageid);
|
|
}
|
|
}
|
|
- fts3Appendf(pRc, &zRet, " FROM '%q'.'%q%s' AS x",
|
|
+ fts3Appendf(pRc, &zRet, " FROM '%q'.'%q%s' AS x",
|
|
p->zDb,
|
|
(p->zContentTbl ? p->zContentTbl : p->zName),
|
|
(p->zContentTbl ? "" : "_content")
|
|
@@ -165838,7 +181106,7 @@ static char *fts3ReadExprList(Fts3Table *p, const char *zFunc, int *pRc){
|
|
**
|
|
** If argument zFunc is not NULL, then all but the first question mark
|
|
** is preceded by zFunc and an open bracket, and followed by a closed
|
|
-** bracket. For example, if zFunc is "zip" and the FTS3 table has three
|
|
+** bracket. For example, if zFunc is "zip" and the FTS3 table has three
|
|
** user-defined text columns, the following string is returned:
|
|
**
|
|
** "?, zip(?), zip(?), zip(?)"
|
|
@@ -165873,13 +181141,29 @@ static char *fts3WriteExprList(Fts3Table *p, const char *zFunc, int *pRc){
|
|
return zRet;
|
|
}
|
|
|
|
+/*
|
|
+** Buffer z contains a positive integer value encoded as utf-8 text.
|
|
+** Decode this value and store it in *pnOut, returning the number of bytes
|
|
+** consumed. If an overflow error occurs return a negative value.
|
|
+*/
|
|
+SQLITE_PRIVATE int sqlite3Fts3ReadInt(const char *z, int *pnOut){
|
|
+ u64 iVal = 0;
|
|
+ int i;
|
|
+ for(i=0; z[i]>='0' && z[i]<='9'; i++){
|
|
+ iVal = iVal*10 + (z[i] - '0');
|
|
+ if( iVal>0x7FFFFFFF ) return -1;
|
|
+ }
|
|
+ *pnOut = (int)iVal;
|
|
+ return i;
|
|
+}
|
|
+
|
|
/*
|
|
** This function interprets the string at (*pp) as a non-negative integer
|
|
-** value. It reads the integer and sets *pnOut to the value read, then
|
|
+** value. It reads the integer and sets *pnOut to the value read, then
|
|
** sets *pp to point to the byte immediately following the last byte of
|
|
** the integer value.
|
|
**
|
|
-** Only decimal digits ('0'..'9') may be part of an integer value.
|
|
+** Only decimal digits ('0'..'9') may be part of an integer value.
|
|
**
|
|
** If *pp does not being with a decimal digit SQLITE_ERROR is returned and
|
|
** the output value undefined. Otherwise SQLITE_OK is returned.
|
|
@@ -165888,19 +181172,17 @@ static char *fts3WriteExprList(Fts3Table *p, const char *zFunc, int *pRc){
|
|
*/
|
|
static int fts3GobbleInt(const char **pp, int *pnOut){
|
|
const int MAX_NPREFIX = 10000000;
|
|
- const char *p; /* Iterator pointer */
|
|
int nInt = 0; /* Output value */
|
|
-
|
|
- for(p=*pp; p[0]>='0' && p[0]<='9'; p++){
|
|
- nInt = nInt * 10 + (p[0] - '0');
|
|
- if( nInt>MAX_NPREFIX ){
|
|
- nInt = 0;
|
|
- break;
|
|
- }
|
|
+ int nByte;
|
|
+ nByte = sqlite3Fts3ReadInt(*pp, &nInt);
|
|
+ if( nInt>MAX_NPREFIX ){
|
|
+ nInt = 0;
|
|
+ }
|
|
+ if( nByte==0 ){
|
|
+ return SQLITE_ERROR;
|
|
}
|
|
- if( p==*pp ) return SQLITE_ERROR;
|
|
*pnOut = nInt;
|
|
- *pp = p;
|
|
+ *pp += nByte;
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
@@ -166000,7 +181282,7 @@ static int fts3ContentColumns(
|
|
char **pzErr /* OUT: error message */
|
|
){
|
|
int rc = SQLITE_OK; /* Return code */
|
|
- char *zSql; /* "SELECT *" statement on zTbl */
|
|
+ char *zSql; /* "SELECT *" statement on zTbl */
|
|
sqlite3_stmt *pStmt = 0; /* Compiled version of zSql */
|
|
|
|
zSql = sqlite3_mprintf("SELECT * FROM %Q.%Q", zDb, zTbl);
|
|
@@ -166074,7 +181356,7 @@ static int fts3InitVtab(
|
|
sqlite3_vtab **ppVTab, /* Write the resulting vtab structure here */
|
|
char **pzErr /* Write any error message here */
|
|
){
|
|
- Fts3Hash *pHash = (Fts3Hash *)pAux;
|
|
+ Fts3Hash *pHash = &((Fts3HashWrapper*)pAux)->hash;
|
|
Fts3Table *p = 0; /* Pointer to allocated vtab */
|
|
int rc = SQLITE_OK; /* Return code */
|
|
int i; /* Iterator variable */
|
|
@@ -166142,9 +181424,9 @@ static int fts3InitVtab(
|
|
char *zVal;
|
|
|
|
/* Check if this is a tokenizer specification */
|
|
- if( !pTokenizer
|
|
+ if( !pTokenizer
|
|
&& strlen(z)>8
|
|
- && 0==sqlite3_strnicmp(z, "tokenize", 8)
|
|
+ && 0==sqlite3_strnicmp(z, "tokenize", 8)
|
|
&& 0==sqlite3Fts3IsIdChar(z[8])
|
|
){
|
|
rc = sqlite3Fts3InitTokenizer(pHash, &z[9], &pTokenizer, pzErr);
|
|
@@ -166204,8 +181486,8 @@ static int fts3InitVtab(
|
|
break;
|
|
|
|
case 4: /* ORDER */
|
|
- if( (strlen(zVal)!=3 || sqlite3_strnicmp(zVal, "asc", 3))
|
|
- && (strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "desc", 4))
|
|
+ if( (strlen(zVal)!=3 || sqlite3_strnicmp(zVal, "asc", 3))
|
|
+ && (strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "desc", 4))
|
|
){
|
|
sqlite3Fts3ErrMsg(pzErr, "unrecognized order: %s", zVal);
|
|
rc = SQLITE_ERROR;
|
|
@@ -166256,17 +181538,17 @@ static int fts3InitVtab(
|
|
** TABLE statement, use all columns from the content table.
|
|
*/
|
|
if( rc==SQLITE_OK && zContent ){
|
|
- sqlite3_free(zCompress);
|
|
- sqlite3_free(zUncompress);
|
|
+ sqlite3_free(zCompress);
|
|
+ sqlite3_free(zUncompress);
|
|
zCompress = 0;
|
|
zUncompress = 0;
|
|
if( nCol==0 ){
|
|
- sqlite3_free((void*)aCol);
|
|
+ sqlite3_free((void*)aCol);
|
|
aCol = 0;
|
|
rc = fts3ContentColumns(db, argv[1], zContent,&aCol,&nCol,&nString,pzErr);
|
|
|
|
/* If a languageid= option was specified, remove the language id
|
|
- ** column from the aCol[] array. */
|
|
+ ** column from the aCol[] array. */
|
|
if( rc==SQLITE_OK && zLanguageid ){
|
|
int j;
|
|
for(j=0; j<nCol; j++){
|
|
@@ -166353,7 +181635,7 @@ static int fts3InitVtab(
|
|
|
|
/* Fill in the azColumn array */
|
|
for(iCol=0; iCol<nCol; iCol++){
|
|
- char *z;
|
|
+ char *z;
|
|
int n = 0;
|
|
z = (char *)sqlite3Fts3NextToken(aCol[iCol], &n);
|
|
if( n>0 ){
|
|
@@ -166372,7 +181654,7 @@ static int fts3InitVtab(
|
|
for(i=0; i<nNotindexed; i++){
|
|
char *zNot = azNotindexed[i];
|
|
if( zNot && n==(int)strlen(zNot)
|
|
- && 0==sqlite3_strnicmp(p->azColumn[iCol], zNot, n)
|
|
+ && 0==sqlite3_strnicmp(p->azColumn[iCol], zNot, n)
|
|
){
|
|
p->abNotindexed[iCol] = 1;
|
|
sqlite3_free(zNot);
|
|
@@ -166396,7 +181678,7 @@ static int fts3InitVtab(
|
|
p->zWriteExprlist = fts3WriteExprList(p, zCompress, &rc);
|
|
if( rc!=SQLITE_OK ) goto fts3_init_out;
|
|
|
|
- /* If this is an xCreate call, create the underlying tables in the
|
|
+ /* If this is an xCreate call, create the underlying tables in the
|
|
** database. TODO: For xConnect(), it could verify that said tables exist.
|
|
*/
|
|
if( isCreate ){
|
|
@@ -166496,11 +181778,11 @@ static void fts3SetUniqueFlag(sqlite3_index_info *pIdxInfo){
|
|
#endif
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** Implementation of the xBestIndex method for FTS3 tables. There
|
|
** are three possible strategies, in order of preference:
|
|
**
|
|
-** 1. Direct lookup by rowid or docid.
|
|
+** 1. Direct lookup by rowid or docid.
|
|
** 2. Full-text search using a MATCH operator on a non-docid column.
|
|
** 3. Linear scan of %_content table.
|
|
*/
|
|
@@ -166519,7 +181801,7 @@ static int fts3BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
|
|
}
|
|
|
|
/* By default use a full table scan. This is an expensive option,
|
|
- ** so search through the constraints to see if a more efficient
|
|
+ ** so search through the constraints to see if a more efficient
|
|
** strategy is possible.
|
|
*/
|
|
pInfo->idxNum = FTS3_FULLSCAN_SEARCH;
|
|
@@ -166555,12 +181837,12 @@ static int fts3BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
|
|
**
|
|
** If there is more than one MATCH constraint available, use the first
|
|
** one encountered. If there is both a MATCH constraint and a direct
|
|
- ** rowid/docid lookup, prefer the MATCH strategy. This is done even
|
|
+ ** rowid/docid lookup, prefer the MATCH strategy. This is done even
|
|
** though the rowid/docid lookup is faster than a MATCH query, selecting
|
|
- ** it would lead to an "unable to use function MATCH in the requested
|
|
+ ** it would lead to an "unable to use function MATCH in the requested
|
|
** context" error.
|
|
*/
|
|
- if( pCons->op==SQLITE_INDEX_CONSTRAINT_MATCH
|
|
+ if( pCons->op==SQLITE_INDEX_CONSTRAINT_MATCH
|
|
&& pCons->iColumn>=0 && pCons->iColumn<=p->nColumn
|
|
){
|
|
pInfo->idxNum = FTS3_FULLTEXT_SEARCH + pCons->iColumn;
|
|
@@ -166569,7 +181851,7 @@ static int fts3BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
|
|
}
|
|
|
|
/* Equality constraint on the langid column */
|
|
- if( pCons->op==SQLITE_INDEX_CONSTRAINT_EQ
|
|
+ if( pCons->op==SQLITE_INDEX_CONSTRAINT_EQ
|
|
&& pCons->iColumn==p->nColumn + 2
|
|
){
|
|
iLangidCons = i;
|
|
@@ -166597,22 +181879,22 @@ static int fts3BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
|
|
if( iCons>=0 ){
|
|
pInfo->aConstraintUsage[iCons].argvIndex = iIdx++;
|
|
pInfo->aConstraintUsage[iCons].omit = 1;
|
|
- }
|
|
+ }
|
|
if( iLangidCons>=0 ){
|
|
pInfo->idxNum |= FTS3_HAVE_LANGID;
|
|
pInfo->aConstraintUsage[iLangidCons].argvIndex = iIdx++;
|
|
- }
|
|
+ }
|
|
if( iDocidGe>=0 ){
|
|
pInfo->idxNum |= FTS3_HAVE_DOCID_GE;
|
|
pInfo->aConstraintUsage[iDocidGe].argvIndex = iIdx++;
|
|
- }
|
|
+ }
|
|
if( iDocidLe>=0 ){
|
|
pInfo->idxNum |= FTS3_HAVE_DOCID_LE;
|
|
pInfo->aConstraintUsage[iDocidLe].argvIndex = iIdx++;
|
|
- }
|
|
+ }
|
|
|
|
/* Regardless of the strategy selected, FTS can deliver rows in rowid (or
|
|
- ** docid) order. Both ascending and descending are possible.
|
|
+ ** docid) order. Both ascending and descending are possible.
|
|
*/
|
|
if( pInfo->nOrderBy==1 ){
|
|
struct sqlite3_index_orderby *pOrder = &pInfo->aOrderBy[0];
|
|
@@ -166639,7 +181921,7 @@ static int fts3OpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){
|
|
UNUSED_PARAMETER(pVTab);
|
|
|
|
/* Allocate a buffer large enough for an Fts3Cursor structure. If the
|
|
- ** allocation succeeds, zero it and return SQLITE_OK. Otherwise,
|
|
+ ** allocation succeeds, zero it and return SQLITE_OK. Otherwise,
|
|
** if the allocation fails, return SQLITE_NOMEM.
|
|
*/
|
|
*ppCsr = pCsr = (sqlite3_vtab_cursor *)sqlite3_malloc(sizeof(Fts3Cursor));
|
|
@@ -166731,7 +182013,7 @@ static int fts3CursorSeekStmt(Fts3Cursor *pCsr){
|
|
/*
|
|
** Position the pCsr->pStmt statement so that it is on the row
|
|
** of the %_content table that contains the last match. Return
|
|
-** SQLITE_OK on success.
|
|
+** SQLITE_OK on success.
|
|
*/
|
|
static int fts3CursorSeek(sqlite3_context *pContext, Fts3Cursor *pCsr){
|
|
int rc = SQLITE_OK;
|
|
@@ -166767,7 +182049,7 @@ static int fts3CursorSeek(sqlite3_context *pContext, Fts3Cursor *pCsr){
|
|
|
|
/*
|
|
** This function is used to process a single interior node when searching
|
|
-** a b-tree for a term or term prefix. The node data is passed to this
|
|
+** a b-tree for a term or term prefix. The node data is passed to this
|
|
** function via the zNode/nNode parameters. The term to search for is
|
|
** passed in zTerm/nTerm.
|
|
**
|
|
@@ -166794,11 +182076,12 @@ static int fts3ScanInteriorNode(
|
|
char *zBuffer = 0; /* Buffer to load terms into */
|
|
i64 nAlloc = 0; /* Size of allocated buffer */
|
|
int isFirstTerm = 1; /* True when processing first term on page */
|
|
- sqlite3_int64 iChild; /* Block id of child node to descend to */
|
|
+ u64 iChild; /* Block id of child node to descend to */
|
|
+ int nBuffer = 0; /* Total term size */
|
|
|
|
- /* Skip over the 'height' varint that occurs at the start of every
|
|
+ /* Skip over the 'height' varint that occurs at the start of every
|
|
** interior node. Then load the blockid of the left-child of the b-tree
|
|
- ** node into variable iChild.
|
|
+ ** node into variable iChild.
|
|
**
|
|
** Even if the data structure on disk is corrupted, this (reading two
|
|
** varints from the buffer) does not risk an overread. If zNode is a
|
|
@@ -166809,26 +182092,29 @@ static int fts3ScanInteriorNode(
|
|
** table, then there are always 20 bytes of zeroed padding following the
|
|
** nNode bytes of content (see sqlite3Fts3ReadBlock() for details).
|
|
*/
|
|
- zCsr += sqlite3Fts3GetVarint(zCsr, &iChild);
|
|
- zCsr += sqlite3Fts3GetVarint(zCsr, &iChild);
|
|
+ zCsr += sqlite3Fts3GetVarintU(zCsr, &iChild);
|
|
+ zCsr += sqlite3Fts3GetVarintU(zCsr, &iChild);
|
|
if( zCsr>zEnd ){
|
|
return FTS_CORRUPT_VTAB;
|
|
}
|
|
-
|
|
+
|
|
while( zCsr<zEnd && (piFirst || piLast) ){
|
|
int cmp; /* memcmp() result */
|
|
int nSuffix; /* Size of term suffix */
|
|
int nPrefix = 0; /* Size of term prefix */
|
|
- int nBuffer; /* Total term size */
|
|
-
|
|
+
|
|
/* Load the next term on the node into zBuffer. Use realloc() to expand
|
|
** the size of zBuffer if required. */
|
|
if( !isFirstTerm ){
|
|
zCsr += fts3GetVarint32(zCsr, &nPrefix);
|
|
+ if( nPrefix>nBuffer ){
|
|
+ rc = FTS_CORRUPT_VTAB;
|
|
+ goto finish_scan;
|
|
+ }
|
|
}
|
|
isFirstTerm = 0;
|
|
zCsr += fts3GetVarint32(zCsr, &nSuffix);
|
|
-
|
|
+
|
|
assert( nPrefix>=0 && nSuffix>=0 );
|
|
if( nPrefix>zCsr-zNode || nSuffix>zEnd-zCsr || nSuffix==0 ){
|
|
rc = FTS_CORRUPT_VTAB;
|
|
@@ -166851,8 +182137,8 @@ static int fts3ScanInteriorNode(
|
|
|
|
/* Compare the term we are searching for with the term just loaded from
|
|
** the interior node. If the specified term is greater than or equal
|
|
- ** to the term from the interior node, then all terms on the sub-tree
|
|
- ** headed by node iChild are smaller than zTerm. No need to search
|
|
+ ** to the term from the interior node, then all terms on the sub-tree
|
|
+ ** headed by node iChild are smaller than zTerm. No need to search
|
|
** iChild.
|
|
**
|
|
** If the interior node term is larger than the specified term, then
|
|
@@ -166860,20 +182146,20 @@ static int fts3ScanInteriorNode(
|
|
*/
|
|
cmp = memcmp(zTerm, zBuffer, (nBuffer>nTerm ? nTerm : nBuffer));
|
|
if( piFirst && (cmp<0 || (cmp==0 && nBuffer>nTerm)) ){
|
|
- *piFirst = iChild;
|
|
+ *piFirst = (i64)iChild;
|
|
piFirst = 0;
|
|
}
|
|
|
|
if( piLast && cmp<0 ){
|
|
- *piLast = iChild;
|
|
+ *piLast = (i64)iChild;
|
|
piLast = 0;
|
|
}
|
|
|
|
iChild++;
|
|
};
|
|
|
|
- if( piFirst ) *piFirst = iChild;
|
|
- if( piLast ) *piLast = iChild;
|
|
+ if( piFirst ) *piFirst = (i64)iChild;
|
|
+ if( piLast ) *piLast = (i64)iChild;
|
|
|
|
finish_scan:
|
|
sqlite3_free(zBuffer);
|
|
@@ -166888,20 +182174,20 @@ static int fts3ScanInteriorNode(
|
|
** node for the range of leaf nodes that may contain the specified term
|
|
** or terms for which the specified term is a prefix.
|
|
**
|
|
-** If piLeaf is not NULL, then *piLeaf is set to the blockid of the
|
|
+** If piLeaf is not NULL, then *piLeaf is set to the blockid of the
|
|
** left-most leaf node in the tree that may contain the specified term.
|
|
** If piLeaf2 is not NULL, then *piLeaf2 is set to the blockid of the
|
|
** right-most leaf node that may contain a term for which the specified
|
|
** term is a prefix.
|
|
**
|
|
-** It is possible that the range of returned leaf nodes does not contain
|
|
-** the specified term or any terms for which it is a prefix. However, if the
|
|
+** It is possible that the range of returned leaf nodes does not contain
|
|
+** the specified term or any terms for which it is a prefix. However, if the
|
|
** segment does contain any such terms, they are stored within the identified
|
|
** range. Because this function only inspects interior segment nodes (and
|
|
** never loads leaf nodes into memory), it is not possible to be sure.
|
|
**
|
|
** If an error occurs, an error code other than SQLITE_OK is returned.
|
|
-*/
|
|
+*/
|
|
static int fts3SelectLeaf(
|
|
Fts3Table *p, /* Virtual table handle */
|
|
const char *zTerm, /* Term to select leaves for */
|
|
@@ -166953,7 +182239,7 @@ static int fts3SelectLeaf(
|
|
}
|
|
|
|
/*
|
|
-** This function is used to create delta-encoded serialized lists of FTS3
|
|
+** This function is used to create delta-encoded serialized lists of FTS3
|
|
** varints. Each call to this function appends a single varint to a list.
|
|
*/
|
|
static void fts3PutDeltaVarint(
|
|
@@ -166961,17 +182247,17 @@ static void fts3PutDeltaVarint(
|
|
sqlite3_int64 *piPrev, /* IN/OUT: Previous value written to list */
|
|
sqlite3_int64 iVal /* Write this value to the list */
|
|
){
|
|
- assert( iVal-*piPrev > 0 || (*piPrev==0 && iVal==0) );
|
|
+ assert_fts3_nc( iVal-*piPrev > 0 || (*piPrev==0 && iVal==0) );
|
|
*pp += sqlite3Fts3PutVarint(*pp, iVal-*piPrev);
|
|
*piPrev = iVal;
|
|
}
|
|
|
|
/*
|
|
-** When this function is called, *ppPoslist is assumed to point to the
|
|
+** When this function is called, *ppPoslist is assumed to point to the
|
|
** start of a position-list. After it returns, *ppPoslist points to the
|
|
** first byte after the position-list.
|
|
**
|
|
-** A position list is list of positions (delta encoded) and columns for
|
|
+** A position list is list of positions (delta encoded) and columns for
|
|
** a single document record of a doclist. So, in other words, this
|
|
** routine advances *ppPoslist so that it points to the next docid in
|
|
** the doclist, or to the first byte past the end of the doclist.
|
|
@@ -166984,12 +182270,12 @@ static void fts3PoslistCopy(char **pp, char **ppPoslist){
|
|
char *pEnd = *ppPoslist;
|
|
char c = 0;
|
|
|
|
- /* The end of a position list is marked by a zero encoded as an FTS3
|
|
+ /* The end of a position list is marked by a zero encoded as an FTS3
|
|
** varint. A single POS_END (0) byte. Except, if the 0 byte is preceded by
|
|
** a byte with the 0x80 bit set, then it is not a varint 0, but the tail
|
|
** of some other, multi-byte, value.
|
|
**
|
|
- ** The following while-loop moves pEnd to point to the first byte that is not
|
|
+ ** The following while-loop moves pEnd to point to the first byte that is not
|
|
** immediately preceded by a byte with the 0x80 bit set. Then increments
|
|
** pEnd once more so that it points to the byte immediately following the
|
|
** last byte in the position-list.
|
|
@@ -167011,7 +182297,7 @@ static void fts3PoslistCopy(char **pp, char **ppPoslist){
|
|
}
|
|
|
|
/*
|
|
-** When this function is called, *ppPoslist is assumed to point to the
|
|
+** When this function is called, *ppPoslist is assumed to point to the
|
|
** start of a column-list. After it returns, *ppPoslist points to the
|
|
** to the terminator (POS_COLUMN or POS_END) byte of the column-list.
|
|
**
|
|
@@ -167062,7 +182348,7 @@ static void fts3ColumnlistCopy(char **pp, char **ppPoslist){
|
|
** (in which case **pp will be a terminator bytes POS_END (0) or
|
|
** (1)).
|
|
**
|
|
-** If *pp points past the end of the current position-list, set *pi to
|
|
+** If *pp points past the end of the current position-list, set *pi to
|
|
** POSITION_LIST_END and return. Otherwise, read the next varint from *pp,
|
|
** increment the current value of *pi by the value read, and set *pp to
|
|
** point to the next value before returning.
|
|
@@ -167078,7 +182364,9 @@ static void fts3ReadNextPos(
|
|
sqlite3_int64 *pi /* IN/OUT: Value read from position-list */
|
|
){
|
|
if( (**pp)&0xFE ){
|
|
- fts3GetDeltaVarint(pp, pi);
|
|
+ int iVal;
|
|
+ *pp += fts3GetVarint32((*pp), &iVal);
|
|
+ *pi += iVal;
|
|
*pi -= 2;
|
|
}else{
|
|
*pi = POSITION_LIST_END;
|
|
@@ -167090,7 +182378,7 @@ static void fts3ReadNextPos(
|
|
** the value of iCol encoded as a varint to *pp. This will start a new
|
|
** column list.
|
|
**
|
|
-** Set *pp to point to the byte just after the last byte written before
|
|
+** Set *pp to point to the byte just after the last byte written before
|
|
** returning (do not modify it if iCol==0). Return the total number of bytes
|
|
** written (0 if iCol==0).
|
|
*/
|
|
@@ -167125,7 +182413,7 @@ static int fts3PoslistMerge(
|
|
int iCol1; /* The current column index in pp1 */
|
|
int iCol2; /* The current column index in pp2 */
|
|
|
|
- if( *p1==POS_COLUMN ){
|
|
+ if( *p1==POS_COLUMN ){
|
|
fts3GetVarint32(&p1[1], &iCol1);
|
|
if( iCol1==0 ) return FTS_CORRUPT_VTAB;
|
|
}
|
|
@@ -167149,7 +182437,7 @@ static int fts3PoslistMerge(
|
|
|
|
/* At this point, both p1 and p2 point to the start of column-lists
|
|
** for the same column (the column with index iCol1 and iCol2).
|
|
- ** A column-list is a list of non-negative delta-encoded varints, each
|
|
+ ** A column-list is a list of non-negative delta-encoded varints, each
|
|
** incremented by 2 before being stored. Each list is terminated by a
|
|
** POS_END (0) or POS_COLUMN (1). The following block merges the two lists
|
|
** and writes the results to buffer p. p is left pointing to the byte
|
|
@@ -167158,8 +182446,11 @@ static int fts3PoslistMerge(
|
|
*/
|
|
fts3GetDeltaVarint(&p1, &i1);
|
|
fts3GetDeltaVarint(&p2, &i2);
|
|
+ if( i1<2 || i2<2 ){
|
|
+ break;
|
|
+ }
|
|
do {
|
|
- fts3PutDeltaVarint(&p, &iPrev, (i1<i2) ? i1 : i2);
|
|
+ fts3PutDeltaVarint(&p, &iPrev, (i1<i2) ? i1 : i2);
|
|
iPrev -= 2;
|
|
if( i1==i2 ){
|
|
fts3ReadNextPos(&p1, &i1);
|
|
@@ -167201,7 +182492,7 @@ static int fts3PoslistMerge(
|
|
** When this function returns, both *pp1 and *pp2 are left pointing to the
|
|
** byte following the 0x00 terminator of their respective position lists.
|
|
**
|
|
-** If isSaveLeft is 0, an entry is added to the output position list for
|
|
+** If isSaveLeft is 0, an entry is added to the output position list for
|
|
** each position in *pp2 for which there exists one or more positions in
|
|
** *pp1 so that (pos(*pp2)>pos(*pp1) && pos(*pp2)-pos(*pp1)<=nToken). i.e.
|
|
** when the *pp1 token appears before the *pp2 token, but not more than nToken
|
|
@@ -167226,12 +182517,12 @@ static int fts3PoslistPhraseMerge(
|
|
/* Never set both isSaveLeft and isExact for the same invocation. */
|
|
assert( isSaveLeft==0 || isExact==0 );
|
|
|
|
- assert( p!=0 && *p1!=0 && *p2!=0 );
|
|
- if( *p1==POS_COLUMN ){
|
|
+ assert_fts3_nc( p!=0 && *p1!=0 && *p2!=0 );
|
|
+ if( *p1==POS_COLUMN ){
|
|
p1++;
|
|
p1 += fts3GetVarint32(p1, &iCol1);
|
|
}
|
|
- if( *p2==POS_COLUMN ){
|
|
+ if( *p2==POS_COLUMN ){
|
|
p2++;
|
|
p2 += fts3GetVarint32(p2, &iCol2);
|
|
}
|
|
@@ -167253,8 +182544,8 @@ static int fts3PoslistPhraseMerge(
|
|
if( iPos1<0 || iPos2<0 ) break;
|
|
|
|
while( 1 ){
|
|
- if( iPos2==iPos1+nToken
|
|
- || (isExact==0 && iPos2>iPos1 && iPos2<=iPos1+nToken)
|
|
+ if( iPos2==iPos1+nToken
|
|
+ || (isExact==0 && iPos2>iPos1 && iPos2<=iPos1+nToken)
|
|
){
|
|
sqlite3_int64 iSave;
|
|
iSave = isSaveLeft ? iPos1 : iPos2;
|
|
@@ -167289,8 +182580,8 @@ static int fts3PoslistPhraseMerge(
|
|
|
|
/* Advance pointer p1 or p2 (whichever corresponds to the smaller of
|
|
** iCol1 and iCol2) so that it points to either the 0x00 that marks the
|
|
- ** end of the position list, or the 0x01 that precedes the next
|
|
- ** column-number in the position list.
|
|
+ ** end of the position list, or the 0x01 that precedes the next
|
|
+ ** column-number in the position list.
|
|
*/
|
|
else if( iCol1<iCol2 ){
|
|
fts3ColumnlistCopy(0, &p1);
|
|
@@ -167319,14 +182610,14 @@ static int fts3PoslistPhraseMerge(
|
|
|
|
/*
|
|
** Merge two position-lists as required by the NEAR operator. The argument
|
|
-** position lists correspond to the left and right phrases of an expression
|
|
+** position lists correspond to the left and right phrases of an expression
|
|
** like:
|
|
**
|
|
** "phrase 1" NEAR "phrase number 2"
|
|
**
|
|
-** Position list *pp1 corresponds to the left-hand side of the NEAR
|
|
-** expression and *pp2 to the right. As usual, the indexes in the position
|
|
-** lists are the offsets of the last token in each phrase (tokens "1" and "2"
|
|
+** Position list *pp1 corresponds to the left-hand side of the NEAR
|
|
+** expression and *pp2 to the right. As usual, the indexes in the position
|
|
+** lists are the offsets of the last token in each phrase (tokens "1" and "2"
|
|
** in the example above).
|
|
**
|
|
** The output position list - written to *pp - is a copy of *pp2 with those
|
|
@@ -167366,7 +182657,7 @@ static int fts3PoslistNearMerge(
|
|
return res;
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** An instance of this function is used to merge together the (potentially
|
|
** large number of) doclists for each term that matches a prefix query.
|
|
** See function fts3TermSelectMerge() for details.
|
|
@@ -167387,7 +182678,7 @@ struct TermSelect {
|
|
** from *pp. *pp is then set to point 1 byte past the end of the read varint.
|
|
**
|
|
** If bDescIdx is false, the value read is added to *pVal before returning.
|
|
-** If it is true, the value read is subtracted from *pVal before this
|
|
+** If it is true, the value read is subtracted from *pVal before this
|
|
** function returns.
|
|
*/
|
|
static void fts3GetDeltaVarint3(
|
|
@@ -167415,9 +182706,9 @@ static void fts3GetDeltaVarint3(
|
|
** end of the value written.
|
|
**
|
|
** If *pbFirst is zero when this function is called, the value written to
|
|
-** the buffer is that of parameter iVal.
|
|
+** the buffer is that of parameter iVal.
|
|
**
|
|
-** If *pbFirst is non-zero when this function is called, then the value
|
|
+** If *pbFirst is non-zero when this function is called, then the value
|
|
** written is either (iVal-*piPrev) (if bDescIdx is zero) or (*piPrev-iVal)
|
|
** (if bDescIdx is non-zero).
|
|
**
|
|
@@ -167450,7 +182741,7 @@ static void fts3PutDeltaVarint3(
|
|
/*
|
|
** This macro is used by various functions that merge doclists. The two
|
|
** arguments are 64-bit docid values. If the value of the stack variable
|
|
-** bDescDoclist is 0 when this macro is invoked, then it returns (i1-i2).
|
|
+** bDescDoclist is 0 when this macro is invoked, then it returns (i1-i2).
|
|
** Otherwise, (i2-i1).
|
|
**
|
|
** Using this makes it easier to write code that can merge doclists that are
|
|
@@ -167461,7 +182752,7 @@ static void fts3PutDeltaVarint3(
|
|
|
|
/*
|
|
** This function does an "OR" merge of two doclists (output contains all
|
|
-** positions contained in either argument doclist). If the docids in the
|
|
+** positions contained in either argument doclist). If the docids in the
|
|
** input doclists are sorted in ascending order, parameter bDescDoclist
|
|
** should be false. If they are sorted in ascending order, it should be
|
|
** passed a non-zero value.
|
|
@@ -167501,12 +182792,12 @@ static int fts3DoclistOrMerge(
|
|
** current and previous docid (a positive number - since the list is in
|
|
** ascending order).
|
|
**
|
|
- ** The first docid written to the output is therefore encoded using the
|
|
+ ** The first docid written to the output is therefore encoded using the
|
|
** same number of bytes as it is in whichever of the input lists it is
|
|
- ** read from. And each subsequent docid read from the same input list
|
|
+ ** read from. And each subsequent docid read from the same input list
|
|
** consumes either the same or less bytes as it did in the input (since
|
|
** the difference between it and the previous value in the output must
|
|
- ** be a positive value less than or equal to the delta value read from
|
|
+ ** be a positive value less than or equal to the delta value read from
|
|
** the input list). The same argument applies to all but the first docid
|
|
** read from the 'other' list. And to the contents of all position lists
|
|
** that will be copied and merged from the input to the output.
|
|
@@ -167518,9 +182809,9 @@ static int fts3DoclistOrMerge(
|
|
**
|
|
** The space required to store the output is therefore the sum of the
|
|
** sizes of the two inputs, plus enough space for exactly one of the input
|
|
- ** docids to grow.
|
|
+ ** docids to grow.
|
|
**
|
|
- ** A symetric argument may be made if the doclists are in descending
|
|
+ ** A symetric argument may be made if the doclists are in descending
|
|
** order.
|
|
*/
|
|
aOut = sqlite3_malloc64((i64)n1+n2+FTS3_VARINT_MAX-1+FTS3_BUFFER_PADDING);
|
|
@@ -167547,7 +182838,7 @@ static int fts3DoclistOrMerge(
|
|
fts3PoslistCopy(&p, &p2);
|
|
fts3GetDeltaVarint3(&p2, pEnd2, bDescDoclist, &i2);
|
|
}
|
|
-
|
|
+
|
|
assert( (p-aOut)<=((p1?(p1-a1):n1)+(p2?(p2-a2):n2)+FTS3_VARINT_MAX-1) );
|
|
}
|
|
|
|
@@ -167570,7 +182861,7 @@ static int fts3DoclistOrMerge(
|
|
** exactly nDist tokens before it.
|
|
**
|
|
** If the docids in the input doclists are sorted in ascending order,
|
|
-** parameter bDescDoclist should be false. If they are sorted in ascending
|
|
+** parameter bDescDoclist should be false. If they are sorted in ascending
|
|
** order, it should be passed a non-zero value.
|
|
**
|
|
** The right-hand input doclist is overwritten by this function.
|
|
@@ -167716,7 +183007,7 @@ static int fts3TermSelectFinishMerge(Fts3Table *p, TermSelect *pTS){
|
|
int nNew;
|
|
char *aNew;
|
|
|
|
- int rc = fts3DoclistOrMerge(p->bDescIdx,
|
|
+ int rc = fts3DoclistOrMerge(p->bDescIdx,
|
|
pTS->aaOutput[i], pTS->anOutput[i], aOut, nOut, &aNew, &nNew
|
|
);
|
|
if( rc!=SQLITE_OK ){
|
|
@@ -167760,22 +183051,22 @@ static int fts3TermSelectMerge(
|
|
){
|
|
if( pTS->aaOutput[0]==0 ){
|
|
/* If this is the first term selected, copy the doclist to the output
|
|
- ** buffer using memcpy().
|
|
+ ** buffer using memcpy().
|
|
**
|
|
- ** Add FTS3_VARINT_MAX bytes of unused space to the end of the
|
|
+ ** Add FTS3_VARINT_MAX bytes of unused space to the end of the
|
|
** allocation. This is so as to ensure that the buffer is big enough
|
|
** to hold the current doclist AND'd with any other doclist. If the
|
|
** doclists are stored in order=ASC order, this padding would not be
|
|
** required (since the size of [doclistA AND doclistB] is always less
|
|
** than or equal to the size of [doclistA] in that case). But this is
|
|
- ** not true for order=DESC. For example, a doclist containing (1, -1)
|
|
+ ** not true for order=DESC. For example, a doclist containing (1, -1)
|
|
** may be smaller than (-1), as in the first example the -1 may be stored
|
|
** as a single-byte delta, whereas in the second it must be stored as a
|
|
** FTS3_VARINT_MAX byte varint.
|
|
**
|
|
** Similar padding is added in the fts3DoclistOrMerge() function.
|
|
*/
|
|
- pTS->aaOutput[0] = sqlite3_malloc(nDoclist + FTS3_VARINT_MAX + 1);
|
|
+ pTS->aaOutput[0] = sqlite3_malloc64((i64)nDoclist + FTS3_VARINT_MAX + 1);
|
|
pTS->anOutput[0] = nDoclist;
|
|
if( pTS->aaOutput[0] ){
|
|
memcpy(pTS->aaOutput[0], aDoclist, nDoclist);
|
|
@@ -167798,7 +183089,7 @@ static int fts3TermSelectMerge(
|
|
char *aNew;
|
|
int nNew;
|
|
|
|
- int rc = fts3DoclistOrMerge(p->bDescIdx, aMerge, nMerge,
|
|
+ int rc = fts3DoclistOrMerge(p->bDescIdx, aMerge, nMerge,
|
|
pTS->aaOutput[iOut], pTS->anOutput[iOut], &aNew, &nNew
|
|
);
|
|
if( rc!=SQLITE_OK ){
|
|
@@ -167809,7 +183100,7 @@ static int fts3TermSelectMerge(
|
|
if( aMerge!=aDoclist ) sqlite3_free(aMerge);
|
|
sqlite3_free(pTS->aaOutput[iOut]);
|
|
pTS->aaOutput[iOut] = 0;
|
|
-
|
|
+
|
|
aMerge = aNew;
|
|
nMerge = nNew;
|
|
if( (iOut+1)==SizeofArray(pTS->aaOutput) ){
|
|
@@ -167826,7 +183117,7 @@ static int fts3TermSelectMerge(
|
|
** Append SegReader object pNew to the end of the pCsr->apSegment[] array.
|
|
*/
|
|
static int fts3SegReaderCursorAppend(
|
|
- Fts3MultiSegReader *pCsr,
|
|
+ Fts3MultiSegReader *pCsr,
|
|
Fts3SegReader *pNew
|
|
){
|
|
if( (pCsr->nSegment%16)==0 ){
|
|
@@ -167865,10 +183156,10 @@ static int fts3SegReaderCursor(
|
|
sqlite3_stmt *pStmt = 0; /* Statement to iterate through segments */
|
|
int rc2; /* Result of sqlite3_reset() */
|
|
|
|
- /* If iLevel is less than 0 and this is not a scan, include a seg-reader
|
|
+ /* If iLevel is less than 0 and this is not a scan, include a seg-reader
|
|
** for the pending-terms. If this is a scan, then this call must be being
|
|
** made by an fts4aux module, not an FTS table. In this case calling
|
|
- ** Fts3SegReaderPending might segfault, as the data structures used by
|
|
+ ** Fts3SegReaderPending might segfault, as the data structures used by
|
|
** fts4aux are not completely populated. So it's easiest to filter these
|
|
** calls out here. */
|
|
if( iLevel<0 && p->aIndex && p->iPrevLangid==iLangid ){
|
|
@@ -167902,10 +183193,10 @@ static int fts3SegReaderCursor(
|
|
if( rc!=SQLITE_OK ) goto finished;
|
|
if( isPrefix==0 && isScan==0 ) iLeavesEndBlock = iStartBlock;
|
|
}
|
|
-
|
|
- rc = sqlite3Fts3SegReaderNew(pCsr->nSegment+1,
|
|
+
|
|
+ rc = sqlite3Fts3SegReaderNew(pCsr->nSegment+1,
|
|
(isPrefix==0 && isScan==0),
|
|
- iStartBlock, iLeavesEndBlock,
|
|
+ iStartBlock, iLeavesEndBlock,
|
|
iEndBlock, zRoot, nRoot, &pSeg
|
|
);
|
|
if( rc!=SQLITE_OK ) goto finished;
|
|
@@ -167921,7 +183212,7 @@ static int fts3SegReaderCursor(
|
|
}
|
|
|
|
/*
|
|
-** Set up a cursor object for iterating through a full-text index or a
|
|
+** Set up a cursor object for iterating through a full-text index or a
|
|
** single level therein.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3Fts3SegReaderCursor(
|
|
@@ -167937,7 +183228,7 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderCursor(
|
|
){
|
|
assert( iIndex>=0 && iIndex<p->nIndex );
|
|
assert( iLevel==FTS3_SEGCURSOR_ALL
|
|
- || iLevel==FTS3_SEGCURSOR_PENDING
|
|
+ || iLevel==FTS3_SEGCURSOR_PENDING
|
|
|| iLevel>=0
|
|
);
|
|
assert( iLevel<FTS3_SEGDIR_MAXLEVEL );
|
|
@@ -167963,20 +183254,20 @@ static int fts3SegReaderCursorAddZero(
|
|
int nTerm, /* Number of bytes in zTerm */
|
|
Fts3MultiSegReader *pCsr /* Fts3MultiSegReader to modify */
|
|
){
|
|
- return fts3SegReaderCursor(p,
|
|
+ return fts3SegReaderCursor(p,
|
|
iLangid, 0, FTS3_SEGCURSOR_ALL, zTerm, nTerm, 0, 0,pCsr
|
|
);
|
|
}
|
|
|
|
/*
|
|
** Open an Fts3MultiSegReader to scan the doclist for term zTerm/nTerm. Or,
|
|
-** if isPrefix is true, to scan the doclist for all terms for which
|
|
+** if isPrefix is true, to scan the doclist for all terms for which
|
|
** zTerm/nTerm is a prefix. If successful, return SQLITE_OK and write
|
|
** a pointer to the new Fts3MultiSegReader to *ppSegcsr. Otherwise, return
|
|
** an SQLite error code.
|
|
**
|
|
** It is the responsibility of the caller to free this object by eventually
|
|
-** passing it to fts3SegReaderCursorFree()
|
|
+** passing it to fts3SegReaderCursorFree()
|
|
**
|
|
** SQLITE_OK is returned if no error occurs, otherwise an SQLite error code.
|
|
** Output parameter *ppSegcsr is set to 0 if an error occurs.
|
|
@@ -168001,7 +183292,7 @@ static int fts3TermSegReaderCursor(
|
|
for(i=1; bFound==0 && i<p->nIndex; i++){
|
|
if( p->aIndex[i].nPrefix==nTerm ){
|
|
bFound = 1;
|
|
- rc = sqlite3Fts3SegReaderCursor(p, pCsr->iLangid,
|
|
+ rc = sqlite3Fts3SegReaderCursor(p, pCsr->iLangid,
|
|
i, FTS3_SEGCURSOR_ALL, zTerm, nTerm, 0, 0, pSegcsr
|
|
);
|
|
pSegcsr->bLookup = 1;
|
|
@@ -168011,7 +183302,7 @@ static int fts3TermSegReaderCursor(
|
|
for(i=1; bFound==0 && i<p->nIndex; i++){
|
|
if( p->aIndex[i].nPrefix==nTerm+1 ){
|
|
bFound = 1;
|
|
- rc = sqlite3Fts3SegReaderCursor(p, pCsr->iLangid,
|
|
+ rc = sqlite3Fts3SegReaderCursor(p, pCsr->iLangid,
|
|
i, FTS3_SEGCURSOR_ALL, zTerm, nTerm, 1, 0, pSegcsr
|
|
);
|
|
if( rc==SQLITE_OK ){
|
|
@@ -168024,7 +183315,7 @@ static int fts3TermSegReaderCursor(
|
|
}
|
|
|
|
if( bFound==0 ){
|
|
- rc = sqlite3Fts3SegReaderCursor(p, pCsr->iLangid,
|
|
+ rc = sqlite3Fts3SegReaderCursor(p, pCsr->iLangid,
|
|
0, FTS3_SEGCURSOR_ALL, zTerm, nTerm, isPrefix, 0, pSegcsr
|
|
);
|
|
pSegcsr->bLookup = !isPrefix;
|
|
@@ -168072,7 +183363,7 @@ static int fts3TermSelect(
|
|
|
|
rc = sqlite3Fts3SegReaderStart(p, pSegcsr, &filter);
|
|
while( SQLITE_OK==rc
|
|
- && SQLITE_ROW==(rc = sqlite3Fts3SegReaderStep(p, pSegcsr))
|
|
+ && SQLITE_ROW==(rc = sqlite3Fts3SegReaderStep(p, pSegcsr))
|
|
){
|
|
rc = fts3TermSelectMerge(p, &tsc, pSegcsr->aDoclist, pSegcsr->nDoclist);
|
|
}
|
|
@@ -168101,7 +183392,7 @@ static int fts3TermSelect(
|
|
**
|
|
** If the isPoslist argument is true, then it is assumed that the doclist
|
|
** contains a position-list following each docid. Otherwise, it is assumed
|
|
-** that the doclist is simply a list of docids stored as delta encoded
|
|
+** that the doclist is simply a list of docids stored as delta encoded
|
|
** varints.
|
|
*/
|
|
static int fts3DoclistCountDocids(char *aList, int nList){
|
|
@@ -168247,7 +183538,7 @@ static int fts3FilterMethod(
|
|
|
|
assert( p->base.zErrMsg==0 );
|
|
rc = sqlite3Fts3ExprParse(p->pTokenizer, pCsr->iLangid,
|
|
- p->azColumn, p->bFts4, p->nColumn, iCol, zQuery, -1, &pCsr->pExpr,
|
|
+ p->azColumn, p->bFts4, p->nColumn, iCol, zQuery, -1, &pCsr->pExpr,
|
|
&p->base.zErrMsg
|
|
);
|
|
if( rc!=SQLITE_OK ){
|
|
@@ -168274,7 +183565,7 @@ static int fts3FilterMethod(
|
|
(pCsr->bDesc ? "DESC" : "ASC")
|
|
);
|
|
}else{
|
|
- zSql = sqlite3_mprintf("SELECT %s ORDER BY rowid %s",
|
|
+ zSql = sqlite3_mprintf("SELECT %s ORDER BY rowid %s",
|
|
p->zReadExprlist, (pCsr->bDesc ? "DESC" : "ASC")
|
|
);
|
|
}
|
|
@@ -168299,8 +183590,8 @@ static int fts3FilterMethod(
|
|
return fts3NextMethod(pCursor);
|
|
}
|
|
|
|
-/*
|
|
-** This is the xEof method of the virtual table. SQLite calls this
|
|
+/*
|
|
+** This is the xEof method of the virtual table. SQLite calls this
|
|
** routine to find out if it has reached the end of a result set.
|
|
*/
|
|
static int fts3EofMethod(sqlite3_vtab_cursor *pCursor){
|
|
@@ -168312,7 +183603,7 @@ static int fts3EofMethod(sqlite3_vtab_cursor *pCursor){
|
|
return pCsr->isEof;
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** This is the xRowid method. The SQLite core calls this routine to
|
|
** retrieve the rowid for the current row of the result set. fts3
|
|
** exposes %_content.docid as the rowid for the virtual table. The
|
|
@@ -168324,7 +183615,7 @@ static int fts3RowidMethod(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** This is the xColumn method, called by SQLite to request a value from
|
|
** the row that the supplied cursor currently points to.
|
|
**
|
|
@@ -168367,7 +183658,7 @@ static int fts3ColumnMethod(
|
|
break;
|
|
}else{
|
|
iCol = p->nColumn;
|
|
- /* fall-through */
|
|
+ /* no break */ deliberate_fall_through
|
|
}
|
|
|
|
default:
|
|
@@ -168384,8 +183675,8 @@ static int fts3ColumnMethod(
|
|
return rc;
|
|
}
|
|
|
|
-/*
|
|
-** This function is the implementation of the xUpdate callback used by
|
|
+/*
|
|
+** This function is the implementation of the xUpdate callback used by
|
|
** FTS3 virtual tables. It is invoked by SQLite each time a row is to be
|
|
** inserted, updated or deleted.
|
|
*/
|
|
@@ -168420,7 +183711,7 @@ static int fts3SyncMethod(sqlite3_vtab *pVtab){
|
|
**
|
|
** Of course, updating the input segments also involves deleting a bunch
|
|
** of blocks from the segments table. But this is not considered overhead
|
|
- ** as it would also be required by a crisis-merge that used the same input
|
|
+ ** as it would also be required by a crisis-merge that used the same input
|
|
** segments.
|
|
*/
|
|
const u32 nMinMerge = 64; /* Minimum amount of incr-merge work to do */
|
|
@@ -168430,8 +183721,8 @@ static int fts3SyncMethod(sqlite3_vtab *pVtab){
|
|
i64 iLastRowid = sqlite3_last_insert_rowid(p->db);
|
|
|
|
rc = sqlite3Fts3PendingTermsFlush(p);
|
|
- if( rc==SQLITE_OK
|
|
- && p->nLeafAdd>(nMinMerge/16)
|
|
+ if( rc==SQLITE_OK
|
|
+ && p->nLeafAdd>(nMinMerge/16)
|
|
&& p->nAutoincrmerge && p->nAutoincrmerge!=0xff
|
|
){
|
|
int mxLevel = 0; /* Maximum relative level value in db */
|
|
@@ -168470,18 +183761,24 @@ static int fts3SetHasStat(Fts3Table *p){
|
|
}
|
|
|
|
/*
|
|
-** Implementation of xBegin() method.
|
|
+** Implementation of xBegin() method.
|
|
*/
|
|
static int fts3BeginMethod(sqlite3_vtab *pVtab){
|
|
Fts3Table *p = (Fts3Table*)pVtab;
|
|
+ int rc;
|
|
UNUSED_PARAMETER(pVtab);
|
|
assert( p->pSegments==0 );
|
|
assert( p->nPendingData==0 );
|
|
assert( p->inTransaction!=1 );
|
|
- TESTONLY( p->inTransaction = 1 );
|
|
- TESTONLY( p->mxSavepoint = -1; );
|
|
p->nLeafAdd = 0;
|
|
- return fts3SetHasStat(p);
|
|
+ rc = fts3SetHasStat(p);
|
|
+#ifdef SQLITE_DEBUG
|
|
+ if( rc==SQLITE_OK ){
|
|
+ p->inTransaction = 1;
|
|
+ p->mxSavepoint = -1;
|
|
+ }
|
|
+#endif
|
|
+ return rc;
|
|
}
|
|
|
|
/*
|
|
@@ -168526,17 +183823,17 @@ static void fts3ReversePoslist(char *pStart, char **ppPoslist){
|
|
/* Skip backwards passed any trailing 0x00 bytes added by NearTrim() */
|
|
while( p>pStart && (c=*p--)==0 );
|
|
|
|
- /* Search backwards for a varint with value zero (the end of the previous
|
|
+ /* Search backwards for a varint with value zero (the end of the previous
|
|
** poslist). This is an 0x00 byte preceded by some byte that does not
|
|
** have the 0x80 bit set. */
|
|
- while( p>pStart && (*p & 0x80) | c ){
|
|
- c = *p--;
|
|
+ while( p>pStart && (*p & 0x80) | c ){
|
|
+ c = *p--;
|
|
}
|
|
assert( p==pStart || c==0 );
|
|
|
|
/* At this point p points to that preceding byte without the 0x80 bit
|
|
** set. So to find the start of the poslist, skip forward 2 bytes then
|
|
- ** over a varint.
|
|
+ ** over a varint.
|
|
**
|
|
** Normally. The other case is that p==pStart and the poslist to return
|
|
** is the first in the doclist. In this case do not skip forward 2 bytes.
|
|
@@ -168557,7 +183854,7 @@ static void fts3ReversePoslist(char *pStart, char **ppPoslist){
|
|
** offsets() and optimize() SQL functions.
|
|
**
|
|
** If the value passed as the third argument is a blob of size
|
|
-** sizeof(Fts3Cursor*), then the blob contents are copied to the
|
|
+** sizeof(Fts3Cursor*), then the blob contents are copied to the
|
|
** output variable *ppCsr and SQLITE_OK is returned. Otherwise, an error
|
|
** message is written to context pContext and SQLITE_ERROR returned. The
|
|
** string passed via zFunc is used as part of the error message.
|
|
@@ -168602,7 +183899,7 @@ static void fts3SnippetFunc(
|
|
assert( nVal>=1 );
|
|
|
|
if( nVal>6 ){
|
|
- sqlite3_result_error(pContext,
|
|
+ sqlite3_result_error(pContext,
|
|
"wrong number of arguments to function snippet()", -1);
|
|
return;
|
|
}
|
|
@@ -168610,9 +183907,13 @@ static void fts3SnippetFunc(
|
|
|
|
switch( nVal ){
|
|
case 6: nToken = sqlite3_value_int(apVal[5]);
|
|
+ /* no break */ deliberate_fall_through
|
|
case 5: iCol = sqlite3_value_int(apVal[4]);
|
|
+ /* no break */ deliberate_fall_through
|
|
case 4: zEllipsis = (const char*)sqlite3_value_text(apVal[3]);
|
|
+ /* no break */ deliberate_fall_through
|
|
case 3: zEnd = (const char*)sqlite3_value_text(apVal[2]);
|
|
+ /* no break */ deliberate_fall_through
|
|
case 2: zStart = (const char*)sqlite3_value_text(apVal[1]);
|
|
}
|
|
if( !zEllipsis || !zEnd || !zStart ){
|
|
@@ -168644,8 +183945,8 @@ static void fts3OffsetsFunc(
|
|
}
|
|
}
|
|
|
|
-/*
|
|
-** Implementation of the special optimize() function for FTS3. This
|
|
+/*
|
|
+** Implementation of the special optimize() function for FTS3. This
|
|
** function merges all segments in the database to a single segment.
|
|
** Example usage is:
|
|
**
|
|
@@ -168754,10 +184055,10 @@ static int fts3RenameMethod(
|
|
/* At this point it must be known if the %_stat table exists or not.
|
|
** So bHasStat may not be 2. */
|
|
rc = fts3SetHasStat(p);
|
|
-
|
|
+
|
|
/* As it happens, the pending terms table is always empty here. This is
|
|
- ** because an "ALTER TABLE RENAME TABLE" statement inside a transaction
|
|
- ** always opens a savepoint transaction. And the xSavepoint() method
|
|
+ ** because an "ALTER TABLE RENAME TABLE" statement inside a transaction
|
|
+ ** always opens a savepoint transaction. And the xSavepoint() method
|
|
** flushes the pending terms table. But leave the (no-op) call to
|
|
** PendingTermsFlush() in in case that changes.
|
|
*/
|
|
@@ -168848,7 +184149,7 @@ static int fts3RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){
|
|
*/
|
|
static int fts3ShadowName(const char *zName){
|
|
static const char *azName[] = {
|
|
- "content", "docsize", "segdir", "segments", "stat",
|
|
+ "content", "docsize", "segdir", "segments", "stat",
|
|
};
|
|
unsigned int i;
|
|
for(i=0; i<sizeof(azName)/sizeof(azName[0]); i++){
|
|
@@ -168890,13 +184191,16 @@ static const sqlite3_module fts3Module = {
|
|
** allocated for the tokenizer hash table.
|
|
*/
|
|
static void hashDestroy(void *p){
|
|
- Fts3Hash *pHash = (Fts3Hash *)p;
|
|
- sqlite3Fts3HashClear(pHash);
|
|
- sqlite3_free(pHash);
|
|
+ Fts3HashWrapper *pHash = (Fts3HashWrapper *)p;
|
|
+ pHash->nRef--;
|
|
+ if( pHash->nRef<=0 ){
|
|
+ sqlite3Fts3HashClear(&pHash->hash);
|
|
+ sqlite3_free(pHash);
|
|
+ }
|
|
}
|
|
|
|
/*
|
|
-** The fts3 built-in tokenizers - "simple", "porter" and "icu"- are
|
|
+** The fts3 built-in tokenizers - "simple", "porter" and "icu"- are
|
|
** implemented in files fts3_tokenizer1.c, fts3_porter.c and fts3_icu.c
|
|
** respectively. The following three forward declarations are for functions
|
|
** declared in these files used to retrieve the respective implementations.
|
|
@@ -168922,7 +184226,7 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(sqlite3_tokenizer_module const
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db){
|
|
int rc = SQLITE_OK;
|
|
- Fts3Hash *pHash = 0;
|
|
+ Fts3HashWrapper *pHash = 0;
|
|
const sqlite3_tokenizer_module *pSimple = 0;
|
|
const sqlite3_tokenizer_module *pPorter = 0;
|
|
#ifndef SQLITE_DISABLE_FTS3_UNICODE
|
|
@@ -168950,23 +184254,24 @@ SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db){
|
|
sqlite3Fts3PorterTokenizerModule(&pPorter);
|
|
|
|
/* Allocate and initialize the hash-table used to store tokenizers. */
|
|
- pHash = sqlite3_malloc(sizeof(Fts3Hash));
|
|
+ pHash = sqlite3_malloc(sizeof(Fts3HashWrapper));
|
|
if( !pHash ){
|
|
rc = SQLITE_NOMEM;
|
|
}else{
|
|
- sqlite3Fts3HashInit(pHash, FTS3_HASH_STRING, 1);
|
|
+ sqlite3Fts3HashInit(&pHash->hash, FTS3_HASH_STRING, 1);
|
|
+ pHash->nRef = 0;
|
|
}
|
|
|
|
/* Load the built-in tokenizers into the hash table */
|
|
if( rc==SQLITE_OK ){
|
|
- if( sqlite3Fts3HashInsert(pHash, "simple", 7, (void *)pSimple)
|
|
- || sqlite3Fts3HashInsert(pHash, "porter", 7, (void *)pPorter)
|
|
+ if( sqlite3Fts3HashInsert(&pHash->hash, "simple", 7, (void *)pSimple)
|
|
+ || sqlite3Fts3HashInsert(&pHash->hash, "porter", 7, (void *)pPorter)
|
|
|
|
#ifndef SQLITE_DISABLE_FTS3_UNICODE
|
|
- || sqlite3Fts3HashInsert(pHash, "unicode61", 10, (void *)pUnicode)
|
|
+ || sqlite3Fts3HashInsert(&pHash->hash, "unicode61", 10, (void *)pUnicode)
|
|
#endif
|
|
#ifdef SQLITE_ENABLE_ICU
|
|
- || (pIcu && sqlite3Fts3HashInsert(pHash, "icu", 4, (void *)pIcu))
|
|
+ || (pIcu && sqlite3Fts3HashInsert(&pHash->hash, "icu", 4, (void *)pIcu))
|
|
#endif
|
|
){
|
|
rc = SQLITE_NOMEM;
|
|
@@ -168975,32 +184280,35 @@ SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db){
|
|
|
|
#ifdef SQLITE_TEST
|
|
if( rc==SQLITE_OK ){
|
|
- rc = sqlite3Fts3ExprInitTestInterface(db, pHash);
|
|
+ rc = sqlite3Fts3ExprInitTestInterface(db, &pHash->hash);
|
|
}
|
|
#endif
|
|
|
|
- /* Create the virtual table wrapper around the hash-table and overload
|
|
+ /* Create the virtual table wrapper around the hash-table and overload
|
|
** the four scalar functions. If this is successful, register the
|
|
** module with sqlite.
|
|
*/
|
|
- if( SQLITE_OK==rc
|
|
- && SQLITE_OK==(rc = sqlite3Fts3InitHashTable(db, pHash, "fts3_tokenizer"))
|
|
+ if( SQLITE_OK==rc
|
|
+ && SQLITE_OK==(rc=sqlite3Fts3InitHashTable(db,&pHash->hash,"fts3_tokenizer"))
|
|
&& SQLITE_OK==(rc = sqlite3_overload_function(db, "snippet", -1))
|
|
&& SQLITE_OK==(rc = sqlite3_overload_function(db, "offsets", 1))
|
|
&& SQLITE_OK==(rc = sqlite3_overload_function(db, "matchinfo", 1))
|
|
&& SQLITE_OK==(rc = sqlite3_overload_function(db, "matchinfo", 2))
|
|
&& SQLITE_OK==(rc = sqlite3_overload_function(db, "optimize", 1))
|
|
){
|
|
+ pHash->nRef++;
|
|
rc = sqlite3_create_module_v2(
|
|
db, "fts3", &fts3Module, (void *)pHash, hashDestroy
|
|
);
|
|
if( rc==SQLITE_OK ){
|
|
+ pHash->nRef++;
|
|
rc = sqlite3_create_module_v2(
|
|
- db, "fts4", &fts3Module, (void *)pHash, 0
|
|
+ db, "fts4", &fts3Module, (void *)pHash, hashDestroy
|
|
);
|
|
}
|
|
if( rc==SQLITE_OK ){
|
|
- rc = sqlite3Fts3InitTok(db, (void *)pHash);
|
|
+ pHash->nRef++;
|
|
+ rc = sqlite3Fts3InitTok(db, (void *)pHash, hashDestroy);
|
|
}
|
|
return rc;
|
|
}
|
|
@@ -169009,7 +184317,7 @@ SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db){
|
|
/* An error has occurred. Delete the hash table and return the error code. */
|
|
assert( rc!=SQLITE_OK );
|
|
if( pHash ){
|
|
- sqlite3Fts3HashClear(pHash);
|
|
+ sqlite3Fts3HashClear(&pHash->hash);
|
|
sqlite3_free(pHash);
|
|
}
|
|
return rc;
|
|
@@ -169017,7 +184325,7 @@ SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db){
|
|
|
|
/*
|
|
** Allocate an Fts3MultiSegReader for each token in the expression headed
|
|
-** by pExpr.
|
|
+** by pExpr.
|
|
**
|
|
** An Fts3SegReader object is a cursor that can seek or scan a range of
|
|
** entries within a single segment b-tree. An Fts3MultiSegReader uses multiple
|
|
@@ -169027,7 +184335,7 @@ SQLITE_PRIVATE int sqlite3Fts3Init(sqlite3 *db){
|
|
** If the allocated Fts3MultiSegReader just seeks to a single entry in a
|
|
** segment b-tree (if the term is not a prefix or it is a prefix for which
|
|
** there exists prefix b-tree of the right length) then it may be traversed
|
|
-** and merged incrementally. Otherwise, it has to be merged into an in-memory
|
|
+** and merged incrementally. Otherwise, it has to be merged into an in-memory
|
|
** doclist and then traversed.
|
|
*/
|
|
static void fts3EvalAllocateReaders(
|
|
@@ -169044,7 +184352,7 @@ static void fts3EvalAllocateReaders(
|
|
*pnToken += nToken;
|
|
for(i=0; i<nToken; i++){
|
|
Fts3PhraseToken *pToken = &pExpr->pPhrase->aToken[i];
|
|
- int rc = fts3TermSegReaderCursor(pCsr,
|
|
+ int rc = fts3TermSegReaderCursor(pCsr,
|
|
pToken->z, pToken->n, pToken->isPrefix, &pToken->pSegcsr
|
|
);
|
|
if( rc!=SQLITE_OK ){
|
|
@@ -169178,8 +184486,7 @@ static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){
|
|
char *aPoslist = 0; /* Position list for deferred tokens */
|
|
int nPoslist = 0; /* Number of bytes in aPoslist */
|
|
int iPrev = -1; /* Token number of previous deferred token */
|
|
-
|
|
- assert( pPhrase->doclist.bFreeList==0 );
|
|
+ char *aFree = (pPhrase->doclist.bFreeList ? pPhrase->doclist.pList : 0);
|
|
|
|
for(iToken=0; iToken<pPhrase->nToken; iToken++){
|
|
Fts3PhraseToken *pToken = &pPhrase->aToken[iToken];
|
|
@@ -169193,6 +184500,7 @@ static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){
|
|
|
|
if( pList==0 ){
|
|
sqlite3_free(aPoslist);
|
|
+ sqlite3_free(aFree);
|
|
pPhrase->doclist.pList = 0;
|
|
pPhrase->doclist.nList = 0;
|
|
return SQLITE_OK;
|
|
@@ -169213,6 +184521,7 @@ static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){
|
|
nPoslist = (int)(aOut - aPoslist);
|
|
if( nPoslist==0 ){
|
|
sqlite3_free(aPoslist);
|
|
+ sqlite3_free(aFree);
|
|
pPhrase->doclist.pList = 0;
|
|
pPhrase->doclist.nList = 0;
|
|
return SQLITE_OK;
|
|
@@ -169245,13 +184554,14 @@ static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){
|
|
nDistance = iPrev - nMaxUndeferred;
|
|
}
|
|
|
|
- aOut = (char *)sqlite3_malloc(nPoslist+8);
|
|
+ aOut = (char *)sqlite3Fts3MallocZero(nPoslist+FTS3_BUFFER_PADDING);
|
|
if( !aOut ){
|
|
sqlite3_free(aPoslist);
|
|
return SQLITE_NOMEM;
|
|
}
|
|
-
|
|
+
|
|
pPhrase->doclist.pList = aOut;
|
|
+ assert( p1 && p2 );
|
|
if( fts3PoslistPhraseMerge(&aOut, nDistance, 0, 1, &p1, &p2) ){
|
|
pPhrase->doclist.bFreeList = 1;
|
|
pPhrase->doclist.nList = (int)(aOut - pPhrase->doclist.pList);
|
|
@@ -169264,6 +184574,7 @@ static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){
|
|
}
|
|
}
|
|
|
|
+ if( pPhrase->doclist.pList!=aFree ) sqlite3_free(aFree);
|
|
return SQLITE_OK;
|
|
}
|
|
#endif /* SQLITE_DISABLE_FTS4_DEFERRED */
|
|
@@ -169275,7 +184586,7 @@ static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){
|
|
#define MAX_INCR_PHRASE_TOKENS 4
|
|
|
|
/*
|
|
-** This function is called for each Fts3Phrase in a full-text query
|
|
+** This function is called for each Fts3Phrase in a full-text query
|
|
** expression to initialize the mechanism for returning rows. Once this
|
|
** function has been called successfully on an Fts3Phrase, it may be
|
|
** used with fts3EvalPhraseNext() to iterate through the matching docids.
|
|
@@ -169293,12 +184604,12 @@ static int fts3EvalPhraseStart(Fts3Cursor *pCsr, int bOptOk, Fts3Phrase *p){
|
|
|
|
/* Determine if doclists may be loaded from disk incrementally. This is
|
|
** possible if the bOptOk argument is true, the FTS doclists will be
|
|
- ** scanned in forward order, and the phrase consists of
|
|
+ ** scanned in forward order, and the phrase consists of
|
|
** MAX_INCR_PHRASE_TOKENS or fewer tokens, none of which are are "^first"
|
|
** tokens or prefix tokens that cannot use a prefix-index. */
|
|
int bHaveIncr = 0;
|
|
- int bIncrOk = (bOptOk
|
|
- && pCsr->bDesc==pTab->bDescIdx
|
|
+ int bIncrOk = (bOptOk
|
|
+ && pCsr->bDesc==pTab->bDescIdx
|
|
&& p->nToken<=MAX_INCR_PHRASE_TOKENS && p->nToken>0
|
|
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
|
|
&& pTab->bNoIncrDoclist==0
|
|
@@ -169334,12 +184645,12 @@ static int fts3EvalPhraseStart(Fts3Cursor *pCsr, int bOptOk, Fts3Phrase *p){
|
|
}
|
|
|
|
/*
|
|
-** This function is used to iterate backwards (from the end to start)
|
|
+** This function is used to iterate backwards (from the end to start)
|
|
** through doclists. It is used by this module to iterate through phrase
|
|
** doclists in reverse and by the fts3_write.c module to iterate through
|
|
** pending-terms lists when writing to databases with "order=desc".
|
|
**
|
|
-** The doclist may be sorted in ascending (parameter bDescIdx==0) or
|
|
+** The doclist may be sorted in ascending (parameter bDescIdx==0) or
|
|
** descending (parameter bDescIdx==1) order of docid. Regardless, this
|
|
** function iterates from the end of the doclist to the beginning.
|
|
*/
|
|
@@ -169356,7 +184667,7 @@ SQLITE_PRIVATE void sqlite3Fts3DoclistPrev(
|
|
|
|
assert( nDoclist>0 );
|
|
assert( *pbEof==0 );
|
|
- assert( p || *piDocid==0 );
|
|
+ assert_fts3_nc( p || *piDocid==0 );
|
|
assert( !p || (p>aDoclist && p<&aDoclist[nDoclist]) );
|
|
|
|
if( p==0 ){
|
|
@@ -169411,7 +184722,7 @@ SQLITE_PRIVATE void sqlite3Fts3DoclistNext(
|
|
|
|
assert( nDoclist>0 );
|
|
assert( *pbEof==0 );
|
|
- assert( p || *piDocid==0 );
|
|
+ assert_fts3_nc( p || *piDocid==0 );
|
|
assert( !p || (p>=aDoclist && p<=&aDoclist[nDoclist]) );
|
|
|
|
if( p==0 ){
|
|
@@ -169419,7 +184730,7 @@ SQLITE_PRIVATE void sqlite3Fts3DoclistNext(
|
|
p += sqlite3Fts3GetVarint(p, piDocid);
|
|
}else{
|
|
fts3PoslistCopy(0, &p);
|
|
- while( p<&aDoclist[nDoclist] && *p==0 ) p++;
|
|
+ while( p<&aDoclist[nDoclist] && *p==0 ) p++;
|
|
if( p>=&aDoclist[nDoclist] ){
|
|
*pbEof = 1;
|
|
}else{
|
|
@@ -169443,7 +184754,7 @@ static void fts3EvalDlPhraseNext(
|
|
){
|
|
char *pIter; /* Used to iterate through aAll */
|
|
char *pEnd; /* 1 byte past end of aAll */
|
|
-
|
|
+
|
|
if( pDL->pNextDocid ){
|
|
pIter = pDL->pNextDocid;
|
|
assert( pDL->aAll!=0 || pIter==0 );
|
|
@@ -169492,12 +184803,12 @@ struct TokenDoclist {
|
|
};
|
|
|
|
/*
|
|
-** Token pToken is an incrementally loaded token that is part of a
|
|
+** Token pToken is an incrementally loaded token that is part of a
|
|
** multi-token phrase. Advance it to the next matching document in the
|
|
** database and populate output variable *p with the details of the new
|
|
** entry. Or, if the iterator has reached EOF, set *pbEof to true.
|
|
**
|
|
-** If an error occurs, return an SQLite error code. Otherwise, return
|
|
+** If an error occurs, return an SQLite error code. Otherwise, return
|
|
** SQLITE_OK.
|
|
*/
|
|
static int incrPhraseTokenNext(
|
|
@@ -169538,18 +184849,18 @@ static int incrPhraseTokenNext(
|
|
/*
|
|
** The phrase iterator passed as the second argument:
|
|
**
|
|
-** * features at least one token that uses an incremental doclist, and
|
|
+** * features at least one token that uses an incremental doclist, and
|
|
**
|
|
** * does not contain any deferred tokens.
|
|
**
|
|
** Advance it to the next matching documnent in the database and populate
|
|
-** the Fts3Doclist.pList and nList fields.
|
|
+** the Fts3Doclist.pList and nList fields.
|
|
**
|
|
** If there is no "next" entry and no error occurs, then *pbEof is set to
|
|
** 1 before returning. Otherwise, if no error occurs and the iterator is
|
|
** successfully advanced, *pbEof is set to 0.
|
|
**
|
|
-** If an error occurs, return an SQLite error code. Otherwise, return
|
|
+** If an error occurs, return an SQLite error code. Otherwise, return
|
|
** SQLITE_OK.
|
|
*/
|
|
static int fts3EvalIncrPhraseNext(
|
|
@@ -169567,7 +184878,7 @@ static int fts3EvalIncrPhraseNext(
|
|
assert( p->bIncr==1 );
|
|
|
|
if( p->nToken==1 ){
|
|
- rc = sqlite3Fts3MsrIncrNext(pTab, p->aToken[0].pSegcsr,
|
|
+ rc = sqlite3Fts3MsrIncrNext(pTab, p->aToken[0].pSegcsr,
|
|
&pDL->iDocid, &pDL->pList, &pDL->nList
|
|
);
|
|
if( pDL->pList==0 ) bEof = 1;
|
|
@@ -169597,8 +184908,8 @@ static int fts3EvalIncrPhraseNext(
|
|
|
|
/* Keep advancing iterators until they all point to the same document */
|
|
for(i=0; i<p->nToken; i++){
|
|
- while( rc==SQLITE_OK && bEof==0
|
|
- && a[i].bIgnore==0 && DOCID_CMP(a[i].iDocid, iMax)<0
|
|
+ while( rc==SQLITE_OK && bEof==0
|
|
+ && a[i].bIgnore==0 && DOCID_CMP(a[i].iDocid, iMax)<0
|
|
){
|
|
rc = incrPhraseTokenNext(pTab, p, i, &a[i], &bEof);
|
|
if( DOCID_CMP(a[i].iDocid, iMax)>0 ){
|
|
@@ -169612,7 +184923,7 @@ static int fts3EvalIncrPhraseNext(
|
|
if( bEof==0 ){
|
|
int nList = 0;
|
|
int nByte = a[p->nToken-1].nList;
|
|
- char *aDoclist = sqlite3_malloc(nByte+FTS3_BUFFER_PADDING);
|
|
+ char *aDoclist = sqlite3_malloc64((i64)nByte+FTS3_BUFFER_PADDING);
|
|
if( !aDoclist ) return SQLITE_NOMEM;
|
|
memcpy(aDoclist, a[p->nToken-1].pList, nByte+1);
|
|
memset(&aDoclist[nByte], 0, FTS3_BUFFER_PADDING);
|
|
@@ -169645,8 +184956,8 @@ static int fts3EvalIncrPhraseNext(
|
|
}
|
|
|
|
/*
|
|
-** Attempt to move the phrase iterator to point to the next matching docid.
|
|
-** If an error occurs, return an SQLite error code. Otherwise, return
|
|
+** Attempt to move the phrase iterator to point to the next matching docid.
|
|
+** If an error occurs, return an SQLite error code. Otherwise, return
|
|
** SQLITE_OK.
|
|
**
|
|
** If there is no "next" entry and no error occurs, then *pbEof is set to
|
|
@@ -169665,7 +184976,7 @@ static int fts3EvalPhraseNext(
|
|
if( p->bIncr ){
|
|
rc = fts3EvalIncrPhraseNext(pCsr, p, pbEof);
|
|
}else if( pCsr->bDesc!=pTab->bDescIdx && pDL->nAll ){
|
|
- sqlite3Fts3DoclistPrev(pTab->bDescIdx, pDL->aAll, pDL->nAll,
|
|
+ sqlite3Fts3DoclistPrev(pTab->bDescIdx, pDL->aAll, pDL->nAll,
|
|
&pDL->pNextDocid, &pDL->iDocid, &pDL->nList, pbEof
|
|
);
|
|
pDL->pList = pDL->pNextDocid;
|
|
@@ -169725,7 +185036,7 @@ static void fts3EvalStartReaders(
|
|
** Tokens are divided into AND/NEAR clusters. All tokens in a cluster belong
|
|
** to phrases that are connected only by AND and NEAR operators (not OR or
|
|
** NOT). When determining tokens to defer, each AND/NEAR cluster is considered
|
|
-** separately. The root of a tokens AND/NEAR cluster is stored in
|
|
+** separately. The root of a tokens AND/NEAR cluster is stored in
|
|
** Fts3TokenAndCost.pRoot.
|
|
*/
|
|
typedef struct Fts3TokenAndCost Fts3TokenAndCost;
|
|
@@ -169793,7 +185104,7 @@ static void fts3EvalTokenCosts(
|
|
** write this value to *pnPage and return SQLITE_OK. Otherwise, return
|
|
** an SQLite error code.
|
|
**
|
|
-** The average document size in pages is calculated by first calculating
|
|
+** The average document size in pages is calculated by first calculating
|
|
** determining the average size in bytes, B. If B is less than the amount
|
|
** of data that will fit on a single leaf page of an intkey table in
|
|
** this database, then the average docsize is 1. Otherwise, it is 1 plus
|
|
@@ -169803,10 +185114,10 @@ static int fts3EvalAverageDocsize(Fts3Cursor *pCsr, int *pnPage){
|
|
int rc = SQLITE_OK;
|
|
if( pCsr->nRowAvg==0 ){
|
|
/* The average document size, which is required to calculate the cost
|
|
- ** of each doclist, has not yet been determined. Read the required
|
|
+ ** of each doclist, has not yet been determined. Read the required
|
|
** data from the %_stat table to calculate it.
|
|
**
|
|
- ** Entry 0 of the %_stat table is a blob containing (nCol+1) FTS3
|
|
+ ** Entry 0 of the %_stat table is a blob containing (nCol+1) FTS3
|
|
** varints, where nCol is the number of columns in the FTS3 table.
|
|
** The first varint is the number of documents currently stored in
|
|
** the table. The following nCol varints contain the total amount of
|
|
@@ -169838,7 +185149,7 @@ static int fts3EvalAverageDocsize(Fts3Cursor *pCsr, int *pnPage){
|
|
|
|
pCsr->nDoc = nDoc;
|
|
pCsr->nRowAvg = (int)(((nByte / nDoc) + p->nPgsz) / p->nPgsz);
|
|
- assert( pCsr->nRowAvg>0 );
|
|
+ assert( pCsr->nRowAvg>0 );
|
|
rc = sqlite3_reset(pStmt);
|
|
}
|
|
|
|
@@ -169847,11 +185158,11 @@ static int fts3EvalAverageDocsize(Fts3Cursor *pCsr, int *pnPage){
|
|
}
|
|
|
|
/*
|
|
-** This function is called to select the tokens (if any) that will be
|
|
+** This function is called to select the tokens (if any) that will be
|
|
** deferred. The array aTC[] has already been populated when this is
|
|
** called.
|
|
**
|
|
-** This function is called once for each AND/NEAR cluster in the
|
|
+** This function is called once for each AND/NEAR cluster in the
|
|
** expression. Each invocation determines which tokens to defer within
|
|
** the cluster with root node pRoot. See comments above the definition
|
|
** of struct Fts3TokenAndCost for more details.
|
|
@@ -169901,8 +185212,8 @@ static int fts3EvalSelectDeferred(
|
|
assert( rc!=SQLITE_OK || nDocSize>0 );
|
|
|
|
|
|
- /* Iterate through all tokens in this AND/NEAR cluster, in ascending order
|
|
- ** of the number of overflow pages that will be loaded by the pager layer
|
|
+ /* Iterate through all tokens in this AND/NEAR cluster, in ascending order
|
|
+ ** of the number of overflow pages that will be loaded by the pager layer
|
|
** to retrieve the entire doclist for the token from the full-text index.
|
|
** Load the doclists for tokens that are either:
|
|
**
|
|
@@ -169913,7 +185224,7 @@ static int fts3EvalSelectDeferred(
|
|
**
|
|
** After each token doclist is loaded, merge it with the others from the
|
|
** same phrase and count the number of documents that the merged doclist
|
|
- ** contains. Set variable "nMinEst" to the smallest number of documents in
|
|
+ ** contains. Set variable "nMinEst" to the smallest number of documents in
|
|
** any phrase doclist for which 1 or more token doclists have been loaded.
|
|
** Let nOther be the number of other phrases for which it is certain that
|
|
** one or more tokens will not be deferred.
|
|
@@ -169929,8 +185240,8 @@ static int fts3EvalSelectDeferred(
|
|
|
|
/* Set pTC to point to the cheapest remaining token. */
|
|
for(iTC=0; iTC<nTC; iTC++){
|
|
- if( aTC[iTC].pToken && aTC[iTC].pRoot==pRoot
|
|
- && (!pTC || aTC[iTC].nOvfl<pTC->nOvfl)
|
|
+ if( aTC[iTC].pToken && aTC[iTC].pRoot==pRoot
|
|
+ && (!pTC || aTC[iTC].nOvfl<pTC->nOvfl)
|
|
){
|
|
pTC = &aTC[iTC];
|
|
}
|
|
@@ -169939,7 +185250,7 @@ static int fts3EvalSelectDeferred(
|
|
|
|
if( ii && pTC->nOvfl>=((nMinEst+(nLoad4/4)-1)/(nLoad4/4))*nDocSize ){
|
|
/* The number of overflow pages to load for this (and therefore all
|
|
- ** subsequent) tokens is greater than the estimated number of pages
|
|
+ ** subsequent) tokens is greater than the estimated number of pages
|
|
** that will be loaded if all subsequent tokens are deferred.
|
|
*/
|
|
Fts3PhraseToken *pToken = pTC->pToken;
|
|
@@ -169948,7 +185259,7 @@ static int fts3EvalSelectDeferred(
|
|
pToken->pSegcsr = 0;
|
|
}else{
|
|
/* Set nLoad4 to the value of (4^nOther) for the next iteration of the
|
|
- ** for-loop. Except, limit the value to 2^24 to prevent it from
|
|
+ ** for-loop. Except, limit the value to 2^24 to prevent it from
|
|
** overflowing the 32-bit integer it is stored in. */
|
|
if( ii<12 ) nLoad4 = nLoad4*4;
|
|
|
|
@@ -170006,16 +185317,15 @@ static int fts3EvalStart(Fts3Cursor *pCsr){
|
|
#ifndef SQLITE_DISABLE_FTS4_DEFERRED
|
|
if( rc==SQLITE_OK && nToken>1 && pTab->bFts4 ){
|
|
Fts3TokenAndCost *aTC;
|
|
- Fts3Expr **apOr;
|
|
aTC = (Fts3TokenAndCost *)sqlite3_malloc64(
|
|
sizeof(Fts3TokenAndCost) * nToken
|
|
+ sizeof(Fts3Expr *) * nOr * 2
|
|
);
|
|
- apOr = (Fts3Expr **)&aTC[nToken];
|
|
|
|
if( !aTC ){
|
|
rc = SQLITE_NOMEM;
|
|
}else{
|
|
+ Fts3Expr **apOr = (Fts3Expr **)&aTC[nToken];
|
|
int ii;
|
|
Fts3TokenAndCost *pTC = aTC;
|
|
Fts3Expr **ppOr = apOr;
|
|
@@ -170061,7 +185371,7 @@ static void fts3EvalInvalidatePoslist(Fts3Phrase *pPhrase){
|
|
**
|
|
** Parameter nNear is passed the NEAR distance of the expression (5 in
|
|
** the example above). When this function is called, *paPoslist points to
|
|
-** the position list, and *pnToken is the number of phrase tokens in, the
|
|
+** the position list, and *pnToken is the number of phrase tokens in the
|
|
** phrase on the other side of the NEAR operator to pPhrase. For example,
|
|
** if pPhrase refers to the "def ghi" phrase, then *paPoslist points to
|
|
** the position list associated with phrase "abc".
|
|
@@ -170070,7 +185380,7 @@ static void fts3EvalInvalidatePoslist(Fts3Phrase *pPhrase){
|
|
** close to a position in the *paPoslist position list are removed. If this
|
|
** leaves 0 positions, zero is returned. Otherwise, non-zero.
|
|
**
|
|
-** Before returning, *paPoslist is set to point to the position lsit
|
|
+** Before returning, *paPoslist is set to point to the position lsit
|
|
** associated with pPhrase. And *pnToken is set to the number of tokens in
|
|
** pPhrase.
|
|
*/
|
|
@@ -170084,8 +185394,8 @@ static int fts3EvalNearTrim(
|
|
int nParam1 = nNear + pPhrase->nToken;
|
|
int nParam2 = nNear + *pnToken;
|
|
int nNew;
|
|
- char *p2;
|
|
- char *pOut;
|
|
+ char *p2;
|
|
+ char *pOut;
|
|
int res;
|
|
|
|
assert( pPhrase->doclist.pList );
|
|
@@ -170096,10 +185406,12 @@ static int fts3EvalNearTrim(
|
|
);
|
|
if( res ){
|
|
nNew = (int)(pOut - pPhrase->doclist.pList) - 1;
|
|
- assert( pPhrase->doclist.pList[nNew]=='\0' );
|
|
- assert( nNew<=pPhrase->doclist.nList && nNew>0 );
|
|
- memset(&pPhrase->doclist.pList[nNew], 0, pPhrase->doclist.nList - nNew);
|
|
- pPhrase->doclist.nList = nNew;
|
|
+ assert_fts3_nc( nNew<=pPhrase->doclist.nList && nNew>0 );
|
|
+ if( nNew>=0 && nNew<=pPhrase->doclist.nList ){
|
|
+ assert( pPhrase->doclist.pList[nNew]=='\0' );
|
|
+ memset(&pPhrase->doclist.pList[nNew], 0, pPhrase->doclist.nList - nNew);
|
|
+ pPhrase->doclist.nList = nNew;
|
|
+ }
|
|
*paPoslist = pPhrase->doclist.pList;
|
|
*pnToken = pPhrase->nToken;
|
|
}
|
|
@@ -170132,19 +185444,19 @@ static int fts3EvalNearTrim(
|
|
**
|
|
** 1. Deferred tokens are not taken into account. If a phrase consists
|
|
** entirely of deferred tokens, it is assumed to match every row in
|
|
-** the db. In this case the position-list is not populated at all.
|
|
+** the db. In this case the position-list is not populated at all.
|
|
**
|
|
** Or, if a phrase contains one or more deferred tokens and one or
|
|
-** more non-deferred tokens, then the expression is advanced to the
|
|
+** more non-deferred tokens, then the expression is advanced to the
|
|
** next possible match, considering only non-deferred tokens. In other
|
|
** words, if the phrase is "A B C", and "B" is deferred, the expression
|
|
-** is advanced to the next row that contains an instance of "A * C",
|
|
+** is advanced to the next row that contains an instance of "A * C",
|
|
** where "*" may match any single token. The position list in this case
|
|
** is populated as for "A * C" before returning.
|
|
**
|
|
-** 2. NEAR is treated as AND. If the expression is "x NEAR y", it is
|
|
+** 2. NEAR is treated as AND. If the expression is "x NEAR y", it is
|
|
** advanced to point to the next row that matches "x AND y".
|
|
-**
|
|
+**
|
|
** See sqlite3Fts3EvalTestDeferred() for details on testing if a row is
|
|
** really a match, taking into account deferred tokens and NEAR operators.
|
|
*/
|
|
@@ -170153,9 +185465,8 @@ static void fts3EvalNextRow(
|
|
Fts3Expr *pExpr, /* Expr. to advance to next matching row */
|
|
int *pRc /* IN/OUT: Error code */
|
|
){
|
|
- if( *pRc==SQLITE_OK ){
|
|
+ if( *pRc==SQLITE_OK && pExpr->bEof==0 ){
|
|
int bDescDoclist = pCsr->bDesc; /* Used by DOCID_CMP() macro */
|
|
- assert( pExpr->bEof==0 );
|
|
pExpr->bStart = 1;
|
|
|
|
switch( pExpr->eType ){
|
|
@@ -170208,18 +185519,19 @@ static void fts3EvalNextRow(
|
|
fts3EvalNextRow(pCsr, pLeft, pRc);
|
|
}
|
|
}
|
|
+ pRight->bEof = pLeft->bEof = 1;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
-
|
|
+
|
|
case FTSQUERY_OR: {
|
|
Fts3Expr *pLeft = pExpr->pLeft;
|
|
Fts3Expr *pRight = pExpr->pRight;
|
|
sqlite3_int64 iCmp = DOCID_CMP(pLeft->iDocid, pRight->iDocid);
|
|
|
|
- assert( pLeft->bStart || pLeft->iDocid==pRight->iDocid );
|
|
- assert( pRight->bStart || pLeft->iDocid==pRight->iDocid );
|
|
+ assert_fts3_nc( pLeft->bStart || pLeft->iDocid==pRight->iDocid );
|
|
+ assert_fts3_nc( pRight->bStart || pLeft->iDocid==pRight->iDocid );
|
|
|
|
if( pRight->bEof || (pLeft->bEof==0 && iCmp<0) ){
|
|
fts3EvalNextRow(pCsr, pLeft, pRc);
|
|
@@ -170252,9 +185564,9 @@ static void fts3EvalNextRow(
|
|
|
|
fts3EvalNextRow(pCsr, pLeft, pRc);
|
|
if( pLeft->bEof==0 ){
|
|
- while( !*pRc
|
|
- && !pRight->bEof
|
|
- && DOCID_CMP(pLeft->iDocid, pRight->iDocid)>0
|
|
+ while( !*pRc
|
|
+ && !pRight->bEof
|
|
+ && DOCID_CMP(pLeft->iDocid, pRight->iDocid)>0
|
|
){
|
|
fts3EvalNextRow(pCsr, pRight, pRc);
|
|
}
|
|
@@ -170279,14 +185591,14 @@ static void fts3EvalNextRow(
|
|
** If *pRc is not SQLITE_OK, or if pExpr is not the root node of a NEAR
|
|
** cluster, then this function returns 1 immediately.
|
|
**
|
|
-** Otherwise, it checks if the current row really does match the NEAR
|
|
-** expression, using the data currently stored in the position lists
|
|
-** (Fts3Expr->pPhrase.doclist.pList/nList) for each phrase in the expression.
|
|
+** Otherwise, it checks if the current row really does match the NEAR
|
|
+** expression, using the data currently stored in the position lists
|
|
+** (Fts3Expr->pPhrase.doclist.pList/nList) for each phrase in the expression.
|
|
**
|
|
** If the current row is a match, the position list associated with each
|
|
** phrase in the NEAR expression is edited in place to contain only those
|
|
** phrase instances sufficiently close to their peers to satisfy all NEAR
|
|
-** constraints. In this case it returns 1. If the NEAR expression does not
|
|
+** constraints. In this case it returns 1. If the NEAR expression does not
|
|
** match the current row, 0 is returned. The position lists may or may not
|
|
** be edited if 0 is returned.
|
|
*/
|
|
@@ -170309,15 +185621,15 @@ static int fts3EvalNearTest(Fts3Expr *pExpr, int *pRc){
|
|
** | |
|
|
** "w" "x"
|
|
**
|
|
- ** The right-hand child of a NEAR node is always a phrase. The
|
|
+ ** The right-hand child of a NEAR node is always a phrase. The
|
|
** left-hand child may be either a phrase or a NEAR node. There are
|
|
** no exceptions to this - it's the way the parser in fts3_expr.c works.
|
|
*/
|
|
- if( *pRc==SQLITE_OK
|
|
- && pExpr->eType==FTSQUERY_NEAR
|
|
+ if( *pRc==SQLITE_OK
|
|
+ && pExpr->eType==FTSQUERY_NEAR
|
|
&& (pExpr->pParent==0 || pExpr->pParent->eType!=FTSQUERY_NEAR)
|
|
){
|
|
- Fts3Expr *p;
|
|
+ Fts3Expr *p;
|
|
sqlite3_int64 nTmp = 0; /* Bytes of temp space */
|
|
char *aTmp; /* Temp space for PoslistNearMerge() */
|
|
|
|
@@ -170364,12 +185676,12 @@ static int fts3EvalNearTest(Fts3Expr *pExpr, int *pRc){
|
|
/*
|
|
** This function is a helper function for sqlite3Fts3EvalTestDeferred().
|
|
** Assuming no error occurs or has occurred, It returns non-zero if the
|
|
-** expression passed as the second argument matches the row that pCsr
|
|
+** expression passed as the second argument matches the row that pCsr
|
|
** currently points to, or zero if it does not.
|
|
**
|
|
** If *pRc is not SQLITE_OK when this function is called, it is a no-op.
|
|
-** If an error occurs during execution of this function, *pRc is set to
|
|
-** the appropriate SQLite error code. In this case the returned value is
|
|
+** If an error occurs during execution of this function, *pRc is set to
|
|
+** the appropriate SQLite error code. In this case the returned value is
|
|
** undefined.
|
|
*/
|
|
static int fts3EvalTestExpr(
|
|
@@ -170388,10 +185700,10 @@ static int fts3EvalTestExpr(
|
|
&& fts3EvalNearTest(pExpr, pRc)
|
|
);
|
|
|
|
- /* If the NEAR expression does not match any rows, zero the doclist for
|
|
+ /* If the NEAR expression does not match any rows, zero the doclist for
|
|
** all phrases involved in the NEAR. This is because the snippet(),
|
|
- ** offsets() and matchinfo() functions are not supposed to recognize
|
|
- ** any instances of phrases that are part of unmatched NEAR queries.
|
|
+ ** offsets() and matchinfo() functions are not supposed to recognize
|
|
+ ** any instances of phrases that are part of unmatched NEAR queries.
|
|
** For example if this expression:
|
|
**
|
|
** ... MATCH 'a OR (b NEAR c)'
|
|
@@ -170403,8 +185715,8 @@ static int fts3EvalTestExpr(
|
|
** then any snippet() should ony highlight the "a" term, not the "b"
|
|
** (as "b" is part of a non-matching NEAR clause).
|
|
*/
|
|
- if( bHit==0
|
|
- && pExpr->eType==FTSQUERY_NEAR
|
|
+ if( bHit==0
|
|
+ && pExpr->eType==FTSQUERY_NEAR
|
|
&& (pExpr->pParent==0 || pExpr->pParent->eType!=FTSQUERY_NEAR)
|
|
){
|
|
Fts3Expr *p;
|
|
@@ -170436,11 +185748,10 @@ static int fts3EvalTestExpr(
|
|
|
|
default: {
|
|
#ifndef SQLITE_DISABLE_FTS4_DEFERRED
|
|
- if( pCsr->pDeferred
|
|
- && (pExpr->iDocid==pCsr->iPrevId || pExpr->bDeferred)
|
|
- ){
|
|
+ if( pCsr->pDeferred && (pExpr->bDeferred || (
|
|
+ pExpr->iDocid==pCsr->iPrevId && pExpr->pPhrase->doclist.pList
|
|
+ ))){
|
|
Fts3Phrase *pPhrase = pExpr->pPhrase;
|
|
- assert( pExpr->bDeferred || pPhrase->doclist.bFreeList==0 );
|
|
if( pExpr->bDeferred ){
|
|
fts3EvalInvalidatePoslist(pPhrase);
|
|
}
|
|
@@ -170450,7 +185761,10 @@ static int fts3EvalTestExpr(
|
|
}else
|
|
#endif
|
|
{
|
|
- bHit = (pExpr->bEof==0 && pExpr->iDocid==pCsr->iPrevId);
|
|
+ bHit = (
|
|
+ pExpr->bEof==0 && pExpr->iDocid==pCsr->iPrevId
|
|
+ && pExpr->pPhrase->doclist.nList>0
|
|
+ );
|
|
}
|
|
break;
|
|
}
|
|
@@ -170492,7 +185806,7 @@ SQLITE_PRIVATE int sqlite3Fts3EvalTestDeferred(Fts3Cursor *pCsr, int *pRc){
|
|
** memory and scan it to determine the position list for each deferred
|
|
** token. Then, see if this row is really a match, considering deferred
|
|
** tokens and NEAR operators (neither of which were taken into account
|
|
- ** earlier, by fts3EvalNextRow()).
|
|
+ ** earlier, by fts3EvalNextRow()).
|
|
*/
|
|
if( pCsr->pDeferred ){
|
|
rc = fts3CursorSeek(0, pCsr);
|
|
@@ -170547,7 +185861,7 @@ static int fts3EvalNext(Fts3Cursor *pCsr){
|
|
|
|
/*
|
|
** Restart interation for expression pExpr so that the next call to
|
|
-** fts3EvalNext() visits the first row. Do not allow incremental
|
|
+** fts3EvalNext() visits the first row. Do not allow incremental
|
|
** loading or merging of phrase doclists for this iteration.
|
|
**
|
|
** If *pRc is other than SQLITE_OK when this function is called, it is
|
|
@@ -170590,11 +185904,11 @@ static void fts3EvalRestart(
|
|
}
|
|
|
|
/*
|
|
-** After allocating the Fts3Expr.aMI[] array for each phrase in the
|
|
+** After allocating the Fts3Expr.aMI[] array for each phrase in the
|
|
** expression rooted at pExpr, the cursor iterates through all rows matched
|
|
** by pExpr, calling this function for each row. This function increments
|
|
** the values in Fts3Expr.aMI[] according to the position-list currently
|
|
-** found in Fts3Expr.pPhrase->doclist.pList for each of the phrase
|
|
+** found in Fts3Expr.pPhrase->doclist.pList for each of the phrase
|
|
** expression nodes.
|
|
*/
|
|
static void fts3EvalUpdateCounts(Fts3Expr *pExpr, int nCol){
|
|
@@ -170628,6 +185942,22 @@ static void fts3EvalUpdateCounts(Fts3Expr *pExpr, int nCol){
|
|
}
|
|
}
|
|
|
|
+/*
|
|
+** This is an sqlite3Fts3ExprIterate() callback. If the Fts3Expr.aMI[] array
|
|
+** has not yet been allocated, allocate and zero it. Otherwise, just zero
|
|
+** it.
|
|
+*/
|
|
+static int fts3AllocateMSI(Fts3Expr *pExpr, int iPhrase, void *pCtx){
|
|
+ Fts3Table *pTab = (Fts3Table*)pCtx;
|
|
+ UNUSED_PARAMETER(iPhrase);
|
|
+ if( pExpr->aMI==0 ){
|
|
+ pExpr->aMI = (u32 *)sqlite3_malloc64(pTab->nColumn * 3 * sizeof(u32));
|
|
+ if( pExpr->aMI==0 ) return SQLITE_NOMEM;
|
|
+ }
|
|
+ memset(pExpr->aMI, 0, pTab->nColumn * 3 * sizeof(u32));
|
|
+ return SQLITE_OK;
|
|
+}
|
|
+
|
|
/*
|
|
** Expression pExpr must be of type FTSQUERY_PHRASE.
|
|
**
|
|
@@ -170649,7 +185979,6 @@ static int fts3EvalGatherStats(
|
|
if( pExpr->aMI==0 ){
|
|
Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
|
|
Fts3Expr *pRoot; /* Root of NEAR expression */
|
|
- Fts3Expr *p; /* Iterator used for several purposes */
|
|
|
|
sqlite3_int64 iPrevId = pCsr->iPrevId;
|
|
sqlite3_int64 iDocid;
|
|
@@ -170657,7 +185986,9 @@ static int fts3EvalGatherStats(
|
|
|
|
/* Find the root of the NEAR expression */
|
|
pRoot = pExpr;
|
|
- while( pRoot->pParent && pRoot->pParent->eType==FTSQUERY_NEAR ){
|
|
+ while( pRoot->pParent
|
|
+ && (pRoot->pParent->eType==FTSQUERY_NEAR || pRoot->bDeferred)
|
|
+ ){
|
|
pRoot = pRoot->pParent;
|
|
}
|
|
iDocid = pRoot->iDocid;
|
|
@@ -170665,14 +185996,8 @@ static int fts3EvalGatherStats(
|
|
assert( pRoot->bStart );
|
|
|
|
/* Allocate space for the aMSI[] array of each FTSQUERY_PHRASE node */
|
|
- for(p=pRoot; p; p=p->pLeft){
|
|
- Fts3Expr *pE = (p->eType==FTSQUERY_PHRASE?p:p->pRight);
|
|
- assert( pE->aMI==0 );
|
|
- pE->aMI = (u32 *)sqlite3_malloc64(pTab->nColumn * 3 * sizeof(u32));
|
|
- if( !pE->aMI ) return SQLITE_NOMEM;
|
|
- memset(pE->aMI, 0, pTab->nColumn * 3 * sizeof(u32));
|
|
- }
|
|
-
|
|
+ rc = sqlite3Fts3ExprIterate(pRoot, fts3AllocateMSI, (void*)pTab);
|
|
+ if( rc!=SQLITE_OK ) return rc;
|
|
fts3EvalRestart(pCsr, pRoot, &rc);
|
|
|
|
while( pCsr->isEof==0 && rc==SQLITE_OK ){
|
|
@@ -170688,9 +186013,9 @@ static int fts3EvalGatherStats(
|
|
pCsr->isRequireSeek = 1;
|
|
pCsr->isMatchinfoNeeded = 1;
|
|
pCsr->iPrevId = pRoot->iDocid;
|
|
- }while( pCsr->isEof==0
|
|
- && pRoot->eType==FTSQUERY_NEAR
|
|
- && sqlite3Fts3EvalTestDeferred(pCsr, &rc)
|
|
+ }while( pCsr->isEof==0
|
|
+ && pRoot->eType==FTSQUERY_NEAR
|
|
+ && sqlite3Fts3EvalTestDeferred(pCsr, &rc)
|
|
);
|
|
|
|
if( rc==SQLITE_OK && pCsr->isEof==0 ){
|
|
@@ -170705,7 +186030,7 @@ static int fts3EvalGatherStats(
|
|
pRoot->bEof = bEof;
|
|
}else{
|
|
/* Caution: pRoot may iterate through docids in ascending or descending
|
|
- ** order. For this reason, even though it seems more defensive, the
|
|
+ ** order. For this reason, even though it seems more defensive, the
|
|
** do loop can not be written:
|
|
**
|
|
** do {...} while( pRoot->iDocid<iDocid && rc==SQLITE_OK );
|
|
@@ -170713,7 +186038,8 @@ static int fts3EvalGatherStats(
|
|
fts3EvalRestart(pCsr, pRoot, &rc);
|
|
do {
|
|
fts3EvalNextRow(pCsr, pRoot, &rc);
|
|
- assert( pRoot->bEof==0 );
|
|
+ assert_fts3_nc( pRoot->bEof==0 );
|
|
+ if( pRoot->bEof ) rc = FTS_CORRUPT_VTAB;
|
|
}while( pRoot->iDocid!=iDocid && rc==SQLITE_OK );
|
|
}
|
|
}
|
|
@@ -170721,10 +186047,10 @@ static int fts3EvalGatherStats(
|
|
}
|
|
|
|
/*
|
|
-** This function is used by the matchinfo() module to query a phrase
|
|
+** This function is used by the matchinfo() module to query a phrase
|
|
** expression node for the following information:
|
|
**
|
|
-** 1. The total number of occurrences of the phrase in each column of
|
|
+** 1. The total number of occurrences of the phrase in each column of
|
|
** the FTS table (considering all rows), and
|
|
**
|
|
** 2. For each column, the number of rows in the table for which the
|
|
@@ -170738,12 +186064,12 @@ static int fts3EvalGatherStats(
|
|
**
|
|
** Caveats:
|
|
**
|
|
-** * If a phrase consists entirely of deferred tokens, then all output
|
|
+** * If a phrase consists entirely of deferred tokens, then all output
|
|
** values are set to the number of documents in the table. In other
|
|
-** words we assume that very common tokens occur exactly once in each
|
|
+** words we assume that very common tokens occur exactly once in each
|
|
** column of each row of the table.
|
|
**
|
|
-** * If a phrase contains some deferred tokens (and some non-deferred
|
|
+** * If a phrase contains some deferred tokens (and some non-deferred
|
|
** tokens), count the potential occurrence identified by considering
|
|
** the non-deferred tokens instead of actual phrase occurrences.
|
|
**
|
|
@@ -170781,14 +186107,14 @@ SQLITE_PRIVATE int sqlite3Fts3EvalPhraseStats(
|
|
|
|
/*
|
|
** The expression pExpr passed as the second argument to this function
|
|
-** must be of type FTSQUERY_PHRASE.
|
|
+** must be of type FTSQUERY_PHRASE.
|
|
**
|
|
** The returned value is either NULL or a pointer to a buffer containing
|
|
** a position-list indicating the occurrences of the phrase in column iCol
|
|
-** of the current row.
|
|
+** of the current row.
|
|
**
|
|
-** More specifically, the returned buffer contains 1 varint for each
|
|
-** occurrence of the phrase in the column, stored using the normal (delta+2)
|
|
+** More specifically, the returned buffer contains 1 varint for each
|
|
+** occurrence of the phrase in the column, stored using the normal (delta+2)
|
|
** compression and is terminated by either an 0x01 or 0x00 byte. For example,
|
|
** if the requested column contains "a b X c d X X" and the position-list
|
|
** for 'X' is requested, the buffer returned may contain:
|
|
@@ -170810,7 +186136,7 @@ SQLITE_PRIVATE int sqlite3Fts3EvalPhrasePoslist(
|
|
int iThis;
|
|
sqlite3_int64 iDocid;
|
|
|
|
- /* If this phrase is applies specifically to some column other than
|
|
+ /* If this phrase is applies specifically to some column other than
|
|
** column iCol, return a NULL pointer. */
|
|
*ppOut = 0;
|
|
assert( iCol>=0 && iCol<pTab->nColumn );
|
|
@@ -170827,10 +186153,11 @@ SQLITE_PRIVATE int sqlite3Fts3EvalPhrasePoslist(
|
|
u8 bTreeEof = 0;
|
|
Fts3Expr *p; /* Used to iterate from pExpr to root */
|
|
Fts3Expr *pNear; /* Most senior NEAR ancestor (or pExpr) */
|
|
+ Fts3Expr *pRun; /* Closest non-deferred ancestor of pNear */
|
|
int bMatch;
|
|
|
|
- /* Check if this phrase descends from an OR expression node. If not,
|
|
- ** return NULL. Otherwise, the entry that corresponds to docid
|
|
+ /* Check if this phrase descends from an OR expression node. If not,
|
|
+ ** return NULL. Otherwise, the entry that corresponds to docid
|
|
** pCsr->iPrevId may lie earlier in the doclist buffer. Or, if the
|
|
** tree that the node is part of has been marked as EOF, but the node
|
|
** itself is not EOF, then it may point to an earlier entry. */
|
|
@@ -170841,22 +186168,30 @@ SQLITE_PRIVATE int sqlite3Fts3EvalPhrasePoslist(
|
|
if( p->bEof ) bTreeEof = 1;
|
|
}
|
|
if( bOr==0 ) return SQLITE_OK;
|
|
+ pRun = pNear;
|
|
+ while( pRun->bDeferred ){
|
|
+ assert( pRun->pParent );
|
|
+ pRun = pRun->pParent;
|
|
+ }
|
|
|
|
/* This is the descendent of an OR node. In this case we cannot use
|
|
** an incremental phrase. Load the entire doclist for the phrase
|
|
** into memory in this case. */
|
|
if( pPhrase->bIncr ){
|
|
- int bEofSave = pNear->bEof;
|
|
- fts3EvalRestart(pCsr, pNear, &rc);
|
|
- while( rc==SQLITE_OK && !pNear->bEof ){
|
|
- fts3EvalNextRow(pCsr, pNear, &rc);
|
|
- if( bEofSave==0 && pNear->iDocid==iDocid ) break;
|
|
+ int bEofSave = pRun->bEof;
|
|
+ fts3EvalRestart(pCsr, pRun, &rc);
|
|
+ while( rc==SQLITE_OK && !pRun->bEof ){
|
|
+ fts3EvalNextRow(pCsr, pRun, &rc);
|
|
+ if( bEofSave==0 && pRun->iDocid==iDocid ) break;
|
|
}
|
|
assert( rc!=SQLITE_OK || pPhrase->bIncr==0 );
|
|
+ if( rc==SQLITE_OK && pRun->bEof!=bEofSave ){
|
|
+ rc = FTS_CORRUPT_VTAB;
|
|
+ }
|
|
}
|
|
if( bTreeEof ){
|
|
- while( rc==SQLITE_OK && !pNear->bEof ){
|
|
- fts3EvalNextRow(pCsr, pNear, &rc);
|
|
+ while( rc==SQLITE_OK && !pRun->bEof ){
|
|
+ fts3EvalNextRow(pCsr, pRun, &rc);
|
|
}
|
|
}
|
|
if( rc!=SQLITE_OK ) return rc;
|
|
@@ -170878,7 +186213,7 @@ SQLITE_PRIVATE int sqlite3Fts3EvalPhrasePoslist(
|
|
(pIter >= (pPh->doclist.aAll + pPh->doclist.nAll));
|
|
while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)<0 ) && bEof==0 ){
|
|
sqlite3Fts3DoclistNext(
|
|
- bDescDoclist, pPh->doclist.aAll, pPh->doclist.nAll,
|
|
+ bDescDoclist, pPh->doclist.aAll, pPh->doclist.nAll,
|
|
&pIter, &iDocid, &bEof
|
|
);
|
|
}
|
|
@@ -170887,7 +186222,7 @@ SQLITE_PRIVATE int sqlite3Fts3EvalPhrasePoslist(
|
|
while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)>0 ) && bEof==0 ){
|
|
int dummy;
|
|
sqlite3Fts3DoclistPrev(
|
|
- bDescDoclist, pPh->doclist.aAll, pPh->doclist.nAll,
|
|
+ bDescDoclist, pPh->doclist.aAll, pPh->doclist.nAll,
|
|
&pIter, &iDocid, &dummy, &bEof
|
|
);
|
|
}
|
|
@@ -170963,7 +186298,7 @@ SQLITE_PRIVATE int sqlite3Fts3Corrupt(){
|
|
__declspec(dllexport)
|
|
#endif
|
|
SQLITE_API int sqlite3_fts3_init(
|
|
- sqlite3 *db,
|
|
+ sqlite3 *db,
|
|
char **pzErrMsg,
|
|
const sqlite3_api_routines *pApi
|
|
){
|
|
@@ -171057,11 +186392,11 @@ static int fts3auxConnectMethod(
|
|
*/
|
|
if( argc!=4 && argc!=5 ) goto bad_args;
|
|
|
|
- zDb = argv[1];
|
|
+ zDb = argv[1];
|
|
nDb = (int)strlen(zDb);
|
|
if( argc==5 ){
|
|
if( nDb==4 && 0==sqlite3_strnicmp("temp", zDb, 4) ){
|
|
- zDb = argv[3];
|
|
+ zDb = argv[3];
|
|
nDb = (int)strlen(zDb);
|
|
zFts3 = argv[4];
|
|
}else{
|
|
@@ -171125,7 +186460,7 @@ static int fts3auxDisconnectMethod(sqlite3_vtab *pVtab){
|
|
** xBestIndex - Analyze a WHERE and ORDER BY clause.
|
|
*/
|
|
static int fts3auxBestIndexMethod(
|
|
- sqlite3_vtab *pVTab,
|
|
+ sqlite3_vtab *pVTab,
|
|
sqlite3_index_info *pInfo
|
|
){
|
|
int i;
|
|
@@ -171138,14 +186473,14 @@ static int fts3auxBestIndexMethod(
|
|
UNUSED_PARAMETER(pVTab);
|
|
|
|
/* This vtab delivers always results in "ORDER BY term ASC" order. */
|
|
- if( pInfo->nOrderBy==1
|
|
- && pInfo->aOrderBy[0].iColumn==0
|
|
+ if( pInfo->nOrderBy==1
|
|
+ && pInfo->aOrderBy[0].iColumn==0
|
|
&& pInfo->aOrderBy[0].desc==0
|
|
){
|
|
pInfo->orderByConsumed = 1;
|
|
}
|
|
|
|
- /* Search for equality and range constraints on the "term" column.
|
|
+ /* Search for equality and range constraints on the "term" column.
|
|
** And equality constraints on the hidden "languageid" column. */
|
|
for(i=0; i<pInfo->nConstraint; i++){
|
|
if( pInfo->aConstraint[i].usable ){
|
|
@@ -171226,11 +186561,11 @@ static int fts3auxCloseMethod(sqlite3_vtab_cursor *pCursor){
|
|
static int fts3auxGrowStatArray(Fts3auxCursor *pCsr, int nSize){
|
|
if( nSize>pCsr->nStat ){
|
|
struct Fts3auxColstats *aNew;
|
|
- aNew = (struct Fts3auxColstats *)sqlite3_realloc64(pCsr->aStat,
|
|
+ aNew = (struct Fts3auxColstats *)sqlite3_realloc64(pCsr->aStat,
|
|
sizeof(struct Fts3auxColstats) * nSize
|
|
);
|
|
if( aNew==0 ) return SQLITE_NOMEM;
|
|
- memset(&aNew[pCsr->nStat], 0,
|
|
+ memset(&aNew[pCsr->nStat], 0,
|
|
sizeof(struct Fts3auxColstats) * (nSize - pCsr->nStat)
|
|
);
|
|
pCsr->aStat = aNew;
|
|
@@ -171275,6 +186610,7 @@ static int fts3auxNextMethod(sqlite3_vtab_cursor *pCursor){
|
|
if( fts3auxGrowStatArray(pCsr, 2) ) return SQLITE_NOMEM;
|
|
memset(pCsr->aStat, 0, sizeof(struct Fts3auxColstats) * pCsr->nStat);
|
|
iCol = 0;
|
|
+ rc = SQLITE_OK;
|
|
|
|
while( i<nDoclist ){
|
|
sqlite3_int64 v = 0;
|
|
@@ -171290,8 +186626,8 @@ static int fts3auxNextMethod(sqlite3_vtab_cursor *pCursor){
|
|
|
|
/* State 1. In this state we are expecting either a 1, indicating
|
|
** that the following integer will be a column number, or the
|
|
- ** start of a position list for column 0.
|
|
- **
|
|
+ ** start of a position list for column 0.
|
|
+ **
|
|
** The only difference between state 1 and state 2 is that if the
|
|
** integer encountered in state 1 is not 0 or 1, then we need to
|
|
** increment the column 0 "nDoc" count for this term.
|
|
@@ -171318,6 +186654,10 @@ static int fts3auxNextMethod(sqlite3_vtab_cursor *pCursor){
|
|
/* State 3. The integer just read is a column number. */
|
|
default: assert( eState==3 );
|
|
iCol = (int)v;
|
|
+ if( iCol<1 ){
|
|
+ rc = SQLITE_CORRUPT_VTAB;
|
|
+ break;
|
|
+ }
|
|
if( fts3auxGrowStatArray(pCsr, iCol+2) ) return SQLITE_NOMEM;
|
|
pCsr->aStat[iCol+1].nDoc++;
|
|
eState = 2;
|
|
@@ -171326,7 +186666,6 @@ static int fts3auxNextMethod(sqlite3_vtab_cursor *pCursor){
|
|
}
|
|
|
|
pCsr->iCol = 0;
|
|
- rc = SQLITE_OK;
|
|
}else{
|
|
pCsr->isEof = 1;
|
|
}
|
|
@@ -171384,6 +186723,7 @@ static int fts3auxFilterMethod(
|
|
sqlite3Fts3SegReaderFinish(&pCsr->csr);
|
|
sqlite3_free((void *)pCsr->filter.zTerm);
|
|
sqlite3_free(pCsr->aStat);
|
|
+ sqlite3_free(pCsr->zStop);
|
|
memset(&pCsr->csr, 0, ((u8*)&pCsr[1]) - (u8*)&pCsr->csr);
|
|
|
|
pCsr->filter.flags = FTS3_SEGMENT_REQUIRE_POS|FTS3_SEGMENT_IGNORE_EMPTY;
|
|
@@ -171404,7 +186744,7 @@ static int fts3auxFilterMethod(
|
|
if( pCsr->zStop==0 ) return SQLITE_NOMEM;
|
|
pCsr->nStop = (int)strlen(pCsr->zStop);
|
|
}
|
|
-
|
|
+
|
|
if( iLangid>=0 ){
|
|
iLangVal = sqlite3_value_int(apVal[iLangid]);
|
|
|
|
@@ -171543,15 +186883,15 @@ SQLITE_PRIVATE int sqlite3Fts3InitAux(sqlite3 *db){
|
|
******************************************************************************
|
|
**
|
|
** This module contains code that implements a parser for fts3 query strings
|
|
-** (the right-hand argument to the MATCH operator). Because the supported
|
|
+** (the right-hand argument to the MATCH operator). Because the supported
|
|
** syntax is relatively simple, the whole tokenizer/parser system is
|
|
-** hand-coded.
|
|
+** hand-coded.
|
|
*/
|
|
/* #include "fts3Int.h" */
|
|
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
|
|
|
|
/*
|
|
-** By default, this module parses the legacy syntax that has been
|
|
+** By default, this module parses the legacy syntax that has been
|
|
** traditionally used by fts3. Or, if SQLITE_ENABLE_FTS3_PARENTHESIS
|
|
** is defined, then it uses the new syntax. The differences between
|
|
** the new and the old syntaxes are:
|
|
@@ -171560,7 +186900,7 @@ SQLITE_PRIVATE int sqlite3Fts3InitAux(sqlite3 *db){
|
|
**
|
|
** b) The new syntax supports the AND and NOT operators. The old does not.
|
|
**
|
|
-** c) The old syntax supports the "-" token qualifier. This is not
|
|
+** c) The old syntax supports the "-" token qualifier. This is not
|
|
** supported by the new syntax (it is replaced by the NOT operator).
|
|
**
|
|
** d) When using the old syntax, the OR operator has a greater precedence
|
|
@@ -171569,7 +186909,7 @@ SQLITE_PRIVATE int sqlite3Fts3InitAux(sqlite3 *db){
|
|
**
|
|
** If compiled with SQLITE_TEST defined, then this module exports the
|
|
** symbol "int sqlite3_fts3_enable_parentheses". Setting this variable
|
|
-** to zero causes the module to use the old syntax. If it is set to
|
|
+** to zero causes the module to use the old syntax. If it is set to
|
|
** non-zero the new syntax is activated. This is so both syntaxes can
|
|
** be tested using a single build of testfixture.
|
|
**
|
|
@@ -171598,7 +186938,7 @@ SQLITE_PRIVATE int sqlite3Fts3InitAux(sqlite3 *db){
|
|
#ifdef SQLITE_TEST
|
|
SQLITE_API int sqlite3_fts3_enable_parentheses = 0;
|
|
#else
|
|
-# ifdef SQLITE_ENABLE_FTS3_PARENTHESIS
|
|
+# ifdef SQLITE_ENABLE_FTS3_PARENTHESIS
|
|
# define sqlite3_fts3_enable_parentheses 1
|
|
# else
|
|
# define sqlite3_fts3_enable_parentheses 0
|
|
@@ -171616,7 +186956,7 @@ SQLITE_API int sqlite3_fts3_enable_parentheses = 0;
|
|
/*
|
|
** isNot:
|
|
** This variable is used by function getNextNode(). When getNextNode() is
|
|
-** called, it sets ParseContext.isNot to true if the 'next node' is a
|
|
+** called, it sets ParseContext.isNot to true if the 'next node' is a
|
|
** FTSQUERY_PHRASE with a unary "-" attached to it. i.e. "mysql" in the
|
|
** FTS3 query "sqlite -mysql". Otherwise, ParseContext.isNot is set to
|
|
** zero.
|
|
@@ -171635,7 +186975,7 @@ struct ParseContext {
|
|
};
|
|
|
|
/*
|
|
-** This function is equivalent to the standard isspace() function.
|
|
+** This function is equivalent to the standard isspace() function.
|
|
**
|
|
** The standard isspace() can be awkward to use safely, because although it
|
|
** is defined to accept an argument of type int, its behavior when passed
|
|
@@ -171651,10 +186991,10 @@ static int fts3isspace(char c){
|
|
|
|
/*
|
|
** Allocate nByte bytes of memory using sqlite3_malloc(). If successful,
|
|
-** zero the memory before returning a pointer to it. If unsuccessful,
|
|
+** zero the memory before returning a pointer to it. If unsuccessful,
|
|
** return NULL.
|
|
*/
|
|
-static void *fts3MallocZero(sqlite3_int64 nByte){
|
|
+SQLITE_PRIVATE void *sqlite3Fts3MallocZero(sqlite3_int64 nByte){
|
|
void *pRet = sqlite3_malloc64(nByte);
|
|
if( pRet ) memset(pRet, 0, nByte);
|
|
return pRet;
|
|
@@ -171699,7 +187039,7 @@ static int fts3ExprParse(ParseContext *, const char *, int, Fts3Expr **, int *);
|
|
** structure of type FTSQUERY_PHRASE containing a phrase consisting of this
|
|
** single token and set *ppExpr to point to it. If the end of the buffer is
|
|
** reached before a token is found, set *ppExpr to zero. It is the
|
|
-** responsibility of the caller to eventually deallocate the allocated
|
|
+** responsibility of the caller to eventually deallocate the allocated
|
|
** Fts3Expr structure (if any) by passing it to sqlite3_free().
|
|
**
|
|
** Return SQLITE_OK if successful, or SQLITE_NOMEM if a memory allocation
|
|
@@ -171735,7 +187075,7 @@ static int getNextToken(
|
|
rc = pModule->xNext(pCursor, &zToken, &nToken, &iStart, &iEnd, &iPosition);
|
|
if( rc==SQLITE_OK ){
|
|
nByte = sizeof(Fts3Expr) + sizeof(Fts3Phrase) + nToken;
|
|
- pRet = (Fts3Expr *)fts3MallocZero(nByte);
|
|
+ pRet = (Fts3Expr *)sqlite3Fts3MallocZero(nByte);
|
|
if( !pRet ){
|
|
rc = SQLITE_NOMEM;
|
|
}else{
|
|
@@ -171753,8 +187093,8 @@ static int getNextToken(
|
|
}
|
|
|
|
while( 1 ){
|
|
- if( !sqlite3_fts3_enable_parentheses
|
|
- && iStart>0 && z[iStart-1]=='-'
|
|
+ if( !sqlite3_fts3_enable_parentheses
|
|
+ && iStart>0 && z[iStart-1]=='-'
|
|
){
|
|
pParse->isNot = 1;
|
|
iStart--;
|
|
@@ -171774,7 +187114,7 @@ static int getNextToken(
|
|
|
|
pModule->xClose(pCursor);
|
|
}
|
|
-
|
|
+
|
|
*ppExpr = pRet;
|
|
return rc;
|
|
}
|
|
@@ -171796,7 +187136,7 @@ static void *fts3ReallocOrFree(void *pOrig, sqlite3_int64 nNew){
|
|
** Buffer zInput, length nInput, contains the contents of a quoted string
|
|
** that appeared as part of an fts3 query expression. Neither quote character
|
|
** is included in the buffer. This function attempts to tokenize the entire
|
|
-** input buffer and create an Fts3Expr structure of type FTSQUERY_PHRASE
|
|
+** input buffer and create an Fts3Expr structure of type FTSQUERY_PHRASE
|
|
** containing the results.
|
|
**
|
|
** If successful, SQLITE_OK is returned and *ppExpr set to point at the
|
|
@@ -171821,7 +187161,7 @@ static int getNextString(
|
|
int nToken = 0;
|
|
|
|
/* The final Fts3Expr data structure, including the Fts3Phrase,
|
|
- ** Fts3PhraseToken structures token buffers are all stored as a single
|
|
+ ** Fts3PhraseToken structures token buffers are all stored as a single
|
|
** allocation so that the expression can be freed with a single call to
|
|
** sqlite3_free(). Setting this up requires a two pass approach.
|
|
**
|
|
@@ -171830,7 +187170,7 @@ static int getNextString(
|
|
** to assemble data in two dynamic buffers:
|
|
**
|
|
** Buffer p: Points to the Fts3Expr structure, followed by the Fts3Phrase
|
|
- ** structure, followed by the array of Fts3PhraseToken
|
|
+ ** structure, followed by the array of Fts3PhraseToken
|
|
** structures. This pass only populates the Fts3PhraseToken array.
|
|
**
|
|
** Buffer zTemp: Contains copies of all tokens.
|
|
@@ -171915,7 +187255,7 @@ static int getNextString(
|
|
}
|
|
|
|
/*
|
|
-** The output variable *ppExpr is populated with an allocated Fts3Expr
|
|
+** The output variable *ppExpr is populated with an allocated Fts3Expr
|
|
** structure, or set to 0 if the end of the input buffer is reached.
|
|
**
|
|
** Returns an SQLite error code. SQLITE_OK if everything works, SQLITE_NOMEM
|
|
@@ -171951,7 +187291,7 @@ static int getNextNode(
|
|
pParse->isNot = 0;
|
|
|
|
/* Skip over any whitespace before checking for a keyword, an open or
|
|
- ** close bracket, or a quoted string.
|
|
+ ** close bracket, or a quoted string.
|
|
*/
|
|
while( nInput>0 && fts3isspace(*zInput) ){
|
|
nInput--;
|
|
@@ -171978,22 +187318,19 @@ static int getNextNode(
|
|
if( pKey->eType==FTSQUERY_NEAR ){
|
|
assert( nKey==4 );
|
|
if( zInput[4]=='/' && zInput[5]>='0' && zInput[5]<='9' ){
|
|
- nNear = 0;
|
|
- for(nKey=5; zInput[nKey]>='0' && zInput[nKey]<='9'; nKey++){
|
|
- nNear = nNear * 10 + (zInput[nKey] - '0');
|
|
- }
|
|
+ nKey += 1+sqlite3Fts3ReadInt(&zInput[nKey+1], &nNear);
|
|
}
|
|
}
|
|
|
|
/* At this point this is probably a keyword. But for that to be true,
|
|
** the next byte must contain either whitespace, an open or close
|
|
- ** parenthesis, a quote character, or EOF.
|
|
+ ** parenthesis, a quote character, or EOF.
|
|
*/
|
|
cNext = zInput[nKey];
|
|
- if( fts3isspace(cNext)
|
|
+ if( fts3isspace(cNext)
|
|
|| cNext=='"' || cNext=='(' || cNext==')' || cNext==0
|
|
){
|
|
- pRet = (Fts3Expr *)fts3MallocZero(sizeof(Fts3Expr));
|
|
+ pRet = (Fts3Expr *)sqlite3Fts3MallocZero(sizeof(Fts3Expr));
|
|
if( !pRet ){
|
|
return SQLITE_NOMEM;
|
|
}
|
|
@@ -172028,6 +187365,11 @@ static int getNextNode(
|
|
if( *zInput=='(' ){
|
|
int nConsumed = 0;
|
|
pParse->nNest++;
|
|
+#if !defined(SQLITE_MAX_EXPR_DEPTH)
|
|
+ if( pParse->nNest>1000 ) return SQLITE_ERROR;
|
|
+#elif SQLITE_MAX_EXPR_DEPTH>0
|
|
+ if( pParse->nNest>SQLITE_MAX_EXPR_DEPTH ) return SQLITE_ERROR;
|
|
+#endif
|
|
rc = fts3ExprParse(pParse, zInput+1, nInput-1, ppExpr, &nConsumed);
|
|
*pnConsumed = (int)(zInput - z) + 1 + nConsumed;
|
|
return rc;
|
|
@@ -172039,15 +187381,15 @@ static int getNextNode(
|
|
}
|
|
}
|
|
|
|
- /* If control flows to this point, this must be a regular token, or
|
|
+ /* If control flows to this point, this must be a regular token, or
|
|
** the end of the input. Read a regular token using the sqlite3_tokenizer
|
|
** interface. Before doing so, figure out if there is an explicit
|
|
- ** column specifier for the token.
|
|
+ ** column specifier for the token.
|
|
**
|
|
** TODO: Strangely, it is not possible to associate a column specifier
|
|
** with a quoted phrase, only with a single token. Not sure if this was
|
|
** an implementation artifact or an intentional decision when fts3 was
|
|
- ** first implemented. Whichever it was, this module duplicates the
|
|
+ ** first implemented. Whichever it was, this module duplicates the
|
|
** limitation.
|
|
*/
|
|
iCol = pParse->iDefaultCol;
|
|
@@ -172055,8 +187397,8 @@ static int getNextNode(
|
|
for(ii=0; ii<pParse->nCol; ii++){
|
|
const char *zStr = pParse->azCol[ii];
|
|
int nStr = (int)strlen(zStr);
|
|
- if( nInput>nStr && zInput[nStr]==':'
|
|
- && sqlite3_strnicmp(zStr, zInput, nStr)==0
|
|
+ if( nInput>nStr && zInput[nStr]==':'
|
|
+ && sqlite3_strnicmp(zStr, zInput, nStr)==0
|
|
){
|
|
iCol = ii;
|
|
iColLen = (int)((zInput - z) + nStr + 1);
|
|
@@ -172101,7 +187443,7 @@ static int opPrecedence(Fts3Expr *p){
|
|
}
|
|
|
|
/*
|
|
-** Argument ppHead contains a pointer to the current head of a query
|
|
+** Argument ppHead contains a pointer to the current head of a query
|
|
** expression tree being parsed. pPrev is the expression node most recently
|
|
** inserted into the tree. This function adds pNew, which is always a binary
|
|
** operator node, into the expression tree based on the relative precedence
|
|
@@ -172131,7 +187473,7 @@ static void insertBinaryOperator(
|
|
|
|
/*
|
|
** Parse the fts3 query expression found in buffer z, length n. This function
|
|
-** returns either when the end of the buffer is reached or an unmatched
|
|
+** returns either when the end of the buffer is reached or an unmatched
|
|
** closing bracket - ')' - is encountered.
|
|
**
|
|
** If successful, SQLITE_OK is returned, *ppExpr is set to point to the
|
|
@@ -172163,11 +187505,11 @@ static int fts3ExprParse(
|
|
if( p ){
|
|
int isPhrase;
|
|
|
|
- if( !sqlite3_fts3_enable_parentheses
|
|
- && p->eType==FTSQUERY_PHRASE && pParse->isNot
|
|
+ if( !sqlite3_fts3_enable_parentheses
|
|
+ && p->eType==FTSQUERY_PHRASE && pParse->isNot
|
|
){
|
|
/* Create an implicit NOT operator. */
|
|
- Fts3Expr *pNot = fts3MallocZero(sizeof(Fts3Expr));
|
|
+ Fts3Expr *pNot = sqlite3Fts3MallocZero(sizeof(Fts3Expr));
|
|
if( !pNot ){
|
|
sqlite3Fts3ExprFree(p);
|
|
rc = SQLITE_NOMEM;
|
|
@@ -172201,7 +187543,7 @@ static int fts3ExprParse(
|
|
/* Insert an implicit AND operator. */
|
|
Fts3Expr *pAnd;
|
|
assert( pRet && pPrev );
|
|
- pAnd = fts3MallocZero(sizeof(Fts3Expr));
|
|
+ pAnd = sqlite3Fts3MallocZero(sizeof(Fts3Expr));
|
|
if( !pAnd ){
|
|
sqlite3Fts3ExprFree(p);
|
|
rc = SQLITE_NOMEM;
|
|
@@ -172285,13 +187627,13 @@ static int fts3ExprParse(
|
|
}
|
|
|
|
/*
|
|
-** Return SQLITE_ERROR if the maximum depth of the expression tree passed
|
|
+** Return SQLITE_ERROR if the maximum depth of the expression tree passed
|
|
** as the only argument is more than nMaxDepth.
|
|
*/
|
|
static int fts3ExprCheckDepth(Fts3Expr *p, int nMaxDepth){
|
|
int rc = SQLITE_OK;
|
|
if( p ){
|
|
- if( nMaxDepth<0 ){
|
|
+ if( nMaxDepth<0 ){
|
|
rc = SQLITE_TOOBIG;
|
|
}else{
|
|
rc = fts3ExprCheckDepth(p->pLeft, nMaxDepth-1);
|
|
@@ -172306,12 +187648,12 @@ static int fts3ExprCheckDepth(Fts3Expr *p, int nMaxDepth){
|
|
/*
|
|
** This function attempts to transform the expression tree at (*pp) to
|
|
** an equivalent but more balanced form. The tree is modified in place.
|
|
-** If successful, SQLITE_OK is returned and (*pp) set to point to the
|
|
-** new root expression node.
|
|
+** If successful, SQLITE_OK is returned and (*pp) set to point to the
|
|
+** new root expression node.
|
|
**
|
|
** nMaxDepth is the maximum allowable depth of the balanced sub-tree.
|
|
**
|
|
-** Otherwise, if an error occurs, an SQLite error code is returned and
|
|
+** Otherwise, if an error occurs, an SQLite error code is returned and
|
|
** expression (*pp) freed.
|
|
*/
|
|
static int fts3ExprBalance(Fts3Expr **pp, int nMaxDepth){
|
|
@@ -172426,7 +187768,7 @@ static int fts3ExprBalance(Fts3Expr **pp, int nMaxDepth){
|
|
}
|
|
pRoot = p;
|
|
}else{
|
|
- /* An error occurred. Delete the contents of the apLeaf[] array
|
|
+ /* An error occurred. Delete the contents of the apLeaf[] array
|
|
** and pFree list. Everything else is cleaned up by the call to
|
|
** sqlite3Fts3ExprFree(pRoot) below. */
|
|
Fts3Expr *pDel;
|
|
@@ -172468,7 +187810,7 @@ static int fts3ExprBalance(Fts3Expr **pp, int nMaxDepth){
|
|
}
|
|
}
|
|
}
|
|
-
|
|
+
|
|
if( rc!=SQLITE_OK ){
|
|
sqlite3Fts3ExprFree(pRoot);
|
|
pRoot = 0;
|
|
@@ -172482,9 +187824,9 @@ static int fts3ExprBalance(Fts3Expr **pp, int nMaxDepth){
|
|
** differences:
|
|
**
|
|
** 1. It does not do expression rebalancing.
|
|
-** 2. It does not check that the expression does not exceed the
|
|
+** 2. It does not check that the expression does not exceed the
|
|
** maximum allowable depth.
|
|
-** 3. Even if it fails, *ppExpr may still be set to point to an
|
|
+** 3. Even if it fails, *ppExpr may still be set to point to an
|
|
** expression tree. It should be deleted using sqlite3Fts3ExprFree()
|
|
** in this case.
|
|
*/
|
|
@@ -172523,7 +187865,7 @@ static int fts3ExprParseUnbalanced(
|
|
if( rc==SQLITE_OK && sParse.nNest ){
|
|
rc = SQLITE_ERROR;
|
|
}
|
|
-
|
|
+
|
|
return rc;
|
|
}
|
|
|
|
@@ -172542,7 +187884,7 @@ static int fts3ExprParseUnbalanced(
|
|
** The first parameter, pTokenizer, is passed the fts3 tokenizer module to
|
|
** use to normalize query tokens while parsing the expression. The azCol[]
|
|
** array, which is assumed to contain nCol entries, should contain the names
|
|
-** of each column in the target fts3 table, in order from left to right.
|
|
+** of each column in the target fts3 table, in order from left to right.
|
|
** Column names must be nul-terminated strings.
|
|
**
|
|
** The iDefaultCol parameter should be passed the index of the table column
|
|
@@ -172565,7 +187907,7 @@ SQLITE_PRIVATE int sqlite3Fts3ExprParse(
|
|
int rc = fts3ExprParseUnbalanced(
|
|
pTokenizer, iLangid, azCol, bFts4, nCol, iDefaultCol, z, n, ppExpr
|
|
);
|
|
-
|
|
+
|
|
/* Rebalance the expression. And check that its depth does not exceed
|
|
** SQLITE_FTS3_MAX_EXPR_DEPTH. */
|
|
if( rc==SQLITE_OK && *ppExpr ){
|
|
@@ -172580,7 +187922,7 @@ SQLITE_PRIVATE int sqlite3Fts3ExprParse(
|
|
*ppExpr = 0;
|
|
if( rc==SQLITE_TOOBIG ){
|
|
sqlite3Fts3ErrMsg(pzErr,
|
|
- "FTS expression tree is too large (maximum depth %d)",
|
|
+ "FTS expression tree is too large (maximum depth %d)",
|
|
SQLITE_FTS3_MAX_EXPR_DEPTH
|
|
);
|
|
rc = SQLITE_ERROR;
|
|
@@ -172642,11 +187984,11 @@ SQLITE_PRIVATE void sqlite3Fts3ExprFree(Fts3Expr *pDel){
|
|
/*
|
|
** Return a pointer to a buffer containing a text representation of the
|
|
** expression passed as the first argument. The buffer is obtained from
|
|
-** sqlite3_malloc(). It is the responsibility of the caller to use
|
|
+** sqlite3_malloc(). It is the responsibility of the caller to use
|
|
** sqlite3_free() to release the memory. If an OOM condition is encountered,
|
|
** NULL is returned.
|
|
**
|
|
-** If the second argument is not NULL, then its contents are prepended to
|
|
+** If the second argument is not NULL, then its contents are prepended to
|
|
** the returned expression text and then freed using sqlite3_free().
|
|
*/
|
|
static char *exprToString(Fts3Expr *pExpr, char *zBuf){
|
|
@@ -172660,7 +188002,7 @@ static char *exprToString(Fts3Expr *pExpr, char *zBuf){
|
|
zBuf = sqlite3_mprintf(
|
|
"%zPHRASE %d 0", zBuf, pPhrase->iColumn);
|
|
for(i=0; zBuf && i<pPhrase->nToken; i++){
|
|
- zBuf = sqlite3_mprintf("%z %.*s%s", zBuf,
|
|
+ zBuf = sqlite3_mprintf("%z %.*s%s", zBuf,
|
|
pPhrase->aToken[i].n, pPhrase->aToken[i].z,
|
|
(pPhrase->aToken[i].isPrefix?"+":"")
|
|
);
|
|
@@ -172693,7 +188035,7 @@ static char *exprToString(Fts3Expr *pExpr, char *zBuf){
|
|
}
|
|
|
|
/*
|
|
-** This is the implementation of a scalar SQL function used to test the
|
|
+** This is the implementation of a scalar SQL function used to test the
|
|
** expression parser. It should be called as follows:
|
|
**
|
|
** fts3_exprtest(<tokenizer>, <expr>, <column 1>, ...);
|
|
@@ -172726,7 +188068,7 @@ static void fts3ExprTestCommon(
|
|
char *zErr = 0;
|
|
|
|
if( argc<3 ){
|
|
- sqlite3_result_error(context,
|
|
+ sqlite3_result_error(context,
|
|
"Usage: fts3_exprtest(tokenizer, expr, col1, ...", -1
|
|
);
|
|
return;
|
|
@@ -172804,15 +188146,15 @@ static void fts3ExprTestRebalance(
|
|
}
|
|
|
|
/*
|
|
-** Register the query expression parser test function fts3_exprtest()
|
|
-** with database connection db.
|
|
+** Register the query expression parser test function fts3_exprtest()
|
|
+** with database connection db.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3Fts3ExprInitTestInterface(sqlite3 *db, Fts3Hash *pHash){
|
|
int rc = sqlite3_create_function(
|
|
db, "fts3_exprtest", -1, SQLITE_UTF8, (void*)pHash, fts3ExprTest, 0, 0
|
|
);
|
|
if( rc==SQLITE_OK ){
|
|
- rc = sqlite3_create_function(db, "fts3_exprtest_rebalance",
|
|
+ rc = sqlite3_create_function(db, "fts3_exprtest_rebalance",
|
|
-1, SQLITE_UTF8, (void*)pHash, fts3ExprTestRebalance, 0, 0
|
|
);
|
|
}
|
|
@@ -172876,8 +188218,8 @@ static void fts3HashFree(void *p){
|
|
** fields of the Hash structure.
|
|
**
|
|
** "pNew" is a pointer to the hash table that is to be initialized.
|
|
-** keyClass is one of the constants
|
|
-** FTS3_HASH_BINARY or FTS3_HASH_STRING. The value of keyClass
|
|
+** keyClass is one of the constants
|
|
+** FTS3_HASH_BINARY or FTS3_HASH_STRING. The value of keyClass
|
|
** determines what kind of key the hash table will use. "copyKey" is
|
|
** true if the hash table should make its own private copy of keys and
|
|
** false if it should just use the supplied pointer.
|
|
@@ -172954,7 +188296,7 @@ static int fts3BinCompare(const void *pKey1, int n1, const void *pKey2, int n2){
|
|
/*
|
|
** Return a pointer to the appropriate hash function given the key class.
|
|
**
|
|
-** The C syntax in this function definition may be unfamilar to some
|
|
+** The C syntax in this function definition may be unfamilar to some
|
|
** programmers, so we provide the following additional explanation:
|
|
**
|
|
** The name of the function is "ftsHashFunction". The function takes a
|
|
@@ -173014,7 +188356,7 @@ static void fts3HashInsertElement(
|
|
|
|
|
|
/* Resize the hash table so that it cantains "new_size" buckets.
|
|
-** "new_size" must be a power of 2. The hash table might fail
|
|
+** "new_size" must be a power of 2. The hash table might fail
|
|
** to resize if sqliteMalloc() fails.
|
|
**
|
|
** Return non-zero if a memory allocation error occurs.
|
|
@@ -173059,7 +188401,7 @@ static Fts3HashElem *fts3FindElementByHash(
|
|
count = pEntry->count;
|
|
xCompare = ftsCompareFunction(pH->keyClass);
|
|
while( count-- && elem ){
|
|
- if( (*xCompare)(elem->pKey,elem->nKey,pKey,nKey)==0 ){
|
|
+ if( (*xCompare)(elem->pKey,elem->nKey,pKey,nKey)==0 ){
|
|
return elem;
|
|
}
|
|
elem = elem->next;
|
|
@@ -173078,7 +188420,7 @@ static void fts3RemoveElementByHash(
|
|
){
|
|
struct _fts3ht *pEntry;
|
|
if( elem->prev ){
|
|
- elem->prev->next = elem->next;
|
|
+ elem->prev->next = elem->next;
|
|
}else{
|
|
pH->first = elem->next;
|
|
}
|
|
@@ -173106,8 +188448,8 @@ static void fts3RemoveElementByHash(
|
|
}
|
|
|
|
SQLITE_PRIVATE Fts3HashElem *sqlite3Fts3HashFindElem(
|
|
- const Fts3Hash *pH,
|
|
- const void *pKey,
|
|
+ const Fts3Hash *pH,
|
|
+ const void *pKey,
|
|
int nKey
|
|
){
|
|
int h; /* A hash on key */
|
|
@@ -173121,7 +188463,7 @@ SQLITE_PRIVATE Fts3HashElem *sqlite3Fts3HashFindElem(
|
|
return fts3FindElementByHash(pH,pKey,nKey, h & (pH->htsize-1));
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** Attempt to locate an element of the hash table pH with a key
|
|
** that matches pKey,nKey. Return the data for this element if it is
|
|
** found, or NULL if there is no match.
|
|
@@ -173295,7 +188637,7 @@ static int porterDestroy(sqlite3_tokenizer *pTokenizer){
|
|
/*
|
|
** Prepare to begin tokenizing a particular string. The input
|
|
** string to be tokenized is zInput[0..nInput-1]. A cursor
|
|
-** used to incrementally tokenize this string is returned in
|
|
+** used to incrementally tokenize this string is returned in
|
|
** *ppCursor.
|
|
*/
|
|
static int porterOpen(
|
|
@@ -173348,7 +188690,7 @@ static const char cType[] = {
|
|
/*
|
|
** isConsonant() and isVowel() determine if their first character in
|
|
** the string they point to is a consonant or a vowel, according
|
|
-** to Porter ruls.
|
|
+** to Porter ruls.
|
|
**
|
|
** A consonate is any letter other than 'a', 'e', 'i', 'o', or 'u'.
|
|
** 'Y' is a consonant unless it follows another consonant,
|
|
@@ -173468,11 +188810,11 @@ static int star_oh(const char *z){
|
|
|
|
/*
|
|
** If the word ends with zFrom and xCond() is true for the stem
|
|
-** of the word that preceeds the zFrom ending, then change the
|
|
+** of the word that preceeds the zFrom ending, then change the
|
|
** ending to zTo.
|
|
**
|
|
** The input word *pz and zFrom are both in reverse order. zTo
|
|
-** is in normal order.
|
|
+** is in normal order.
|
|
**
|
|
** Return TRUE if zFrom matches. Return FALSE if zFrom does not
|
|
** match. Not that TRUE is returned even if xCond() fails and
|
|
@@ -173541,9 +188883,9 @@ static void copy_stemmer(const char *zIn, int nIn, char *zOut, int *pnOut){
|
|
** word contains digits, 3 bytes are taken from the beginning and
|
|
** 3 bytes from the end. For long words without digits, 10 bytes
|
|
** are taken from each end. US-ASCII case folding still applies.
|
|
-**
|
|
-** If the input word contains not digits but does characters not
|
|
-** in [a-zA-Z] then no stemming is attempted and this routine just
|
|
+**
|
|
+** If the input word contains not digits but does characters not
|
|
+** in [a-zA-Z] then no stemming is attempted and this routine just
|
|
** copies the input into the input into the output with US-ASCII
|
|
** case folding.
|
|
**
|
|
@@ -173588,11 +188930,11 @@ static void porter_stemmer(const char *zIn, int nIn, char *zOut, int *pnOut){
|
|
}
|
|
}
|
|
|
|
- /* Step 1b */
|
|
+ /* Step 1b */
|
|
z2 = z;
|
|
if( stem(&z, "dee", "ee", m_gt_0) ){
|
|
/* Do nothing. The work was all in the test */
|
|
- }else if(
|
|
+ }else if(
|
|
(stem(&z, "gni", "", hasVowel) || stem(&z, "de", "", hasVowel))
|
|
&& z!=z2
|
|
){
|
|
@@ -173631,7 +188973,7 @@ static void porter_stemmer(const char *zIn, int nIn, char *zOut, int *pnOut){
|
|
stem(&z, "igol", "log", m_gt_0);
|
|
break;
|
|
case 'l':
|
|
- if( !stem(&z, "ilb", "ble", m_gt_0)
|
|
+ if( !stem(&z, "ilb", "ble", m_gt_0)
|
|
&& !stem(&z, "illa", "al", m_gt_0)
|
|
&& !stem(&z, "iltne", "ent", m_gt_0)
|
|
&& !stem(&z, "ile", "e", m_gt_0)
|
|
@@ -173833,7 +189175,7 @@ static int porterNext(
|
|
if( n>c->nAllocated ){
|
|
char *pNew;
|
|
c->nAllocated = n+20;
|
|
- pNew = sqlite3_realloc(c->zToken, c->nAllocated);
|
|
+ pNew = sqlite3_realloc64(c->zToken, c->nAllocated);
|
|
if( !pNew ) return SQLITE_NOMEM;
|
|
c->zToken = pNew;
|
|
}
|
|
@@ -173919,7 +189261,7 @@ static int fts3TokenizerEnabled(sqlite3_context *context){
|
|
}
|
|
|
|
/*
|
|
-** Implementation of the SQL scalar function for accessing the underlying
|
|
+** Implementation of the SQL scalar function for accessing the underlying
|
|
** hash table. This function may be called as follows:
|
|
**
|
|
** SELECT <function-name>(<key-name>);
|
|
@@ -174091,7 +189433,7 @@ SQLITE_PRIVATE int sqlite3Fts3InitTokenizer(
|
|
if( rc!=SQLITE_OK ){
|
|
sqlite3Fts3ErrMsg(pzErr, "unknown tokenizer");
|
|
}else{
|
|
- (*ppTok)->pModule = m;
|
|
+ (*ppTok)->pModule = m;
|
|
}
|
|
sqlite3_free((void *)aArg);
|
|
}
|
|
@@ -174111,7 +189453,7 @@ SQLITE_PRIVATE int sqlite3Fts3InitTokenizer(
|
|
/* #include <string.h> */
|
|
|
|
/*
|
|
-** Implementation of a special SQL scalar function for testing tokenizers
|
|
+** Implementation of a special SQL scalar function for testing tokenizers
|
|
** designed to be used in concert with the Tcl testing framework. This
|
|
** function must be called with two or more arguments:
|
|
**
|
|
@@ -174123,9 +189465,9 @@ SQLITE_PRIVATE int sqlite3Fts3InitTokenizer(
|
|
**
|
|
** The return value is a string that may be interpreted as a Tcl
|
|
** list. For each token in the <input-string>, three elements are
|
|
-** added to the returned list. The first is the token position, the
|
|
+** added to the returned list. The first is the token position, the
|
|
** second is the token text (folded, stemmed, etc.) and the third is the
|
|
-** substring of <input-string> associated with the token. For example,
|
|
+** substring of <input-string> associated with the token. For example,
|
|
** using the built-in "simple" tokenizer:
|
|
**
|
|
** SELECT fts_tokenizer_test('simple', 'I don't see how');
|
|
@@ -174133,7 +189475,7 @@ SQLITE_PRIVATE int sqlite3Fts3InitTokenizer(
|
|
** will return the string:
|
|
**
|
|
** "{0 i I 1 dont don't 2 see see 3 how how}"
|
|
-**
|
|
+**
|
|
*/
|
|
static void testFunc(
|
|
sqlite3_context *context,
|
|
@@ -174228,8 +189570,8 @@ static void testFunc(
|
|
|
|
static
|
|
int registerTokenizer(
|
|
- sqlite3 *db,
|
|
- char *zName,
|
|
+ sqlite3 *db,
|
|
+ char *zName,
|
|
const sqlite3_tokenizer_module *p
|
|
){
|
|
int rc;
|
|
@@ -174251,8 +189593,8 @@ int registerTokenizer(
|
|
|
|
static
|
|
int queryTokenizer(
|
|
- sqlite3 *db,
|
|
- char *zName,
|
|
+ sqlite3 *db,
|
|
+ char *zName,
|
|
const sqlite3_tokenizer_module **pp
|
|
){
|
|
int rc;
|
|
@@ -174337,23 +189679,23 @@ static void intTestFunc(
|
|
/*
|
|
** Set up SQL objects in database db used to access the contents of
|
|
** the hash table pointed to by argument pHash. The hash table must
|
|
-** been initialized to use string keys, and to take a private copy
|
|
+** been initialized to use string keys, and to take a private copy
|
|
** of the key when a value is inserted. i.e. by a call similar to:
|
|
**
|
|
** sqlite3Fts3HashInit(pHash, FTS3_HASH_STRING, 1);
|
|
**
|
|
** This function adds a scalar function (see header comment above
|
|
** fts3TokenizerFunc() in this file for details) and, if ENABLE_TABLE is
|
|
-** defined at compilation time, a temporary virtual table (see header
|
|
-** comment above struct HashTableVtab) to the database schema. Both
|
|
+** defined at compilation time, a temporary virtual table (see header
|
|
+** comment above struct HashTableVtab) to the database schema. Both
|
|
** provide read/write access to the contents of *pHash.
|
|
**
|
|
** The third argument to this function, zName, is used as the name
|
|
** of both the scalar and, if created, the virtual table.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3Fts3InitHashTable(
|
|
- sqlite3 *db,
|
|
- Fts3Hash *pHash,
|
|
+ sqlite3 *db,
|
|
+ Fts3Hash *pHash,
|
|
const char *zName
|
|
){
|
|
int rc = SQLITE_OK;
|
|
@@ -174507,7 +189849,7 @@ static int simpleDestroy(sqlite3_tokenizer *pTokenizer){
|
|
/*
|
|
** Prepare to begin tokenizing a particular string. The input
|
|
** string to be tokenized is pInput[0..nBytes-1]. A cursor
|
|
-** used to incrementally tokenize this string is returned in
|
|
+** used to incrementally tokenize this string is returned in
|
|
** *ppCursor.
|
|
*/
|
|
static int simpleOpen(
|
|
@@ -174585,7 +189927,7 @@ static int simpleNext(
|
|
if( n>c->nTokenAllocated ){
|
|
char *pNew;
|
|
c->nTokenAllocated = n+20;
|
|
- pNew = sqlite3_realloc(c->pToken, c->nTokenAllocated);
|
|
+ pNew = sqlite3_realloc64(c->pToken, c->nTokenAllocated);
|
|
if( !pNew ) return SQLITE_NOMEM;
|
|
c->pToken = pNew;
|
|
}
|
|
@@ -174662,8 +190004,8 @@ SQLITE_PRIVATE void sqlite3Fts3SimpleTokenizerModule(
|
|
**
|
|
** input = <string>
|
|
**
|
|
-** The virtual table module tokenizes this <string>, using the FTS3
|
|
-** tokenizer specified by the arguments to the CREATE VIRTUAL TABLE
|
|
+** The virtual table module tokenizes this <string>, using the FTS3
|
|
+** tokenizer specified by the arguments to the CREATE VIRTUAL TABLE
|
|
** statement and returns one row for each token in the result. With
|
|
** fields set as follows:
|
|
**
|
|
@@ -174732,7 +190074,7 @@ static int fts3tokQueryTokenizer(
|
|
|
|
/*
|
|
** The second argument, argv[], is an array of pointers to nul-terminated
|
|
-** strings. This function makes a copy of the array and strings into a
|
|
+** strings. This function makes a copy of the array and strings into a
|
|
** single block of memory. It then dequotes any of the strings that appear
|
|
** to be quoted.
|
|
**
|
|
@@ -174788,7 +190130,7 @@ static int fts3tokDequoteArray(
|
|
** and xCreate are identical operations.
|
|
**
|
|
** argv[0]: module name
|
|
-** argv[1]: database name
|
|
+** argv[1]: database name
|
|
** argv[2]: table name
|
|
** argv[3]: first argument (tokenizer name)
|
|
*/
|
|
@@ -174825,7 +190167,8 @@ static int fts3tokConnectMethod(
|
|
|
|
assert( (rc==SQLITE_OK)==(pMod!=0) );
|
|
if( rc==SQLITE_OK ){
|
|
- const char * const *azArg = (const char * const *)&azDequote[1];
|
|
+ const char * const *azArg = 0;
|
|
+ if( nDequote>1 ) azArg = (const char * const *)&azDequote[1];
|
|
rc = pMod->xCreate((nDequote>1 ? nDequote-1 : 0), azArg, &pTok);
|
|
}
|
|
|
|
@@ -174868,16 +190211,16 @@ static int fts3tokDisconnectMethod(sqlite3_vtab *pVtab){
|
|
** xBestIndex - Analyze a WHERE and ORDER BY clause.
|
|
*/
|
|
static int fts3tokBestIndexMethod(
|
|
- sqlite3_vtab *pVTab,
|
|
+ sqlite3_vtab *pVTab,
|
|
sqlite3_index_info *pInfo
|
|
){
|
|
int i;
|
|
UNUSED_PARAMETER(pVTab);
|
|
|
|
for(i=0; i<pInfo->nConstraint; i++){
|
|
- if( pInfo->aConstraint[i].usable
|
|
- && pInfo->aConstraint[i].iColumn==0
|
|
- && pInfo->aConstraint[i].op==SQLITE_INDEX_CONSTRAINT_EQ
|
|
+ if( pInfo->aConstraint[i].usable
|
|
+ && pInfo->aConstraint[i].iColumn==0
|
|
+ && pInfo->aConstraint[i].op==SQLITE_INDEX_CONSTRAINT_EQ
|
|
){
|
|
pInfo->idxNum = 1;
|
|
pInfo->aConstraintUsage[i].argvIndex = 1;
|
|
@@ -174987,7 +190330,7 @@ static int fts3tokFilterMethod(
|
|
if( pCsr->zInput==0 ){
|
|
rc = SQLITE_NOMEM;
|
|
}else{
|
|
- memcpy(pCsr->zInput, zByte, nByte);
|
|
+ if( nByte>0 ) memcpy(pCsr->zInput, zByte, nByte);
|
|
pCsr->zInput[nByte] = 0;
|
|
rc = pTab->pMod->xOpen(pTab->pTok, pCsr->zInput, nByte, &pCsr->pCsr);
|
|
if( rc==SQLITE_OK ){
|
|
@@ -175056,7 +190399,7 @@ static int fts3tokRowidMethod(
|
|
** Register the fts3tok module with database connection db. Return SQLITE_OK
|
|
** if successful or an error code if sqlite3_create_module() fails.
|
|
*/
|
|
-SQLITE_PRIVATE int sqlite3Fts3InitTok(sqlite3 *db, Fts3Hash *pHash){
|
|
+SQLITE_PRIVATE int sqlite3Fts3InitTok(sqlite3 *db, Fts3Hash *pHash, void(*xDestroy)(void*)){
|
|
static const sqlite3_module fts3tok_module = {
|
|
0, /* iVersion */
|
|
fts3tokConnectMethod, /* xCreate */
|
|
@@ -175085,7 +190428,9 @@ SQLITE_PRIVATE int sqlite3Fts3InitTok(sqlite3 *db, Fts3Hash *pHash){
|
|
};
|
|
int rc; /* Return code */
|
|
|
|
- rc = sqlite3_create_module(db, "fts3tokenize", &fts3tok_module, (void*)pHash);
|
|
+ rc = sqlite3_create_module_v2(
|
|
+ db, "fts3tokenize", &fts3tok_module, (void*)pHash, xDestroy
|
|
+ );
|
|
return rc;
|
|
}
|
|
|
|
@@ -175108,7 +190453,7 @@ SQLITE_PRIVATE int sqlite3Fts3InitTok(sqlite3 *db, Fts3Hash *pHash){
|
|
** This file is part of the SQLite FTS3 extension module. Specifically,
|
|
** this file contains code to insert, update and delete rows from FTS3
|
|
** tables. It also contains code to merge FTS3 b-tree segments. Some
|
|
-** of the sub-routines used to merge segments are also used by the query
|
|
+** of the sub-routines used to merge segments are also used by the query
|
|
** code in fts3.c.
|
|
*/
|
|
|
|
@@ -175124,7 +190469,7 @@ SQLITE_PRIVATE int sqlite3Fts3InitTok(sqlite3 *db, Fts3Hash *pHash){
|
|
|
|
/*
|
|
** When full-text index nodes are loaded from disk, the buffer that they
|
|
-** are loaded into has the following number of bytes of padding at the end
|
|
+** are loaded into has the following number of bytes of padding at the end
|
|
** of it. i.e. if a full-text index node is 900 bytes in size, then a buffer
|
|
** of 920 bytes is allocated for it.
|
|
**
|
|
@@ -175141,10 +190486,10 @@ SQLITE_PRIVATE int sqlite3Fts3InitTok(sqlite3 *db, Fts3Hash *pHash){
|
|
** method before retrieving all query results (as may happen, for example,
|
|
** if a query has a LIMIT clause).
|
|
**
|
|
-** Incremental loading is used for b-tree nodes FTS3_NODE_CHUNK_THRESHOLD
|
|
+** Incremental loading is used for b-tree nodes FTS3_NODE_CHUNK_THRESHOLD
|
|
** bytes and larger. Nodes are loaded in chunks of FTS3_NODE_CHUNKSIZE bytes.
|
|
-** The code is written so that the hard lower-limit for each of these values
|
|
-** is 1. Clearly such small values would be inefficient, but can be useful
|
|
+** The code is written so that the hard lower-limit for each of these values
|
|
+** is 1. Clearly such small values would be inefficient, but can be useful
|
|
** for testing purposes.
|
|
**
|
|
** If this module is built with SQLITE_TEST defined, these constants may
|
|
@@ -175157,7 +190502,7 @@ int test_fts3_node_chunk_threshold = (4*1024)*4;
|
|
# define FTS3_NODE_CHUNKSIZE test_fts3_node_chunksize
|
|
# define FTS3_NODE_CHUNK_THRESHOLD test_fts3_node_chunk_threshold
|
|
#else
|
|
-# define FTS3_NODE_CHUNKSIZE (4*1024)
|
|
+# define FTS3_NODE_CHUNKSIZE (4*1024)
|
|
# define FTS3_NODE_CHUNK_THRESHOLD (FTS3_NODE_CHUNKSIZE*4)
|
|
#endif
|
|
|
|
@@ -175171,7 +190516,7 @@ int test_fts3_node_chunk_threshold = (4*1024)*4;
|
|
|
|
/*
|
|
** If FTS_LOG_MERGES is defined, call sqlite3_log() to report each automatic
|
|
-** and incremental merge operation that takes place. This is used for
|
|
+** and incremental merge operation that takes place. This is used for
|
|
** debugging FTS only, it should not usually be turned on in production
|
|
** systems.
|
|
*/
|
|
@@ -175257,7 +190602,7 @@ struct Fts3SegReader {
|
|
char *aDoclist; /* Pointer to doclist of current entry */
|
|
int nDoclist; /* Size of doclist in current entry */
|
|
|
|
- /* The following variables are used by fts3SegReaderNextDocid() to iterate
|
|
+ /* The following variables are used by fts3SegReaderNextDocid() to iterate
|
|
** through the current doclist (aDoclist/nDoclist).
|
|
*/
|
|
char *pOffsetList;
|
|
@@ -175302,11 +190647,11 @@ struct SegmentWriter {
|
|
** fts3NodeFree()
|
|
**
|
|
** When a b+tree is written to the database (either as a result of a merge
|
|
-** or the pending-terms table being flushed), leaves are written into the
|
|
+** or the pending-terms table being flushed), leaves are written into the
|
|
** database file as soon as they are completely populated. The interior of
|
|
** the tree is assembled in memory and written out only once all leaves have
|
|
** been populated and stored. This is Ok, as the b+-tree fanout is usually
|
|
-** very large, meaning that the interior of the tree consumes relatively
|
|
+** very large, meaning that the interior of the tree consumes relatively
|
|
** little memory.
|
|
*/
|
|
struct SegmentNode {
|
|
@@ -175327,7 +190672,7 @@ struct SegmentNode {
|
|
*/
|
|
#define SQL_DELETE_CONTENT 0
|
|
#define SQL_IS_EMPTY 1
|
|
-#define SQL_DELETE_ALL_CONTENT 2
|
|
+#define SQL_DELETE_ALL_CONTENT 2
|
|
#define SQL_DELETE_ALL_SEGMENTS 3
|
|
#define SQL_DELETE_ALL_SEGDIR 4
|
|
#define SQL_DELETE_ALL_DOCSIZE 5
|
|
@@ -175375,7 +190720,7 @@ struct SegmentNode {
|
|
** Otherwise, an SQLite error code is returned and *pp is set to 0.
|
|
**
|
|
** If argument apVal is not NULL, then it must point to an array with
|
|
-** at least as many entries as the requested statement has bound
|
|
+** at least as many entries as the requested statement has bound
|
|
** parameters. The values are bound to the statements parameters before
|
|
** returning.
|
|
*/
|
|
@@ -175399,7 +190744,7 @@ static int fts3SqlStmt(
|
|
/* 10 */ "SELECT coalesce((SELECT max(blockid) FROM %Q.'%q_segments') + 1, 1)",
|
|
/* 11 */ "REPLACE INTO %Q.'%q_segdir' VALUES(?,?,?,?,?,?)",
|
|
|
|
- /* Return segments in order from oldest to newest.*/
|
|
+ /* Return segments in order from oldest to newest.*/
|
|
/* 12 */ "SELECT idx, start_block, leaves_end_block, end_block, root "
|
|
"FROM %Q.'%q_segdir' WHERE level = ? ORDER BY idx ASC",
|
|
/* 13 */ "SELECT idx, start_block, leaves_end_block, end_block, root "
|
|
@@ -175433,10 +190778,12 @@ static int fts3SqlStmt(
|
|
" ORDER BY (level %% 1024) ASC, 2 DESC LIMIT 1",
|
|
|
|
/* Estimate the upper limit on the number of leaf nodes in a new segment
|
|
-** created by merging the oldest :2 segments from absolute level :1. See
|
|
+** created by merging the oldest :2 segments from absolute level :1. See
|
|
** function sqlite3Fts3Incrmerge() for details. */
|
|
/* 29 */ "SELECT 2 * total(1 + leaves_end_block - start_block) "
|
|
- " FROM %Q.'%q_segdir' WHERE level = ? AND idx < ?",
|
|
+ " FROM (SELECT * FROM %Q.'%q_segdir' "
|
|
+ " WHERE level = ? ORDER BY idx ASC LIMIT ?"
|
|
+ " )",
|
|
|
|
/* SQL_DELETE_SEGDIR_ENTRY
|
|
** Delete the %_segdir entry on absolute level :1 with index :2. */
|
|
@@ -175448,7 +190795,7 @@ static int fts3SqlStmt(
|
|
/* 31 */ "UPDATE %Q.'%q_segdir' SET idx = ? WHERE level=? AND idx=?",
|
|
|
|
/* SQL_SELECT_SEGDIR
|
|
-** Read a single entry from the %_segdir table. The entry from absolute
|
|
+** Read a single entry from the %_segdir table. The entry from absolute
|
|
** level :1 with index value :2. */
|
|
/* 32 */ "SELECT idx, start_block, leaves_end_block, end_block, root "
|
|
"FROM %Q.'%q_segdir' WHERE level = ? AND idx = ?",
|
|
@@ -175472,7 +190819,7 @@ static int fts3SqlStmt(
|
|
** Return the largest relative level in the FTS index or indexes. */
|
|
/* 36 */ "SELECT max( level %% 1024 ) FROM %Q.'%q_segdir'",
|
|
|
|
- /* Return segments in order from oldest to newest.*/
|
|
+ /* Return segments in order from oldest to newest.*/
|
|
/* 37 */ "SELECT level, idx, end_block "
|
|
"FROM %Q.'%q_segdir' WHERE level BETWEEN ? AND ? "
|
|
"ORDER BY level DESC, idx ASC",
|
|
@@ -175488,7 +190835,7 @@ static int fts3SqlStmt(
|
|
|
|
assert( SizeofArray(azSql)==SizeofArray(p->aStmt) );
|
|
assert( eStmt<SizeofArray(azSql) && eStmt>=0 );
|
|
-
|
|
+
|
|
pStmt = p->aStmt[eStmt];
|
|
if( !pStmt ){
|
|
int f = SQLITE_PREPARE_PERSISTENT|SQLITE_PREPARE_NO_VTAB;
|
|
@@ -175593,7 +190940,7 @@ static void fts3SqlExec(
|
|
sqlite3_stmt *pStmt;
|
|
int rc;
|
|
if( *pRC ) return;
|
|
- rc = fts3SqlStmt(p, eStmt, &pStmt, apVal);
|
|
+ rc = fts3SqlStmt(p, eStmt, &pStmt, apVal);
|
|
if( rc==SQLITE_OK ){
|
|
sqlite3_step(pStmt);
|
|
rc = sqlite3_reset(pStmt);
|
|
@@ -175603,22 +190950,22 @@ static void fts3SqlExec(
|
|
|
|
|
|
/*
|
|
-** This function ensures that the caller has obtained an exclusive
|
|
-** shared-cache table-lock on the %_segdir table. This is required before
|
|
+** This function ensures that the caller has obtained an exclusive
|
|
+** shared-cache table-lock on the %_segdir table. This is required before
|
|
** writing data to the fts3 table. If this lock is not acquired first, then
|
|
** the caller may end up attempting to take this lock as part of committing
|
|
-** a transaction, causing SQLite to return SQLITE_LOCKED or
|
|
+** a transaction, causing SQLite to return SQLITE_LOCKED or
|
|
** LOCKED_SHAREDCACHEto a COMMIT command.
|
|
**
|
|
-** It is best to avoid this because if FTS3 returns any error when
|
|
-** committing a transaction, the whole transaction will be rolled back.
|
|
-** And this is not what users expect when they get SQLITE_LOCKED_SHAREDCACHE.
|
|
-** It can still happen if the user locks the underlying tables directly
|
|
+** It is best to avoid this because if FTS3 returns any error when
|
|
+** committing a transaction, the whole transaction will be rolled back.
|
|
+** And this is not what users expect when they get SQLITE_LOCKED_SHAREDCACHE.
|
|
+** It can still happen if the user locks the underlying tables directly
|
|
** instead of accessing them via FTS.
|
|
*/
|
|
static int fts3Writelock(Fts3Table *p){
|
|
int rc = SQLITE_OK;
|
|
-
|
|
+
|
|
if( p->nPendingData==0 ){
|
|
sqlite3_stmt *pStmt;
|
|
rc = fts3SqlStmt(p, SQL_DELETE_SEGDIR_LEVEL, &pStmt, 0);
|
|
@@ -175635,7 +190982,7 @@ static int fts3Writelock(Fts3Table *p){
|
|
/*
|
|
** FTS maintains a separate indexes for each language-id (a 32-bit integer).
|
|
** Within each language id, a separate index is maintained to store the
|
|
-** document terms, and each configured prefix size (configured the FTS
|
|
+** document terms, and each configured prefix size (configured the FTS
|
|
** "prefix=" option). And each index consists of multiple levels ("relative
|
|
** levels").
|
|
**
|
|
@@ -175645,14 +190992,14 @@ static int fts3Writelock(Fts3Table *p){
|
|
** separate component values into the single 64-bit integer value that
|
|
** can be used to query the %_segdir table.
|
|
**
|
|
-** Specifically, each language-id/index combination is allocated 1024
|
|
+** Specifically, each language-id/index combination is allocated 1024
|
|
** 64-bit integer level values ("absolute levels"). The main terms index
|
|
** for language-id 0 is allocate values 0-1023. The first prefix index
|
|
** (if any) for language-id 0 is allocated values 1024-2047. And so on.
|
|
** Language 1 indexes are allocated immediately following language 0.
|
|
**
|
|
** So, for a system with nPrefix prefix indexes configured, the block of
|
|
-** absolute levels that corresponds to language-id iLangid and index
|
|
+** absolute levels that corresponds to language-id iLangid and index
|
|
** iIndex starts at absolute level ((iLangid * (nPrefix+1) + iIndex) * 1024).
|
|
*/
|
|
static sqlite3_int64 getAbsoluteLevel(
|
|
@@ -175673,7 +191020,7 @@ static sqlite3_int64 getAbsoluteLevel(
|
|
/*
|
|
** Set *ppStmt to a statement handle that may be used to iterate through
|
|
** all rows in the %_segdir table, from oldest to newest. If successful,
|
|
-** return SQLITE_OK. If an error occurs while preparing the statement,
|
|
+** return SQLITE_OK. If an error occurs while preparing the statement,
|
|
** return an SQLite error code.
|
|
**
|
|
** There is only ever one instance of this SQL statement compiled for
|
|
@@ -175704,16 +191051,16 @@ SQLITE_PRIVATE int sqlite3Fts3AllSegdirs(
|
|
if( iLevel<0 ){
|
|
/* "SELECT * FROM %_segdir WHERE level BETWEEN ? AND ? ORDER BY ..." */
|
|
rc = fts3SqlStmt(p, SQL_SELECT_LEVEL_RANGE, &pStmt, 0);
|
|
- if( rc==SQLITE_OK ){
|
|
+ if( rc==SQLITE_OK ){
|
|
sqlite3_bind_int64(pStmt, 1, getAbsoluteLevel(p, iLangid, iIndex, 0));
|
|
- sqlite3_bind_int64(pStmt, 2,
|
|
+ sqlite3_bind_int64(pStmt, 2,
|
|
getAbsoluteLevel(p, iLangid, iIndex, FTS3_SEGDIR_MAXLEVEL-1)
|
|
);
|
|
}
|
|
}else{
|
|
/* "SELECT * FROM %_segdir WHERE level = ? ORDER BY ..." */
|
|
rc = fts3SqlStmt(p, SQL_SELECT_LEVEL, &pStmt, 0);
|
|
- if( rc==SQLITE_OK ){
|
|
+ if( rc==SQLITE_OK ){
|
|
sqlite3_bind_int64(pStmt, 1, getAbsoluteLevel(p, iLangid, iIndex,iLevel));
|
|
}
|
|
}
|
|
@@ -175742,7 +191089,7 @@ static int fts3PendingListAppendVarint(
|
|
|
|
/* Allocate or grow the PendingList as required. */
|
|
if( !p ){
|
|
- p = sqlite3_malloc(sizeof(*p) + 100);
|
|
+ p = sqlite3_malloc64(sizeof(*p) + 100);
|
|
if( !p ){
|
|
return SQLITE_NOMEM;
|
|
}
|
|
@@ -175751,14 +191098,14 @@ static int fts3PendingListAppendVarint(
|
|
p->nData = 0;
|
|
}
|
|
else if( p->nData+FTS3_VARINT_MAX+1>p->nSpace ){
|
|
- int nNew = p->nSpace * 2;
|
|
- p = sqlite3_realloc(p, sizeof(*p) + nNew);
|
|
+ i64 nNew = p->nSpace * 2;
|
|
+ p = sqlite3_realloc64(p, sizeof(*p) + nNew);
|
|
if( !p ){
|
|
sqlite3_free(*pp);
|
|
*pp = 0;
|
|
return SQLITE_NOMEM;
|
|
}
|
|
- p->nSpace = nNew;
|
|
+ p->nSpace = (int)nNew;
|
|
p->aData = (char *)&p[1];
|
|
}
|
|
|
|
@@ -175857,7 +191204,7 @@ static int fts3PendingTermsAddOne(
|
|
}
|
|
if( fts3PendingListAppend(&pList, p->iPrevDocid, iCol, iPos, &rc) ){
|
|
if( pList==fts3HashInsert(pHash, zToken, nToken, pList) ){
|
|
- /* Malloc failed while inserting the new entry. This can only
|
|
+ /* Malloc failed while inserting the new entry. This can only
|
|
** happen if there was no previous entry for this token.
|
|
*/
|
|
assert( 0==fts3HashFind(pHash, zToken, nToken) );
|
|
@@ -175903,7 +191250,7 @@ static int fts3PendingTermsAdd(
|
|
assert( pTokenizer && pModule );
|
|
|
|
/* If the user has inserted a NULL value, this function may be called with
|
|
- ** zText==0. In this case, add zero token entries to the hash table and
|
|
+ ** zText==0. In this case, add zero token entries to the hash table and
|
|
** return early. */
|
|
if( zText==0 ){
|
|
*pnWord = 0;
|
|
@@ -175934,8 +191281,8 @@ static int fts3PendingTermsAdd(
|
|
rc = fts3PendingTermsAddOne(
|
|
p, iCol, iPos, &p->aIndex[0].hPending, zToken, nToken
|
|
);
|
|
-
|
|
- /* Add the term to each of the prefix indexes that it is not too
|
|
+
|
|
+ /* Add the term to each of the prefix indexes that it is not too
|
|
** short for. */
|
|
for(i=1; rc==SQLITE_OK && i<p->nIndex; i++){
|
|
struct Fts3Index *pIndex = &p->aIndex[i];
|
|
@@ -175951,8 +191298,8 @@ static int fts3PendingTermsAdd(
|
|
return (rc==SQLITE_DONE ? SQLITE_OK : rc);
|
|
}
|
|
|
|
-/*
|
|
-** Calling this function indicates that subsequent calls to
|
|
+/*
|
|
+** Calling this function indicates that subsequent calls to
|
|
** fts3PendingTermsAdd() are to add term/position-list pairs for the
|
|
** contents of the document with docid iDocid.
|
|
*/
|
|
@@ -175971,10 +191318,10 @@ static int fts3PendingTermsDocid(
|
|
** buffer was half empty, that would let the less frequent terms
|
|
** generate longer doclists.
|
|
*/
|
|
- if( iDocid<p->iPrevDocid
|
|
+ if( iDocid<p->iPrevDocid
|
|
|| (iDocid==p->iPrevDocid && p->bPrevDelete==0)
|
|
|| p->iPrevLangid!=iLangid
|
|
- || p->nPendingData>p->nMaxPendingData
|
|
+ || p->nPendingData>p->nMaxPendingData
|
|
){
|
|
int rc = sqlite3Fts3PendingTermsFlush(p);
|
|
if( rc!=SQLITE_OK ) return rc;
|
|
@@ -175986,7 +191333,7 @@ static int fts3PendingTermsDocid(
|
|
}
|
|
|
|
/*
|
|
-** Discard the contents of the pending-terms hash tables.
|
|
+** Discard the contents of the pending-terms hash tables.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3Fts3PendingTermsClear(Fts3Table *p){
|
|
int i;
|
|
@@ -176011,9 +191358,9 @@ SQLITE_PRIVATE void sqlite3Fts3PendingTermsClear(Fts3Table *p){
|
|
** fts3InsertData(). Parameter iDocid is the docid of the new row.
|
|
*/
|
|
static int fts3InsertTerms(
|
|
- Fts3Table *p,
|
|
- int iLangid,
|
|
- sqlite3_value **apVal,
|
|
+ Fts3Table *p,
|
|
+ int iLangid,
|
|
+ sqlite3_value **apVal,
|
|
u32 *aSz
|
|
){
|
|
int i; /* Iterator variable */
|
|
@@ -176076,7 +191423,7 @@ static int fts3InsertData(
|
|
rc = fts3SqlStmt(p, SQL_CONTENT_INSERT, &pContentInsert, &apVal[1]);
|
|
if( rc==SQLITE_OK && p->zLanguageid ){
|
|
rc = sqlite3_bind_int(
|
|
- pContentInsert, p->nColumn+2,
|
|
+ pContentInsert, p->nColumn+2,
|
|
sqlite3_value_int(apVal[p->nColumn+4])
|
|
);
|
|
}
|
|
@@ -176103,8 +191450,8 @@ static int fts3InsertData(
|
|
if( rc!=SQLITE_OK ) return rc;
|
|
}
|
|
|
|
- /* Execute the statement to insert the record. Set *piDocid to the
|
|
- ** new docid value.
|
|
+ /* Execute the statement to insert the record. Set *piDocid to the
|
|
+ ** new docid value.
|
|
*/
|
|
sqlite3_step(pContentInsert);
|
|
rc = sqlite3_reset(pContentInsert);
|
|
@@ -176154,7 +191501,7 @@ static int langidFromSelect(Fts3Table *p, sqlite3_stmt *pSelect){
|
|
** (an integer) of a row about to be deleted. Remove all terms from the
|
|
** full-text index.
|
|
*/
|
|
-static void fts3DeleteTerms(
|
|
+static void fts3DeleteTerms(
|
|
int *pRC, /* Result code */
|
|
Fts3Table *p, /* The FTS table to delete from */
|
|
sqlite3_value *pRowid, /* The docid to be deleted */
|
|
@@ -176201,7 +191548,7 @@ static void fts3DeleteTerms(
|
|
*/
|
|
static int fts3SegmentMerge(Fts3Table *, int, int, int);
|
|
|
|
-/*
|
|
+/*
|
|
** This function allocates a new level iLevel index in the segdir table.
|
|
** Usually, indexes are allocated within a level sequentially starting
|
|
** with 0, so the allocated index is one greater than the value returned
|
|
@@ -176210,17 +191557,17 @@ static int fts3SegmentMerge(Fts3Table *, int, int, int);
|
|
** SELECT max(idx) FROM %_segdir WHERE level = :iLevel
|
|
**
|
|
** However, if there are already FTS3_MERGE_COUNT indexes at the requested
|
|
-** level, they are merged into a single level (iLevel+1) segment and the
|
|
+** level, they are merged into a single level (iLevel+1) segment and the
|
|
** allocated index is 0.
|
|
**
|
|
** If successful, *piIdx is set to the allocated index slot and SQLITE_OK
|
|
** returned. Otherwise, an SQLite error code is returned.
|
|
*/
|
|
static int fts3AllocateSegdirIdx(
|
|
- Fts3Table *p,
|
|
+ Fts3Table *p,
|
|
int iLangid, /* Language id */
|
|
int iIndex, /* Index for p->aIndex */
|
|
- int iLevel,
|
|
+ int iLevel,
|
|
int *piIdx
|
|
){
|
|
int rc; /* Return Code */
|
|
@@ -176268,7 +191615,7 @@ static int fts3AllocateSegdirIdx(
|
|
** This function reads data from a single row of the %_segments table. The
|
|
** specific row is identified by the iBlockid parameter. If paBlob is not
|
|
** NULL, then a buffer is allocated using sqlite3_malloc() and populated
|
|
-** with the contents of the blob stored in the "block" column of the
|
|
+** with the contents of the blob stored in the "block" column of the
|
|
** identified table row is. Whether or not paBlob is NULL, *pnBlob is set
|
|
** to the size of the blob in bytes before returning.
|
|
**
|
|
@@ -176315,7 +191662,7 @@ SQLITE_PRIVATE int sqlite3Fts3ReadBlock(
|
|
int nByte = sqlite3_blob_bytes(p->pSegments);
|
|
*pnBlob = nByte;
|
|
if( paBlob ){
|
|
- char *aByte = sqlite3_malloc(nByte + FTS3_NODE_PADDING);
|
|
+ char *aByte = sqlite3_malloc64((i64)nByte + FTS3_NODE_PADDING);
|
|
if( !aByte ){
|
|
rc = SQLITE_NOMEM;
|
|
}else{
|
|
@@ -176347,14 +191694,14 @@ SQLITE_PRIVATE void sqlite3Fts3SegmentsClose(Fts3Table *p){
|
|
sqlite3_blob_close(p->pSegments);
|
|
p->pSegments = 0;
|
|
}
|
|
-
|
|
+
|
|
static int fts3SegReaderIncrRead(Fts3SegReader *pReader){
|
|
int nRead; /* Number of bytes to read */
|
|
int rc; /* Return code */
|
|
|
|
nRead = MIN(pReader->nNode - pReader->nPopulate, FTS3_NODE_CHUNKSIZE);
|
|
rc = sqlite3_blob_read(
|
|
- pReader->pBlob,
|
|
+ pReader->pBlob,
|
|
&pReader->aNode[pReader->nPopulate],
|
|
nRead,
|
|
pReader->nPopulate
|
|
@@ -176374,10 +191721,10 @@ static int fts3SegReaderIncrRead(Fts3SegReader *pReader){
|
|
|
|
static int fts3SegReaderRequire(Fts3SegReader *pReader, char *pFrom, int nByte){
|
|
int rc = SQLITE_OK;
|
|
- assert( !pReader->pBlob
|
|
+ assert( !pReader->pBlob
|
|
|| (pFrom>=pReader->aNode && pFrom<&pReader->aNode[pReader->nNode])
|
|
);
|
|
- while( pReader->pBlob && rc==SQLITE_OK
|
|
+ while( pReader->pBlob && rc==SQLITE_OK
|
|
&& (pFrom - pReader->aNode + nByte)>pReader->nPopulate
|
|
){
|
|
rc = fts3SegReaderIncrRead(pReader);
|
|
@@ -176403,7 +191750,7 @@ static void fts3SegReaderSetEof(Fts3SegReader *pSeg){
|
|
** SQLITE_DONE. Otherwise, an SQLite error code.
|
|
*/
|
|
static int fts3SegReaderNext(
|
|
- Fts3Table *p,
|
|
+ Fts3Table *p,
|
|
Fts3SegReader *pReader,
|
|
int bIncr
|
|
){
|
|
@@ -176428,9 +191775,19 @@ static int fts3SegReaderNext(
|
|
char *aCopy;
|
|
PendingList *pList = (PendingList *)fts3HashData(pElem);
|
|
int nCopy = pList->nData+1;
|
|
- pReader->zTerm = (char *)fts3HashKey(pElem);
|
|
- pReader->nTerm = fts3HashKeysize(pElem);
|
|
- aCopy = (char*)sqlite3_malloc(nCopy);
|
|
+
|
|
+ int nTerm = fts3HashKeysize(pElem);
|
|
+ if( (nTerm+1)>pReader->nTermAlloc ){
|
|
+ sqlite3_free(pReader->zTerm);
|
|
+ pReader->zTerm = (char*)sqlite3_malloc64(((i64)nTerm+1)*2);
|
|
+ if( !pReader->zTerm ) return SQLITE_NOMEM;
|
|
+ pReader->nTermAlloc = (nTerm+1)*2;
|
|
+ }
|
|
+ memcpy(pReader->zTerm, fts3HashKey(pElem), nTerm);
|
|
+ pReader->zTerm[nTerm] = '\0';
|
|
+ pReader->nTerm = nTerm;
|
|
+
|
|
+ aCopy = (char*)sqlite3_malloc64(nCopy);
|
|
if( !aCopy ) return SQLITE_NOMEM;
|
|
memcpy(aCopy, pList->aData, nCopy);
|
|
pReader->nNode = pReader->nDoclist = nCopy;
|
|
@@ -176443,7 +191800,7 @@ static int fts3SegReaderNext(
|
|
|
|
fts3SegReaderSetEof(pReader);
|
|
|
|
- /* If iCurrentBlock>=iLeafEndBlock, this is an EOF condition. All leaf
|
|
+ /* If iCurrentBlock>=iLeafEndBlock, this is an EOF condition. All leaf
|
|
** blocks have already been traversed. */
|
|
#ifdef CORRUPT_DB
|
|
assert( pReader->iCurrentBlock<=pReader->iLeafEndBlock || CORRUPT_DB );
|
|
@@ -176453,7 +191810,7 @@ static int fts3SegReaderNext(
|
|
}
|
|
|
|
rc = sqlite3Fts3ReadBlock(
|
|
- p, ++pReader->iCurrentBlock, &pReader->aNode, &pReader->nNode,
|
|
+ p, ++pReader->iCurrentBlock, &pReader->aNode, &pReader->nNode,
|
|
(bIncr ? &pReader->nPopulate : 0)
|
|
);
|
|
if( rc!=SQLITE_OK ) return rc;
|
|
@@ -176469,12 +191826,12 @@ static int fts3SegReaderNext(
|
|
|
|
rc = fts3SegReaderRequire(pReader, pNext, FTS3_VARINT_MAX*2);
|
|
if( rc!=SQLITE_OK ) return rc;
|
|
-
|
|
- /* Because of the FTS3_NODE_PADDING bytes of padding, the following is
|
|
+
|
|
+ /* Because of the FTS3_NODE_PADDING bytes of padding, the following is
|
|
** safe (no risk of overread) even if the node data is corrupted. */
|
|
pNext += fts3GetVarint32(pNext, &nPrefix);
|
|
pNext += fts3GetVarint32(pNext, &nSuffix);
|
|
- if( nSuffix<=0
|
|
+ if( nSuffix<=0
|
|
|| (&pReader->aNode[pReader->nNode] - pNext)<nSuffix
|
|
|| nPrefix>pReader->nTerm
|
|
){
|
|
@@ -176505,11 +191862,12 @@ static int fts3SegReaderNext(
|
|
pReader->pOffsetList = 0;
|
|
|
|
/* Check that the doclist does not appear to extend past the end of the
|
|
- ** b-tree node. And that the final byte of the doclist is 0x00. If either
|
|
+ ** b-tree node. And that the final byte of the doclist is 0x00. If either
|
|
** of these statements is untrue, then the data structure is corrupt.
|
|
*/
|
|
if( pReader->nDoclist > pReader->nNode-(pReader->aDoclist-pReader->aNode)
|
|
|| (pReader->nPopulate==0 && pReader->aDoclist[pReader->nDoclist-1])
|
|
+ || pReader->nDoclist==0
|
|
){
|
|
return FTS_CORRUPT_VTAB;
|
|
}
|
|
@@ -176529,7 +191887,7 @@ static int fts3SegReaderFirstDocid(Fts3Table *pTab, Fts3SegReader *pReader){
|
|
pReader->iDocid = 0;
|
|
pReader->nOffsetList = 0;
|
|
sqlite3Fts3DoclistPrev(0,
|
|
- pReader->aDoclist, pReader->nDoclist, &pReader->pOffsetList,
|
|
+ pReader->aDoclist, pReader->nDoclist, &pReader->pOffsetList,
|
|
&pReader->iDocid, &pReader->nOffsetList, &bEof
|
|
);
|
|
}else{
|
|
@@ -176545,8 +191903,8 @@ static int fts3SegReaderFirstDocid(Fts3Table *pTab, Fts3SegReader *pReader){
|
|
/*
|
|
** Advance the SegReader to point to the next docid in the doclist
|
|
** associated with the current term.
|
|
-**
|
|
-** If arguments ppOffsetList and pnOffsetList are not NULL, then
|
|
+**
|
|
+** If arguments ppOffsetList and pnOffsetList are not NULL, then
|
|
** *ppOffsetList is set to point to the first column-offset list
|
|
** in the doclist entry (i.e. immediately past the docid varint).
|
|
** *pnOffsetList is set to the length of the set of column-offset
|
|
@@ -176589,22 +191947,22 @@ static int fts3SegReaderNextDocid(
|
|
** following block advances it to point one byte past the end of
|
|
** the same offset list. */
|
|
while( 1 ){
|
|
-
|
|
+
|
|
/* The following line of code (and the "p++" below the while() loop) is
|
|
- ** normally all that is required to move pointer p to the desired
|
|
+ ** normally all that is required to move pointer p to the desired
|
|
** position. The exception is if this node is being loaded from disk
|
|
** incrementally and pointer "p" now points to the first byte past
|
|
** the populated part of pReader->aNode[].
|
|
*/
|
|
while( *p | c ) c = *p++ & 0x80;
|
|
assert( *p==0 );
|
|
-
|
|
+
|
|
if( pReader->pBlob==0 || p<&pReader->aNode[pReader->nPopulate] ) break;
|
|
rc = fts3SegReaderIncrRead(pReader);
|
|
if( rc!=SQLITE_OK ) return rc;
|
|
}
|
|
p++;
|
|
-
|
|
+
|
|
/* If required, populate the output variables with a pointer to and the
|
|
** size of the previous offset-list.
|
|
*/
|
|
@@ -176615,7 +191973,7 @@ static int fts3SegReaderNextDocid(
|
|
|
|
/* List may have been edited in place by fts3EvalNearTrim() */
|
|
while( p<pEnd && *p==0 ) p++;
|
|
-
|
|
+
|
|
/* If there are no more entries in the doclist, set pOffsetList to
|
|
** NULL. Otherwise, set Fts3SegReader.iDocid to the next docid and
|
|
** Fts3SegReader.pOffsetList to point to the next offset list before
|
|
@@ -176642,7 +192000,7 @@ static int fts3SegReaderNextDocid(
|
|
|
|
|
|
SQLITE_PRIVATE int sqlite3Fts3MsrOvfl(
|
|
- Fts3Cursor *pCsr,
|
|
+ Fts3Cursor *pCsr,
|
|
Fts3MultiSegReader *pMsr,
|
|
int *pnOvfl
|
|
){
|
|
@@ -176657,8 +192015,8 @@ SQLITE_PRIVATE int sqlite3Fts3MsrOvfl(
|
|
|
|
for(ii=0; rc==SQLITE_OK && ii<pMsr->nSegment; ii++){
|
|
Fts3SegReader *pReader = pMsr->apSegment[ii];
|
|
- if( !fts3SegReaderIsPending(pReader)
|
|
- && !fts3SegReaderIsRootOnly(pReader)
|
|
+ if( !fts3SegReaderIsPending(pReader)
|
|
+ && !fts3SegReaderIsRootOnly(pReader)
|
|
){
|
|
sqlite3_int64 jj;
|
|
for(jj=pReader->iStartBlock; jj<=pReader->iLeafEndBlock; jj++){
|
|
@@ -176676,14 +192034,12 @@ SQLITE_PRIVATE int sqlite3Fts3MsrOvfl(
|
|
}
|
|
|
|
/*
|
|
-** Free all allocations associated with the iterator passed as the
|
|
+** Free all allocations associated with the iterator passed as the
|
|
** second argument.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3Fts3SegReaderFree(Fts3SegReader *pReader){
|
|
if( pReader ){
|
|
- if( !fts3SegReaderIsPending(pReader) ){
|
|
- sqlite3_free(pReader->zTerm);
|
|
- }
|
|
+ sqlite3_free(pReader->zTerm);
|
|
if( !fts3SegReaderIsRootOnly(pReader) ){
|
|
sqlite3_free(pReader->aNode);
|
|
}
|
|
@@ -176718,7 +192074,7 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderNew(
|
|
nExtra = nRoot + FTS3_NODE_PADDING;
|
|
}
|
|
|
|
- pReader = (Fts3SegReader *)sqlite3_malloc(sizeof(Fts3SegReader) + nExtra);
|
|
+ pReader = (Fts3SegReader *)sqlite3_malloc64(sizeof(Fts3SegReader) + nExtra);
|
|
if( !pReader ){
|
|
return SQLITE_NOMEM;
|
|
}
|
|
@@ -176810,7 +192166,7 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderPending(
|
|
if( nElem==nAlloc ){
|
|
Fts3HashElem **aElem2;
|
|
nAlloc += 16;
|
|
- aElem2 = (Fts3HashElem **)sqlite3_realloc(
|
|
+ aElem2 = (Fts3HashElem **)sqlite3_realloc64(
|
|
aElem, nAlloc*sizeof(Fts3HashElem *)
|
|
);
|
|
if( !aElem2 ){
|
|
@@ -176835,7 +192191,7 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderPending(
|
|
|
|
}else{
|
|
/* The query is a simple term lookup that matches at most one term in
|
|
- ** the index. All that is required is a straight hash-lookup.
|
|
+ ** the index. All that is required is a straight hash-lookup.
|
|
**
|
|
** Because the stack address of pE may be accessed via the aElem pointer
|
|
** below, the "Fts3HashElem *pE" must be declared so that it is valid
|
|
@@ -176870,7 +192226,7 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderPending(
|
|
}
|
|
|
|
/*
|
|
-** Compare the entries pointed to by two Fts3SegReader structures.
|
|
+** Compare the entries pointed to by two Fts3SegReader structures.
|
|
** Comparison is as follows:
|
|
**
|
|
** 1) EOF is greater than not EOF.
|
|
@@ -176899,7 +192255,7 @@ static int fts3SegReaderCmp(Fts3SegReader *pLhs, Fts3SegReader *pRhs){
|
|
if( rc==0 ){
|
|
rc = pRhs->iIdx - pLhs->iIdx;
|
|
}
|
|
- assert( rc!=0 );
|
|
+ assert_fts3_nc( rc!=0 );
|
|
return rc;
|
|
}
|
|
|
|
@@ -176941,7 +192297,7 @@ static int fts3SegReaderDoclistCmpRev(Fts3SegReader *pLhs, Fts3SegReader *pRhs){
|
|
|
|
/*
|
|
** Compare the term that the Fts3SegReader object passed as the first argument
|
|
-** points to with the term specified by arguments zTerm and nTerm.
|
|
+** points to with the term specified by arguments zTerm and nTerm.
|
|
**
|
|
** If the pSeg iterator is already at EOF, return 0. Otherwise, return
|
|
** -ve if the pSeg term is less than zTerm/nTerm, 0 if the two terms are
|
|
@@ -177002,7 +192358,7 @@ static void fts3SegReaderSort(
|
|
#endif
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** Insert a record into the %_segments table.
|
|
*/
|
|
static int fts3WriteSegment(
|
|
@@ -177044,7 +192400,7 @@ SQLITE_PRIVATE int sqlite3Fts3MaxLevel(Fts3Table *p, int *pnMax){
|
|
return rc;
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** Insert a record into the %_segdir table.
|
|
*/
|
|
static int fts3WriteSegdir(
|
|
@@ -177082,7 +192438,7 @@ static int fts3WriteSegdir(
|
|
|
|
/*
|
|
** Return the size of the common prefix (if any) shared by zPrev and
|
|
-** zNext, in bytes. For example,
|
|
+** zNext, in bytes. For example,
|
|
**
|
|
** fts3PrefixCompress("abc", 3, "abcdef", 6) // returns 3
|
|
** fts3PrefixCompress("abX", 3, "abcdef", 6) // returns 2
|
|
@@ -177095,8 +192451,8 @@ static int fts3PrefixCompress(
|
|
int nNext /* Size of buffer zNext in bytes */
|
|
){
|
|
int n;
|
|
- UNUSED_PARAMETER(nNext);
|
|
- for(n=0; n<nPrev && zPrev[n]==zNext[n]; n++);
|
|
+ for(n=0; n<nPrev && n<nNext && zPrev[n]==zNext[n]; n++);
|
|
+ assert_fts3_nc( n<nNext );
|
|
return n;
|
|
}
|
|
|
|
@@ -177106,7 +192462,7 @@ static int fts3PrefixCompress(
|
|
*/
|
|
static int fts3NodeAddTerm(
|
|
Fts3Table *p, /* Virtual table handle */
|
|
- SegmentNode **ppTree, /* IN/OUT: SegmentNode handle */
|
|
+ SegmentNode **ppTree, /* IN/OUT: SegmentNode handle */
|
|
int isCopyTerm, /* True if zTerm/nTerm is transient */
|
|
const char *zTerm, /* Pointer to buffer containing term */
|
|
int nTerm /* Size of term in bytes */
|
|
@@ -177115,7 +192471,7 @@ static int fts3NodeAddTerm(
|
|
int rc;
|
|
SegmentNode *pNew;
|
|
|
|
- /* First try to append the term to the current node. Return early if
|
|
+ /* First try to append the term to the current node. Return early if
|
|
** this is possible.
|
|
*/
|
|
if( pTree ){
|
|
@@ -177127,7 +192483,7 @@ static int fts3NodeAddTerm(
|
|
nPrefix = fts3PrefixCompress(pTree->zTerm, pTree->nTerm, zTerm, nTerm);
|
|
nSuffix = nTerm-nPrefix;
|
|
|
|
- /* If nSuffix is zero or less, then zTerm/nTerm must be a prefix of
|
|
+ /* If nSuffix is zero or less, then zTerm/nTerm must be a prefix of
|
|
** pWriter->zTerm/pWriter->nTerm. i.e. must be equal to or less than when
|
|
** compared with BINARY collation. This indicates corruption. */
|
|
if( nSuffix<=0 ) return FTS_CORRUPT_VTAB;
|
|
@@ -177140,11 +192496,11 @@ static int fts3NodeAddTerm(
|
|
** and the static node buffer (p->nNodeSize bytes) is not large
|
|
** enough. Use a separately malloced buffer instead This wastes
|
|
** p->nNodeSize bytes, but since this scenario only comes about when
|
|
- ** the database contain two terms that share a prefix of almost 2KB,
|
|
- ** this is not expected to be a serious problem.
|
|
+ ** the database contain two terms that share a prefix of almost 2KB,
|
|
+ ** this is not expected to be a serious problem.
|
|
*/
|
|
assert( pTree->aData==(char *)&pTree[1] );
|
|
- pTree->aData = (char *)sqlite3_malloc(nReq);
|
|
+ pTree->aData = (char *)sqlite3_malloc64(nReq);
|
|
if( !pTree->aData ){
|
|
return SQLITE_NOMEM;
|
|
}
|
|
@@ -177162,7 +192518,7 @@ static int fts3NodeAddTerm(
|
|
|
|
if( isCopyTerm ){
|
|
if( pTree->nMalloc<nTerm ){
|
|
- char *zNew = sqlite3_realloc(pTree->zMalloc, nTerm*2);
|
|
+ char *zNew = sqlite3_realloc64(pTree->zMalloc, (i64)nTerm*2);
|
|
if( !zNew ){
|
|
return SQLITE_NOMEM;
|
|
}
|
|
@@ -177185,10 +192541,10 @@ static int fts3NodeAddTerm(
|
|
** If this is the first node in the tree, the term is added to it.
|
|
**
|
|
** Otherwise, the term is not added to the new node, it is left empty for
|
|
- ** now. Instead, the term is inserted into the parent of pTree. If pTree
|
|
+ ** now. Instead, the term is inserted into the parent of pTree. If pTree
|
|
** has no parent, one is created here.
|
|
*/
|
|
- pNew = (SegmentNode *)sqlite3_malloc(sizeof(SegmentNode) + p->nNodeSize);
|
|
+ pNew = (SegmentNode *)sqlite3_malloc64(sizeof(SegmentNode) + p->nNodeSize);
|
|
if( !pNew ){
|
|
return SQLITE_NOMEM;
|
|
}
|
|
@@ -177210,7 +192566,7 @@ static int fts3NodeAddTerm(
|
|
pTree->zMalloc = 0;
|
|
}else{
|
|
pNew->pLeftmost = pNew;
|
|
- rc = fts3NodeAddTerm(p, &pNew, isCopyTerm, zTerm, nTerm);
|
|
+ rc = fts3NodeAddTerm(p, &pNew, isCopyTerm, zTerm, nTerm);
|
|
}
|
|
|
|
*ppTree = pNew;
|
|
@@ -177221,8 +192577,8 @@ static int fts3NodeAddTerm(
|
|
** Helper function for fts3NodeWrite().
|
|
*/
|
|
static int fts3TreeFinishNode(
|
|
- SegmentNode *pTree,
|
|
- int iHeight,
|
|
+ SegmentNode *pTree,
|
|
+ int iHeight,
|
|
sqlite3_int64 iLeftChild
|
|
){
|
|
int nStart;
|
|
@@ -177235,15 +192591,15 @@ static int fts3TreeFinishNode(
|
|
|
|
/*
|
|
** Write the buffer for the segment node pTree and all of its peers to the
|
|
-** database. Then call this function recursively to write the parent of
|
|
-** pTree and its peers to the database.
|
|
+** database. Then call this function recursively to write the parent of
|
|
+** pTree and its peers to the database.
|
|
**
|
|
** Except, if pTree is a root node, do not write it to the database. Instead,
|
|
** set output variables *paRoot and *pnRoot to contain the root node.
|
|
**
|
|
** If successful, SQLITE_OK is returned and output variable *piLast is
|
|
** set to the largest blockid written to the database (or zero if no
|
|
-** blocks were written to the db). Otherwise, an SQLite error code is
|
|
+** blocks were written to the db). Otherwise, an SQLite error code is
|
|
** returned.
|
|
*/
|
|
static int fts3NodeWrite(
|
|
@@ -177271,7 +192627,7 @@ static int fts3NodeWrite(
|
|
for(pIter=pTree->pLeftmost; pIter && rc==SQLITE_OK; pIter=pIter->pRight){
|
|
int nStart = fts3TreeFinishNode(pIter, iHeight, iNextLeaf);
|
|
int nWrite = pIter->nData - nStart;
|
|
-
|
|
+
|
|
rc = fts3WriteSegment(p, iNextFree, &pIter->aData[nStart], nWrite);
|
|
iNextFree++;
|
|
iNextLeaf += (pIter->nEntry+1);
|
|
@@ -177317,7 +192673,7 @@ static void fts3NodeFree(SegmentNode *pTree){
|
|
*/
|
|
static int fts3SegWriterAdd(
|
|
Fts3Table *p, /* Virtual table handle */
|
|
- SegmentWriter **ppWriter, /* IN/OUT: SegmentWriter handle */
|
|
+ SegmentWriter **ppWriter, /* IN/OUT: SegmentWriter handle */
|
|
int isCopyTerm, /* True if buffer zTerm must be copied */
|
|
const char *zTerm, /* Pointer to buffer containing term */
|
|
int nTerm, /* Size of term in bytes */
|
|
@@ -177326,7 +192682,7 @@ static int fts3SegWriterAdd(
|
|
){
|
|
int nPrefix; /* Size of term prefix in bytes */
|
|
int nSuffix; /* Size of term suffix in bytes */
|
|
- int nReq; /* Number of bytes required on leaf page */
|
|
+ i64 nReq; /* Number of bytes required on leaf page */
|
|
int nData;
|
|
SegmentWriter *pWriter = *ppWriter;
|
|
|
|
@@ -177335,13 +192691,13 @@ static int fts3SegWriterAdd(
|
|
sqlite3_stmt *pStmt;
|
|
|
|
/* Allocate the SegmentWriter structure */
|
|
- pWriter = (SegmentWriter *)sqlite3_malloc(sizeof(SegmentWriter));
|
|
+ pWriter = (SegmentWriter *)sqlite3_malloc64(sizeof(SegmentWriter));
|
|
if( !pWriter ) return SQLITE_NOMEM;
|
|
memset(pWriter, 0, sizeof(SegmentWriter));
|
|
*ppWriter = pWriter;
|
|
|
|
/* Allocate a buffer in which to accumulate data */
|
|
- pWriter->aData = (char *)sqlite3_malloc(p->nNodeSize);
|
|
+ pWriter->aData = (char *)sqlite3_malloc64(p->nNodeSize);
|
|
if( !pWriter->aData ) return SQLITE_NOMEM;
|
|
pWriter->nSize = p->nNodeSize;
|
|
|
|
@@ -177360,7 +192716,7 @@ static int fts3SegWriterAdd(
|
|
nPrefix = fts3PrefixCompress(pWriter->zTerm, pWriter->nTerm, zTerm, nTerm);
|
|
nSuffix = nTerm-nPrefix;
|
|
|
|
- /* If nSuffix is zero or less, then zTerm/nTerm must be a prefix of
|
|
+ /* If nSuffix is zero or less, then zTerm/nTerm must be a prefix of
|
|
** pWriter->zTerm/pWriter->nTerm. i.e. must be equal to or less than when
|
|
** compared with BINARY collation. This indicates corruption. */
|
|
if( nSuffix<=0 ) return FTS_CORRUPT_VTAB;
|
|
@@ -177416,7 +192772,7 @@ static int fts3SegWriterAdd(
|
|
** the buffer to make it large enough.
|
|
*/
|
|
if( nReq>pWriter->nSize ){
|
|
- char *aNew = sqlite3_realloc(pWriter->aData, nReq);
|
|
+ char *aNew = sqlite3_realloc64(pWriter->aData, nReq);
|
|
if( !aNew ) return SQLITE_NOMEM;
|
|
pWriter->aData = aNew;
|
|
pWriter->nSize = nReq;
|
|
@@ -177441,7 +192797,7 @@ static int fts3SegWriterAdd(
|
|
*/
|
|
if( isCopyTerm ){
|
|
if( nTerm>pWriter->nMalloc ){
|
|
- char *zNew = sqlite3_realloc(pWriter->zMalloc, nTerm*2);
|
|
+ char *zNew = sqlite3_realloc64(pWriter->zMalloc, (i64)nTerm*2);
|
|
if( !zNew ){
|
|
return SQLITE_NOMEM;
|
|
}
|
|
@@ -177486,12 +192842,12 @@ static int fts3SegWriterFlush(
|
|
pWriter->iFirst, pWriter->iFree, &iLast, &zRoot, &nRoot);
|
|
}
|
|
if( rc==SQLITE_OK ){
|
|
- rc = fts3WriteSegdir(p, iLevel, iIdx,
|
|
+ rc = fts3WriteSegdir(p, iLevel, iIdx,
|
|
pWriter->iFirst, iLastLeaf, iLast, pWriter->nLeafData, zRoot, nRoot);
|
|
}
|
|
}else{
|
|
/* The entire tree fits on the root node. Write it to the segdir table. */
|
|
- rc = fts3WriteSegdir(p, iLevel, iIdx,
|
|
+ rc = fts3WriteSegdir(p, iLevel, iIdx,
|
|
0, 0, 0, pWriter->nLeafData, pWriter->aData, pWriter->nData);
|
|
}
|
|
p->nLeafAdd++;
|
|
@@ -177499,7 +192855,7 @@ static int fts3SegWriterFlush(
|
|
}
|
|
|
|
/*
|
|
-** Release all memory held by the SegmentWriter object passed as the
|
|
+** Release all memory held by the SegmentWriter object passed as the
|
|
** first argument.
|
|
*/
|
|
static void fts3SegWriterFree(SegmentWriter *pWriter){
|
|
@@ -177549,9 +192905,9 @@ static int fts3IsEmpty(Fts3Table *p, sqlite3_value *pRowid, int *pisEmpty){
|
|
** Return SQLITE_OK if successful, or an SQLite error code if not.
|
|
*/
|
|
static int fts3SegmentMaxLevel(
|
|
- Fts3Table *p,
|
|
+ Fts3Table *p,
|
|
int iLangid,
|
|
- int iIndex,
|
|
+ int iIndex,
|
|
sqlite3_int64 *pnMax
|
|
){
|
|
sqlite3_stmt *pStmt;
|
|
@@ -177567,7 +192923,7 @@ static int fts3SegmentMaxLevel(
|
|
rc = fts3SqlStmt(p, SQL_SELECT_SEGDIR_MAX_LEVEL, &pStmt, 0);
|
|
if( rc!=SQLITE_OK ) return rc;
|
|
sqlite3_bind_int64(pStmt, 1, getAbsoluteLevel(p, iLangid, iIndex, 0));
|
|
- sqlite3_bind_int64(pStmt, 2,
|
|
+ sqlite3_bind_int64(pStmt, 2,
|
|
getAbsoluteLevel(p, iLangid, iIndex, FTS3_SEGDIR_MAXLEVEL-1)
|
|
);
|
|
if( SQLITE_ROW==sqlite3_step(pStmt) ){
|
|
@@ -177596,8 +192952,8 @@ static int fts3SegmentIsMaxLevel(Fts3Table *p, i64 iAbsLevel, int *pbMax){
|
|
int rc = fts3SqlStmt(p, SQL_SELECT_SEGDIR_MAX_LEVEL, &pStmt, 0);
|
|
if( rc!=SQLITE_OK ) return rc;
|
|
sqlite3_bind_int64(pStmt, 1, iAbsLevel+1);
|
|
- sqlite3_bind_int64(pStmt, 2,
|
|
- ((iAbsLevel/FTS3_SEGDIR_MAXLEVEL)+1) * FTS3_SEGDIR_MAXLEVEL
|
|
+ sqlite3_bind_int64(pStmt, 2,
|
|
+ (((u64)iAbsLevel/FTS3_SEGDIR_MAXLEVEL)+1) * FTS3_SEGDIR_MAXLEVEL
|
|
);
|
|
|
|
*pbMax = 0;
|
|
@@ -177634,9 +192990,9 @@ static int fts3DeleteSegment(
|
|
** This function is used after merging multiple segments into a single large
|
|
** segment to delete the old, now redundant, segment b-trees. Specifically,
|
|
** it:
|
|
-**
|
|
-** 1) Deletes all %_segments entries for the segments associated with
|
|
-** each of the SegReader objects in the array passed as the third
|
|
+**
|
|
+** 1) Deletes all %_segments entries for the segments associated with
|
|
+** each of the SegReader objects in the array passed as the third
|
|
** argument, and
|
|
**
|
|
** 2) deletes all %_segdir entries with level iLevel, or all %_segdir
|
|
@@ -177668,7 +193024,7 @@ static int fts3DeleteSegdir(
|
|
rc = fts3SqlStmt(p, SQL_DELETE_SEGDIR_RANGE, &pDelete, 0);
|
|
if( rc==SQLITE_OK ){
|
|
sqlite3_bind_int64(pDelete, 1, getAbsoluteLevel(p, iLangid, iIndex, 0));
|
|
- sqlite3_bind_int64(pDelete, 2,
|
|
+ sqlite3_bind_int64(pDelete, 2,
|
|
getAbsoluteLevel(p, iLangid, iIndex, FTS3_SEGDIR_MAXLEVEL-1)
|
|
);
|
|
}
|
|
@@ -177690,7 +193046,7 @@ static int fts3DeleteSegdir(
|
|
}
|
|
|
|
/*
|
|
-** When this function is called, buffer *ppList (size *pnList bytes) contains
|
|
+** When this function is called, buffer *ppList (size *pnList bytes) contains
|
|
** a position list that may (or may not) feature multiple columns. This
|
|
** function adjusts the pointer *ppList and the length *pnList so that they
|
|
** identify the subset of the position list that corresponds to column iCol.
|
|
@@ -177717,7 +193073,7 @@ static void fts3ColumnFilter(
|
|
while( 1 ){
|
|
char c = 0;
|
|
while( p<pEnd && (c | *p)&0xFE ) c = *p++ & 0x80;
|
|
-
|
|
+
|
|
if( iCol==iCurrent ){
|
|
nList = (int)(p - pList);
|
|
break;
|
|
@@ -177749,18 +193105,20 @@ static void fts3ColumnFilter(
|
|
static int fts3MsrBufferData(
|
|
Fts3MultiSegReader *pMsr, /* Multi-segment-reader handle */
|
|
char *pList,
|
|
- int nList
|
|
+ i64 nList
|
|
){
|
|
- if( nList>pMsr->nBuffer ){
|
|
+ if( (nList+FTS3_NODE_PADDING)>pMsr->nBuffer ){
|
|
char *pNew;
|
|
- pMsr->nBuffer = nList*2;
|
|
- pNew = (char *)sqlite3_realloc(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;
|
|
}
|
|
|
|
@@ -177798,7 +193156,7 @@ SQLITE_PRIVATE int sqlite3Fts3MsrIncrNext(
|
|
|
|
rc = fts3SegReaderNextDocid(p, apSegment[0], &pList, &nList);
|
|
j = 1;
|
|
- while( rc==SQLITE_OK
|
|
+ while( rc==SQLITE_OK
|
|
&& j<nMerge
|
|
&& apSegment[j]->pOffsetList
|
|
&& apSegment[j]->iDocid==iDocid
|
|
@@ -177810,7 +193168,7 @@ SQLITE_PRIVATE int sqlite3Fts3MsrIncrNext(
|
|
fts3SegReaderSort(pMsr->apSegment, nMerge, j, xCmp);
|
|
|
|
if( nList>0 && fts3SegReaderIsPending(apSegment[0]) ){
|
|
- rc = fts3MsrBufferData(pMsr, pList, nList+1);
|
|
+ rc = fts3MsrBufferData(pMsr, pList, (i64)nList+1);
|
|
if( rc!=SQLITE_OK ) return rc;
|
|
assert( (pMsr->aBuffer[nList] & 0xFE)==0x00 );
|
|
pList = pMsr->aBuffer;
|
|
@@ -177841,7 +193199,7 @@ static int fts3SegReaderStart(
|
|
int i;
|
|
int nSeg = pCsr->nSegment;
|
|
|
|
- /* If the Fts3SegFilter defines a specific term (or term prefix) to search
|
|
+ /* If the Fts3SegFilter defines a specific term (or term prefix) to search
|
|
** for, then advance each segment iterator until it points to a term of
|
|
** equal or greater value than the specified term. This prevents many
|
|
** unnecessary merge/sort operations for the case where single segment
|
|
@@ -177925,7 +193283,7 @@ SQLITE_PRIVATE int sqlite3Fts3MsrIncrStart(
|
|
** sqlite3Fts3SegReaderStart()
|
|
** sqlite3Fts3SegReaderStep()
|
|
**
|
|
-** then the entire doclist for the term is available in
|
|
+** then the entire doclist for the term is available in
|
|
** MultiSegReader.aDoclist/nDoclist.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr){
|
|
@@ -177947,6 +193305,19 @@ SQLITE_PRIVATE int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr){
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
+static int fts3GrowSegReaderBuffer(Fts3MultiSegReader *pCsr, i64 nReq){
|
|
+ if( nReq>pCsr->nBuffer ){
|
|
+ char *aNew;
|
|
+ pCsr->nBuffer = nReq*2;
|
|
+ aNew = sqlite3_realloc64(pCsr->aBuffer, pCsr->nBuffer);
|
|
+ if( !aNew ){
|
|
+ return SQLITE_NOMEM;
|
|
+ }
|
|
+ pCsr->aBuffer = aNew;
|
|
+ }
|
|
+ return SQLITE_OK;
|
|
+}
|
|
+
|
|
|
|
SQLITE_PRIVATE int sqlite3Fts3SegReaderStep(
|
|
Fts3Table *p, /* Virtual table handle */
|
|
@@ -177973,9 +193344,9 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderStep(
|
|
do {
|
|
int nMerge;
|
|
int i;
|
|
-
|
|
+
|
|
/* Advance the first pCsr->nAdvance entries in the apSegment[] array
|
|
- ** forward. Then sort the list in order of current term again.
|
|
+ ** forward. Then sort the list in order of current term again.
|
|
*/
|
|
for(i=0; i<pCsr->nAdvance; i++){
|
|
Fts3SegReader *pSeg = apSegment[i];
|
|
@@ -177997,39 +193368,40 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderStep(
|
|
pCsr->zTerm = apSegment[0]->zTerm;
|
|
|
|
/* If this is a prefix-search, and if the term that apSegment[0] points
|
|
- ** to does not share a suffix with pFilter->zTerm/nTerm, then all
|
|
+ ** to does not share a suffix with pFilter->zTerm/nTerm, then all
|
|
** required callbacks have been made. In this case exit early.
|
|
**
|
|
** Similarly, if this is a search for an exact match, and the first term
|
|
** of segment apSegment[0] is not a match, exit early.
|
|
*/
|
|
if( pFilter->zTerm && !isScan ){
|
|
- if( pCsr->nTerm<pFilter->nTerm
|
|
+ if( pCsr->nTerm<pFilter->nTerm
|
|
|| (!isPrefix && pCsr->nTerm>pFilter->nTerm)
|
|
- || memcmp(pCsr->zTerm, pFilter->zTerm, pFilter->nTerm)
|
|
+ || memcmp(pCsr->zTerm, pFilter->zTerm, pFilter->nTerm)
|
|
){
|
|
break;
|
|
}
|
|
}
|
|
|
|
nMerge = 1;
|
|
- while( nMerge<nSegment
|
|
+ while( nMerge<nSegment
|
|
&& apSegment[nMerge]->aNode
|
|
- && apSegment[nMerge]->nTerm==pCsr->nTerm
|
|
+ && apSegment[nMerge]->nTerm==pCsr->nTerm
|
|
&& 0==memcmp(pCsr->zTerm, apSegment[nMerge]->zTerm, pCsr->nTerm)
|
|
){
|
|
nMerge++;
|
|
}
|
|
|
|
assert( isIgnoreEmpty || (isRequirePos && !isColFilter) );
|
|
- if( nMerge==1
|
|
- && !isIgnoreEmpty
|
|
- && !isFirst
|
|
+ if( nMerge==1
|
|
+ && !isIgnoreEmpty
|
|
+ && !isFirst
|
|
&& (p->bDescIdx==0 || fts3SegReaderIsPending(apSegment[0])==0)
|
|
){
|
|
pCsr->nDoclist = apSegment[0]->nDoclist;
|
|
if( fts3SegReaderIsPending(apSegment[0]) ){
|
|
- rc = fts3MsrBufferData(pCsr, apSegment[0]->aDoclist, pCsr->nDoclist);
|
|
+ rc = fts3MsrBufferData(pCsr, apSegment[0]->aDoclist,
|
|
+ (i64)pCsr->nDoclist);
|
|
pCsr->aDoclist = pCsr->aBuffer;
|
|
}else{
|
|
pCsr->aDoclist = apSegment[0]->aDoclist;
|
|
@@ -178069,7 +193441,7 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderStep(
|
|
|
|
if( !isIgnoreEmpty || nList>0 ){
|
|
|
|
- /* Calculate the 'docid' delta value to write into the merged
|
|
+ /* Calculate the 'docid' delta value to write into the merged
|
|
** doclist. */
|
|
sqlite3_int64 iDelta;
|
|
if( p->bDescIdx && nDoclist>0 ){
|
|
@@ -178081,20 +193453,15 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderStep(
|
|
}
|
|
|
|
nByte = sqlite3Fts3VarintLen(iDelta) + (isRequirePos?nList+1:0);
|
|
- if( nDoclist+nByte>pCsr->nBuffer ){
|
|
- char *aNew;
|
|
- pCsr->nBuffer = (nDoclist+nByte)*2;
|
|
- aNew = sqlite3_realloc(pCsr->aBuffer, pCsr->nBuffer);
|
|
- if( !aNew ){
|
|
- return SQLITE_NOMEM;
|
|
- }
|
|
- pCsr->aBuffer = aNew;
|
|
- }
|
|
+
|
|
+ rc = fts3GrowSegReaderBuffer(pCsr,
|
|
+ (i64)nByte+nDoclist+FTS3_NODE_PADDING);
|
|
+ if( rc ) return rc;
|
|
|
|
if( isFirst ){
|
|
char *a = &pCsr->aBuffer[nDoclist];
|
|
int nWrite;
|
|
-
|
|
+
|
|
nWrite = sqlite3Fts3FirstFilter(iDelta, pList, nList, a);
|
|
if( nWrite ){
|
|
iPrev = iDocid;
|
|
@@ -178114,6 +193481,9 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderStep(
|
|
fts3SegReaderSort(apSegment, nMerge, j, xCmp);
|
|
}
|
|
if( nDoclist>0 ){
|
|
+ rc = fts3GrowSegReaderBuffer(pCsr, (i64)nDoclist+FTS3_NODE_PADDING);
|
|
+ if( rc ) return rc;
|
|
+ memset(&pCsr->aBuffer[nDoclist], 0, FTS3_NODE_PADDING);
|
|
pCsr->aDoclist = pCsr->aBuffer;
|
|
pCsr->nDoclist = nDoclist;
|
|
rc = SQLITE_ROW;
|
|
@@ -178144,18 +193514,18 @@ SQLITE_PRIVATE void sqlite3Fts3SegReaderFinish(
|
|
}
|
|
|
|
/*
|
|
-** Decode the "end_block" field, selected by column iCol of the SELECT
|
|
-** statement passed as the first argument.
|
|
+** Decode the "end_block" field, selected by column iCol of the SELECT
|
|
+** statement passed as the first argument.
|
|
**
|
|
** The "end_block" field may contain either an integer, or a text field
|
|
-** containing the text representation of two non-negative integers separated
|
|
-** by one or more space (0x20) characters. In the first case, set *piEndBlock
|
|
-** to the integer value and *pnByte to zero before returning. In the second,
|
|
+** containing the text representation of two non-negative integers separated
|
|
+** by one or more space (0x20) characters. In the first case, set *piEndBlock
|
|
+** to the integer value and *pnByte to zero before returning. In the second,
|
|
** set *piEndBlock to the first value and *pnByte to the second.
|
|
*/
|
|
static void fts3ReadEndBlockField(
|
|
- sqlite3_stmt *pStmt,
|
|
- int iCol,
|
|
+ sqlite3_stmt *pStmt,
|
|
+ int iCol,
|
|
i64 *piEndBlock,
|
|
i64 *pnByte
|
|
){
|
|
@@ -178163,11 +193533,11 @@ static void fts3ReadEndBlockField(
|
|
if( zText ){
|
|
int i;
|
|
int iMul = 1;
|
|
- i64 iVal = 0;
|
|
+ u64 iVal = 0;
|
|
for(i=0; zText[i]>='0' && zText[i]<='9'; i++){
|
|
iVal = iVal*10 + (zText[i] - '0');
|
|
}
|
|
- *piEndBlock = iVal;
|
|
+ *piEndBlock = (i64)iVal;
|
|
while( zText[i]==' ' ) i++;
|
|
iVal = 0;
|
|
if( zText[i]=='-' ){
|
|
@@ -178177,7 +193547,7 @@ static void fts3ReadEndBlockField(
|
|
for(/* no-op */; zText[i]>='0' && zText[i]<='9'; i++){
|
|
iVal = iVal*10 + (zText[i] - '0');
|
|
}
|
|
- *pnByte = (iVal * (i64)iMul);
|
|
+ *pnByte = ((i64)iVal * (i64)iMul);
|
|
}
|
|
}
|
|
|
|
@@ -178201,10 +193571,10 @@ static int fts3PromoteSegments(
|
|
i64 iLast = (iAbsLevel/FTS3_SEGDIR_MAXLEVEL + 1) * FTS3_SEGDIR_MAXLEVEL - 1;
|
|
i64 nLimit = (nByte*3)/2;
|
|
|
|
- /* Loop through all entries in the %_segdir table corresponding to
|
|
+ /* Loop through all entries in the %_segdir table corresponding to
|
|
** segments in this index on levels greater than iAbsLevel. If there is
|
|
- ** at least one such segment, and it is possible to determine that all
|
|
- ** such segments are smaller than nLimit bytes in size, they will be
|
|
+ ** at least one such segment, and it is possible to determine that all
|
|
+ ** such segments are smaller than nLimit bytes in size, they will be
|
|
** promoted to level iAbsLevel. */
|
|
sqlite3_bind_int64(pRange, 1, iAbsLevel+1);
|
|
sqlite3_bind_int64(pRange, 2, iLast);
|
|
@@ -178212,7 +193582,7 @@ static int fts3PromoteSegments(
|
|
i64 nSize = 0, dummy;
|
|
fts3ReadEndBlockField(pRange, 2, &dummy, &nSize);
|
|
if( nSize<=0 || nSize>nLimit ){
|
|
- /* If nSize==0, then the %_segdir.end_block field does not not
|
|
+ /* If nSize==0, then the %_segdir.end_block field does not not
|
|
** contain a size value. This happens if it was written by an
|
|
** old version of FTS. In this case it is not possible to determine
|
|
** the size of the segment, and so segment promotion does not
|
|
@@ -178278,18 +193648,18 @@ static int fts3PromoteSegments(
|
|
}
|
|
|
|
/*
|
|
-** Merge all level iLevel segments in the database into a single
|
|
+** Merge all level iLevel segments in the database into a single
|
|
** iLevel+1 segment. Or, if iLevel<0, merge all segments into a
|
|
-** single segment with a level equal to the numerically largest level
|
|
+** single segment with a level equal to the numerically largest level
|
|
** currently present in the database.
|
|
**
|
|
** If this function is called with iLevel<0, but there is only one
|
|
-** segment in the database, SQLITE_DONE is returned immediately.
|
|
-** Otherwise, if successful, SQLITE_OK is returned. If an error occurs,
|
|
+** segment in the database, SQLITE_DONE is returned immediately.
|
|
+** Otherwise, if successful, SQLITE_OK is returned. If an error occurs,
|
|
** an SQLite error code is returned.
|
|
*/
|
|
static int fts3SegmentMerge(
|
|
- Fts3Table *p,
|
|
+ Fts3Table *p,
|
|
int iLangid, /* Language id to merge */
|
|
int iIndex, /* Index in p->aIndex[] to merge */
|
|
int iLevel /* Level to merge */
|
|
@@ -178333,7 +193703,7 @@ static int fts3SegmentMerge(
|
|
}else{
|
|
/* This call is to merge all segments at level iLevel. find the next
|
|
** available segment index at level iLevel+1. The call to
|
|
- ** fts3AllocateSegdirIdx() will merge the segments at level iLevel+1 to
|
|
+ ** fts3AllocateSegdirIdx() will merge the segments at level iLevel+1 to
|
|
** a single iLevel+2 segment if necessary. */
|
|
assert( FTS3_SEGCURSOR_PENDING==-1 );
|
|
iNewLevel = getAbsoluteLevel(p, iLangid, iIndex, iLevel+1);
|
|
@@ -178344,8 +193714,8 @@ static int fts3SegmentMerge(
|
|
|
|
assert( csr.nSegment>0 );
|
|
assert_fts3_nc( iNewLevel>=getAbsoluteLevel(p, iLangid, iIndex, 0) );
|
|
- assert_fts3_nc(
|
|
- iNewLevel<getAbsoluteLevel(p, iLangid, iIndex,FTS3_SEGDIR_MAXLEVEL)
|
|
+ assert_fts3_nc(
|
|
+ iNewLevel<getAbsoluteLevel(p, iLangid, iIndex,FTS3_SEGDIR_MAXLEVEL)
|
|
);
|
|
|
|
memset(&filter, 0, sizeof(Fts3SegFilter));
|
|
@@ -178356,7 +193726,7 @@ static int fts3SegmentMerge(
|
|
while( SQLITE_OK==rc ){
|
|
rc = sqlite3Fts3SegReaderStep(p, &csr);
|
|
if( rc!=SQLITE_ROW ) break;
|
|
- rc = fts3SegWriterAdd(p, &pWriter, 1,
|
|
+ rc = fts3SegWriterAdd(p, &pWriter, 1,
|
|
csr.zTerm, csr.nTerm, csr.aDoclist, csr.nDoclist);
|
|
}
|
|
if( rc!=SQLITE_OK ) goto finished;
|
|
@@ -178384,13 +193754,13 @@ static int fts3SegmentMerge(
|
|
}
|
|
|
|
|
|
-/*
|
|
-** Flush the contents of pendingTerms to level 0 segments.
|
|
+/*
|
|
+** Flush the contents of pendingTerms to level 0 segments.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3Fts3PendingTermsFlush(Fts3Table *p){
|
|
int rc = SQLITE_OK;
|
|
int i;
|
|
-
|
|
+
|
|
for(i=0; rc==SQLITE_OK && i<p->nIndex; i++){
|
|
rc = fts3SegmentMerge(p, p->iPrevLangid, i, FTS3_SEGCURSOR_PENDING);
|
|
if( rc==SQLITE_DONE ) rc = SQLITE_OK;
|
|
@@ -178494,7 +193864,7 @@ static void fts3InsertDocsize(
|
|
/*
|
|
** Record 0 of the %_stat table contains a blob consisting of N varints,
|
|
** where N is the number of user defined columns in the fts3 table plus
|
|
-** two. If nCol is the number of user defined columns, then values of the
|
|
+** two. If nCol is the number of user defined columns, then values of the
|
|
** varints are set as follows:
|
|
**
|
|
** Varint 0: Total number of rows in the table.
|
|
@@ -178579,7 +193949,7 @@ static void fts3UpdateDocTotals(
|
|
}
|
|
|
|
/*
|
|
-** Merge the entire database so that there is one segment for each
|
|
+** Merge the entire database so that there is one segment for each
|
|
** iIndex/iLangid combination.
|
|
*/
|
|
static int fts3DoOptimize(Fts3Table *p, int bReturnDone){
|
|
@@ -178620,7 +193990,7 @@ static int fts3DoOptimize(Fts3Table *p, int bReturnDone){
|
|
**
|
|
** INSERT INTO <tbl>(<tbl>) VALUES('rebuild');
|
|
**
|
|
-** The entire FTS index is discarded and rebuilt. If the table is one
|
|
+** The entire FTS index is discarded and rebuilt. If the table is one
|
|
** created using the content=xxx option, then the new index is based on
|
|
** the current contents of the xxx table. Otherwise, it is rebuilt based
|
|
** on the contents of the %_content table.
|
|
@@ -178700,9 +194070,9 @@ static int fts3DoRebuild(Fts3Table *p){
|
|
|
|
|
|
/*
|
|
-** This function opens a cursor used to read the input data for an
|
|
+** This function opens a cursor used to read the input data for an
|
|
** incremental merge operation. Specifically, it opens a cursor to scan
|
|
-** the oldest nSeg segments (idx=0 through idx=(nSeg-1)) in absolute
|
|
+** the oldest nSeg segments (idx=0 through idx=(nSeg-1)) in absolute
|
|
** level iAbsLevel.
|
|
*/
|
|
static int fts3IncrmergeCsr(
|
|
@@ -178712,7 +194082,7 @@ static int fts3IncrmergeCsr(
|
|
Fts3MultiSegReader *pCsr /* Cursor object to populate */
|
|
){
|
|
int rc; /* Return Code */
|
|
- sqlite3_stmt *pStmt = 0; /* Statement used to read %_segdir entry */
|
|
+ sqlite3_stmt *pStmt = 0; /* Statement used to read %_segdir entry */
|
|
sqlite3_int64 nByte; /* Bytes allocated at pCsr->apSegment[] */
|
|
|
|
/* Allocate space for the Fts3MultiSegReader.aCsr[] array */
|
|
@@ -178767,7 +194137,7 @@ struct Blob {
|
|
};
|
|
|
|
/*
|
|
-** This structure is used to build up buffers containing segment b-tree
|
|
+** This structure is used to build up buffers containing segment b-tree
|
|
** nodes (blocks).
|
|
*/
|
|
struct NodeWriter {
|
|
@@ -178824,7 +194194,7 @@ struct NodeReader {
|
|
static void blobGrowBuffer(Blob *pBlob, int nMin, int *pRc){
|
|
if( *pRc==SQLITE_OK && nMin>pBlob->nAlloc ){
|
|
int nAlloc = nMin;
|
|
- char *a = (char *)sqlite3_realloc(pBlob->a, nAlloc);
|
|
+ char *a = (char *)sqlite3_realloc64(pBlob->a, nAlloc);
|
|
if( a ){
|
|
pBlob->nAlloc = nAlloc;
|
|
pBlob->a = a;
|
|
@@ -178836,12 +194206,12 @@ static void blobGrowBuffer(Blob *pBlob, int nMin, int *pRc){
|
|
|
|
/*
|
|
** Attempt to advance the node-reader object passed as the first argument to
|
|
-** the next entry on the node.
|
|
+** the next entry on the node.
|
|
**
|
|
-** Return an error code if an error occurs (SQLITE_NOMEM is possible).
|
|
+** Return an error code if an error occurs (SQLITE_NOMEM is possible).
|
|
** Otherwise return SQLITE_OK. If there is no next entry on the node
|
|
** (e.g. because the current entry is the last) set NodeReader->aNode to
|
|
-** NULL to indicate EOF. Otherwise, populate the NodeReader structure output
|
|
+** NULL to indicate EOF. Otherwise, populate the NodeReader structure output
|
|
** variables for the new entry.
|
|
*/
|
|
static int nodeReaderNext(NodeReader *p){
|
|
@@ -178865,7 +194235,7 @@ static int nodeReaderNext(NodeReader *p){
|
|
return FTS_CORRUPT_VTAB;
|
|
}
|
|
blobGrowBuffer(&p->term, nPrefix+nSuffix, &rc);
|
|
- if( rc==SQLITE_OK ){
|
|
+ if( rc==SQLITE_OK && ALWAYS(p->term.a!=0) ){
|
|
memcpy(&p->term.a[nPrefix], &p->aNode[p->iOff], nSuffix);
|
|
p->term.n = nPrefix+nSuffix;
|
|
p->iOff += nSuffix;
|
|
@@ -178894,7 +194264,7 @@ static void nodeReaderRelease(NodeReader *p){
|
|
/*
|
|
** Initialize a node-reader object to read the node in buffer aNode/nNode.
|
|
**
|
|
-** If successful, SQLITE_OK is returned and the NodeReader object set to
|
|
+** If successful, SQLITE_OK is returned and the NodeReader object set to
|
|
** point to the first entry on the node (if any). Otherwise, an SQLite
|
|
** error code is returned.
|
|
*/
|
|
@@ -178943,7 +194313,7 @@ static int fts3IncrmergePush(
|
|
int nSpace;
|
|
|
|
/* Figure out how much space the key will consume if it is written to
|
|
- ** the current node of layer iLayer. Due to the prefix compression,
|
|
+ ** the current node of layer iLayer. Due to the prefix compression,
|
|
** the space required changes depending on which node the key is to
|
|
** be added to. */
|
|
nPrefix = fts3PrefixCompress(pNode->key.a, pNode->key.n, zTerm, nTerm);
|
|
@@ -178952,9 +194322,9 @@ static int fts3IncrmergePush(
|
|
nSpace = sqlite3Fts3VarintLen(nPrefix);
|
|
nSpace += sqlite3Fts3VarintLen(nSuffix) + nSuffix;
|
|
|
|
- if( pNode->key.n==0 || (pNode->block.n + nSpace)<=p->nNodeSize ){
|
|
+ if( pNode->key.n==0 || (pNode->block.n + nSpace)<=p->nNodeSize ){
|
|
/* If the current node of layer iLayer contains zero keys, or if adding
|
|
- ** the key to it will not cause it to grow to larger than nNodeSize
|
|
+ ** the key to it will not cause it to grow to larger than nNodeSize
|
|
** bytes in size, write the key here. */
|
|
|
|
Blob *pBlk = &pNode->block;
|
|
@@ -178973,6 +194343,8 @@ static int fts3IncrmergePush(
|
|
pBlk->n += sqlite3Fts3PutVarint(&pBlk->a[pBlk->n], nPrefix);
|
|
}
|
|
pBlk->n += sqlite3Fts3PutVarint(&pBlk->a[pBlk->n], nSuffix);
|
|
+ assert( nPrefix+nSuffix<=nTerm );
|
|
+ assert( nPrefix>=0 );
|
|
memcpy(&pBlk->a[pBlk->n], &zTerm[nPrefix], nSuffix);
|
|
pBlk->n += nSuffix;
|
|
|
|
@@ -179010,12 +194382,12 @@ static int fts3IncrmergePush(
|
|
** A node header is a single 0x00 byte for a leaf node, or a height varint
|
|
** followed by the left-hand-child varint for an internal node.
|
|
**
|
|
-** The term to be appended is passed via arguments zTerm/nTerm. For a
|
|
+** The term to be appended is passed via arguments zTerm/nTerm. For a
|
|
** leaf node, the doclist is passed as aDoclist/nDoclist. For an internal
|
|
** node, both aDoclist and nDoclist must be passed 0.
|
|
**
|
|
** If the size of the value in blob pPrev is zero, then this is the first
|
|
-** term written to the node. Otherwise, pPrev contains a copy of the
|
|
+** term written to the node. Otherwise, pPrev contains a copy of the
|
|
** previous term. Before this function returns, it is updated to contain a
|
|
** copy of zTerm/nTerm.
|
|
**
|
|
@@ -179032,7 +194404,7 @@ static int fts3AppendToNode(
|
|
const char *zTerm, /* New term to write */
|
|
int nTerm, /* Size of zTerm in bytes */
|
|
const char *aDoclist, /* Doclist (or NULL) to write */
|
|
- int nDoclist /* Size of aDoclist in bytes */
|
|
+ int nDoclist /* Size of aDoclist in bytes */
|
|
){
|
|
int rc = SQLITE_OK; /* Return code */
|
|
int bFirst = (pPrev->n==0); /* True if this is the first term written */
|
|
@@ -179095,6 +194467,7 @@ static int fts3IncrmergeAppend(
|
|
pLeaf = &pWriter->aNodeWriter[0];
|
|
nPrefix = fts3PrefixCompress(pLeaf->key.a, pLeaf->key.n, zTerm, nTerm);
|
|
nSuffix = nTerm - nPrefix;
|
|
+ if(nSuffix<=0 ) return FTS_CORRUPT_VTAB;
|
|
|
|
nSpace = sqlite3Fts3VarintLen(nPrefix);
|
|
nSpace += sqlite3Fts3VarintLen(nSuffix) + nSuffix;
|
|
@@ -179107,7 +194480,7 @@ static int fts3IncrmergeAppend(
|
|
rc = fts3WriteSegment(p, pLeaf->iBlock, pLeaf->block.a, pLeaf->block.n);
|
|
pWriter->nWork++;
|
|
|
|
- /* Add the current term to the parent node. The term added to the
|
|
+ /* Add the current term to the parent node. The term added to the
|
|
** parent must:
|
|
**
|
|
** a) be greater than the largest term on the leaf node just written
|
|
@@ -179172,7 +194545,7 @@ static void fts3IncrmergeRelease(
|
|
NodeWriter *pRoot; /* NodeWriter for root node */
|
|
int rc = *pRc; /* Error code */
|
|
|
|
- /* Set iRoot to the index in pWriter->aNodeWriter[] of the output segment
|
|
+ /* Set iRoot to the index in pWriter->aNodeWriter[] of the output segment
|
|
** root node. If the segment fits entirely on a single leaf node, iRoot
|
|
** will be set to 0. If the root node is the parent of the leaves, iRoot
|
|
** will be 1. And so on. */
|
|
@@ -179190,17 +194563,17 @@ static void fts3IncrmergeRelease(
|
|
|
|
/* The entire output segment fits on a single node. Normally, this means
|
|
** the node would be stored as a blob in the "root" column of the %_segdir
|
|
- ** table. However, this is not permitted in this case. The problem is that
|
|
- ** space has already been reserved in the %_segments table, and so the
|
|
- ** start_block and end_block fields of the %_segdir table must be populated.
|
|
- ** And, by design or by accident, released versions of FTS cannot handle
|
|
+ ** table. However, this is not permitted in this case. The problem is that
|
|
+ ** space has already been reserved in the %_segments table, and so the
|
|
+ ** start_block and end_block fields of the %_segdir table must be populated.
|
|
+ ** And, by design or by accident, released versions of FTS cannot handle
|
|
** segments that fit entirely on the root node with start_block!=0.
|
|
**
|
|
- ** Instead, create a synthetic root node that contains nothing but a
|
|
+ ** Instead, create a synthetic root node that contains nothing but a
|
|
** pointer to the single content node. So that the segment consists of a
|
|
** single leaf and a single interior (root) node.
|
|
**
|
|
- ** Todo: Better might be to defer allocating space in the %_segments
|
|
+ ** Todo: Better might be to defer allocating space in the %_segments
|
|
** table until we are sure it is needed.
|
|
*/
|
|
if( iRoot==0 ){
|
|
@@ -179228,7 +194601,7 @@ static void fts3IncrmergeRelease(
|
|
|
|
/* Write the %_segdir record. */
|
|
if( rc==SQLITE_OK ){
|
|
- rc = fts3WriteSegdir(p,
|
|
+ rc = fts3WriteSegdir(p,
|
|
pWriter->iAbsLevel+1, /* level */
|
|
pWriter->iIdx, /* idx */
|
|
pWriter->iStart, /* start_block */
|
|
@@ -179259,7 +194632,11 @@ static int fts3TermCmp(
|
|
int nCmp = MIN(nLhs, nRhs);
|
|
int res;
|
|
|
|
- res = (nCmp ? memcmp(zLhs, zRhs, nCmp) : 0);
|
|
+ if( nCmp && ALWAYS(zLhs) && ALWAYS(zRhs) ){
|
|
+ res = memcmp(zLhs, zRhs, nCmp);
|
|
+ }else{
|
|
+ res = 0;
|
|
+ }
|
|
if( res==0 ) res = nLhs - nRhs;
|
|
|
|
return res;
|
|
@@ -179267,11 +194644,11 @@ static int fts3TermCmp(
|
|
|
|
|
|
/*
|
|
-** Query to see if the entry in the %_segments table with blockid iEnd is
|
|
+** Query to see if the entry in the %_segments table with blockid iEnd is
|
|
** NULL. If no error occurs and the entry is NULL, set *pbRes 1 before
|
|
-** returning. Otherwise, set *pbRes to 0.
|
|
+** returning. Otherwise, set *pbRes to 0.
|
|
**
|
|
-** Or, if an error occurs while querying the database, return an SQLite
|
|
+** Or, if an error occurs while querying the database, return an SQLite
|
|
** error code. The final value of *pbRes is undefined in this case.
|
|
**
|
|
** This is used to test if a segment is an "appendable" segment. If it
|
|
@@ -179289,14 +194666,14 @@ static int fts3IsAppendable(Fts3Table *p, sqlite3_int64 iEnd, int *pbRes){
|
|
if( SQLITE_ROW==sqlite3_step(pCheck) ) bRes = 1;
|
|
rc = sqlite3_reset(pCheck);
|
|
}
|
|
-
|
|
+
|
|
*pbRes = bRes;
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
** This function is called when initializing an incremental-merge operation.
|
|
-** It checks if the existing segment with index value iIdx at absolute level
|
|
+** It checks if the existing segment with index value iIdx at absolute level
|
|
** (iAbsLevel+1) can be appended to by the incremental merge. If it can, the
|
|
** merge-writer object *pWriter is initialized to write to it.
|
|
**
|
|
@@ -179305,7 +194682,7 @@ static int fts3IsAppendable(Fts3Table *p, sqlite3_int64 iEnd, int *pbRes){
|
|
** * It was initially created as an appendable segment (with all required
|
|
** space pre-allocated), and
|
|
**
|
|
-** * The first key read from the input (arguments zKey and nKey) is
|
|
+** * The first key read from the input (arguments zKey and nKey) is
|
|
** greater than the largest key currently stored in the potential
|
|
** output segment.
|
|
*/
|
|
@@ -179382,7 +194759,7 @@ static int fts3IncrmergeLoad(
|
|
int i;
|
|
int nHeight = (int)aRoot[0];
|
|
NodeWriter *pNode;
|
|
- if( nHeight<1 || nHeight>FTS_MAX_APPENDABLE_HEIGHT ){
|
|
+ if( nHeight<1 || nHeight>=FTS_MAX_APPENDABLE_HEIGHT ){
|
|
sqlite3_reset(pSelect);
|
|
return FTS_CORRUPT_VTAB;
|
|
}
|
|
@@ -179399,7 +194776,7 @@ static int fts3IncrmergeLoad(
|
|
|
|
pNode = &pWriter->aNodeWriter[nHeight];
|
|
pNode->iBlock = pWriter->iStart + pWriter->nLeafEst*nHeight;
|
|
- blobGrowBuffer(&pNode->block,
|
|
+ blobGrowBuffer(&pNode->block,
|
|
MAX(nRoot, p->nNodeSize)+FTS3_NODE_PADDING, &rc
|
|
);
|
|
if( rc==SQLITE_OK ){
|
|
@@ -179417,17 +194794,20 @@ static int fts3IncrmergeLoad(
|
|
while( reader.aNode && rc==SQLITE_OK ) rc = nodeReaderNext(&reader);
|
|
blobGrowBuffer(&pNode->key, reader.term.n, &rc);
|
|
if( rc==SQLITE_OK ){
|
|
- memcpy(pNode->key.a, reader.term.a, reader.term.n);
|
|
+ assert_fts3_nc( reader.term.n>0 || reader.aNode==0 );
|
|
+ if( reader.term.n>0 ){
|
|
+ memcpy(pNode->key.a, reader.term.a, reader.term.n);
|
|
+ }
|
|
pNode->key.n = reader.term.n;
|
|
if( i>0 ){
|
|
char *aBlock = 0;
|
|
int nBlock = 0;
|
|
pNode = &pWriter->aNodeWriter[i-1];
|
|
pNode->iBlock = reader.iChild;
|
|
- rc = sqlite3Fts3ReadBlock(p, reader.iChild, &aBlock, &nBlock, 0);
|
|
- blobGrowBuffer(&pNode->block,
|
|
+ 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;
|
|
@@ -179451,13 +194831,13 @@ static int fts3IncrmergeLoad(
|
|
/*
|
|
** Determine the largest segment index value that exists within absolute
|
|
** level iAbsLevel+1. If no error occurs, set *piIdx to this value plus
|
|
-** one before returning SQLITE_OK. Or, if there are no segments at all
|
|
+** one before returning SQLITE_OK. Or, if there are no segments at all
|
|
** within level iAbsLevel, set *piIdx to zero.
|
|
**
|
|
** If an error occurs, return an SQLite error code. The final value of
|
|
** *piIdx is undefined in this case.
|
|
*/
|
|
-static int fts3IncrmergeOutputIdx(
|
|
+static int fts3IncrmergeOutputIdx(
|
|
Fts3Table *p, /* FTS Table handle */
|
|
sqlite3_int64 iAbsLevel, /* Absolute index of input segments */
|
|
int *piIdx /* OUT: Next free index at iAbsLevel+1 */
|
|
@@ -179476,7 +194856,7 @@ static int fts3IncrmergeOutputIdx(
|
|
return rc;
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** Allocate an appendable output segment on absolute level iAbsLevel+1
|
|
** with idx value iIdx.
|
|
**
|
|
@@ -179490,7 +194870,7 @@ static int fts3IncrmergeOutputIdx(
|
|
** When an appendable segment is allocated, it is estimated that the
|
|
** maximum number of leaf blocks that may be required is the sum of the
|
|
** number of leaf blocks consumed by the input segments, plus the number
|
|
-** of input segments, multiplied by two. This value is stored in stack
|
|
+** of input segments, multiplied by two. This value is stored in stack
|
|
** variable nLeafEst.
|
|
**
|
|
** A total of 16*nLeafEst blocks are allocated when an appendable segment
|
|
@@ -179499,10 +194879,10 @@ static int fts3IncrmergeOutputIdx(
|
|
** of interior nodes that are parents of the leaf nodes start at block
|
|
** (start_block + (1 + end_block - start_block) / 16). And so on.
|
|
**
|
|
-** In the actual code below, the value "16" is replaced with the
|
|
+** In the actual code below, the value "16" is replaced with the
|
|
** pre-processor macro FTS_MAX_APPENDABLE_HEIGHT.
|
|
*/
|
|
-static int fts3IncrmergeWriter(
|
|
+static int fts3IncrmergeWriter(
|
|
Fts3Table *p, /* Fts3 table handle */
|
|
sqlite3_int64 iAbsLevel, /* Absolute level of input segments */
|
|
int iIdx, /* Index of new output segment */
|
|
@@ -179540,7 +194920,7 @@ static int fts3IncrmergeWriter(
|
|
if( rc!=SQLITE_OK ) return rc;
|
|
|
|
/* Insert the marker in the %_segments table to make sure nobody tries
|
|
- ** to steal the space just allocated. This is also used to identify
|
|
+ ** to steal the space just allocated. This is also used to identify
|
|
** appendable segments. */
|
|
rc = fts3WriteSegment(p, pWriter->iEnd, 0, 0);
|
|
if( rc!=SQLITE_OK ) return rc;
|
|
@@ -179557,13 +194937,13 @@ static int fts3IncrmergeWriter(
|
|
}
|
|
|
|
/*
|
|
-** Remove an entry from the %_segdir table. This involves running the
|
|
+** Remove an entry from the %_segdir table. This involves running the
|
|
** following two statements:
|
|
**
|
|
** DELETE FROM %_segdir WHERE level = :iAbsLevel AND idx = :iIdx
|
|
** UPDATE %_segdir SET idx = idx - 1 WHERE level = :iAbsLevel AND idx > :iIdx
|
|
**
|
|
-** The DELETE statement removes the specific %_segdir level. The UPDATE
|
|
+** The DELETE statement removes the specific %_segdir level. The UPDATE
|
|
** statement ensures that the remaining segments have contiguously allocated
|
|
** idx values.
|
|
*/
|
|
@@ -179611,7 +194991,7 @@ static int fts3RepackSegdirLevel(
|
|
if( nIdx>=nAlloc ){
|
|
int *aNew;
|
|
nAlloc += 16;
|
|
- aNew = sqlite3_realloc(aIdx, nAlloc*sizeof(int));
|
|
+ aNew = sqlite3_realloc64(aIdx, nAlloc*sizeof(int));
|
|
if( !aNew ){
|
|
rc = SQLITE_NOMEM;
|
|
break;
|
|
@@ -179688,8 +195068,8 @@ static int fts3TruncateNode(
|
|
pNew->n = 0;
|
|
|
|
/* Populate new node buffer */
|
|
- for(rc = nodeReaderInit(&reader, aNode, nNode);
|
|
- rc==SQLITE_OK && reader.aNode;
|
|
+ for(rc = nodeReaderInit(&reader, aNode, nNode);
|
|
+ rc==SQLITE_OK && reader.aNode;
|
|
rc = nodeReaderNext(&reader)
|
|
){
|
|
if( pNew->n==0 ){
|
|
@@ -179716,7 +195096,7 @@ static int fts3TruncateNode(
|
|
}
|
|
|
|
/*
|
|
-** Remove all terms smaller than zTerm/nTerm from segment iIdx in absolute
|
|
+** Remove all terms smaller than zTerm/nTerm from segment iIdx in absolute
|
|
** level iAbsLevel. This may involve deleting entries from the %_segments
|
|
** table, and modifying existing entries in both the %_segments and %_segdir
|
|
** tables.
|
|
@@ -179840,9 +195220,9 @@ static int fts3IncrmergeChomp(
|
|
}
|
|
*pnRem = 0;
|
|
}else{
|
|
- /* The incremental merge did not copy all the data from this
|
|
+ /* The incremental merge did not copy all the data from this
|
|
** segment to the upper level. The segment is modified in place
|
|
- ** so that it contains no keys smaller than zTerm/nTerm. */
|
|
+ ** so that it contains no keys smaller than zTerm/nTerm. */
|
|
const char *zTerm = pSeg->zTerm;
|
|
int nTerm = pSeg->nTerm;
|
|
rc = fts3TruncateSegment(p, iAbsLevel, pSeg->iIdx, zTerm, nTerm);
|
|
@@ -179878,7 +195258,7 @@ static int fts3IncrmergeHintStore(Fts3Table *p, Blob *pHint){
|
|
}
|
|
|
|
/*
|
|
-** Load an incr-merge hint from the database. The incr-merge hint, if one
|
|
+** Load an incr-merge hint from the database. The incr-merge hint, if one
|
|
** exists, is stored in the rowid==1 row of the %_stat table.
|
|
**
|
|
** If successful, populate blob *pHint with the value read from the %_stat
|
|
@@ -179900,7 +195280,7 @@ static int fts3IncrmergeHintLoad(Fts3Table *p, Blob *pHint){
|
|
if( aHint ){
|
|
blobGrowBuffer(pHint, nHint, &rc);
|
|
if( rc==SQLITE_OK ){
|
|
- memcpy(pHint->a, aHint, nHint);
|
|
+ if( ALWAYS(pHint->a!=0) ) memcpy(pHint->a, aHint, nHint);
|
|
pHint->n = nHint;
|
|
}
|
|
}
|
|
@@ -179915,7 +195295,7 @@ static int fts3IncrmergeHintLoad(Fts3Table *p, Blob *pHint){
|
|
/*
|
|
** If *pRc is not SQLITE_OK when this function is called, it is a no-op.
|
|
** Otherwise, append an entry to the hint stored in blob *pHint. Each entry
|
|
-** consists of two varints, the absolute level number of the input segments
|
|
+** consists of two varints, the absolute level number of the input segments
|
|
** and the number of input segments.
|
|
**
|
|
** If successful, leave *pRc set to SQLITE_OK and return. If an error occurs,
|
|
@@ -179936,7 +195316,7 @@ static void fts3IncrmergeHintPush(
|
|
|
|
/*
|
|
** Read the last entry (most recently pushed) from the hint blob *pHint
|
|
-** and then remove the entry. Write the two values read to *piAbsLevel and
|
|
+** and then remove the entry. Write the two values read to *piAbsLevel and
|
|
** *pnInput before returning.
|
|
**
|
|
** If no error occurs, return SQLITE_OK. If the hint blob in *pHint does
|
|
@@ -179966,10 +195346,10 @@ static int fts3IncrmergeHintPop(Blob *pHint, i64 *piAbsLevel, int *pnInput){
|
|
/*
|
|
** Attempt an incremental merge that writes nMerge leaf blocks.
|
|
**
|
|
-** Incremental merges happen nMin segments at a time. The segments
|
|
-** to be merged are the nMin oldest segments (the ones with the smallest
|
|
-** values for the _segdir.idx field) in the highest level that contains
|
|
-** at least nMin segments. Multiple merges might occur in an attempt to
|
|
+** Incremental merges happen nMin segments at a time. The segments
|
|
+** to be merged are the nMin oldest segments (the ones with the smallest
|
|
+** values for the _segdir.idx field) in the highest level that contains
|
|
+** at least nMin segments. Multiple merges might occur in an attempt to
|
|
** write the quota of nMerge leaf blocks.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
|
|
@@ -179985,7 +195365,7 @@ SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
|
|
|
|
/* Allocate space for the cursor, filter and writer objects */
|
|
const int nAlloc = sizeof(*pCsr) + sizeof(*pFilter) + sizeof(*pWriter);
|
|
- pWriter = (IncrmergeWriter *)sqlite3_malloc(nAlloc);
|
|
+ pWriter = (IncrmergeWriter *)sqlite3_malloc64(nAlloc);
|
|
if( !pWriter ) return SQLITE_NOMEM;
|
|
pFilter = (Fts3SegFilter *)&pWriter[1];
|
|
pCsr = (Fts3MultiSegReader *)&pFilter[1];
|
|
@@ -180000,7 +195380,7 @@ SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
|
|
/* Search the %_segdir table for the absolute level with the smallest
|
|
** relative level number that contains at least nMin segments, if any.
|
|
** If one is found, set iAbsLevel to the absolute level number and
|
|
- ** nSeg to nMin. If no level with at least nMin segments can be found,
|
|
+ ** nSeg to nMin. If no level with at least nMin segments can be found,
|
|
** set nSeg to -1.
|
|
*/
|
|
rc = fts3SqlStmt(p, SQL_FIND_MERGE_LEVEL, &pFindLevel, 0);
|
|
@@ -180016,7 +195396,7 @@ SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
|
|
|
|
/* If the hint read from the %_stat table is not empty, check if the
|
|
** last entry in it specifies a relative level smaller than or equal
|
|
- ** to the level identified by the block above (if any). If so, this
|
|
+ ** to the level identified by the block above (if any). If so, this
|
|
** iteration of the loop will work on merging at the hinted level.
|
|
*/
|
|
if( rc==SQLITE_OK && hint.n ){
|
|
@@ -180028,9 +195408,9 @@ SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
|
|
if( nSeg<0 || (iAbsLevel % nMod) >= (iHintAbsLevel % nMod) ){
|
|
/* Based on the scan in the block above, it is known that there
|
|
** are no levels with a relative level smaller than that of
|
|
- ** iAbsLevel with more than nSeg segments, or if nSeg is -1,
|
|
+ ** iAbsLevel with more than nSeg segments, or if nSeg is -1,
|
|
** no levels with more than nMin segments. Use this to limit the
|
|
- ** value of nHintSeg to avoid a large memory allocation in case the
|
|
+ ** value of nHintSeg to avoid a large memory allocation in case the
|
|
** merge-hint is corrupt*/
|
|
iAbsLevel = iHintAbsLevel;
|
|
nSeg = MIN(MAX(nMin,nSeg), nHintSeg);
|
|
@@ -180048,11 +195428,17 @@ SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
|
|
** Exit early in this case. */
|
|
if( nSeg<=0 ) break;
|
|
|
|
- /* Open a cursor to iterate through the contents of the oldest nSeg
|
|
- ** indexes of absolute level iAbsLevel. If this cursor is opened using
|
|
+ assert( nMod<=0x7FFFFFFF );
|
|
+ if( iAbsLevel<0 || iAbsLevel>(nMod<<32) ){
|
|
+ rc = FTS_CORRUPT_VTAB;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ /* Open a cursor to iterate through the contents of the oldest nSeg
|
|
+ ** indexes of absolute level iAbsLevel. If this cursor is opened using
|
|
** the 'hint' parameters, it is possible that there are less than nSeg
|
|
** segments available in level iAbsLevel. In this case, no work is
|
|
- ** done on iAbsLevel - fall through to the next iteration of the loop
|
|
+ ** done on iAbsLevel - fall through to the next iteration of the loop
|
|
** to start work on some other level. */
|
|
memset(pWriter, 0, nAlloc);
|
|
pFilter->flags = FTS3_SEGMENT_REQUIRE_POS;
|
|
@@ -180140,7 +195526,7 @@ SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){
|
|
** the integer.
|
|
**
|
|
** This function used for parameters to merge= and incrmerge=
|
|
-** commands.
|
|
+** commands.
|
|
*/
|
|
static int fts3Getint(const char **pz){
|
|
const char *z = *pz;
|
|
@@ -180335,7 +195721,7 @@ static u64 fts3ChecksumIndex(
|
|
** to true and return SQLITE_OK. Or if the contents do not match, set *pbOk
|
|
** to false before returning.
|
|
**
|
|
-** If an error occurs (e.g. an OOM or IO error), return an SQLite error
|
|
+** If an error occurs (e.g. an OOM or IO error), return an SQLite error
|
|
** code. The final value of *pbOk is undefined in this case.
|
|
*/
|
|
static int fts3IntegrityCheck(Fts3Table *p, int *pbOk){
|
|
@@ -180366,7 +195752,7 @@ static int fts3IntegrityCheck(Fts3Table *p, int *pbOk){
|
|
sqlite3_tokenizer_module const *pModule = p->pTokenizer->pModule;
|
|
sqlite3_stmt *pStmt = 0;
|
|
char *zSql;
|
|
-
|
|
+
|
|
zSql = sqlite3_mprintf("SELECT %s" , p->zReadExprlist);
|
|
if( !zSql ){
|
|
rc = SQLITE_NOMEM;
|
|
@@ -180425,7 +195811,7 @@ static int fts3IntegrityCheck(Fts3Table *p, int *pbOk){
|
|
** the FTS index are correct, return SQLITE_OK. Or, if the contents of the
|
|
** FTS index are incorrect, return SQLITE_CORRUPT_VTAB.
|
|
**
|
|
-** Or, if an error (e.g. an OOM or IO error) occurs, return an SQLite
|
|
+** Or, if an error (e.g. an OOM or IO error) occurs, return an SQLite
|
|
** error code.
|
|
**
|
|
** The integrity-check works as follows. For each token and indexed token
|
|
@@ -180434,7 +195820,7 @@ static int fts3IntegrityCheck(Fts3Table *p, int *pbOk){
|
|
**
|
|
** + The index number (0 for the main index, 1 for the first prefix
|
|
** index etc.),
|
|
-** + The token (or token prefix) text itself,
|
|
+** + The token (or token prefix) text itself,
|
|
** + The language-id of the row it appears in,
|
|
** + The docid of the row it appears in,
|
|
** + The column it appears in, and
|
|
@@ -180445,7 +195831,7 @@ static int fts3IntegrityCheck(Fts3Table *p, int *pbOk){
|
|
**
|
|
** The integrity-check code calculates the same checksum in two ways:
|
|
**
|
|
-** 1. By scanning the contents of the FTS index, and
|
|
+** 1. By scanning the contents of the FTS index, and
|
|
** 2. By scanning and tokenizing the content table.
|
|
**
|
|
** If the two checksums are identical, the integrity-check is deemed to have
|
|
@@ -180466,7 +195852,7 @@ static int fts3DoIntegrityCheck(
|
|
**
|
|
** "INSERT INTO tbl(tbl) VALUES(<expr>)"
|
|
**
|
|
-** Argument pVal contains the result of <expr>. Currently the only
|
|
+** Argument pVal contains the result of <expr>. Currently the only
|
|
** meaningful value to insert is the text 'optimize'.
|
|
*/
|
|
static int fts3SpecialInsert(Fts3Table *p, sqlite3_value *pVal){
|
|
@@ -180524,7 +195910,7 @@ SQLITE_PRIVATE void sqlite3Fts3FreeDeferredDoclists(Fts3Cursor *pCsr){
|
|
}
|
|
|
|
/*
|
|
-** Free all entries in the pCsr->pDeffered list. Entries are added to
|
|
+** Free all entries in the pCsr->pDeffered list. Entries are added to
|
|
** this list using sqlite3Fts3DeferToken().
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3Fts3FreeDeferredTokens(Fts3Cursor *pCsr){
|
|
@@ -180552,14 +195938,14 @@ SQLITE_PRIVATE int sqlite3Fts3CacheDeferredDoclists(Fts3Cursor *pCsr){
|
|
int i; /* Used to iterate through table columns */
|
|
sqlite3_int64 iDocid; /* Docid of the row pCsr points to */
|
|
Fts3DeferredToken *pDef; /* Used to iterate through deferred tokens */
|
|
-
|
|
+
|
|
Fts3Table *p = (Fts3Table *)pCsr->base.pVtab;
|
|
sqlite3_tokenizer *pT = p->pTokenizer;
|
|
sqlite3_tokenizer_module const *pModule = pT->pModule;
|
|
-
|
|
+
|
|
assert( pCsr->isRequireSeek==0 );
|
|
iDocid = sqlite3_column_int64(pCsr->pStmt, 0);
|
|
-
|
|
+
|
|
for(i=0; i<p->nColumn && rc==SQLITE_OK; i++){
|
|
if( p->abNotindexed[i]==0 ){
|
|
const char *zText = (const char *)sqlite3_column_text(pCsr->pStmt, i+1);
|
|
@@ -180600,8 +195986,8 @@ SQLITE_PRIVATE int sqlite3Fts3CacheDeferredDoclists(Fts3Cursor *pCsr){
|
|
}
|
|
|
|
SQLITE_PRIVATE int sqlite3Fts3DeferredTokenList(
|
|
- Fts3DeferredToken *p,
|
|
- char **ppData,
|
|
+ Fts3DeferredToken *p,
|
|
+ char **ppData,
|
|
int *pnData
|
|
){
|
|
char *pRet;
|
|
@@ -180615,13 +196001,13 @@ SQLITE_PRIVATE int sqlite3Fts3DeferredTokenList(
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
- pRet = (char *)sqlite3_malloc(p->pList->nData);
|
|
+ pRet = (char *)sqlite3_malloc64(p->pList->nData);
|
|
if( !pRet ) return SQLITE_NOMEM;
|
|
|
|
nSkip = sqlite3Fts3GetVarint(p->pList->aData, &dummy);
|
|
*pnData = p->pList->nData - nSkip;
|
|
*ppData = pRet;
|
|
-
|
|
+
|
|
memcpy(pRet, &p->pList->aData[nSkip], *pnData);
|
|
return SQLITE_OK;
|
|
}
|
|
@@ -180635,13 +196021,13 @@ SQLITE_PRIVATE int sqlite3Fts3DeferToken(
|
|
int iCol /* Column that token must appear in (or -1) */
|
|
){
|
|
Fts3DeferredToken *pDeferred;
|
|
- pDeferred = sqlite3_malloc(sizeof(*pDeferred));
|
|
+ pDeferred = sqlite3_malloc64(sizeof(*pDeferred));
|
|
if( !pDeferred ){
|
|
return SQLITE_NOMEM;
|
|
}
|
|
memset(pDeferred, 0, sizeof(*pDeferred));
|
|
pDeferred->pToken = pToken;
|
|
- pDeferred->pNext = pCsr->pDeferred;
|
|
+ pDeferred->pNext = pCsr->pDeferred;
|
|
pDeferred->iCol = iCol;
|
|
pCsr->pDeferred = pDeferred;
|
|
|
|
@@ -180658,8 +196044,8 @@ SQLITE_PRIVATE int sqlite3Fts3DeferToken(
|
|
** of subsiduary data structures accordingly.
|
|
*/
|
|
static int fts3DeleteByRowid(
|
|
- Fts3Table *p,
|
|
- sqlite3_value *pRowid,
|
|
+ Fts3Table *p,
|
|
+ sqlite3_value *pRowid,
|
|
int *pnChng, /* IN/OUT: Decrement if row is deleted */
|
|
u32 *aSzDel
|
|
){
|
|
@@ -180697,14 +196083,14 @@ static int fts3DeleteByRowid(
|
|
** This function does the work for the xUpdate method of FTS3 virtual
|
|
** tables. The schema of the virtual table being:
|
|
**
|
|
-** CREATE TABLE <table name>(
|
|
+** CREATE TABLE <table name>(
|
|
** <user columns>,
|
|
-** <table name> HIDDEN,
|
|
-** docid HIDDEN,
|
|
+** <table name> HIDDEN,
|
|
+** docid HIDDEN,
|
|
** <langid> HIDDEN
|
|
** );
|
|
**
|
|
-**
|
|
+**
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3Fts3UpdateMethod(
|
|
sqlite3_vtab *pVtab, /* FTS3 vtab object */
|
|
@@ -180724,7 +196110,7 @@ SQLITE_PRIVATE int sqlite3Fts3UpdateMethod(
|
|
assert( p->bHasStat==0 || p->bHasStat==1 );
|
|
|
|
assert( p->pSegments==0 );
|
|
- assert(
|
|
+ assert(
|
|
nArg==1 /* DELETE operations */
|
|
|| nArg==(2 + p->nColumn + 3) /* INSERT or UPDATE operations */
|
|
);
|
|
@@ -180733,9 +196119,9 @@ SQLITE_PRIVATE int sqlite3Fts3UpdateMethod(
|
|
**
|
|
** INSERT INTO xyz(xyz) VALUES('command');
|
|
*/
|
|
- if( nArg>1
|
|
- && sqlite3_value_type(apVal[0])==SQLITE_NULL
|
|
- && sqlite3_value_type(apVal[p->nColumn+2])!=SQLITE_NULL
|
|
+ if( nArg>1
|
|
+ && sqlite3_value_type(apVal[0])==SQLITE_NULL
|
|
+ && sqlite3_value_type(apVal[p->nColumn+2])!=SQLITE_NULL
|
|
){
|
|
rc = fts3SpecialInsert(p, apVal[p->nColumn+2]);
|
|
goto update_out;
|
|
@@ -180774,24 +196160,24 @@ SQLITE_PRIVATE int sqlite3Fts3UpdateMethod(
|
|
pNewRowid = apVal[1];
|
|
}
|
|
|
|
- if( sqlite3_value_type(pNewRowid)!=SQLITE_NULL && (
|
|
+ if( sqlite3_value_type(pNewRowid)!=SQLITE_NULL && (
|
|
sqlite3_value_type(apVal[0])==SQLITE_NULL
|
|
|| sqlite3_value_int64(apVal[0])!=sqlite3_value_int64(pNewRowid)
|
|
)){
|
|
/* The new rowid is not NULL (in this case the rowid will be
|
|
- ** automatically assigned and there is no chance of a conflict), and
|
|
+ ** automatically assigned and there is no chance of a conflict), and
|
|
** the statement is either an INSERT or an UPDATE that modifies the
|
|
** rowid column. So if the conflict mode is REPLACE, then delete any
|
|
- ** existing row with rowid=pNewRowid.
|
|
+ ** existing row with rowid=pNewRowid.
|
|
**
|
|
- ** Or, if the conflict mode is not REPLACE, insert the new record into
|
|
+ ** Or, if the conflict mode is not REPLACE, insert the new record into
|
|
** the %_content table. If we hit the duplicate rowid constraint (or any
|
|
** other error) while doing so, return immediately.
|
|
**
|
|
** This branch may also run if pNewRowid contains a value that cannot
|
|
- ** be losslessly converted to an integer. In this case, the eventual
|
|
+ ** be losslessly converted to an integer. In this case, the eventual
|
|
** call to fts3InsertData() (either just below or further on in this
|
|
- ** function) will return SQLITE_MISMATCH. If fts3DeleteByRowid is
|
|
+ ** function) will return SQLITE_MISMATCH. If fts3DeleteByRowid is
|
|
** invoked, it will delete zero rows (since no row will have
|
|
** docid=$pNewRowid if $pNewRowid is not an integer value).
|
|
*/
|
|
@@ -180812,7 +196198,7 @@ SQLITE_PRIVATE int sqlite3Fts3UpdateMethod(
|
|
assert( sqlite3_value_type(apVal[0])==SQLITE_INTEGER );
|
|
rc = fts3DeleteByRowid(p, apVal[0], &nChng, aSzDel);
|
|
}
|
|
-
|
|
+
|
|
/* If this is an INSERT or UPDATE operation, insert the new record. */
|
|
if( nArg>1 && rc==SQLITE_OK ){
|
|
int iLangid = sqlite3_value_int(apVal[2 + p->nColumn + 2]);
|
|
@@ -180845,10 +196231,10 @@ SQLITE_PRIVATE int sqlite3Fts3UpdateMethod(
|
|
return rc;
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** Flush any data in the pending-terms hash table to disk. If successful,
|
|
-** merge all segments in the database (including the new segment, if
|
|
-** there was any data to flush) into a single segment.
|
|
+** merge all segments in the database (including the new segment, if
|
|
+** there was any data to flush) into a single segment.
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3Fts3Optimize(Fts3Table *p){
|
|
int rc;
|
|
@@ -180890,6 +196276,10 @@ SQLITE_PRIVATE int sqlite3Fts3Optimize(Fts3Table *p){
|
|
/* #include <string.h> */
|
|
/* #include <assert.h> */
|
|
|
|
+#ifndef SQLITE_AMALGAMATION
|
|
+typedef sqlite3_int64 i64;
|
|
+#endif
|
|
+
|
|
/*
|
|
** Characters that may appear in the second argument to matchinfo().
|
|
*/
|
|
@@ -180904,13 +196294,13 @@ SQLITE_PRIVATE int sqlite3Fts3Optimize(Fts3Table *p){
|
|
#define FTS3_MATCHINFO_LHITS_BM 'b' /* nCol*nPhrase values */
|
|
|
|
/*
|
|
-** The default value for the second argument to matchinfo().
|
|
+** The default value for the second argument to matchinfo().
|
|
*/
|
|
#define FTS3_MATCHINFO_DEFAULT "pcx"
|
|
|
|
|
|
/*
|
|
-** Used as an fts3ExprIterate() context when loading phrase doclists to
|
|
+** Used as an sqlite3Fts3ExprIterate() context when loading phrase doclists to
|
|
** Fts3Expr.aDoclist[]/nDoclist.
|
|
*/
|
|
typedef struct LoadDoclistCtx LoadDoclistCtx;
|
|
@@ -180921,7 +196311,7 @@ struct LoadDoclistCtx {
|
|
};
|
|
|
|
/*
|
|
-** The following types are used as part of the implementation of the
|
|
+** The following types are used as part of the implementation of the
|
|
** fts3BestSnippet() routine.
|
|
*/
|
|
typedef struct SnippetIter SnippetIter;
|
|
@@ -180940,9 +196330,9 @@ struct SnippetIter {
|
|
struct SnippetPhrase {
|
|
int nToken; /* Number of tokens in phrase */
|
|
char *pList; /* Pointer to start of phrase position list */
|
|
- int iHead; /* Next value in position list */
|
|
+ i64 iHead; /* Next value in position list */
|
|
char *pHead; /* Position list data following iHead */
|
|
- int iTail; /* Next value in trailing position list */
|
|
+ i64 iTail; /* Next value in trailing position list */
|
|
char *pTail; /* Position list data following iTail */
|
|
};
|
|
|
|
@@ -180954,7 +196344,7 @@ struct SnippetFragment {
|
|
};
|
|
|
|
/*
|
|
-** This type is used as an fts3ExprIterate() context object while
|
|
+** This type is used as an sqlite3Fts3ExprIterate() context object while
|
|
** accumulating the data returned by the matchinfo() function.
|
|
*/
|
|
typedef struct MatchInfo MatchInfo;
|
|
@@ -181007,9 +196397,8 @@ static MatchinfoBuffer *fts3MIBufferNew(size_t nElem, const char *zMatchinfo){
|
|
+ sizeof(MatchinfoBuffer);
|
|
sqlite3_int64 nStr = strlen(zMatchinfo);
|
|
|
|
- pRet = sqlite3_malloc64(nByte + nStr+1);
|
|
+ pRet = sqlite3Fts3MallocZero(nByte + nStr+1);
|
|
if( pRet ){
|
|
- memset(pRet, 0, nByte);
|
|
pRet->aMatchinfo[0] = (u8*)(&pRet->aMatchinfo[1]) - (u8*)pRet;
|
|
pRet->aMatchinfo[1+nElem] = pRet->aMatchinfo[0]
|
|
+ sizeof(u32)*((int)nElem+1);
|
|
@@ -181025,8 +196414,8 @@ static MatchinfoBuffer *fts3MIBufferNew(size_t nElem, const char *zMatchinfo){
|
|
static void fts3MIBufferFree(void *p){
|
|
MatchinfoBuffer *pBuf = (MatchinfoBuffer*)((u8*)p - ((u32*)p)[-1]);
|
|
|
|
- assert( (u32*)p==&pBuf->aMatchinfo[1]
|
|
- || (u32*)p==&pBuf->aMatchinfo[pBuf->nElem+2]
|
|
+ assert( (u32*)p==&pBuf->aMatchinfo[1]
|
|
+ || (u32*)p==&pBuf->aMatchinfo[pBuf->nElem+2]
|
|
);
|
|
if( (u32*)p==&pBuf->aMatchinfo[1] ){
|
|
pBuf->aRef[1] = 0;
|
|
@@ -181082,7 +196471,7 @@ SQLITE_PRIVATE void sqlite3Fts3MIBufferFree(MatchinfoBuffer *p){
|
|
}
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** End of MatchinfoBuffer code.
|
|
*************************************************************************/
|
|
|
|
@@ -181107,14 +196496,14 @@ SQLITE_PRIVATE void sqlite3Fts3MIBufferFree(MatchinfoBuffer *p){
|
|
** After it returns, *piPos contains the value of the next element of the
|
|
** list and *pp is advanced to the following varint.
|
|
*/
|
|
-static void fts3GetDeltaPosition(char **pp, int *piPos){
|
|
+static void fts3GetDeltaPosition(char **pp, i64 *piPos){
|
|
int iVal;
|
|
*pp += fts3GetVarint32(*pp, &iVal);
|
|
*piPos += (iVal-2);
|
|
}
|
|
|
|
/*
|
|
-** Helper function for fts3ExprIterate() (see below).
|
|
+** Helper function for sqlite3Fts3ExprIterate() (see below).
|
|
*/
|
|
static int fts3ExprIterate2(
|
|
Fts3Expr *pExpr, /* Expression to iterate phrases of */
|
|
@@ -181143,12 +196532,12 @@ static int fts3ExprIterate2(
|
|
** are part of a sub-tree that is the right-hand-side of a NOT operator.
|
|
** For each phrase node found, the supplied callback function is invoked.
|
|
**
|
|
-** If the callback function returns anything other than SQLITE_OK,
|
|
+** If the callback function returns anything other than SQLITE_OK,
|
|
** the iteration is abandoned and the error code returned immediately.
|
|
** Otherwise, SQLITE_OK is returned after a callback has been made for
|
|
** all eligible phrase nodes.
|
|
*/
|
|
-static int fts3ExprIterate(
|
|
+SQLITE_PRIVATE int sqlite3Fts3ExprIterate(
|
|
Fts3Expr *pExpr, /* Expression to iterate phrases of */
|
|
int (*x)(Fts3Expr*,int,void*), /* Callback function to invoke for phrases */
|
|
void *pCtx /* Second argument to pass to callback */
|
|
@@ -181157,10 +196546,9 @@ static int fts3ExprIterate(
|
|
return fts3ExprIterate2(pExpr, &iPhrase, x, pCtx);
|
|
}
|
|
|
|
-
|
|
/*
|
|
-** This is an fts3ExprIterate() callback used while loading the doclists
|
|
-** for each phrase into Fts3Expr.aDoclist[]/nDoclist. See also
|
|
+** This is an sqlite3Fts3ExprIterate() callback used while loading the
|
|
+** doclists for each phrase into Fts3Expr.aDoclist[]/nDoclist. See also
|
|
** fts3ExprLoadDoclists().
|
|
*/
|
|
static int fts3ExprLoadDoclistsCb(Fts3Expr *pExpr, int iPhrase, void *ctx){
|
|
@@ -181178,11 +196566,11 @@ static int fts3ExprLoadDoclistsCb(Fts3Expr *pExpr, int iPhrase, void *ctx){
|
|
|
|
/*
|
|
** Load the doclists for each phrase in the query associated with FTS3 cursor
|
|
-** pCsr.
|
|
+** pCsr.
|
|
**
|
|
-** If pnPhrase is not NULL, then *pnPhrase is set to the number of matchable
|
|
-** phrases in the expression (all phrases except those directly or
|
|
-** indirectly descended from the right-hand-side of a NOT operator). If
|
|
+** If pnPhrase is not NULL, then *pnPhrase is set to the number of matchable
|
|
+** phrases in the expression (all phrases except those directly or
|
|
+** indirectly descended from the right-hand-side of a NOT operator). If
|
|
** pnToken is not NULL, then it is set to the number of tokens in all
|
|
** matchable phrases of the expression.
|
|
*/
|
|
@@ -181192,9 +196580,9 @@ static int fts3ExprLoadDoclists(
|
|
int *pnToken /* OUT: Number of tokens in query */
|
|
){
|
|
int rc; /* Return Code */
|
|
- LoadDoclistCtx sCtx = {0,0,0}; /* Context for fts3ExprIterate() */
|
|
+ LoadDoclistCtx sCtx = {0,0,0}; /* Context for sqlite3Fts3ExprIterate() */
|
|
sCtx.pCsr = pCsr;
|
|
- rc = fts3ExprIterate(pCsr->pExpr, fts3ExprLoadDoclistsCb, (void *)&sCtx);
|
|
+ rc = sqlite3Fts3ExprIterate(pCsr->pExpr,fts3ExprLoadDoclistsCb,(void*)&sCtx);
|
|
if( pnPhrase ) *pnPhrase = sCtx.nPhrase;
|
|
if( pnToken ) *pnToken = sCtx.nToken;
|
|
return rc;
|
|
@@ -181207,19 +196595,19 @@ static int fts3ExprPhraseCountCb(Fts3Expr *pExpr, int iPhrase, void *ctx){
|
|
}
|
|
static int fts3ExprPhraseCount(Fts3Expr *pExpr){
|
|
int nPhrase = 0;
|
|
- (void)fts3ExprIterate(pExpr, fts3ExprPhraseCountCb, (void *)&nPhrase);
|
|
+ (void)sqlite3Fts3ExprIterate(pExpr, fts3ExprPhraseCountCb, (void *)&nPhrase);
|
|
return nPhrase;
|
|
}
|
|
|
|
/*
|
|
-** Advance the position list iterator specified by the first two
|
|
+** Advance the position list iterator specified by the first two
|
|
** arguments so that it points to the first element with a value greater
|
|
** than or equal to parameter iNext.
|
|
*/
|
|
-static void fts3SnippetAdvance(char **ppIter, int *piIter, int iNext){
|
|
+static void fts3SnippetAdvance(char **ppIter, i64 *piIter, int iNext){
|
|
char *pIter = *ppIter;
|
|
if( pIter ){
|
|
- int iIter = *piIter;
|
|
+ i64 iIter = *piIter;
|
|
|
|
while( iIter<iNext ){
|
|
if( 0==(*pIter & 0xFE) ){
|
|
@@ -181281,7 +196669,7 @@ static int fts3SnippetNextCandidate(SnippetIter *pIter){
|
|
}
|
|
|
|
/*
|
|
-** Retrieve information about the current candidate snippet of snippet
|
|
+** Retrieve information about the current candidate snippet of snippet
|
|
** iterator pIter.
|
|
*/
|
|
static void fts3SnippetDetails(
|
|
@@ -181302,7 +196690,7 @@ static void fts3SnippetDetails(
|
|
SnippetPhrase *pPhrase = &pIter->aPhrase[i];
|
|
if( pPhrase->pTail ){
|
|
char *pCsr = pPhrase->pTail;
|
|
- int iCsr = pPhrase->iTail;
|
|
+ i64 iCsr = pPhrase->iTail;
|
|
|
|
while( iCsr<(iStart+pIter->nSnippet) && iCsr>=iStart ){
|
|
int j;
|
|
@@ -181335,8 +196723,9 @@ static void fts3SnippetDetails(
|
|
}
|
|
|
|
/*
|
|
-** This function is an fts3ExprIterate() callback used by fts3BestSnippet().
|
|
-** Each invocation populates an element of the SnippetIter.aPhrase[] array.
|
|
+** This function is an sqlite3Fts3ExprIterate() callback used by
|
|
+** fts3BestSnippet(). Each invocation populates an element of the
|
|
+** SnippetIter.aPhrase[] array.
|
|
*/
|
|
static int fts3SnippetFindPositions(Fts3Expr *pExpr, int iPhrase, void *ctx){
|
|
SnippetIter *p = (SnippetIter *)ctx;
|
|
@@ -181348,7 +196737,7 @@ static int fts3SnippetFindPositions(Fts3Expr *pExpr, int iPhrase, void *ctx){
|
|
rc = sqlite3Fts3EvalPhrasePoslist(p->pCsr, pExpr, p->iCol, &pCsr);
|
|
assert( rc==SQLITE_OK || pCsr==0 );
|
|
if( pCsr ){
|
|
- int iFirst = 0;
|
|
+ i64 iFirst = 0;
|
|
pPhrase->pList = pCsr;
|
|
fts3GetDeltaPosition(&pCsr, &iFirst);
|
|
if( iFirst<0 ){
|
|
@@ -181361,7 +196750,7 @@ static int fts3SnippetFindPositions(Fts3Expr *pExpr, int iPhrase, void *ctx){
|
|
}
|
|
}else{
|
|
assert( rc!=SQLITE_OK || (
|
|
- pPhrase->pList==0 && pPhrase->pHead==0 && pPhrase->pTail==0
|
|
+ pPhrase->pList==0 && pPhrase->pHead==0 && pPhrase->pTail==0
|
|
));
|
|
}
|
|
|
|
@@ -181369,14 +196758,14 @@ static int fts3SnippetFindPositions(Fts3Expr *pExpr, int iPhrase, void *ctx){
|
|
}
|
|
|
|
/*
|
|
-** Select the fragment of text consisting of nFragment contiguous tokens
|
|
+** Select the fragment of text consisting of nFragment contiguous tokens
|
|
** from column iCol that represent the "best" snippet. The best snippet
|
|
** is the snippet with the highest score, where scores are calculated
|
|
** by adding:
|
|
**
|
|
** (a) +1 point for each occurrence of a matchable phrase in the snippet.
|
|
**
|
|
-** (b) +1000 points for the first occurrence of each matchable phrase in
|
|
+** (b) +1000 points for the first occurrence of each matchable phrase in
|
|
** the snippet for which the corresponding mCovered bit is not set.
|
|
**
|
|
** The selected snippet parameters are stored in structure *pFragment before
|
|
@@ -181413,11 +196802,10 @@ static int fts3BestSnippet(
|
|
** the required space using malloc().
|
|
*/
|
|
nByte = sizeof(SnippetPhrase) * nList;
|
|
- sIter.aPhrase = (SnippetPhrase *)sqlite3_malloc64(nByte);
|
|
+ sIter.aPhrase = (SnippetPhrase *)sqlite3Fts3MallocZero(nByte);
|
|
if( !sIter.aPhrase ){
|
|
return SQLITE_NOMEM;
|
|
}
|
|
- memset(sIter.aPhrase, 0, nByte);
|
|
|
|
/* Initialize the contents of the SnippetIter object. Then iterate through
|
|
** the set of phrases in the expression to populate the aPhrase[] array.
|
|
@@ -181427,7 +196815,9 @@ static int fts3BestSnippet(
|
|
sIter.nSnippet = nSnippet;
|
|
sIter.nPhrase = nList;
|
|
sIter.iCurrent = -1;
|
|
- rc = fts3ExprIterate(pCsr->pExpr, fts3SnippetFindPositions, (void*)&sIter);
|
|
+ rc = sqlite3Fts3ExprIterate(
|
|
+ pCsr->pExpr, fts3SnippetFindPositions, (void*)&sIter
|
|
+ );
|
|
if( rc==SQLITE_OK ){
|
|
|
|
/* Set the *pmSeen output variable. */
|
|
@@ -181437,7 +196827,7 @@ static int fts3BestSnippet(
|
|
}
|
|
}
|
|
|
|
- /* Loop through all candidate snippets. Store the best snippet in
|
|
+ /* Loop through all candidate snippets. Store the best snippet in
|
|
** *pFragment. Store its associated 'score' in iBestScore.
|
|
*/
|
|
pFragment->iCol = iCol;
|
|
@@ -181509,8 +196899,8 @@ static int fts3StringAppend(
|
|
**
|
|
** ........X.....X
|
|
**
|
|
-** This function "shifts" the beginning of the snippet forward in the
|
|
-** document so that there are approximately the same number of
|
|
+** This function "shifts" the beginning of the snippet forward in the
|
|
+** document so that there are approximately the same number of
|
|
** non-highlighted terms to the right of the final highlighted term as there
|
|
** are to the left of the first highlighted term. For example, to this:
|
|
**
|
|
@@ -181518,8 +196908,8 @@ static int fts3StringAppend(
|
|
**
|
|
** This is done as part of extracting the snippet text, not when selecting
|
|
** the snippet. Snippet selection is done based on doclists only, so there
|
|
-** is no way for fts3BestSnippet() to know whether or not the document
|
|
-** actually contains terms that follow the final highlighted term.
|
|
+** is no way for fts3BestSnippet() to know whether or not the document
|
|
+** actually contains terms that follow the final highlighted term.
|
|
*/
|
|
static int fts3SnippetShift(
|
|
Fts3Table *pTab, /* FTS3 table snippet comes from */
|
|
@@ -181609,7 +196999,7 @@ static int fts3SnippetText(
|
|
int iCol = pFragment->iCol+1; /* Query column to extract text from */
|
|
sqlite3_tokenizer_module *pMod; /* Tokenizer module methods object */
|
|
sqlite3_tokenizer_cursor *pC; /* Tokenizer cursor open on zDoc/nDoc */
|
|
-
|
|
+
|
|
zDoc = (const char *)sqlite3_column_text(pCsr->pStmt, iCol);
|
|
if( zDoc==0 ){
|
|
if( sqlite3_column_type(pCsr->pStmt, iCol)!=SQLITE_NULL ){
|
|
@@ -181649,7 +197039,7 @@ static int fts3SnippetText(
|
|
if( rc==SQLITE_DONE ){
|
|
/* Special case - the last token of the snippet is also the last token
|
|
** of the column. Append any punctuation that occurred between the end
|
|
- ** of the previous token and the end of the document to the output.
|
|
+ ** of the previous token and the end of the document to the output.
|
|
** Then break out of the loop. */
|
|
rc = fts3StringAppend(pOut, &zDoc[iEnd], -1);
|
|
}
|
|
@@ -181666,7 +197056,7 @@ static int fts3SnippetText(
|
|
|
|
/* Now that the shift has been done, check if the initial "..." are
|
|
** required. They are required if (a) this is not the first fragment,
|
|
- ** or (b) this fragment does not begin at position 0 of its column.
|
|
+ ** or (b) this fragment does not begin at position 0 of its column.
|
|
*/
|
|
if( rc==SQLITE_OK ){
|
|
if( iPos>0 || iFragment>0 ){
|
|
@@ -181702,8 +197092,8 @@ static int fts3SnippetText(
|
|
|
|
|
|
/*
|
|
-** This function is used to count the entries in a column-list (a
|
|
-** delta-encoded list of term offsets within a single column of a single
|
|
+** This function is used to count the entries in a column-list (a
|
|
+** delta-encoded list of term offsets within a single column of a single
|
|
** row). When this function is called, *ppCollist should point to the
|
|
** beginning of the first varint in the column-list (the varint that
|
|
** contains the position of the first matching term in the column data).
|
|
@@ -181749,7 +197139,7 @@ static int fts3ExprLHits(
|
|
iStart = pExpr->iPhrase * ((p->nCol + 31) / 32);
|
|
}
|
|
|
|
- while( 1 ){
|
|
+ if( pIter ) while( 1 ){
|
|
int nHit = fts3ColumnlistCount(&pIter);
|
|
if( (pPhrase->iColumn>=pTab->nColumn || pPhrase->iColumn==iCol) ){
|
|
if( p->flag==FTS3_MATCHINFO_LHITS ){
|
|
@@ -181788,12 +197178,12 @@ static int fts3ExprLHitGather(
|
|
}
|
|
|
|
/*
|
|
-** fts3ExprIterate() callback used to collect the "global" matchinfo stats
|
|
-** for a single query.
|
|
+** sqlite3Fts3ExprIterate() callback used to collect the "global" matchinfo
|
|
+** stats for a single query.
|
|
**
|
|
-** fts3ExprIterate() callback to load the 'global' elements of a
|
|
-** FTS3_MATCHINFO_HITS matchinfo array. The global stats are those elements
|
|
-** of the matchinfo array that are constant for all rows returned by the
|
|
+** sqlite3Fts3ExprIterate() callback to load the 'global' elements of a
|
|
+** FTS3_MATCHINFO_HITS matchinfo array. The global stats are those elements
|
|
+** of the matchinfo array that are constant for all rows returned by the
|
|
** current query.
|
|
**
|
|
** Argument pCtx is actually a pointer to a struct of type MatchInfo. This
|
|
@@ -181809,7 +197199,7 @@ static int fts3ExprLHitGather(
|
|
** at least one instance of phrase iPhrase.
|
|
**
|
|
** If the phrase pExpr consists entirely of deferred tokens, then all X and
|
|
-** Y values are set to nDoc, where nDoc is the number of documents in the
|
|
+** Y values are set to nDoc, where nDoc is the number of documents in the
|
|
** file system. This is done because the full-text index doclist is required
|
|
** to calculate these values properly, and the full-text index doclist is
|
|
** not available for deferred tokens.
|
|
@@ -181826,8 +197216,8 @@ static int fts3ExprGlobalHitsCb(
|
|
}
|
|
|
|
/*
|
|
-** fts3ExprIterate() callback used to collect the "local" part of the
|
|
-** FTS3_MATCHINFO_HITS array. The local stats are those elements of the
|
|
+** sqlite3Fts3ExprIterate() callback used to collect the "local" part of the
|
|
+** FTS3_MATCHINFO_HITS array. The local stats are those elements of the
|
|
** array that are different for each row returned by the query.
|
|
*/
|
|
static int fts3ExprLocalHitsCb(
|
|
@@ -181854,7 +197244,7 @@ static int fts3ExprLocalHitsCb(
|
|
}
|
|
|
|
static int fts3MatchinfoCheck(
|
|
- Fts3Table *pTab,
|
|
+ Fts3Table *pTab,
|
|
char cArg,
|
|
char **pzErr
|
|
){
|
|
@@ -181879,8 +197269,8 @@ static size_t fts3MatchinfoSize(MatchInfo *pInfo, char cArg){
|
|
|
|
switch( cArg ){
|
|
case FTS3_MATCHINFO_NDOC:
|
|
- case FTS3_MATCHINFO_NPHRASE:
|
|
- case FTS3_MATCHINFO_NCOL:
|
|
+ case FTS3_MATCHINFO_NPHRASE:
|
|
+ case FTS3_MATCHINFO_NCOL:
|
|
nVal = 1;
|
|
break;
|
|
|
|
@@ -181946,7 +197336,7 @@ static int fts3MatchinfoSelectDoctotal(
|
|
}
|
|
|
|
/*
|
|
-** An instance of the following structure is used to store state while
|
|
+** An instance of the following structure is used to store state while
|
|
** iterating through a multi-column position-list corresponding to the
|
|
** hits for a single phrase on a single row in order to calculate the
|
|
** values for a matchinfo() FTS3_MATCHINFO_LCS request.
|
|
@@ -181959,7 +197349,7 @@ struct LcsIterator {
|
|
int iPos; /* Current position */
|
|
};
|
|
|
|
-/*
|
|
+/*
|
|
** If LcsIterator.iCol is set to the following value, the iterator has
|
|
** finished iterating through all offsets for all columns.
|
|
*/
|
|
@@ -181981,10 +197371,12 @@ static int fts3MatchinfoLcsCb(
|
|
** position list for the next column.
|
|
*/
|
|
static int fts3LcsIteratorAdvance(LcsIterator *pIter){
|
|
- char *pRead = pIter->pRead;
|
|
+ char *pRead;
|
|
sqlite3_int64 iRead;
|
|
int rc = 0;
|
|
|
|
+ if( NEVER(pIter==0) ) return 1;
|
|
+ pRead = pIter->pRead;
|
|
pRead += sqlite3Fts3GetVarint(pRead, &iRead);
|
|
if( iRead==0 || iRead==1 ){
|
|
pRead = 0;
|
|
@@ -181996,16 +197388,16 @@ static int fts3LcsIteratorAdvance(LcsIterator *pIter){
|
|
pIter->pRead = pRead;
|
|
return rc;
|
|
}
|
|
-
|
|
+
|
|
/*
|
|
-** This function implements the FTS3_MATCHINFO_LCS matchinfo() flag.
|
|
+** This function implements the FTS3_MATCHINFO_LCS matchinfo() flag.
|
|
**
|
|
** If the call is successful, the longest-common-substring lengths for each
|
|
-** column are written into the first nCol elements of the pInfo->aMatchinfo[]
|
|
+** column are written into the first nCol elements of the pInfo->aMatchinfo[]
|
|
** array before returning. SQLITE_OK is returned in this case.
|
|
**
|
|
** Otherwise, if an error occurs, an SQLite error code is returned and the
|
|
-** data written to the first nCol elements of pInfo->aMatchinfo[] is
|
|
+** data written to the first nCol elements of pInfo->aMatchinfo[] is
|
|
** undefined.
|
|
*/
|
|
static int fts3MatchinfoLcs(Fts3Cursor *pCsr, MatchInfo *pInfo){
|
|
@@ -182018,10 +197410,9 @@ static int fts3MatchinfoLcs(Fts3Cursor *pCsr, MatchInfo *pInfo){
|
|
/* Allocate and populate the array of LcsIterator objects. The array
|
|
** contains one element for each matchable phrase in the query.
|
|
**/
|
|
- aIter = sqlite3_malloc64(sizeof(LcsIterator) * pCsr->nPhrase);
|
|
+ aIter = sqlite3Fts3MallocZero(sizeof(LcsIterator) * pCsr->nPhrase);
|
|
if( !aIter ) return SQLITE_NOMEM;
|
|
- memset(aIter, 0, sizeof(LcsIterator) * pCsr->nPhrase);
|
|
- (void)fts3ExprIterate(pCsr->pExpr, fts3MatchinfoLcsCb, (void*)aIter);
|
|
+ (void)sqlite3Fts3ExprIterate(pCsr->pExpr, fts3MatchinfoLcsCb, (void*)aIter);
|
|
|
|
for(i=0; i<pInfo->nPhrase; i++){
|
|
LcsIterator *pIter = &aIter[i];
|
|
@@ -182082,7 +197473,7 @@ static int fts3MatchinfoLcs(Fts3Cursor *pCsr, MatchInfo *pInfo){
|
|
|
|
/*
|
|
** Populate the buffer pInfo->aMatchinfo[] with an array of integers to
|
|
-** be returned by the matchinfo() function. Argument zArg contains the
|
|
+** be returned by the matchinfo() function. Argument zArg contains the
|
|
** format string passed as the second argument to matchinfo (or the
|
|
** default value "pcx" if no second argument was specified). The format
|
|
** string has already been validated and the pInfo->aMatchinfo[] array
|
|
@@ -182093,7 +197484,7 @@ static int fts3MatchinfoLcs(Fts3Cursor *pCsr, MatchInfo *pInfo){
|
|
** rows (i.e. FTS3_MATCHINFO_NPHRASE, NCOL, NDOC, AVGLENGTH and part of HITS)
|
|
** have already been populated.
|
|
**
|
|
-** Return SQLITE_OK if successful, or an SQLite error code if an error
|
|
+** Return SQLITE_OK if successful, or an SQLite error code if an error
|
|
** occurs. If a value other than SQLITE_OK is returned, the state the
|
|
** pInfo->aMatchinfo[] buffer is left in is undefined.
|
|
*/
|
|
@@ -182118,7 +197509,7 @@ static int fts3MatchinfoValues(
|
|
case FTS3_MATCHINFO_NCOL:
|
|
if( bGlobal ) pInfo->aMatchinfo[0] = pInfo->nCol;
|
|
break;
|
|
-
|
|
+
|
|
case FTS3_MATCHINFO_NDOC:
|
|
if( bGlobal ){
|
|
sqlite3_int64 nDoc = 0;
|
|
@@ -182127,7 +197518,7 @@ static int fts3MatchinfoValues(
|
|
}
|
|
break;
|
|
|
|
- case FTS3_MATCHINFO_AVGLENGTH:
|
|
+ case FTS3_MATCHINFO_AVGLENGTH:
|
|
if( bGlobal ){
|
|
sqlite3_int64 nDoc; /* Number of rows in table */
|
|
const char *a; /* Aggregate column length array */
|
|
@@ -182198,11 +197589,11 @@ static int fts3MatchinfoValues(
|
|
rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &pInfo->nDoc,0,0);
|
|
if( rc!=SQLITE_OK ) break;
|
|
}
|
|
- rc = fts3ExprIterate(pExpr, fts3ExprGlobalHitsCb,(void*)pInfo);
|
|
+ rc = sqlite3Fts3ExprIterate(pExpr, fts3ExprGlobalHitsCb,(void*)pInfo);
|
|
sqlite3Fts3EvalTestDeferred(pCsr, &rc);
|
|
if( rc!=SQLITE_OK ) break;
|
|
}
|
|
- (void)fts3ExprIterate(pExpr, fts3ExprLocalHitsCb,(void*)pInfo);
|
|
+ (void)sqlite3Fts3ExprIterate(pExpr, fts3ExprLocalHitsCb,(void*)pInfo);
|
|
break;
|
|
}
|
|
}
|
|
@@ -182216,7 +197607,7 @@ static int fts3MatchinfoValues(
|
|
|
|
|
|
/*
|
|
-** Populate pCsr->aMatchinfo[] with data for the current row. The
|
|
+** Populate pCsr->aMatchinfo[] with data for the current row. The
|
|
** 'matchinfo' data is an array of 32-bit unsigned integers (C type u32).
|
|
*/
|
|
static void fts3GetMatchinfo(
|
|
@@ -182236,8 +197627,8 @@ static void fts3GetMatchinfo(
|
|
sInfo.pCursor = pCsr;
|
|
sInfo.nCol = pTab->nColumn;
|
|
|
|
- /* If there is cached matchinfo() data, but the format string for the
|
|
- ** cache does not match the format string for this request, discard
|
|
+ /* If there is cached matchinfo() data, but the format string for the
|
|
+ ** cache does not match the format string for this request, discard
|
|
** the cached data. */
|
|
if( pCsr->pMIBuffer && strcmp(pCsr->pMIBuffer->zMatchinfo, zArg) ){
|
|
sqlite3Fts3MIBufferFree(pCsr->pMIBuffer);
|
|
@@ -182245,7 +197636,7 @@ static void fts3GetMatchinfo(
|
|
}
|
|
|
|
/* If Fts3Cursor.pMIBuffer is NULL, then this is the first time the
|
|
- ** matchinfo function has been called for this query. In this case
|
|
+ ** matchinfo function has been called for this query. In this case
|
|
** allocate the array used to accumulate the matchinfo data and
|
|
** initialize those elements that are constant for every row.
|
|
*/
|
|
@@ -182320,7 +197711,7 @@ SQLITE_PRIVATE void sqlite3Fts3Snippet(
|
|
|
|
/* The returned text includes up to four fragments of text extracted from
|
|
** the data in the current row. The first iteration of the for(...) loop
|
|
- ** below attempts to locate a single fragment of text nToken tokens in
|
|
+ ** below attempts to locate a single fragment of text nToken tokens in
|
|
** size that contains at least one instance of all phrases in the query
|
|
** expression that appear in the current row. If such a fragment of text
|
|
** cannot be found, the second iteration of the loop attempts to locate
|
|
@@ -182391,7 +197782,7 @@ SQLITE_PRIVATE void sqlite3Fts3Snippet(
|
|
assert( nFToken>0 );
|
|
|
|
for(i=0; i<nSnippet && rc==SQLITE_OK; i++){
|
|
- rc = fts3SnippetText(pCsr, &aSnippet[i],
|
|
+ rc = fts3SnippetText(pCsr, &aSnippet[i],
|
|
i, (i==nSnippet-1), nFToken, zStart, zEnd, zEllipsis, &res
|
|
);
|
|
}
|
|
@@ -182412,8 +197803,8 @@ typedef struct TermOffsetCtx TermOffsetCtx;
|
|
|
|
struct TermOffset {
|
|
char *pList; /* Position-list */
|
|
- int iPos; /* Position just read from pList */
|
|
- int iOff; /* Offset of this term from read positions */
|
|
+ i64 iPos; /* Position just read from pList */
|
|
+ i64 iOff; /* Offset of this term from read positions */
|
|
};
|
|
|
|
struct TermOffsetCtx {
|
|
@@ -182425,14 +197816,14 @@ struct TermOffsetCtx {
|
|
};
|
|
|
|
/*
|
|
-** This function is an fts3ExprIterate() callback used by sqlite3Fts3Offsets().
|
|
+** This function is an sqlite3Fts3ExprIterate() callback used by sqlite3Fts3Offsets().
|
|
*/
|
|
static int fts3ExprTermOffsetInit(Fts3Expr *pExpr, int iPhrase, void *ctx){
|
|
TermOffsetCtx *p = (TermOffsetCtx *)ctx;
|
|
int nTerm; /* Number of tokens in phrase */
|
|
int iTerm; /* For looping through nTerm phrase terms */
|
|
char *pList; /* Pointer to position list for phrase */
|
|
- int iPos = 0; /* First position in position-list */
|
|
+ i64 iPos = 0; /* First position in position-list */
|
|
int rc;
|
|
|
|
UNUSED_PARAMETER(iPhrase);
|
|
@@ -182481,7 +197872,7 @@ SQLITE_PRIVATE void sqlite3Fts3Offsets(
|
|
if( rc!=SQLITE_OK ) goto offsets_out;
|
|
|
|
/* Allocate the array of TermOffset iterators. */
|
|
- sCtx.aTerm = (TermOffset *)sqlite3_malloc64(sizeof(TermOffset)*nToken);
|
|
+ sCtx.aTerm = (TermOffset *)sqlite3Fts3MallocZero(sizeof(TermOffset)*nToken);
|
|
if( 0==sCtx.aTerm ){
|
|
rc = SQLITE_NOMEM;
|
|
goto offsets_out;
|
|
@@ -182489,7 +197880,7 @@ SQLITE_PRIVATE void sqlite3Fts3Offsets(
|
|
sCtx.iDocid = pCsr->iPrevId;
|
|
sCtx.pCsr = pCsr;
|
|
|
|
- /* Loop through the table columns, appending offset information to
|
|
+ /* Loop through the table columns, appending offset information to
|
|
** string-buffer res for each column.
|
|
*/
|
|
for(iCol=0; iCol<pTab->nColumn; iCol++){
|
|
@@ -182502,19 +197893,21 @@ SQLITE_PRIVATE void sqlite3Fts3Offsets(
|
|
const char *zDoc;
|
|
int nDoc;
|
|
|
|
- /* Initialize the contents of sCtx.aTerm[] for column iCol. There is
|
|
- ** no way that this operation can fail, so the return code from
|
|
- ** fts3ExprIterate() can be discarded.
|
|
+ /* Initialize the contents of sCtx.aTerm[] for column iCol. This
|
|
+ ** operation may fail if the database contains corrupt records.
|
|
*/
|
|
sCtx.iCol = iCol;
|
|
sCtx.iTerm = 0;
|
|
- (void)fts3ExprIterate(pCsr->pExpr, fts3ExprTermOffsetInit, (void*)&sCtx);
|
|
+ rc = sqlite3Fts3ExprIterate(
|
|
+ pCsr->pExpr, fts3ExprTermOffsetInit, (void*)&sCtx
|
|
+ );
|
|
+ if( rc!=SQLITE_OK ) goto offsets_out;
|
|
|
|
- /* Retreive the text stored in column iCol. If an SQL NULL is stored
|
|
+ /* Retreive the text stored in column iCol. If an SQL NULL is stored
|
|
** in column iCol, jump immediately to the next iteration of the loop.
|
|
** If an OOM occurs while retrieving the data (this can happen if SQLite
|
|
- ** needs to transform the data from utf-16 to utf-8), return SQLITE_NOMEM
|
|
- ** to the caller.
|
|
+ ** needs to transform the data from utf-16 to utf-8), return SQLITE_NOMEM
|
|
+ ** to the caller.
|
|
*/
|
|
zDoc = (const char *)sqlite3_column_text(pCsr->pStmt, iCol+1);
|
|
nDoc = sqlite3_column_bytes(pCsr->pStmt, iCol+1);
|
|
@@ -182561,7 +197954,7 @@ SQLITE_PRIVATE void sqlite3Fts3Offsets(
|
|
}
|
|
if( rc==SQLITE_OK ){
|
|
char aBuffer[64];
|
|
- sqlite3_snprintf(sizeof(aBuffer), aBuffer,
|
|
+ sqlite3_snprintf(sizeof(aBuffer), aBuffer,
|
|
"%d %d %d %d ", iCol, pTerm-sCtx.aTerm, iStart, iEnd-iStart
|
|
);
|
|
rc = fts3StringAppend(&res, aBuffer, -1);
|
|
@@ -182742,7 +198135,7 @@ static int unicodeDestroy(sqlite3_tokenizer *pTokenizer){
|
|
**
|
|
** For each codepoint in the zIn/nIn string, this function checks if the
|
|
** sqlite3FtsUnicodeIsalnum() function already returns the desired result.
|
|
-** If so, no action is taken. Otherwise, the codepoint is added to the
|
|
+** If so, no action is taken. Otherwise, the codepoint is added to the
|
|
** unicode_tokenizer.aiException[] array. For the purposes of tokenization,
|
|
** the return value of sqlite3FtsUnicodeIsalnum() is inverted for all
|
|
** codepoints in the aiException[] array.
|
|
@@ -182768,8 +198161,8 @@ static int unicodeAddExceptions(
|
|
while( z<zTerm ){
|
|
READ_UTF8(z, zTerm, iCode);
|
|
assert( (sqlite3FtsUnicodeIsalnum((int)iCode) & 0xFFFFFFFE)==0 );
|
|
- if( sqlite3FtsUnicodeIsalnum((int)iCode)!=bAlnum
|
|
- && sqlite3FtsUnicodeIsdiacritic((int)iCode)==0
|
|
+ if( sqlite3FtsUnicodeIsalnum((int)iCode)!=bAlnum
|
|
+ && sqlite3FtsUnicodeIsdiacritic((int)iCode)==0
|
|
){
|
|
nEntry++;
|
|
}
|
|
@@ -182786,7 +198179,7 @@ static int unicodeAddExceptions(
|
|
z = (const unsigned char *)zIn;
|
|
while( z<zTerm ){
|
|
READ_UTF8(z, zTerm, iCode);
|
|
- if( sqlite3FtsUnicodeIsalnum((int)iCode)!=bAlnum
|
|
+ if( sqlite3FtsUnicodeIsalnum((int)iCode)!=bAlnum
|
|
&& sqlite3FtsUnicodeIsdiacritic((int)iCode)==0
|
|
){
|
|
int i, j;
|
|
@@ -182889,7 +198282,7 @@ static int unicodeCreate(
|
|
/*
|
|
** Prepare to begin tokenizing a particular string. The input
|
|
** string to be tokenized is pInput[0..nBytes-1]. A cursor
|
|
-** used to incrementally tokenize this string is returned in
|
|
+** used to incrementally tokenize this string is returned in
|
|
** *ppCursor.
|
|
*/
|
|
static int unicodeOpen(
|
|
@@ -182909,6 +198302,7 @@ static int unicodeOpen(
|
|
pCsr->aInput = (const unsigned char *)aInput;
|
|
if( aInput==0 ){
|
|
pCsr->nInput = 0;
|
|
+ pCsr->aInput = (const unsigned char*)"";
|
|
}else if( nInput<0 ){
|
|
pCsr->nInput = (int)strlen(aInput);
|
|
}else{
|
|
@@ -182953,7 +198347,7 @@ static int unicodeNext(
|
|
const unsigned char *zTerm = &pCsr->aInput[pCsr->nInput];
|
|
|
|
/* Scan past any delimiter characters before the start of the next token.
|
|
- ** Return SQLITE_DONE early if this takes us all the way to the end of
|
|
+ ** Return SQLITE_DONE early if this takes us all the way to the end of
|
|
** the input. */
|
|
while( z<zTerm ){
|
|
READ_UTF8(z, zTerm, iCode);
|
|
@@ -182985,7 +198379,7 @@ static int unicodeNext(
|
|
/* If the cursor is not at EOF, read the next character */
|
|
if( z>=zTerm ) break;
|
|
READ_UTF8(z, zTerm, iCode);
|
|
- }while( unicodeIsAlnum(p, (int)iCode)
|
|
+ }while( unicodeIsAlnum(p, (int)iCode)
|
|
|| sqlite3FtsUnicodeIsdiacritic((int)iCode)
|
|
);
|
|
|
|
@@ -183000,7 +198394,7 @@ static int unicodeNext(
|
|
}
|
|
|
|
/*
|
|
-** Set *ppModule to a pointer to the sqlite3_tokenizer_module
|
|
+** Set *ppModule to a pointer to the sqlite3_tokenizer_module
|
|
** structure for the unicode tokenizer.
|
|
*/
|
|
SQLITE_PRIVATE void sqlite3Fts3UnicodeTokenizer(sqlite3_tokenizer_module const **ppModule){
|
|
@@ -183055,11 +198449,11 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeIsalnum(int c){
|
|
** range of unicode codepoints that are not either letters or numbers (i.e.
|
|
** codepoints for which this function should return 0).
|
|
**
|
|
- ** The most significant 22 bits in each 32-bit value contain the first
|
|
+ ** The most significant 22 bits in each 32-bit value contain the first
|
|
** codepoint in the range. The least significant 10 bits are used to store
|
|
- ** the size of the range (always at least 1). In other words, the value
|
|
- ** ((C<<22) + N) represents a range of N codepoints starting with codepoint
|
|
- ** C. It is not possible to represent a range larger than 1023 codepoints
|
|
+ ** the size of the range (always at least 1). In other words, the value
|
|
+ ** ((C<<22) + N) represents a range of N codepoints starting with codepoint
|
|
+ ** C. It is not possible to represent a range larger than 1023 codepoints
|
|
** using this format.
|
|
*/
|
|
static const unsigned int aEntry[] = {
|
|
@@ -183184,46 +198578,46 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeIsalnum(int c){
|
|
*/
|
|
static int remove_diacritic(int c, int bComplex){
|
|
unsigned short aDia[] = {
|
|
- 0, 1797, 1848, 1859, 1891, 1928, 1940, 1995,
|
|
- 2024, 2040, 2060, 2110, 2168, 2206, 2264, 2286,
|
|
- 2344, 2383, 2472, 2488, 2516, 2596, 2668, 2732,
|
|
- 2782, 2842, 2894, 2954, 2984, 3000, 3028, 3336,
|
|
- 3456, 3696, 3712, 3728, 3744, 3766, 3832, 3896,
|
|
- 3912, 3928, 3944, 3968, 4008, 4040, 4056, 4106,
|
|
- 4138, 4170, 4202, 4234, 4266, 4296, 4312, 4344,
|
|
- 4408, 4424, 4442, 4472, 4488, 4504, 6148, 6198,
|
|
- 6264, 6280, 6360, 6429, 6505, 6529, 61448, 61468,
|
|
- 61512, 61534, 61592, 61610, 61642, 61672, 61688, 61704,
|
|
- 61726, 61784, 61800, 61816, 61836, 61880, 61896, 61914,
|
|
- 61948, 61998, 62062, 62122, 62154, 62184, 62200, 62218,
|
|
- 62252, 62302, 62364, 62410, 62442, 62478, 62536, 62554,
|
|
- 62584, 62604, 62640, 62648, 62656, 62664, 62730, 62766,
|
|
- 62830, 62890, 62924, 62974, 63032, 63050, 63082, 63118,
|
|
- 63182, 63242, 63274, 63310, 63368, 63390,
|
|
+ 0, 1797, 1848, 1859, 1891, 1928, 1940, 1995,
|
|
+ 2024, 2040, 2060, 2110, 2168, 2206, 2264, 2286,
|
|
+ 2344, 2383, 2472, 2488, 2516, 2596, 2668, 2732,
|
|
+ 2782, 2842, 2894, 2954, 2984, 3000, 3028, 3336,
|
|
+ 3456, 3696, 3712, 3728, 3744, 3766, 3832, 3896,
|
|
+ 3912, 3928, 3944, 3968, 4008, 4040, 4056, 4106,
|
|
+ 4138, 4170, 4202, 4234, 4266, 4296, 4312, 4344,
|
|
+ 4408, 4424, 4442, 4472, 4488, 4504, 6148, 6198,
|
|
+ 6264, 6280, 6360, 6429, 6505, 6529, 61448, 61468,
|
|
+ 61512, 61534, 61592, 61610, 61642, 61672, 61688, 61704,
|
|
+ 61726, 61784, 61800, 61816, 61836, 61880, 61896, 61914,
|
|
+ 61948, 61998, 62062, 62122, 62154, 62184, 62200, 62218,
|
|
+ 62252, 62302, 62364, 62410, 62442, 62478, 62536, 62554,
|
|
+ 62584, 62604, 62640, 62648, 62656, 62664, 62730, 62766,
|
|
+ 62830, 62890, 62924, 62974, 63032, 63050, 63082, 63118,
|
|
+ 63182, 63242, 63274, 63310, 63368, 63390,
|
|
};
|
|
#define HIBIT ((unsigned char)0x80)
|
|
unsigned char aChar[] = {
|
|
- '\0', 'a', 'c', 'e', 'i', 'n',
|
|
- 'o', 'u', 'y', 'y', 'a', 'c',
|
|
- 'd', 'e', 'e', 'g', 'h', 'i',
|
|
- 'j', 'k', 'l', 'n', 'o', 'r',
|
|
- 's', 't', 'u', 'u', 'w', 'y',
|
|
- 'z', 'o', 'u', 'a', 'i', 'o',
|
|
- 'u', 'u'|HIBIT, 'a'|HIBIT, 'g', 'k', 'o',
|
|
- 'o'|HIBIT, 'j', 'g', 'n', 'a'|HIBIT, 'a',
|
|
- 'e', 'i', 'o', 'r', 'u', 's',
|
|
- 't', 'h', 'a', 'e', 'o'|HIBIT, 'o',
|
|
- 'o'|HIBIT, 'y', '\0', '\0', '\0', '\0',
|
|
- '\0', '\0', '\0', '\0', 'a', 'b',
|
|
- 'c'|HIBIT, 'd', 'd', 'e'|HIBIT, 'e', 'e'|HIBIT,
|
|
- 'f', 'g', 'h', 'h', 'i', 'i'|HIBIT,
|
|
- 'k', 'l', 'l'|HIBIT, 'l', 'm', 'n',
|
|
- 'o'|HIBIT, 'p', 'r', 'r'|HIBIT, 'r', 's',
|
|
- 's'|HIBIT, 't', 'u', 'u'|HIBIT, 'v', 'w',
|
|
- 'w', 'x', 'y', 'z', 'h', 't',
|
|
- 'w', 'y', 'a', 'a'|HIBIT, 'a'|HIBIT, 'a'|HIBIT,
|
|
- 'e', 'e'|HIBIT, 'e'|HIBIT, 'i', 'o', 'o'|HIBIT,
|
|
- 'o'|HIBIT, 'o'|HIBIT, 'u', 'u'|HIBIT, 'u'|HIBIT, 'y',
|
|
+ '\0', 'a', 'c', 'e', 'i', 'n',
|
|
+ 'o', 'u', 'y', 'y', 'a', 'c',
|
|
+ 'd', 'e', 'e', 'g', 'h', 'i',
|
|
+ 'j', 'k', 'l', 'n', 'o', 'r',
|
|
+ 's', 't', 'u', 'u', 'w', 'y',
|
|
+ 'z', 'o', 'u', 'a', 'i', 'o',
|
|
+ 'u', 'u'|HIBIT, 'a'|HIBIT, 'g', 'k', 'o',
|
|
+ 'o'|HIBIT, 'j', 'g', 'n', 'a'|HIBIT, 'a',
|
|
+ 'e', 'i', 'o', 'r', 'u', 's',
|
|
+ 't', 'h', 'a', 'e', 'o'|HIBIT, 'o',
|
|
+ 'o'|HIBIT, 'y', '\0', '\0', '\0', '\0',
|
|
+ '\0', '\0', '\0', '\0', 'a', 'b',
|
|
+ 'c'|HIBIT, 'd', 'd', 'e'|HIBIT, 'e', 'e'|HIBIT,
|
|
+ 'f', 'g', 'h', 'h', 'i', 'i'|HIBIT,
|
|
+ 'k', 'l', 'l'|HIBIT, 'l', 'm', 'n',
|
|
+ 'o'|HIBIT, 'p', 'r', 'r'|HIBIT, 'r', 's',
|
|
+ 's'|HIBIT, 't', 'u', 'u'|HIBIT, 'v', 'w',
|
|
+ 'w', 'x', 'y', 'z', 'h', 't',
|
|
+ 'w', 'y', 'a', 'a'|HIBIT, 'a'|HIBIT, 'a'|HIBIT,
|
|
+ 'e', 'e'|HIBIT, 'e'|HIBIT, 'i', 'o', 'o'|HIBIT,
|
|
+ 'o'|HIBIT, 'o'|HIBIT, 'u', 'u'|HIBIT, 'u'|HIBIT, 'y',
|
|
};
|
|
|
|
unsigned int key = (((unsigned int)c)<<3) | 0x00000007;
|
|
@@ -183345,19 +198739,19 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int eRemoveDiacritic){
|
|
{42802, 1, 62}, {42873, 1, 4}, {42877, 76, 1},
|
|
{42878, 1, 10}, {42891, 0, 1}, {42893, 74, 1},
|
|
{42896, 1, 4}, {42912, 1, 10}, {42922, 72, 1},
|
|
- {65313, 14, 26},
|
|
+ {65313, 14, 26},
|
|
};
|
|
static const unsigned short aiOff[] = {
|
|
- 1, 2, 8, 15, 16, 26, 28, 32,
|
|
- 37, 38, 40, 48, 63, 64, 69, 71,
|
|
- 79, 80, 116, 202, 203, 205, 206, 207,
|
|
- 209, 210, 211, 213, 214, 217, 218, 219,
|
|
- 775, 7264, 10792, 10795, 23228, 23256, 30204, 54721,
|
|
- 54753, 54754, 54756, 54787, 54793, 54809, 57153, 57274,
|
|
- 57921, 58019, 58363, 61722, 65268, 65341, 65373, 65406,
|
|
- 65408, 65410, 65415, 65424, 65436, 65439, 65450, 65462,
|
|
- 65472, 65476, 65478, 65480, 65482, 65488, 65506, 65511,
|
|
- 65514, 65521, 65527, 65528, 65529,
|
|
+ 1, 2, 8, 15, 16, 26, 28, 32,
|
|
+ 37, 38, 40, 48, 63, 64, 69, 71,
|
|
+ 79, 80, 116, 202, 203, 205, 206, 207,
|
|
+ 209, 210, 211, 213, 214, 217, 218, 219,
|
|
+ 775, 7264, 10792, 10795, 23228, 23256, 30204, 54721,
|
|
+ 54753, 54754, 54756, 54787, 54793, 54809, 57153, 57274,
|
|
+ 57921, 58019, 58363, 61722, 65268, 65341, 65373, 65406,
|
|
+ 65408, 65410, 65415, 65424, 65436, 65439, 65450, 65462,
|
|
+ 65472, 65476, 65478, 65480, 65482, 65488, 65506, 65511,
|
|
+ 65514, 65521, 65527, 65528, 65529,
|
|
};
|
|
|
|
int ret = c;
|
|
@@ -183395,7 +198789,7 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int eRemoveDiacritic){
|
|
ret = remove_diacritic(ret, eRemoveDiacritic==2);
|
|
}
|
|
}
|
|
-
|
|
+
|
|
else if( c>=66560 && c<66600 ){
|
|
ret = c + 40;
|
|
}
|
|
@@ -183406,7 +198800,7 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int eRemoveDiacritic){
|
|
#endif /* !defined(SQLITE_DISABLE_FTS3_UNICODE) */
|
|
|
|
/************** End of fts3_unicode2.c ***************************************/
|
|
-/************** Begin file json1.c *******************************************/
|
|
+/************** Begin file json.c ********************************************/
|
|
/*
|
|
** 2015-08-12
|
|
**
|
|
@@ -183419,10 +198813,10 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int eRemoveDiacritic){
|
|
**
|
|
******************************************************************************
|
|
**
|
|
-** This SQLite extension implements JSON functions. The interface is
|
|
-** modeled after MySQL JSON functions:
|
|
+** This SQLite JSON functions.
|
|
**
|
|
-** https://dev.mysql.com/doc/refman/5.7/en/json.html
|
|
+** This file began as an extension in ext/misc/json1.c in 2015. That
|
|
+** extension proved so useful that it has now been moved into the core.
|
|
**
|
|
** For the time being, all JSON is stored as pure text. (We might add
|
|
** a JSONB type in the future which stores a binary encoding of JSON in
|
|
@@ -183430,44 +198824,8 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int eRemoveDiacritic){
|
|
** This implementation parses JSON text at 250 MB/s, so it is hard to see
|
|
** how JSONB might improve on that.)
|
|
*/
|
|
-#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_JSON1)
|
|
-#if !defined(SQLITEINT_H)
|
|
-/* #include "sqlite3ext.h" */
|
|
-#endif
|
|
-SQLITE_EXTENSION_INIT1
|
|
-/* #include <assert.h> */
|
|
-/* #include <string.h> */
|
|
-/* #include <stdlib.h> */
|
|
-/* #include <stdarg.h> */
|
|
-
|
|
-/* Mark a function parameter as unused, to suppress nuisance compiler
|
|
-** warnings. */
|
|
-#ifndef UNUSED_PARAM
|
|
-# define UNUSED_PARAM(X) (void)(X)
|
|
-#endif
|
|
-
|
|
-#ifndef LARGEST_INT64
|
|
-# define LARGEST_INT64 (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32))
|
|
-# define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64)
|
|
-#endif
|
|
-
|
|
-/*
|
|
-** Versions of isspace(), isalnum() and isdigit() to which it is safe
|
|
-** to pass signed char values.
|
|
-*/
|
|
-#ifdef sqlite3Isdigit
|
|
- /* Use the SQLite core versions if this routine is part of the
|
|
- ** SQLite amalgamation */
|
|
-# define safe_isdigit(x) sqlite3Isdigit(x)
|
|
-# define safe_isalnum(x) sqlite3Isalnum(x)
|
|
-# define safe_isxdigit(x) sqlite3Isxdigit(x)
|
|
-#else
|
|
- /* Use the standard library for separate compilation */
|
|
-#include <ctype.h> /* amalgamator: keep */
|
|
-# define safe_isdigit(x) isdigit((unsigned char)(x))
|
|
-# define safe_isalnum(x) isalnum((unsigned char)(x))
|
|
-# define safe_isxdigit(x) isxdigit((unsigned char)(x))
|
|
-#endif
|
|
+#ifndef SQLITE_OMIT_JSON
|
|
+/* #include "sqliteInt.h" */
|
|
|
|
/*
|
|
** Growing our own isspace() routine this way is twice as fast as
|
|
@@ -183492,15 +198850,12 @@ static const char jsonIsSpace[] = {
|
|
0, 0, 0, 0, 0, 0, 0, 0, 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 safe_isspace(x) (jsonIsSpace[(unsigned char)x])
|
|
+#define fast_isspace(x) (jsonIsSpace[(unsigned char)x])
|
|
|
|
-#ifndef SQLITE_AMALGAMATION
|
|
- /* Unsigned integer types. These are already defined in the sqliteInt.h,
|
|
- ** but the definitions need to be repeated for separate compilation. */
|
|
- typedef sqlite3_uint64 u64;
|
|
- typedef unsigned int u32;
|
|
- typedef unsigned short int u16;
|
|
- typedef unsigned char u8;
|
|
+#if !defined(SQLITE_DEBUG) && !defined(SQLITE_COVERAGE_TEST)
|
|
+# define VVA(X)
|
|
+#else
|
|
+# define VVA(X) X
|
|
#endif
|
|
|
|
/* Objects */
|
|
@@ -183559,13 +198914,14 @@ static const char * const jsonType[] = {
|
|
struct JsonNode {
|
|
u8 eType; /* One of the JSON_ type values */
|
|
u8 jnFlags; /* JNODE flags */
|
|
+ u8 eU; /* Which union element to use */
|
|
u32 n; /* Bytes of content, or number of sub-nodes */
|
|
union {
|
|
- const char *zJContent; /* Content for INT, REAL, and STRING */
|
|
- u32 iAppend; /* More terms for ARRAY and OBJECT */
|
|
- u32 iKey; /* Key for ARRAY objects in json_tree() */
|
|
- u32 iReplace; /* Replacement content for JNODE_REPLACE */
|
|
- JsonNode *pPatch; /* Node chain of patch for JNODE_PATCH */
|
|
+ const char *zJContent; /* 1: Content for INT, REAL, and STRING */
|
|
+ u32 iAppend; /* 2: More terms for ARRAY and OBJECT */
|
|
+ u32 iKey; /* 3: Key for ARRAY objects in json_tree() */
|
|
+ u32 iReplace; /* 4: Replacement content for JNODE_REPLACE */
|
|
+ JsonNode *pPatch; /* 5: Node chain of patch for JNODE_PATCH */
|
|
} u;
|
|
};
|
|
|
|
@@ -183624,7 +198980,7 @@ static void jsonReset(JsonString *p){
|
|
}
|
|
|
|
|
|
-/* Report an out-of-memory (OOM) condition
|
|
+/* Report an out-of-memory (OOM) condition
|
|
*/
|
|
static void jsonOom(JsonString *p){
|
|
p->bErr = 1;
|
|
@@ -183663,6 +199019,7 @@ 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;
|
|
memcpy(p->zBuf+p->nUsed, zIn, N);
|
|
p->nUsed += N;
|
|
@@ -183703,7 +199060,7 @@ static void jsonAppendSeparator(JsonString *p){
|
|
*/
|
|
static void jsonAppendString(JsonString *p, const char *zIn, u32 N){
|
|
u32 i;
|
|
- if( (N+p->nUsed+2 >= p->nAlloc) && jsonGrow(p,N+2)!=0 ) return;
|
|
+ if( zIn==0 || ((N+p->nUsed+2 >= p->nAlloc) && jsonGrow(p,N+2)!=0) ) return;
|
|
p->zBuf[p->nUsed++] = '"';
|
|
for(i=0; i<N; i++){
|
|
unsigned char c = ((unsigned const char*)zIn)[i];
|
|
@@ -183741,7 +199098,7 @@ static void jsonAppendString(JsonString *p, const char *zIn, u32 N){
|
|
}
|
|
|
|
/*
|
|
-** Append a function parameter value to the JSON string under
|
|
+** Append a function parameter value to the JSON string under
|
|
** construction.
|
|
*/
|
|
static void jsonAppendValue(
|
|
@@ -183786,7 +199143,7 @@ static void jsonAppendValue(
|
|
*/
|
|
static void jsonResult(JsonString *p){
|
|
if( p->bErr==0 ){
|
|
- sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed,
|
|
+ sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed,
|
|
p->bStatic ? SQLITE_TRANSIENT : sqlite3_free,
|
|
SQLITE_UTF8);
|
|
jsonZero(p);
|
|
@@ -183842,11 +199199,14 @@ static void jsonRenderNode(
|
|
JsonString *pOut, /* Write JSON here */
|
|
sqlite3_value **aReplace /* Replacement values */
|
|
){
|
|
+ assert( pNode!=0 );
|
|
if( pNode->jnFlags & (JNODE_REPLACE|JNODE_PATCH) ){
|
|
- if( pNode->jnFlags & JNODE_REPLACE ){
|
|
+ if( (pNode->jnFlags & JNODE_REPLACE)!=0 && ALWAYS(aReplace!=0) ){
|
|
+ assert( pNode->eU==4 );
|
|
jsonAppendValue(pOut, aReplace[pNode->u.iReplace]);
|
|
return;
|
|
}
|
|
+ assert( pNode->eU==5 );
|
|
pNode = pNode->u.pPatch;
|
|
}
|
|
switch( pNode->eType ){
|
|
@@ -183865,13 +199225,15 @@ static void jsonRenderNode(
|
|
}
|
|
case JSON_STRING: {
|
|
if( pNode->jnFlags & JNODE_RAW ){
|
|
+ assert( pNode->eU==1 );
|
|
jsonAppendString(pOut, pNode->u.zJContent, pNode->n);
|
|
break;
|
|
}
|
|
- /* Fall through into the next case */
|
|
+ /* no break */ deliberate_fall_through
|
|
}
|
|
case JSON_REAL:
|
|
case JSON_INT: {
|
|
+ assert( pNode->eU==1 );
|
|
jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n);
|
|
break;
|
|
}
|
|
@@ -183887,6 +199249,7 @@ static void jsonRenderNode(
|
|
j += jsonNodeSize(&pNode[j]);
|
|
}
|
|
if( (pNode->jnFlags & JNODE_APPEND)==0 ) break;
|
|
+ assert( pNode->eU==2 );
|
|
pNode = &pNode[pNode->u.iAppend];
|
|
j = 1;
|
|
}
|
|
@@ -183907,6 +199270,7 @@ static void jsonRenderNode(
|
|
j += 1 + jsonNodeSize(&pNode[j+1]);
|
|
}
|
|
if( (pNode->jnFlags & JNODE_APPEND)==0 ) break;
|
|
+ assert( pNode->eU==2 );
|
|
pNode = &pNode[pNode->u.iAppend];
|
|
j = 1;
|
|
}
|
|
@@ -183951,10 +199315,10 @@ static u8 jsonHexToInt(int h){
|
|
*/
|
|
static u32 jsonHexToInt4(const char *z){
|
|
u32 v;
|
|
- assert( safe_isxdigit(z[0]) );
|
|
- assert( safe_isxdigit(z[1]) );
|
|
- assert( safe_isxdigit(z[2]) );
|
|
- assert( safe_isxdigit(z[3]) );
|
|
+ assert( sqlite3Isxdigit(z[0]) );
|
|
+ assert( sqlite3Isxdigit(z[1]) );
|
|
+ assert( sqlite3Isxdigit(z[2]) );
|
|
+ assert( sqlite3Isxdigit(z[3]) );
|
|
v = (jsonHexToInt(z[0])<<12)
|
|
+ (jsonHexToInt(z[1])<<8)
|
|
+ (jsonHexToInt(z[2])<<4)
|
|
@@ -183986,7 +199350,9 @@ static void jsonReturn(
|
|
}
|
|
case JSON_INT: {
|
|
sqlite3_int64 i = 0;
|
|
- const char *z = pNode->u.zJContent;
|
|
+ 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';
|
|
@@ -184009,14 +199375,17 @@ static void jsonReturn(
|
|
sqlite3_result_int64(pCtx, i);
|
|
int_done:
|
|
break;
|
|
- int_as_real: /* fall through to real */;
|
|
+ int_as_real: ; /* no break */ deliberate_fall_through
|
|
}
|
|
case JSON_REAL: {
|
|
double r;
|
|
#ifdef SQLITE_AMALGAMATION
|
|
- const char *z = pNode->u.zJContent;
|
|
+ const char *z;
|
|
+ assert( pNode->eU==1 );
|
|
+ z = pNode->u.zJContent;
|
|
sqlite3AtoF(z, &r, sqlite3Strlen30(z), SQLITE_UTF8);
|
|
#else
|
|
+ assert( pNode->eU==1 );
|
|
r = strtod(pNode->u.zJContent, 0);
|
|
#endif
|
|
sqlite3_result_double(pCtx, r);
|
|
@@ -184027,22 +199396,26 @@ static void jsonReturn(
|
|
** 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
|
|
+ }else
|
|
#endif
|
|
assert( (pNode->jnFlags & JNODE_RAW)==0 );
|
|
if( (pNode->jnFlags & JNODE_ESCAPE)==0 ){
|
|
/* JSON formatted without any backslash-escapes */
|
|
+ assert( pNode->eU==1 );
|
|
sqlite3_result_text(pCtx, pNode->u.zJContent+1, pNode->n-2,
|
|
SQLITE_TRANSIENT);
|
|
}else{
|
|
/* Translate JSON formatted string into raw text */
|
|
u32 i;
|
|
u32 n = pNode->n;
|
|
- const char *z = pNode->u.zJContent;
|
|
+ const char *z;
|
|
char *zOut;
|
|
u32 j;
|
|
+ assert( pNode->eU==1 );
|
|
+ z = pNode->u.zJContent;
|
|
zOut = sqlite3_malloc( n+1 );
|
|
if( zOut==0 ){
|
|
sqlite3_result_error_nomem(pCtx);
|
|
@@ -184163,12 +199536,13 @@ static int jsonParseAddNode(
|
|
const char *zContent /* Content */
|
|
){
|
|
JsonNode *p;
|
|
- if( pParse->nNode>=pParse->nAlloc ){
|
|
+ if( pParse->aNode==0 || pParse->nNode>=pParse->nAlloc ){
|
|
return jsonParseAddNodeExpand(pParse, eType, n, zContent);
|
|
}
|
|
p = &pParse->aNode[pParse->nNode];
|
|
p->eType = (u8)eType;
|
|
p->jnFlags = 0;
|
|
+ VVA( p->eU = zContent ? 1 : 0 );
|
|
p->n = n;
|
|
p->u.zJContent = zContent;
|
|
return pParse->nNode++;
|
|
@@ -184179,7 +199553,7 @@ static int jsonParseAddNode(
|
|
*/
|
|
static int jsonIs4Hex(const char *z){
|
|
int i;
|
|
- for(i=0; i<4; i++) if( !safe_isxdigit(z[i]) ) return 0;
|
|
+ for(i=0; i<4; i++) if( !sqlite3Isxdigit(z[i]) ) return 0;
|
|
return 1;
|
|
}
|
|
|
|
@@ -184198,13 +199572,13 @@ static int jsonParseValue(JsonParse *pParse, u32 i){
|
|
int x;
|
|
JsonNode *pNode;
|
|
const char *z = pParse->zJson;
|
|
- while( safe_isspace(z[i]) ){ i++; }
|
|
+ while( fast_isspace(z[i]) ){ i++; }
|
|
if( (c = z[i])=='{' ){
|
|
/* Parse object */
|
|
iThis = jsonParseAddNode(pParse, JSON_OBJECT, 0, 0);
|
|
if( iThis<0 ) return -1;
|
|
for(j=i+1;;j++){
|
|
- while( safe_isspace(z[j]) ){ j++; }
|
|
+ while( fast_isspace(z[j]) ){ j++; }
|
|
if( ++pParse->iDepth > JSON_MAX_DEPTH ) return -1;
|
|
x = jsonParseValue(pParse, j);
|
|
if( x<0 ){
|
|
@@ -184217,14 +199591,14 @@ static int jsonParseValue(JsonParse *pParse, u32 i){
|
|
if( pNode->eType!=JSON_STRING ) return -1;
|
|
pNode->jnFlags |= JNODE_LABEL;
|
|
j = x;
|
|
- while( safe_isspace(z[j]) ){ j++; }
|
|
+ while( fast_isspace(z[j]) ){ j++; }
|
|
if( z[j]!=':' ) return -1;
|
|
j++;
|
|
x = jsonParseValue(pParse, j);
|
|
pParse->iDepth--;
|
|
if( x<0 ) return -1;
|
|
j = x;
|
|
- while( safe_isspace(z[j]) ){ j++; }
|
|
+ while( fast_isspace(z[j]) ){ j++; }
|
|
c = z[j];
|
|
if( c==',' ) continue;
|
|
if( c!='}' ) return -1;
|
|
@@ -184236,8 +199610,9 @@ static int jsonParseValue(JsonParse *pParse, u32 i){
|
|
/* Parse array */
|
|
iThis = jsonParseAddNode(pParse, JSON_ARRAY, 0, 0);
|
|
if( iThis<0 ) return -1;
|
|
+ memset(&pParse->aNode[iThis].u, 0, sizeof(pParse->aNode[iThis].u));
|
|
for(j=i+1;;j++){
|
|
- while( safe_isspace(z[j]) ){ j++; }
|
|
+ while( fast_isspace(z[j]) ){ j++; }
|
|
if( ++pParse->iDepth > JSON_MAX_DEPTH ) return -1;
|
|
x = jsonParseValue(pParse, j);
|
|
pParse->iDepth--;
|
|
@@ -184246,7 +199621,7 @@ static int jsonParseValue(JsonParse *pParse, u32 i){
|
|
return -1;
|
|
}
|
|
j = x;
|
|
- while( safe_isspace(z[j]) ){ j++; }
|
|
+ while( fast_isspace(z[j]) ){ j++; }
|
|
c = z[j];
|
|
if( c==',' ) continue;
|
|
if( c!=']' ) return -1;
|
|
@@ -184283,17 +199658,17 @@ static int jsonParseValue(JsonParse *pParse, u32 i){
|
|
return j+1;
|
|
}else if( c=='n'
|
|
&& strncmp(z+i,"null",4)==0
|
|
- && !safe_isalnum(z[i+4]) ){
|
|
+ && !sqlite3Isalnum(z[i+4]) ){
|
|
jsonParseAddNode(pParse, JSON_NULL, 0, 0);
|
|
return i+4;
|
|
}else if( c=='t'
|
|
&& strncmp(z+i,"true",4)==0
|
|
- && !safe_isalnum(z[i+4]) ){
|
|
+ && !sqlite3Isalnum(z[i+4]) ){
|
|
jsonParseAddNode(pParse, JSON_TRUE, 0, 0);
|
|
return i+4;
|
|
}else if( c=='f'
|
|
&& strncmp(z+i,"false",5)==0
|
|
- && !safe_isalnum(z[i+5]) ){
|
|
+ && !sqlite3Isalnum(z[i+5]) ){
|
|
jsonParseAddNode(pParse, JSON_FALSE, 0, 0);
|
|
return i+5;
|
|
}else if( c=='-' || (c>='0' && c<='9') ){
|
|
@@ -184364,7 +199739,7 @@ static int jsonParse(
|
|
if( pParse->oom ) i = -1;
|
|
if( i>0 ){
|
|
assert( pParse->iDepth==0 );
|
|
- while( safe_isspace(zJson[i]) ) i++;
|
|
+ while( fast_isspace(zJson[i]) ) i++;
|
|
if( zJson[i] ) i = -1;
|
|
}
|
|
if( i<=0 ){
|
|
@@ -184500,6 +199875,7 @@ static JsonParse *jsonParseCached(
|
|
** a match.
|
|
*/
|
|
static int jsonLabelCompare(JsonNode *pNode, const char *zKey, u32 nKey){
|
|
+ assert( pNode->eU==1 );
|
|
if( pNode->jnFlags & JNODE_RAW ){
|
|
if( pNode->n!=nKey ) return 0;
|
|
return strncmp(pNode->u.zJContent, zKey, nKey)==0;
|
|
@@ -184546,14 +199922,15 @@ static JsonNode *jsonLookupStep(
|
|
*pzErr = zPath;
|
|
return 0;
|
|
}
|
|
+ testcase( nKey==0 );
|
|
}else{
|
|
zKey = zPath;
|
|
for(i=0; zPath[i] && zPath[i]!='.' && zPath[i]!='['; i++){}
|
|
nKey = i;
|
|
- }
|
|
- if( nKey==0 ){
|
|
- *pzErr = zPath;
|
|
- return 0;
|
|
+ if( nKey==0 ){
|
|
+ *pzErr = zPath;
|
|
+ return 0;
|
|
+ }
|
|
}
|
|
j = 1;
|
|
for(;;){
|
|
@@ -184565,6 +199942,7 @@ static JsonNode *jsonLookupStep(
|
|
j += jsonNodeSize(&pRoot[j]);
|
|
}
|
|
if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break;
|
|
+ assert( pRoot->eU==2 );
|
|
iRoot += pRoot->u.iAppend;
|
|
pRoot = &pParse->aNode[iRoot];
|
|
j = 1;
|
|
@@ -184579,8 +199957,10 @@ static JsonNode *jsonLookupStep(
|
|
if( pParse->oom ) return 0;
|
|
if( pNode ){
|
|
pRoot = &pParse->aNode[iRoot];
|
|
+ assert( pRoot->eU==0 );
|
|
pRoot->u.iAppend = iStart - iRoot;
|
|
pRoot->jnFlags |= JNODE_APPEND;
|
|
+ VVA( pRoot->eU = 2 );
|
|
pParse->aNode[iLabel].jnFlags |= JNODE_RAW;
|
|
}
|
|
return pNode;
|
|
@@ -184588,7 +199968,7 @@ static JsonNode *jsonLookupStep(
|
|
}else if( zPath[0]=='[' ){
|
|
i = 0;
|
|
j = 1;
|
|
- while( safe_isdigit(zPath[j]) ){
|
|
+ while( sqlite3Isdigit(zPath[j]) ){
|
|
i = i*10 + zPath[j] - '0';
|
|
j++;
|
|
}
|
|
@@ -184603,18 +199983,19 @@ static JsonNode *jsonLookupStep(
|
|
j += jsonNodeSize(&pBase[j]);
|
|
}
|
|
if( (pBase->jnFlags & JNODE_APPEND)==0 ) break;
|
|
+ assert( pBase->eU==2 );
|
|
iBase += pBase->u.iAppend;
|
|
pBase = &pParse->aNode[iBase];
|
|
j = 1;
|
|
}
|
|
j = 2;
|
|
- if( zPath[2]=='-' && safe_isdigit(zPath[3]) ){
|
|
+ if( zPath[2]=='-' && sqlite3Isdigit(zPath[3]) ){
|
|
unsigned int x = 0;
|
|
j = 3;
|
|
do{
|
|
x = x*10 + zPath[j] - '0';
|
|
j++;
|
|
- }while( safe_isdigit(zPath[j]) );
|
|
+ }while( sqlite3Isdigit(zPath[j]) );
|
|
if( x>i ) return 0;
|
|
i -= x;
|
|
}
|
|
@@ -184636,6 +200017,7 @@ static JsonNode *jsonLookupStep(
|
|
j += jsonNodeSize(&pRoot[j]);
|
|
}
|
|
if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break;
|
|
+ assert( pRoot->eU==2 );
|
|
iRoot += pRoot->u.iAppend;
|
|
pRoot = &pParse->aNode[iRoot];
|
|
j = 1;
|
|
@@ -184651,8 +200033,10 @@ static JsonNode *jsonLookupStep(
|
|
if( pParse->oom ) return 0;
|
|
if( pNode ){
|
|
pRoot = &pParse->aNode[iRoot];
|
|
+ assert( pRoot->eU==0 );
|
|
pRoot->u.iAppend = iStart - iRoot;
|
|
pRoot->jnFlags |= JNODE_APPEND;
|
|
+ VVA( pRoot->eU = 2 );
|
|
}
|
|
return pNode;
|
|
}
|
|
@@ -184750,7 +200134,7 @@ static void jsonWrongNumArgs(
|
|
char *zMsg = sqlite3_mprintf("json_%s() needs an odd number of arguments",
|
|
zFuncName);
|
|
sqlite3_result_error(pCtx, zMsg, -1);
|
|
- sqlite3_free(zMsg);
|
|
+ sqlite3_free(zMsg);
|
|
}
|
|
|
|
/*
|
|
@@ -184806,9 +200190,13 @@ static void jsonParseFunc(
|
|
}
|
|
jsonPrintf(100, &s,"node %3u: %7s n=%-4d up=%-4d",
|
|
i, zType, x.aNode[i].n, x.aUp[i]);
|
|
+ assert( x.aNode[i].eU==0 || x.aNode[i].eU==1 );
|
|
if( x.aNode[i].u.zJContent!=0 ){
|
|
+ assert( x.aNode[i].eU==1 );
|
|
jsonAppendRaw(&s, " ", 1);
|
|
jsonAppendRaw(&s, x.aNode[i].u.zJContent, x.aNode[i].n);
|
|
+ }else{
|
|
+ assert( x.aNode[i].eU==0 );
|
|
}
|
|
jsonAppendRaw(&s, "\n", 1);
|
|
}
|
|
@@ -184826,7 +200214,7 @@ static void jsonTest1Func(
|
|
int argc,
|
|
sqlite3_value **argv
|
|
){
|
|
- UNUSED_PARAM(argc);
|
|
+ UNUSED_PARAMETER(argc);
|
|
sqlite3_result_int(ctx, sqlite3_value_subtype(argv[0])==JSON_SUBTYPE);
|
|
}
|
|
#endif /* SQLITE_DEBUG */
|
|
@@ -184837,7 +200225,7 @@ static void jsonTest1Func(
|
|
|
|
/*
|
|
** Implementation of the json_QUOTE(VALUE) function. Return a JSON value
|
|
-** corresponding to the SQL value input. Mostly this means putting
|
|
+** corresponding to the SQL value input. Mostly this means putting
|
|
** double-quotes around strings and returning the unquoted string "null"
|
|
** when given a NULL input.
|
|
*/
|
|
@@ -184847,7 +200235,7 @@ static void jsonQuoteFunc(
|
|
sqlite3_value **argv
|
|
){
|
|
JsonString jx;
|
|
- UNUSED_PARAM(argc);
|
|
+ UNUSED_PARAMETER(argc);
|
|
|
|
jsonInit(&jx, ctx);
|
|
jsonAppendValue(&jx, argv[0]);
|
|
@@ -184884,7 +200272,7 @@ static void jsonArrayFunc(
|
|
** json_array_length(JSON)
|
|
** json_array_length(JSON, PATH)
|
|
**
|
|
-** Return the number of elements in the top-level JSON array.
|
|
+** Return the number of elements in the top-level JSON array.
|
|
** Return 0 if the input is not a well-formed JSON array.
|
|
*/
|
|
static void jsonArrayLengthFunc(
|
|
@@ -184918,13 +200306,34 @@ static void jsonArrayLengthFunc(
|
|
sqlite3_result_int64(ctx, n);
|
|
}
|
|
|
|
+/*
|
|
+** Bit values for the flags passed into jsonExtractFunc() or
|
|
+** jsonSetFunc() via the user-data value.
|
|
+*/
|
|
+#define JSON_JSON 0x01 /* Result is always JSON */
|
|
+#define JSON_SQL 0x02 /* Result is always SQL */
|
|
+#define JSON_ABPATH 0x03 /* Allow abbreviated JSON path specs */
|
|
+#define JSON_ISSET 0x04 /* json_set(), not json_insert() */
|
|
+
|
|
/*
|
|
** json_extract(JSON, PATH, ...)
|
|
+** "->"(JSON,PATH)
|
|
+** "->>"(JSON,PATH)
|
|
**
|
|
-** Return the element described by PATH. Return NULL if there is no
|
|
-** PATH element. If there are multiple PATHs, then return a JSON array
|
|
-** with the result from each path. Throw an error if the JSON or any PATH
|
|
-** is malformed.
|
|
+** Return the element described by PATH. Return NULL if that PATH element
|
|
+** is not found.
|
|
+**
|
|
+** If JSON_JSON is set or if more that one PATH argument is supplied then
|
|
+** always return a JSON representation of the result. If JSON_SQL is set,
|
|
+** then always return an SQL representation of the result. If neither flag
|
|
+** is present and argc==2, then return JSON for objects and arrays and SQL
|
|
+** for all other values.
|
|
+**
|
|
+** When multiple PATH arguments are supplied, the result is a JSON array
|
|
+** containing the result of each PATH.
|
|
+**
|
|
+** Abbreviated JSON path expressions are allows if JSON_ABPATH, for
|
|
+** compatibility with PG.
|
|
*/
|
|
static void jsonExtractFunc(
|
|
sqlite3_context *ctx,
|
|
@@ -184934,35 +200343,77 @@ static void jsonExtractFunc(
|
|
JsonParse *p; /* The parse */
|
|
JsonNode *pNode;
|
|
const char *zPath;
|
|
+ int flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx));
|
|
JsonString jx;
|
|
- int i;
|
|
|
|
if( argc<2 ) return;
|
|
p = jsonParseCached(ctx, argv, ctx);
|
|
if( p==0 ) return;
|
|
- jsonInit(&jx, ctx);
|
|
- jsonAppendChar(&jx, '[');
|
|
- for(i=1; i<argc; i++){
|
|
- zPath = (const char*)sqlite3_value_text(argv[i]);
|
|
- pNode = jsonLookup(p, zPath, 0, ctx);
|
|
- if( p->nErr ) break;
|
|
- if( argc>2 ){
|
|
+ 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]!='$' ){
|
|
+ /* The -> and ->> operators accept abbreviated PATH arguments. This
|
|
+ ** is mostly for compatibility with PostgreSQL, but also for
|
|
+ ** convenience.
|
|
+ **
|
|
+ ** NUMBER ==> $[NUMBER] // PG compatible
|
|
+ ** LABEL ==> $.LABEL // PG compatible
|
|
+ ** [NUMBER] ==> $[NUMBER] // Not PG. Purely for convenience
|
|
+ */
|
|
+ jsonInit(&jx, ctx);
|
|
+ if( sqlite3Isdigit(zPath[0]) ){
|
|
+ jsonAppendRaw(&jx, "$[", 2);
|
|
+ jsonAppendRaw(&jx, zPath, (int)strlen(zPath));
|
|
+ jsonAppendRaw(&jx, "]", 2);
|
|
+ }else{
|
|
+ jsonAppendRaw(&jx, "$.", 1 + (zPath[0]!='['));
|
|
+ jsonAppendRaw(&jx, zPath, (int)strlen(zPath));
|
|
+ jsonAppendChar(&jx, 0);
|
|
+ }
|
|
+ pNode = jx.bErr ? 0 : jsonLookup(p, jx.zBuf, 0, ctx);
|
|
+ jsonReset(&jx);
|
|
+ }else{
|
|
+ pNode = jsonLookup(p, zPath, 0, ctx);
|
|
+ }
|
|
+ if( pNode ){
|
|
+ if( flags & JSON_JSON ){
|
|
+ jsonReturnJson(pNode, ctx, 0);
|
|
+ }else{
|
|
+ jsonReturn(pNode, ctx, 0);
|
|
+ sqlite3_result_subtype(ctx, 0);
|
|
+ }
|
|
+ }
|
|
+ }else{
|
|
+ pNode = jsonLookup(p, zPath, 0, ctx);
|
|
+ if( p->nErr==0 && pNode ) jsonReturn(pNode, ctx, 0);
|
|
+ }
|
|
+ }else{
|
|
+ /* Two or more PATH arguments results in a JSON array with each
|
|
+ ** element of the array being the value selected by one of the PATHs */
|
|
+ int i;
|
|
+ jsonInit(&jx, ctx);
|
|
+ jsonAppendChar(&jx, '[');
|
|
+ for(i=1; i<argc; i++){
|
|
+ zPath = (const char*)sqlite3_value_text(argv[i]);
|
|
+ pNode = jsonLookup(p, zPath, 0, ctx);
|
|
+ if( p->nErr ) break;
|
|
jsonAppendSeparator(&jx);
|
|
if( pNode ){
|
|
jsonRenderNode(pNode, &jx, 0);
|
|
}else{
|
|
jsonAppendRaw(&jx, "null", 4);
|
|
}
|
|
- }else if( pNode ){
|
|
- jsonReturn(pNode, ctx, 0);
|
|
}
|
|
+ if( i==argc ){
|
|
+ jsonAppendChar(&jx, ']');
|
|
+ jsonResult(&jx);
|
|
+ sqlite3_result_subtype(ctx, JSON_SUBTYPE);
|
|
+ }
|
|
+ jsonReset(&jx);
|
|
}
|
|
- if( argc>2 && i==argc ){
|
|
- jsonAppendChar(&jx, ']');
|
|
- jsonResult(&jx);
|
|
- sqlite3_result_subtype(ctx, JSON_SUBTYPE);
|
|
- }
|
|
- jsonReset(&jx);
|
|
}
|
|
|
|
/* This is the RFC 7396 MergePatch algorithm.
|
|
@@ -184978,7 +200429,7 @@ static JsonNode *jsonMergePatch(
|
|
if( pPatch->eType!=JSON_OBJECT ){
|
|
return pPatch;
|
|
}
|
|
- assert( iTarget>=0 && iTarget<pParse->nNode );
|
|
+ assert( iTarget<pParse->nNode );
|
|
pTarget = &pParse->aNode[iTarget];
|
|
assert( (pPatch->jnFlags & JNODE_APPEND)==0 );
|
|
if( pTarget->eType!=JSON_OBJECT ){
|
|
@@ -184991,6 +200442,7 @@ static JsonNode *jsonMergePatch(
|
|
const char *zKey;
|
|
assert( pPatch[i].eType==JSON_STRING );
|
|
assert( pPatch[i].jnFlags & JNODE_LABEL );
|
|
+ assert( pPatch[i].eU==1 );
|
|
nKey = pPatch[i].n;
|
|
zKey = pPatch[i].u.zJContent;
|
|
assert( (pPatch[i].jnFlags & JNODE_RAW)==0 );
|
|
@@ -185007,6 +200459,12 @@ static JsonNode *jsonMergePatch(
|
|
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;
|
|
}
|
|
@@ -185022,9 +200480,14 @@ static JsonNode *jsonMergePatch(
|
|
if( pParse->oom ) return 0;
|
|
jsonRemoveAllNulls(pPatch);
|
|
pTarget = &pParse->aNode[iTarget];
|
|
+ assert( pParse->aNode[iRoot].eU==0 || pParse->aNode[iRoot].eU==2 );
|
|
+ testcase( pParse->aNode[iRoot].eU==2 );
|
|
pParse->aNode[iRoot].jnFlags |= JNODE_APPEND;
|
|
+ VVA( pParse->aNode[iRoot].eU = 2 );
|
|
pParse->aNode[iRoot].u.iAppend = iStart - iRoot;
|
|
iRoot = iStart;
|
|
+ assert( pParse->aNode[iPatch].eU==0 );
|
|
+ VVA( pParse->aNode[iPatch].eU = 5 );
|
|
pParse->aNode[iPatch].jnFlags |= JNODE_PATCH;
|
|
pParse->aNode[iPatch].u.pPatch = &pPatch[i+1];
|
|
}
|
|
@@ -185046,7 +200509,7 @@ static void jsonPatchFunc(
|
|
JsonParse y; /* The patch */
|
|
JsonNode *pResult; /* The result of the merge */
|
|
|
|
- UNUSED_PARAM(argc);
|
|
+ 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);
|
|
@@ -185166,11 +200629,15 @@ static void jsonReplaceFunc(
|
|
pNode = jsonLookup(&x, zPath, 0, ctx);
|
|
if( x.nErr ) goto replace_err;
|
|
if( pNode ){
|
|
+ assert( pNode->eU==0 || pNode->eU==1 || pNode->eU==4 );
|
|
+ testcase( pNode->eU!=0 && pNode->eU!=1 );
|
|
pNode->jnFlags |= (u8)JNODE_REPLACE;
|
|
+ VVA( pNode->eU = 4 );
|
|
pNode->u.iReplace = i + 1;
|
|
}
|
|
}
|
|
if( x.aNode[0].jnFlags & JNODE_REPLACE ){
|
|
+ assert( x.aNode[0].eU==4 );
|
|
sqlite3_result_value(ctx, argv[x.aNode[0].u.iReplace]);
|
|
}else{
|
|
jsonReturnJson(x.aNode, ctx, argv);
|
|
@@ -185179,6 +200646,7 @@ static void jsonReplaceFunc(
|
|
jsonParseReset(&x);
|
|
}
|
|
|
|
+
|
|
/*
|
|
** json_set(JSON, PATH, VALUE, ...)
|
|
**
|
|
@@ -185201,7 +200669,7 @@ static void jsonSetFunc(
|
|
const char *zPath;
|
|
u32 i;
|
|
int bApnd;
|
|
- int bIsSet = *(int*)sqlite3_user_data(ctx);
|
|
+ int bIsSet = sqlite3_user_data(ctx)!=0;
|
|
|
|
if( argc<1 ) return;
|
|
if( (argc&1)==0 ) {
|
|
@@ -185220,11 +200688,15 @@ static void jsonSetFunc(
|
|
}else if( x.nErr ){
|
|
goto jsonSetDone;
|
|
}else if( pNode && (bApnd || bIsSet) ){
|
|
+ testcase( pNode->eU!=0 && pNode->eU!=1 );
|
|
+ assert( pNode->eU!=3 && pNode->eU!=5 );
|
|
+ VVA( pNode->eU = 4 );
|
|
pNode->jnFlags |= (u8)JNODE_REPLACE;
|
|
pNode->u.iReplace = i + 1;
|
|
}
|
|
}
|
|
if( x.aNode[0].jnFlags & JNODE_REPLACE ){
|
|
+ assert( x.aNode[0].eU==4 );
|
|
sqlite3_result_value(ctx, argv[x.aNode[0].u.iReplace]);
|
|
}else{
|
|
jsonReturnJson(x.aNode, ctx, argv);
|
|
@@ -185237,8 +200709,8 @@ static void jsonSetFunc(
|
|
** json_type(JSON)
|
|
** json_type(JSON, PATH)
|
|
**
|
|
-** Return the top-level "type" of a JSON string. Throw an error if
|
|
-** either the JSON or PATH inputs are not well-formed.
|
|
+** Return the top-level "type" of a JSON string. json_type() raises an
|
|
+** error if either the JSON or PATH inputs are not well-formed.
|
|
*/
|
|
static void jsonTypeFunc(
|
|
sqlite3_context *ctx,
|
|
@@ -185274,7 +200746,7 @@ static void jsonValidFunc(
|
|
sqlite3_value **argv
|
|
){
|
|
JsonParse *p; /* The parse */
|
|
- UNUSED_PARAM(argc);
|
|
+ UNUSED_PARAMETER(argc);
|
|
p = jsonParseCached(ctx, argv, 0);
|
|
sqlite3_result_int(ctx, p!=0);
|
|
}
|
|
@@ -185294,7 +200766,7 @@ static void jsonArrayStep(
|
|
sqlite3_value **argv
|
|
){
|
|
JsonString *pStr;
|
|
- UNUSED_PARAM(argc);
|
|
+ UNUSED_PARAMETER(argc);
|
|
pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr));
|
|
if( pStr ){
|
|
if( pStr->zBuf==0 ){
|
|
@@ -185302,8 +200774,8 @@ static void jsonArrayStep(
|
|
jsonAppendChar(pStr, '[');
|
|
}else if( pStr->nUsed>1 ){
|
|
jsonAppendChar(pStr, ',');
|
|
- pStr->pCtx = ctx;
|
|
}
|
|
+ pStr->pCtx = ctx;
|
|
jsonAppendValue(pStr, argv[0]);
|
|
}
|
|
}
|
|
@@ -185354,8 +200826,8 @@ static void jsonGroupInverse(
|
|
char *z;
|
|
char c;
|
|
JsonString *pStr;
|
|
- UNUSED_PARAM(argc);
|
|
- UNUSED_PARAM(argv);
|
|
+ UNUSED_PARAMETER(argc);
|
|
+ UNUSED_PARAMETER(argv);
|
|
pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
|
|
#ifdef NEVER
|
|
/* pStr is always non-NULL since jsonArrayStep() or jsonObjectStep() will
|
|
@@ -185363,11 +200835,7 @@ static void jsonGroupInverse(
|
|
if( NEVER(!pStr) ) return;
|
|
#endif
|
|
z = pStr->zBuf;
|
|
- for(i=1; (c = z[i])!=',' || inStr || nNest; i++){
|
|
- if( i>=pStr->nUsed ){
|
|
- pStr->nUsed = 1;
|
|
- return;
|
|
- }
|
|
+ for(i=1; i<pStr->nUsed && ((c = z[i])!=',' || inStr || nNest); i++){
|
|
if( c=='"' ){
|
|
inStr = !inStr;
|
|
}else if( c=='\\' ){
|
|
@@ -185377,8 +200845,13 @@ static void jsonGroupInverse(
|
|
if( c=='}' || c==']' ) nNest--;
|
|
}
|
|
}
|
|
- pStr->nUsed -= i;
|
|
- memmove(&z[1], &z[i+1], (size_t)pStr->nUsed-1);
|
|
+ if( i<pStr->nUsed ){
|
|
+ pStr->nUsed -= i;
|
|
+ memmove(&z[1], &z[i+1], (size_t)pStr->nUsed-1);
|
|
+ z[pStr->nUsed] = 0;
|
|
+ }else{
|
|
+ pStr->nUsed = 1;
|
|
+ }
|
|
}
|
|
#else
|
|
# define jsonGroupInverse 0
|
|
@@ -185398,7 +200871,7 @@ static void jsonObjectStep(
|
|
JsonString *pStr;
|
|
const char *z;
|
|
u32 n;
|
|
- UNUSED_PARAM(argc);
|
|
+ UNUSED_PARAMETER(argc);
|
|
pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr));
|
|
if( pStr ){
|
|
if( pStr->zBuf==0 ){
|
|
@@ -185406,8 +200879,8 @@ static void jsonObjectStep(
|
|
jsonAppendChar(pStr, '{');
|
|
}else if( pStr->nUsed>1 ){
|
|
jsonAppendChar(pStr, ',');
|
|
- pStr->pCtx = ctx;
|
|
}
|
|
+ pStr->pCtx = ctx;
|
|
z = (const char*)sqlite3_value_text(argv[0]);
|
|
n = (u32)sqlite3_value_bytes(argv[0]);
|
|
jsonAppendString(pStr, z, n);
|
|
@@ -185489,11 +200962,11 @@ static int jsonEachConnect(
|
|
#define JEACH_JSON 8
|
|
#define JEACH_ROOT 9
|
|
|
|
- UNUSED_PARAM(pzErr);
|
|
- UNUSED_PARAM(argv);
|
|
- UNUSED_PARAM(argc);
|
|
- UNUSED_PARAM(pAux);
|
|
- rc = sqlite3_declare_vtab(db,
|
|
+ UNUSED_PARAMETER(pzErr);
|
|
+ UNUSED_PARAMETER(argv);
|
|
+ UNUSED_PARAMETER(argc);
|
|
+ UNUSED_PARAMETER(pAux);
|
|
+ rc = sqlite3_declare_vtab(db,
|
|
"CREATE TABLE x(key,value,type,atom,id,parent,fullkey,path,"
|
|
"json HIDDEN,root HIDDEN)");
|
|
if( rc==SQLITE_OK ){
|
|
@@ -185515,7 +200988,7 @@ static int jsonEachDisconnect(sqlite3_vtab *pVtab){
|
|
static int jsonEachOpenEach(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
|
|
JsonEachCursor *pCur;
|
|
|
|
- UNUSED_PARAM(p);
|
|
+ UNUSED_PARAMETER(p);
|
|
pCur = sqlite3_malloc( sizeof(*pCur) );
|
|
if( pCur==0 ) return SQLITE_NOMEM;
|
|
memset(pCur, 0, sizeof(*pCur));
|
|
@@ -185574,6 +201047,9 @@ static int jsonEachNext(sqlite3_vtab_cursor *cur){
|
|
JsonNode *pUp = &p->sParse.aNode[iUp];
|
|
p->eType = pUp->eType;
|
|
if( pUp->eType==JSON_ARRAY ){
|
|
+ assert( pUp->eU==0 || pUp->eU==3 );
|
|
+ testcase( pUp->eU==3 );
|
|
+ VVA( pUp->eU = 3 );
|
|
if( iUp==p->i-1 ){
|
|
pUp->u.iKey = 0;
|
|
}else{
|
|
@@ -185602,6 +201078,33 @@ static int jsonEachNext(sqlite3_vtab_cursor *cur){
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
+/* Append an object label to the JSON Path being constructed
|
|
+** in pStr.
|
|
+*/
|
|
+static void jsonAppendObjectPathElement(
|
|
+ JsonString *pStr,
|
|
+ JsonNode *pNode
|
|
+){
|
|
+ int jj, nn;
|
|
+ const char *z;
|
|
+ assert( pNode->eType==JSON_STRING );
|
|
+ assert( pNode->jnFlags & JNODE_LABEL );
|
|
+ assert( pNode->eU==1 );
|
|
+ z = pNode->u.zJContent;
|
|
+ nn = pNode->n;
|
|
+ assert( nn>=2 );
|
|
+ assert( z[0]=='"' );
|
|
+ assert( z[nn-1]=='"' );
|
|
+ if( nn>2 && sqlite3Isalpha(z[1]) ){
|
|
+ for(jj=2; jj<nn-1 && sqlite3Isalnum(z[jj]); jj++){}
|
|
+ if( jj==nn-1 ){
|
|
+ z++;
|
|
+ nn -= 2;
|
|
+ }
|
|
+ }
|
|
+ jsonPrintf(nn+2, pStr, ".%.*s", nn, z);
|
|
+}
|
|
+
|
|
/* Append the name of the path for element i to pStr
|
|
*/
|
|
static void jsonEachComputePath(
|
|
@@ -185620,13 +201123,13 @@ static void jsonEachComputePath(
|
|
pNode = &p->sParse.aNode[i];
|
|
pUp = &p->sParse.aNode[iUp];
|
|
if( pUp->eType==JSON_ARRAY ){
|
|
+ assert( pUp->eU==3 || (pUp->eU==0 && pUp->u.iKey==0) );
|
|
+ testcase( pUp->eU==0 );
|
|
jsonPrintf(30, pStr, "[%d]", pUp->u.iKey);
|
|
}else{
|
|
assert( pUp->eType==JSON_OBJECT );
|
|
if( (pNode->jnFlags & JNODE_LABEL)==0 ) pNode--;
|
|
- assert( pNode->eType==JSON_STRING );
|
|
- assert( pNode->jnFlags & JNODE_LABEL );
|
|
- jsonPrintf(pNode->n+1, pStr, ".%.*s", pNode->n-2, pNode->u.zJContent+1);
|
|
+ jsonAppendObjectPathElement(pStr, pNode);
|
|
}
|
|
}
|
|
|
|
@@ -185647,6 +201150,7 @@ static int jsonEachColumn(
|
|
u32 iKey;
|
|
if( p->bRecursive ){
|
|
if( p->iRowid==0 ) break;
|
|
+ assert( p->sParse.aNode[p->sParse.aUp[p->i]].eU==3 );
|
|
iKey = p->sParse.aNode[p->sParse.aUp[p->i]].u.iKey;
|
|
}else{
|
|
iKey = p->iRowid;
|
|
@@ -185672,7 +201176,7 @@ static int jsonEachColumn(
|
|
break;
|
|
}
|
|
case JEACH_ID: {
|
|
- sqlite3_result_int64(ctx,
|
|
+ sqlite3_result_int64(ctx,
|
|
(sqlite3_int64)p->i + ((pThis->jnFlags & JNODE_LABEL)!=0));
|
|
break;
|
|
}
|
|
@@ -185696,7 +201200,7 @@ static int jsonEachColumn(
|
|
if( p->eType==JSON_ARRAY ){
|
|
jsonPrintf(30, &x, "[%d]", p->iRowid);
|
|
}else if( p->eType==JSON_OBJECT ){
|
|
- jsonPrintf(pThis->n, &x, ".%.*s", pThis->n-2, pThis->u.zJContent+1);
|
|
+ jsonAppendObjectPathElement(&x, pThis);
|
|
}
|
|
}
|
|
jsonResult(&x);
|
|
@@ -185712,6 +201216,7 @@ static int jsonEachColumn(
|
|
}
|
|
/* For json_each() path and root are the same so fall through
|
|
** into the root case */
|
|
+ /* no break */ deliberate_fall_through
|
|
}
|
|
default: {
|
|
const char *zRoot = p->zRoot;
|
|
@@ -185753,7 +201258,7 @@ static int jsonEachBestIndex(
|
|
/* This implementation assumes that JSON and ROOT are the last two
|
|
** columns in the table */
|
|
assert( JEACH_ROOT == JEACH_JSON+1 );
|
|
- UNUSED_PARAM(tab);
|
|
+ UNUSED_PARAMETER(tab);
|
|
aIdx[0] = aIdx[1] = -1;
|
|
pConstraint = pIdxInfo->aConstraint;
|
|
for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
|
|
@@ -185762,6 +201267,7 @@ static int jsonEachBestIndex(
|
|
if( pConstraint->iColumn < JEACH_JSON ) continue;
|
|
iCol = pConstraint->iColumn - JEACH_JSON;
|
|
assert( iCol==0 || iCol==1 );
|
|
+ testcase( iCol==0 );
|
|
iMask = 1 << iCol;
|
|
if( pConstraint->usable==0 ){
|
|
unusableMask |= iMask;
|
|
@@ -185770,6 +201276,13 @@ static int jsonEachBestIndex(
|
|
idxMask |= iMask;
|
|
}
|
|
}
|
|
+ if( pIdxInfo->nOrderBy>0
|
|
+ && pIdxInfo->aOrderBy[0].iColumn<0
|
|
+ && pIdxInfo->aOrderBy[0].desc==0
|
|
+ ){
|
|
+ pIdxInfo->orderByConsumed = 1;
|
|
+ }
|
|
+
|
|
if( (unusableMask & ~idxMask)!=0 ){
|
|
/* If there are any unusable constraints on JSON or ROOT, then reject
|
|
** this entire plan */
|
|
@@ -185808,8 +201321,8 @@ static int jsonEachFilter(
|
|
const char *zRoot = 0;
|
|
sqlite3_int64 n;
|
|
|
|
- UNUSED_PARAM(idxStr);
|
|
- UNUSED_PARAM(argc);
|
|
+ UNUSED_PARAMETER(idxStr);
|
|
+ UNUSED_PARAMETER(argc);
|
|
jsonEachCursorReset(p);
|
|
if( idxNum==0 ) return SQLITE_OK;
|
|
z = (const char*)sqlite3_value_text(argv[0]);
|
|
@@ -185859,6 +201372,8 @@ static int jsonEachFilter(
|
|
p->iBegin = p->i = (int)(pNode - p->sParse.aNode);
|
|
p->eType = pNode->eType;
|
|
if( p->eType>=JSON_ARRAY ){
|
|
+ assert( pNode->eU==0 );
|
|
+ VVA( pNode->eU = 3 );
|
|
pNode->u.iKey = 0;
|
|
p->iEnd = p->i + pNode->n + 1;
|
|
if( p->bRecursive ){
|
|
@@ -185932,108 +201447,68 @@ static sqlite3_module jsonTreeModule = {
|
|
0 /* xShadowName */
|
|
};
|
|
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
|
-
|
|
-/****************************************************************************
|
|
-** The following routines are the only publically visible identifiers in this
|
|
-** file. Call the following routines in order to register the various SQL
|
|
-** functions and the virtual table implemented by this file.
|
|
-****************************************************************************/
|
|
-
|
|
-SQLITE_PRIVATE int sqlite3Json1Init(sqlite3 *db){
|
|
- int rc = SQLITE_OK;
|
|
- unsigned int i;
|
|
- static const struct {
|
|
- const char *zName;
|
|
- int nArg;
|
|
- int flag;
|
|
- void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
|
|
- } aFunc[] = {
|
|
- { "json", 1, 0, jsonRemoveFunc },
|
|
- { "json_array", -1, 0, jsonArrayFunc },
|
|
- { "json_array_length", 1, 0, jsonArrayLengthFunc },
|
|
- { "json_array_length", 2, 0, jsonArrayLengthFunc },
|
|
- { "json_extract", -1, 0, jsonExtractFunc },
|
|
- { "json_insert", -1, 0, jsonSetFunc },
|
|
- { "json_object", -1, 0, jsonObjectFunc },
|
|
- { "json_patch", 2, 0, jsonPatchFunc },
|
|
- { "json_quote", 1, 0, jsonQuoteFunc },
|
|
- { "json_remove", -1, 0, jsonRemoveFunc },
|
|
- { "json_replace", -1, 0, jsonReplaceFunc },
|
|
- { "json_set", -1, 1, jsonSetFunc },
|
|
- { "json_type", 1, 0, jsonTypeFunc },
|
|
- { "json_type", 2, 0, jsonTypeFunc },
|
|
- { "json_valid", 1, 0, jsonValidFunc },
|
|
-
|
|
+#endif /* !defined(SQLITE_OMIT_JSON) */
|
|
+
|
|
+/*
|
|
+** Register JSON functions.
|
|
+*/
|
|
+SQLITE_PRIVATE void sqlite3RegisterJsonFunctions(void){
|
|
+#ifndef SQLITE_OMIT_JSON
|
|
+ static FuncDef aJsonFunc[] = {
|
|
+ JFUNCTION(json, 1, 0, jsonRemoveFunc),
|
|
+ JFUNCTION(json_array, -1, 0, jsonArrayFunc),
|
|
+ JFUNCTION(json_array_length, 1, 0, jsonArrayLengthFunc),
|
|
+ JFUNCTION(json_array_length, 2, 0, jsonArrayLengthFunc),
|
|
+ JFUNCTION(json_extract, -1, 0, jsonExtractFunc),
|
|
+ JFUNCTION(->, 2, JSON_JSON, jsonExtractFunc),
|
|
+ JFUNCTION(->>, 2, JSON_SQL, jsonExtractFunc),
|
|
+ JFUNCTION(json_insert, -1, 0, jsonSetFunc),
|
|
+ JFUNCTION(json_object, -1, 0, jsonObjectFunc),
|
|
+ JFUNCTION(json_patch, 2, 0, jsonPatchFunc),
|
|
+ JFUNCTION(json_quote, 1, 0, jsonQuoteFunc),
|
|
+ JFUNCTION(json_remove, -1, 0, jsonRemoveFunc),
|
|
+ JFUNCTION(json_replace, -1, 0, jsonReplaceFunc),
|
|
+ JFUNCTION(json_set, -1, JSON_ISSET, jsonSetFunc),
|
|
+ JFUNCTION(json_type, 1, 0, jsonTypeFunc),
|
|
+ JFUNCTION(json_type, 2, 0, jsonTypeFunc),
|
|
+ JFUNCTION(json_valid, 1, 0, jsonValidFunc),
|
|
#if SQLITE_DEBUG
|
|
- /* DEBUG and TESTING functions */
|
|
- { "json_parse", 1, 0, jsonParseFunc },
|
|
- { "json_test1", 1, 0, jsonTest1Func },
|
|
-#endif
|
|
- };
|
|
- static const struct {
|
|
- const char *zName;
|
|
- int nArg;
|
|
- void (*xStep)(sqlite3_context*,int,sqlite3_value**);
|
|
- void (*xFinal)(sqlite3_context*);
|
|
- void (*xValue)(sqlite3_context*);
|
|
- } aAgg[] = {
|
|
- { "json_group_array", 1,
|
|
- jsonArrayStep, jsonArrayFinal, jsonArrayValue },
|
|
- { "json_group_object", 2,
|
|
- jsonObjectStep, jsonObjectFinal, jsonObjectValue },
|
|
+ JFUNCTION(json_parse, 1, 0, jsonParseFunc),
|
|
+ JFUNCTION(json_test1, 1, 0, jsonTest1Func),
|
|
+#endif
|
|
+ WAGGREGATE(json_group_array, 1, 0, 0,
|
|
+ jsonArrayStep, jsonArrayFinal, jsonArrayValue, jsonGroupInverse,
|
|
+ SQLITE_SUBTYPE|SQLITE_UTF8|SQLITE_DETERMINISTIC),
|
|
+ WAGGREGATE(json_group_object, 2, 0, 0,
|
|
+ jsonObjectStep, jsonObjectFinal, jsonObjectValue, jsonGroupInverse,
|
|
+ SQLITE_SUBTYPE|SQLITE_UTF8|SQLITE_DETERMINISTIC)
|
|
};
|
|
-#ifndef SQLITE_OMIT_VIRTUALTABLE
|
|
+ sqlite3InsertBuiltinFuncs(aJsonFunc, ArraySize(aJsonFunc));
|
|
+#endif
|
|
+}
|
|
+
|
|
+#if !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_JSON)
|
|
+/*
|
|
+** Register the JSON table-valued functions
|
|
+*/
|
|
+SQLITE_PRIVATE int sqlite3JsonTableFunctions(sqlite3 *db){
|
|
+ int rc = SQLITE_OK;
|
|
static const struct {
|
|
- const char *zName;
|
|
- sqlite3_module *pModule;
|
|
+ const char *zName;
|
|
+ sqlite3_module *pModule;
|
|
} aMod[] = {
|
|
{ "json_each", &jsonEachModule },
|
|
{ "json_tree", &jsonTreeModule },
|
|
};
|
|
-#endif
|
|
- static const int enc =
|
|
- SQLITE_UTF8 |
|
|
- SQLITE_DETERMINISTIC |
|
|
- SQLITE_INNOCUOUS;
|
|
- for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){
|
|
- rc = sqlite3_create_function(db, aFunc[i].zName, aFunc[i].nArg, enc,
|
|
- (void*)&aFunc[i].flag,
|
|
- aFunc[i].xFunc, 0, 0);
|
|
- }
|
|
-#ifndef SQLITE_OMIT_WINDOWFUNC
|
|
- for(i=0; i<sizeof(aAgg)/sizeof(aAgg[0]) && rc==SQLITE_OK; i++){
|
|
- rc = sqlite3_create_window_function(db, aAgg[i].zName, aAgg[i].nArg,
|
|
- SQLITE_SUBTYPE | enc, 0,
|
|
- aAgg[i].xStep, aAgg[i].xFinal,
|
|
- aAgg[i].xValue, jsonGroupInverse, 0);
|
|
- }
|
|
-#endif
|
|
-#ifndef SQLITE_OMIT_VIRTUALTABLE
|
|
+ unsigned int i;
|
|
for(i=0; i<sizeof(aMod)/sizeof(aMod[0]) && rc==SQLITE_OK; i++){
|
|
rc = sqlite3_create_module(db, aMod[i].zName, aMod[i].pModule, 0);
|
|
}
|
|
-#endif
|
|
return rc;
|
|
}
|
|
+#endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) && !defined(SQLITE_OMIT_JSON) */
|
|
|
|
-
|
|
-#ifndef SQLITE_CORE
|
|
-#ifdef _WIN32
|
|
-__declspec(dllexport)
|
|
-#endif
|
|
-SQLITE_API int sqlite3_json_init(
|
|
- sqlite3 *db,
|
|
- char **pzErrMsg,
|
|
- const sqlite3_api_routines *pApi
|
|
-){
|
|
- SQLITE_EXTENSION_INIT2(pApi);
|
|
- (void)pzErrMsg; /* Unused parameter */
|
|
- return sqlite3Json1Init(db);
|
|
-}
|
|
-#endif
|
|
-#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_JSON1) */
|
|
-
|
|
-/************** End of json1.c ***********************************************/
|
|
+/************** End of json.c ************************************************/
|
|
/************** Begin file rtree.c *******************************************/
|
|
/*
|
|
** 2001 September 15
|
|
@@ -186054,7 +201529,7 @@ SQLITE_API int sqlite3_json_init(
|
|
** Database Format of R-Tree Tables
|
|
** --------------------------------
|
|
**
|
|
-** The data structure for a single virtual r-tree table is stored in three
|
|
+** The data structure for a single virtual r-tree table is stored in three
|
|
** native SQLite tables declared as follows. In each case, the '%' character
|
|
** in the table name is replaced with the user-supplied name of the r-tree
|
|
** table.
|
|
@@ -186080,7 +201555,7 @@ SQLITE_API int sqlite3_json_init(
|
|
** of the node contain the tree depth as a big-endian integer.
|
|
** For non-root nodes, the first 2 bytes are left unused.
|
|
**
|
|
-** 2. The next 2 bytes contain the number of entries currently
|
|
+** 2. The next 2 bytes contain the number of entries currently
|
|
** stored in the node.
|
|
**
|
|
** 3. The remainder of the node contains the node entries. Each entry
|
|
@@ -186101,7 +201576,11 @@ SQLITE_API int sqlite3_json_init(
|
|
#endif
|
|
SQLITE_PRIVATE int sqlite3GetToken(const unsigned char*,int*); /* In the SQLite core */
|
|
|
|
-#ifndef SQLITE_AMALGAMATION
|
|
+/*
|
|
+** If building separately, we will need some setup that is normally
|
|
+** found in sqliteInt.h
|
|
+*/
|
|
+#if !defined(SQLITE_AMALGAMATION)
|
|
#include "sqlite3rtree.h"
|
|
typedef sqlite3_int64 i64;
|
|
typedef sqlite3_uint64 u64;
|
|
@@ -186114,11 +201593,25 @@ typedef unsigned int u32;
|
|
#if defined(NDEBUG) && defined(SQLITE_DEBUG)
|
|
# undef NDEBUG
|
|
#endif
|
|
+#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST)
|
|
+# define SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS 1
|
|
+#endif
|
|
+#if defined(SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS)
|
|
+# define ALWAYS(X) (1)
|
|
+# define NEVER(X) (0)
|
|
+#elif !defined(NDEBUG)
|
|
+# define ALWAYS(X) ((X)?1:(assert(0),0))
|
|
+# define NEVER(X) ((X)?(assert(0),1):0)
|
|
+#else
|
|
+# define ALWAYS(X) (X)
|
|
+# define NEVER(X) (X)
|
|
#endif
|
|
+#endif /* !defined(SQLITE_AMALGAMATION) */
|
|
|
|
/* #include <string.h> */
|
|
/* #include <stdio.h> */
|
|
/* #include <assert.h> */
|
|
+/* #include <stdlib.h> */
|
|
|
|
/* The following macro is used to suppress compiler warnings.
|
|
*/
|
|
@@ -186143,7 +201636,7 @@ typedef struct RtreeSearchPoint RtreeSearchPoint;
|
|
#define RTREE_MAX_AUX_COLUMN 100
|
|
|
|
/* Size of hash table Rtree.aHash. This hash table is not expected to
|
|
-** ever contain very many entries, so a fixed number of buckets is
|
|
+** ever contain very many entries, so a fixed number of buckets is
|
|
** used.
|
|
*/
|
|
#define HASHSIZE 97
|
|
@@ -186152,13 +201645,13 @@ typedef struct RtreeSearchPoint RtreeSearchPoint;
|
|
** the number of rows in the virtual table to calculate the costs of
|
|
** various strategies. If possible, this estimate is loaded from the
|
|
** sqlite_stat1 table (with RTREE_MIN_ROWEST as a hard-coded minimum).
|
|
-** Otherwise, if no sqlite_stat1 entry is available, use
|
|
+** Otherwise, if no sqlite_stat1 entry is available, use
|
|
** RTREE_DEFAULT_ROWEST.
|
|
*/
|
|
#define RTREE_DEFAULT_ROWEST 1048576
|
|
#define RTREE_MIN_ROWEST 100
|
|
|
|
-/*
|
|
+/*
|
|
** An rtree virtual-table object.
|
|
*/
|
|
struct Rtree {
|
|
@@ -186171,13 +201664,15 @@ struct Rtree {
|
|
u8 nBytesPerCell; /* Bytes consumed per cell */
|
|
u8 inWrTrans; /* True if inside write transaction */
|
|
u8 nAux; /* # of auxiliary columns in %_rowid */
|
|
+#ifdef SQLITE_ENABLE_GEOPOLY
|
|
u8 nAuxNotNull; /* Number of initial not-null aux columns */
|
|
+#endif
|
|
#ifdef SQLITE_DEBUG
|
|
u8 bCorrupt; /* Shadow table corruption detected */
|
|
#endif
|
|
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 *zName; /* Name of r-tree 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 */
|
|
@@ -186186,7 +201681,7 @@ struct Rtree {
|
|
|
|
/* List of nodes removed during a CondenseTree operation. List is
|
|
** linked together via the pointer normally used for hash chains -
|
|
- ** RtreeNode.pNext. RtreeNode.iNode stores the depth of the sub-tree
|
|
+ ** RtreeNode.pNext. RtreeNode.iNode stores the depth of the sub-tree
|
|
** headed by the node (leaf nodes have RtreeNode.iNode==0).
|
|
*/
|
|
RtreeNode *pDeleted;
|
|
@@ -186212,7 +201707,7 @@ struct Rtree {
|
|
/* Statement for writing to the "aux:" fields, if there are any */
|
|
sqlite3_stmt *pWriteAux;
|
|
|
|
- RtreeNode *aHash[HASHSIZE]; /* Hash table of in-memory nodes. */
|
|
+ RtreeNode *aHash[HASHSIZE]; /* Hash table of in-memory nodes. */
|
|
};
|
|
|
|
/* Possible values for Rtree.eCoordType: */
|
|
@@ -186261,7 +201756,7 @@ struct RtreeSearchPoint {
|
|
};
|
|
|
|
/*
|
|
-** The minimum number of cells allowed for a node is a third of the
|
|
+** The minimum number of cells allowed for a node is a third of the
|
|
** maximum. In Gutman's notation:
|
|
**
|
|
** m = M/3
|
|
@@ -186276,7 +201771,7 @@ struct RtreeSearchPoint {
|
|
/*
|
|
** The smallest possible node-size is (512-64)==448 bytes. And the largest
|
|
** supported cell size is 48 bytes (8 byte rowid + ten 4 byte coordinates).
|
|
-** Therefore all non-root nodes must contain at least 3 entries. Since
|
|
+** Therefore all non-root nodes must contain at least 3 entries. Since
|
|
** 3^40 is greater than 2^64, an r-tree structure always has a depth of
|
|
** 40 or less.
|
|
*/
|
|
@@ -186290,7 +201785,7 @@ struct RtreeSearchPoint {
|
|
*/
|
|
#define RTREE_CACHE_SZ 5
|
|
|
|
-/*
|
|
+/*
|
|
** An rtree cursor object.
|
|
*/
|
|
struct RtreeCursor {
|
|
@@ -186370,7 +201865,7 @@ struct RtreeConstraint {
|
|
#define RTREE_TRUE 0x3f /* ? */
|
|
#define RTREE_FALSE 0x40 /* @ */
|
|
|
|
-/*
|
|
+/*
|
|
** An rtree structure node.
|
|
*/
|
|
struct RtreeNode {
|
|
@@ -186385,7 +201880,7 @@ struct RtreeNode {
|
|
/* Return the number of cells in a node */
|
|
#define NCELL(pNode) readInt16(&(pNode)->zData[2])
|
|
|
|
-/*
|
|
+/*
|
|
** A single cell from a node, deserialized
|
|
*/
|
|
struct RtreeCell {
|
|
@@ -186400,11 +201895,11 @@ struct RtreeCell {
|
|
** sqlite3_rtree_query_callback() and which appear on the right of MATCH
|
|
** operators in order to constrain a search.
|
|
**
|
|
-** xGeom and xQueryFunc are the callback functions. Exactly one of
|
|
+** xGeom and xQueryFunc are the callback functions. Exactly one of
|
|
** xGeom and xQueryFunc fields is non-NULL, depending on whether the
|
|
** SQL function was created using sqlite3_rtree_geometry_callback() or
|
|
** sqlite3_rtree_query_callback().
|
|
-**
|
|
+**
|
|
** This object is deleted automatically by the destructor mechanism in
|
|
** sqlite3_create_function_v2().
|
|
*/
|
|
@@ -186453,7 +201948,29 @@ struct RtreeMatchArg {
|
|
** it is not, make it a no-op.
|
|
*/
|
|
#ifndef SQLITE_AMALGAMATION
|
|
-# define testcase(X)
|
|
+# if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_DEBUG)
|
|
+ unsigned int sqlite3RtreeTestcase = 0;
|
|
+# define testcase(X) if( X ){ sqlite3RtreeTestcase += __LINE__; }
|
|
+# else
|
|
+# define testcase(X)
|
|
+# endif
|
|
+#endif
|
|
+
|
|
+/*
|
|
+** Make sure that the compiler intrinsics we desire are enabled when
|
|
+** compiling with an appropriate version of MSVC unless prevented by
|
|
+** the SQLITE_DISABLE_INTRINSIC define.
|
|
+*/
|
|
+#if !defined(SQLITE_DISABLE_INTRINSIC)
|
|
+# if defined(_MSC_VER) && _MSC_VER>=1400
|
|
+# if !defined(_WIN32_WCE)
|
|
+/* # include <intrin.h> */
|
|
+# pragma intrinsic(_byteswap_ulong)
|
|
+# pragma intrinsic(_byteswap_uint64)
|
|
+# else
|
|
+/* # include <cmnintrin.h> */
|
|
+# endif
|
|
+# endif
|
|
#endif
|
|
|
|
/*
|
|
@@ -186496,7 +202013,7 @@ static int readInt16(u8 *p){
|
|
return (p[0]<<8) + p[1];
|
|
}
|
|
static void readCoord(u8 *p, RtreeCoord *pCoord){
|
|
- assert( ((((char*)p) - (char*)0)&3)==0 ); /* p is always 4-byte aligned */
|
|
+ assert( (((sqlite3_uint64)p)&3)==0 ); /* p is always 4-byte aligned */
|
|
#if SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300
|
|
pCoord->u = _byteswap_ulong(*(u32*)p);
|
|
#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000
|
|
@@ -186505,9 +202022,9 @@ static void readCoord(u8 *p, RtreeCoord *pCoord){
|
|
pCoord->u = *(u32*)p;
|
|
#else
|
|
pCoord->u = (
|
|
- (((u32)p[0]) << 24) +
|
|
- (((u32)p[1]) << 16) +
|
|
- (((u32)p[2]) << 8) +
|
|
+ (((u32)p[0]) << 24) +
|
|
+ (((u32)p[1]) << 16) +
|
|
+ (((u32)p[2]) << 8) +
|
|
(((u32)p[3]) << 0)
|
|
);
|
|
#endif
|
|
@@ -186527,13 +202044,13 @@ static i64 readInt64(u8 *p){
|
|
return x;
|
|
#else
|
|
return (i64)(
|
|
- (((u64)p[0]) << 56) +
|
|
- (((u64)p[1]) << 48) +
|
|
- (((u64)p[2]) << 40) +
|
|
- (((u64)p[3]) << 32) +
|
|
- (((u64)p[4]) << 24) +
|
|
- (((u64)p[5]) << 16) +
|
|
- (((u64)p[6]) << 8) +
|
|
+ (((u64)p[0]) << 56) +
|
|
+ (((u64)p[1]) << 48) +
|
|
+ (((u64)p[2]) << 40) +
|
|
+ (((u64)p[3]) << 32) +
|
|
+ (((u64)p[4]) << 24) +
|
|
+ (((u64)p[5]) << 16) +
|
|
+ (((u64)p[6]) << 8) +
|
|
(((u64)p[7]) << 0)
|
|
);
|
|
#endif
|
|
@@ -186550,7 +202067,7 @@ static void writeInt16(u8 *p, int i){
|
|
}
|
|
static int writeCoord(u8 *p, RtreeCoord *pCoord){
|
|
u32 i;
|
|
- assert( ((((char*)p) - (char*)0)&3)==0 ); /* p is always 4-byte aligned */
|
|
+ assert( (((sqlite3_uint64)p)&3)==0 ); /* p is always 4-byte aligned */
|
|
assert( sizeof(RtreeCoord)==4 );
|
|
assert( sizeof(u32)==4 );
|
|
#if SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000
|
|
@@ -186685,18 +202202,6 @@ static void nodeBlobReset(Rtree *pRtree){
|
|
}
|
|
}
|
|
|
|
-/*
|
|
-** Check to see if pNode is the same as pParent or any of the parents
|
|
-** of pParent.
|
|
-*/
|
|
-static int nodeInParentChain(const RtreeNode *pNode, const RtreeNode *pParent){
|
|
- do{
|
|
- if( pNode==pParent ) return 1;
|
|
- pParent = pParent->pParent;
|
|
- }while( pParent );
|
|
- return 0;
|
|
-}
|
|
-
|
|
/*
|
|
** Obtain a reference to an r-tree node.
|
|
*/
|
|
@@ -186713,14 +202218,7 @@ static int nodeAcquire(
|
|
** increase its reference count and return it.
|
|
*/
|
|
if( (pNode = nodeHashLookup(pRtree, iNode))!=0 ){
|
|
- if( pParent && !pNode->pParent ){
|
|
- if( nodeInParentChain(pNode, pParent) ){
|
|
- RTREE_IS_CORRUPT(pRtree);
|
|
- return SQLITE_CORRUPT_VTAB;
|
|
- }
|
|
- pParent->nRef++;
|
|
- pNode->pParent = pParent;
|
|
- }else if( pParent && pNode->pParent && pParent!=pNode->pParent ){
|
|
+ if( pParent && pParent!=pNode->pParent ){
|
|
RTREE_IS_CORRUPT(pRtree);
|
|
return SQLITE_CORRUPT_VTAB;
|
|
}
|
|
@@ -186778,7 +202276,7 @@ static int nodeAcquire(
|
|
** are the leaves, and so on. If the depth as specified on the root node
|
|
** is greater than RTREE_MAX_DEPTH, the r-tree structure must be corrupt.
|
|
*/
|
|
- if( pNode && iNode==1 ){
|
|
+ if( rc==SQLITE_OK && pNode && iNode==1 ){
|
|
pRtree->iDepth = readInt16(pNode->zData);
|
|
if( pRtree->iDepth>RTREE_MAX_DEPTH ){
|
|
rc = SQLITE_CORRUPT_VTAB;
|
|
@@ -186787,7 +202285,7 @@ static int nodeAcquire(
|
|
}
|
|
|
|
/* If no error has occurred so far, check if the "number of entries"
|
|
- ** field on the node is too large. If so, set the return code to
|
|
+ ** field on the node is too large. If so, set the return code to
|
|
** SQLITE_CORRUPT_VTAB.
|
|
*/
|
|
if( pNode && rc==SQLITE_OK ){
|
|
@@ -186986,7 +202484,7 @@ static int rtreeInit(
|
|
sqlite3 *, void *, int, const char *const*, sqlite3_vtab **, char **, int
|
|
);
|
|
|
|
-/*
|
|
+/*
|
|
** Rtree virtual table module xCreate method.
|
|
*/
|
|
static int rtreeCreate(
|
|
@@ -186999,7 +202497,7 @@ static int rtreeCreate(
|
|
return rtreeInit(db, pAux, argc, argv, ppVtab, pzErr, 1);
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** Rtree virtual table module xConnect method.
|
|
*/
|
|
static int rtreeConnect(
|
|
@@ -187044,7 +202542,7 @@ static void rtreeRelease(Rtree *pRtree){
|
|
}
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** Rtree virtual table module xDisconnect method.
|
|
*/
|
|
static int rtreeDisconnect(sqlite3_vtab *pVtab){
|
|
@@ -187052,7 +202550,7 @@ static int rtreeDisconnect(sqlite3_vtab *pVtab){
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** Rtree virtual table module xDestroy method.
|
|
*/
|
|
static int rtreeDestroy(sqlite3_vtab *pVtab){
|
|
@@ -187062,7 +202560,7 @@ static int rtreeDestroy(sqlite3_vtab *pVtab){
|
|
"DROP TABLE '%q'.'%q_node';"
|
|
"DROP TABLE '%q'.'%q_rowid';"
|
|
"DROP TABLE '%q'.'%q_parent';",
|
|
- pRtree->zDb, pRtree->zName,
|
|
+ pRtree->zDb, pRtree->zName,
|
|
pRtree->zDb, pRtree->zName,
|
|
pRtree->zDb, pRtree->zName
|
|
);
|
|
@@ -187080,7 +202578,7 @@ static int rtreeDestroy(sqlite3_vtab *pVtab){
|
|
return rc;
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** Rtree virtual table module xOpen method.
|
|
*/
|
|
static int rtreeOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
|
|
@@ -187129,7 +202627,7 @@ static void resetCursor(RtreeCursor *pCsr){
|
|
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** Rtree virtual table module xClose method.
|
|
*/
|
|
static int rtreeClose(sqlite3_vtab_cursor *cur){
|
|
@@ -187147,7 +202645,7 @@ static int rtreeClose(sqlite3_vtab_cursor *cur){
|
|
/*
|
|
** Rtree virtual table module xEof method.
|
|
**
|
|
-** Return non-zero if the cursor does not currently point to a valid
|
|
+** Return non-zero if the cursor does not currently point to a valid
|
|
** record (i.e if the scan has finished), or zero otherwise.
|
|
*/
|
|
static int rtreeEof(sqlite3_vtab_cursor *cur){
|
|
@@ -187203,7 +202701,7 @@ static int rtreeEof(sqlite3_vtab_cursor *cur){
|
|
|
|
/*
|
|
** Check the RTree node or entry given by pCellData and p against the MATCH
|
|
-** constraint pConstraint.
|
|
+** constraint pConstraint.
|
|
*/
|
|
static int rtreeCallbackConstraint(
|
|
RtreeConstraint *pConstraint, /* The constraint to test */
|
|
@@ -187276,7 +202774,7 @@ static int rtreeCallbackConstraint(
|
|
return rc;
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** Check the internal RTree node given by pCellData against constraint p.
|
|
** If this constraint cannot be satisfied by any child within the node,
|
|
** set *peWithin to NOT_WITHIN.
|
|
@@ -187294,27 +202792,36 @@ static void rtreeNonleafConstraint(
|
|
*/
|
|
pCellData += 8 + 4*(p->iCoord&0xfe);
|
|
|
|
- assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE
|
|
+ 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( ((((char*)pCellData) - (char*)0)&3)==0 ); /* 4-byte aligned */
|
|
+ assert( (((sqlite3_uint64)pCellData)&3)==0 ); /* 4-byte aligned */
|
|
switch( p->op ){
|
|
case RTREE_TRUE: return; /* Always satisfied */
|
|
case RTREE_FALSE: break; /* Never satisfied */
|
|
+ case RTREE_EQ:
|
|
+ RTREE_DECODE_COORD(eInt, pCellData, val);
|
|
+ /* val now holds the lower bound of the coordinate pair */
|
|
+ if( p->u.rValue>=val ){
|
|
+ pCellData += 4;
|
|
+ RTREE_DECODE_COORD(eInt, pCellData, val);
|
|
+ /* val now holds the upper bound of the coordinate pair */
|
|
+ if( p->u.rValue<=val ) return;
|
|
+ }
|
|
+ break;
|
|
case RTREE_LE:
|
|
case RTREE_LT:
|
|
- case RTREE_EQ:
|
|
RTREE_DECODE_COORD(eInt, pCellData, val);
|
|
/* val now holds the lower bound of the coordinate pair */
|
|
if( p->u.rValue>=val ) return;
|
|
- if( p->op!=RTREE_EQ ) break; /* RTREE_LE and RTREE_LT end here */
|
|
- /* Fall through for the RTREE_EQ case */
|
|
+ break;
|
|
|
|
- default: /* RTREE_GT or RTREE_GE, or fallthrough of RTREE_EQ */
|
|
+ default:
|
|
pCellData += 4;
|
|
RTREE_DECODE_COORD(eInt, pCellData, val);
|
|
/* val now holds the upper bound of the coordinate pair */
|
|
if( p->u.rValue<=val ) return;
|
|
+ break;
|
|
}
|
|
*peWithin = NOT_WITHIN;
|
|
}
|
|
@@ -187337,11 +202844,11 @@ static void rtreeLeafConstraint(
|
|
){
|
|
RtreeDValue xN; /* Coordinate value converted to a double */
|
|
|
|
- assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE
|
|
+ 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 );
|
|
pCellData += 8 + p->iCoord*4;
|
|
- assert( ((((char*)pCellData) - (char*)0)&3)==0 ); /* 4-byte aligned */
|
|
+ assert( (((sqlite3_uint64)pCellData)&3)==0 ); /* 4-byte aligned */
|
|
RTREE_DECODE_COORD(eInt, pCellData, xN);
|
|
switch( p->op ){
|
|
case RTREE_TRUE: return; /* Always satisfied */
|
|
@@ -187356,12 +202863,12 @@ static void rtreeLeafConstraint(
|
|
}
|
|
|
|
/*
|
|
-** One of the cells in node pNode is guaranteed to have a 64-bit
|
|
+** One of the cells in node pNode is guaranteed to have a 64-bit
|
|
** integer value equal to iRowid. Return the index of this cell.
|
|
*/
|
|
static int nodeRowidIndex(
|
|
- Rtree *pRtree,
|
|
- RtreeNode *pNode,
|
|
+ Rtree *pRtree,
|
|
+ RtreeNode *pNode,
|
|
i64 iRowid,
|
|
int *piIndex
|
|
){
|
|
@@ -187384,11 +202891,12 @@ static int nodeRowidIndex(
|
|
*/
|
|
static int nodeParentIndex(Rtree *pRtree, RtreeNode *pNode, int *piIndex){
|
|
RtreeNode *pParent = pNode->pParent;
|
|
- if( pParent ){
|
|
+ if( ALWAYS(pParent) ){
|
|
return nodeRowidIndex(pRtree, pParent, pNode->iNode, piIndex);
|
|
+ }else{
|
|
+ *piIndex = -1;
|
|
+ return SQLITE_OK;
|
|
}
|
|
- *piIndex = -1;
|
|
- return SQLITE_OK;
|
|
}
|
|
|
|
/*
|
|
@@ -187503,7 +203011,7 @@ static RtreeSearchPoint *rtreeSearchPointNew(
|
|
pFirst = rtreeSearchPointFirst(pCur);
|
|
pCur->anQueue[iLevel]++;
|
|
if( pFirst==0
|
|
- || pFirst->rScore>rScore
|
|
+ || pFirst->rScore>rScore
|
|
|| (pFirst->rScore==rScore && pFirst->iLevel>iLevel)
|
|
){
|
|
if( pCur->bPoint ){
|
|
@@ -187511,7 +203019,8 @@ static RtreeSearchPoint *rtreeSearchPointNew(
|
|
pNew = rtreeEnqueue(pCur, rScore, iLevel);
|
|
if( pNew==0 ) return 0;
|
|
ii = (int)(pNew - pCur->aPoint) + 1;
|
|
- if( ii<RTREE_CACHE_SZ ){
|
|
+ assert( ii==1 );
|
|
+ if( ALWAYS(ii<RTREE_CACHE_SZ) ){
|
|
assert( pCur->aNode[ii]==0 );
|
|
pCur->aNode[ii] = pCur->aNode[0];
|
|
}else{
|
|
@@ -187572,7 +203081,7 @@ static void rtreeSearchPointPop(RtreeCursor *p){
|
|
if( p->bPoint ){
|
|
p->anQueue[p->sPoint.iLevel]--;
|
|
p->bPoint = 0;
|
|
- }else if( p->nPoint ){
|
|
+ }else if( ALWAYS(p->nPoint) ){
|
|
p->anQueue[p->aPoint[0].iLevel]--;
|
|
n = --p->nPoint;
|
|
p->aPoint[0] = p->aPoint[n];
|
|
@@ -187687,7 +203196,7 @@ static int rtreeStepToLeaf(RtreeCursor *pCur){
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** Rtree virtual table module xNext method.
|
|
*/
|
|
static int rtreeNext(sqlite3_vtab_cursor *pVtabCursor){
|
|
@@ -187705,7 +203214,7 @@ static int rtreeNext(sqlite3_vtab_cursor *pVtabCursor){
|
|
return rc;
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** Rtree virtual table module xRowid method.
|
|
*/
|
|
static int rtreeRowid(sqlite3_vtab_cursor *pVtabCursor, sqlite_int64 *pRowid){
|
|
@@ -187713,13 +203222,13 @@ static int rtreeRowid(sqlite3_vtab_cursor *pVtabCursor, sqlite_int64 *pRowid){
|
|
RtreeSearchPoint *p = rtreeSearchPointFirst(pCsr);
|
|
int rc = SQLITE_OK;
|
|
RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc);
|
|
- if( rc==SQLITE_OK && p ){
|
|
+ if( rc==SQLITE_OK && ALWAYS(p) ){
|
|
*pRowid = nodeGetRowid(RTREE_OF_CURSOR(pCsr), pNode, p->iCell);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** Rtree virtual table module xColumn method.
|
|
*/
|
|
static int rtreeColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
|
|
@@ -187731,7 +203240,7 @@ static int rtreeColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
|
|
RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc);
|
|
|
|
if( rc ) return rc;
|
|
- if( p==0 ) return SQLITE_OK;
|
|
+ if( NEVER(p==0) ) return SQLITE_OK;
|
|
if( i==0 ){
|
|
sqlite3_result_int64(ctx, nodeGetRowid(pRtree, pNode, p->iCell));
|
|
}else if( i<=pRtree->nDim2 ){
|
|
@@ -187752,7 +203261,7 @@ static int rtreeColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
|
|
&pCsr->pReadAux, 0);
|
|
if( rc ) return rc;
|
|
}
|
|
- sqlite3_bind_int64(pCsr->pReadAux, 1,
|
|
+ sqlite3_bind_int64(pCsr->pReadAux, 1,
|
|
nodeGetRowid(pRtree, pNode, p->iCell));
|
|
rc = sqlite3_step(pCsr->pReadAux);
|
|
if( rc==SQLITE_ROW ){
|
|
@@ -187765,12 +203274,12 @@ static int rtreeColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
|
|
}
|
|
sqlite3_result_value(ctx,
|
|
sqlite3_column_value(pCsr->pReadAux, i - pRtree->nDim2 + 1));
|
|
- }
|
|
+ }
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
-/*
|
|
-** Use nodeAcquire() to obtain the leaf node containing the record with
|
|
+/*
|
|
+** Use nodeAcquire() to obtain the leaf node containing the record with
|
|
** rowid iRowid. If successful, set *ppLeaf to point to the node and
|
|
** return SQLITE_OK. If there is no such record in the table, set
|
|
** *ppLeaf to 0 and return SQLITE_OK. If an error occurs, set *ppLeaf
|
|
@@ -187829,11 +203338,11 @@ static int deserializeGeometry(sqlite3_value *pValue, RtreeConstraint *pCons){
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** Rtree virtual table module xFilter method.
|
|
*/
|
|
static int rtreeFilter(
|
|
- sqlite3_vtab_cursor *pVtabCursor,
|
|
+ sqlite3_vtab_cursor *pVtabCursor,
|
|
int idxNum, const char *idxStr,
|
|
int argc, sqlite3_value **argv
|
|
){
|
|
@@ -187878,8 +203387,8 @@ static int rtreeFilter(
|
|
pCsr->atEOF = 1;
|
|
}
|
|
}else{
|
|
- /* Normal case - r-tree scan. Set up the RtreeCursor.aConstraint array
|
|
- ** with the configured constraints.
|
|
+ /* Normal case - r-tree scan. Set up the RtreeCursor.aConstraint array
|
|
+ ** with the configured constraints.
|
|
*/
|
|
rc = nodeAcquire(pRtree, 1, 0, &pRoot);
|
|
if( rc==SQLITE_OK && argc>0 ){
|
|
@@ -187930,8 +203439,11 @@ static int rtreeFilter(
|
|
}
|
|
if( rc==SQLITE_OK ){
|
|
RtreeSearchPoint *pNew;
|
|
+ assert( pCsr->bPoint==0 ); /* Due to the resetCursor() call above */
|
|
pNew = rtreeSearchPointNew(pCsr, RTREE_ZERO, (u8)(pRtree->iDepth+1));
|
|
- if( pNew==0 ) return SQLITE_NOMEM;
|
|
+ if( NEVER(pNew==0) ){ /* Because pCsr->bPoint was FALSE */
|
|
+ return SQLITE_NOMEM;
|
|
+ }
|
|
pNew->id = 1;
|
|
pNew->iCell = 0;
|
|
pNew->eWithin = PARTLY_WITHIN;
|
|
@@ -187950,7 +203462,7 @@ static int rtreeFilter(
|
|
|
|
/*
|
|
** Rtree virtual table module xBestIndex method. There are three
|
|
-** table scan strategies to choose from (in order from most to
|
|
+** table scan strategies to choose from (in order from most to
|
|
** least desirable):
|
|
**
|
|
** idxNum idxStr Strategy
|
|
@@ -187960,8 +203472,8 @@ static int rtreeFilter(
|
|
** ------------------------------------------------
|
|
**
|
|
** If strategy 1 is used, then idxStr is not meaningful. If strategy
|
|
-** 2 is used, idxStr is formatted to contain 2 bytes for each
|
|
-** constraint used. The first two bytes of idxStr correspond to
|
|
+** 2 is used, idxStr is formatted to contain 2 bytes for each
|
|
+** constraint used. The first two bytes of idxStr correspond to
|
|
** the constraint in sqlite3_index_info.aConstraintUsage[] with
|
|
** (argvIndex==1) etc.
|
|
**
|
|
@@ -188007,8 +203519,8 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
|
|
for(ii=0; ii<pIdxInfo->nConstraint && iIdx<(int)(sizeof(zIdxStr)-1); ii++){
|
|
struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[ii];
|
|
|
|
- if( bMatch==0 && p->usable
|
|
- && p->iColumn==0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ
|
|
+ if( bMatch==0 && p->usable
|
|
+ && p->iColumn<=0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ
|
|
){
|
|
/* We have an equality constraint on the rowid. Use strategy 1. */
|
|
int jj;
|
|
@@ -188021,11 +203533,11 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
|
|
pIdxInfo->aConstraintUsage[jj].omit = 1;
|
|
|
|
/* This strategy involves a two rowid lookups on an B-Tree structures
|
|
- ** and then a linear search of an R-Tree node. This should be
|
|
- ** considered almost as quick as a direct rowid lookup (for which
|
|
+ ** and then a linear search of an R-Tree node. This should be
|
|
+ ** considered almost as quick as a direct rowid lookup (for which
|
|
** sqlite uses an internal cost of 0.0). It is expected to return
|
|
** a single row.
|
|
- */
|
|
+ */
|
|
pIdxInfo->estimatedCost = 30.0;
|
|
pIdxInfo->estimatedRows = 1;
|
|
pIdxInfo->idxFlags = SQLITE_INDEX_SCAN_UNIQUE;
|
|
@@ -188141,8 +203653,8 @@ static int cellContains(Rtree *pRtree, RtreeCell *p1, RtreeCell *p2){
|
|
for(ii=0; ii<pRtree->nDim2; ii+=2){
|
|
RtreeCoord *a1 = &p1->aCoord[ii];
|
|
RtreeCoord *a2 = &p2->aCoord[ii];
|
|
- if( (!isInt && (a2[0].f<a1[0].f || a2[1].f>a1[1].f))
|
|
- || ( isInt && (a2[0].i<a1[0].i || a2[1].i>a1[1].i))
|
|
+ if( (!isInt && (a2[0].f<a1[0].f || a2[1].f>a1[1].f))
|
|
+ || ( isInt && (a2[0].i<a1[0].i || a2[1].i>a1[1].i))
|
|
){
|
|
return 0;
|
|
}
|
|
@@ -188163,9 +203675,9 @@ static RtreeDValue cellGrowth(Rtree *pRtree, RtreeCell *p, RtreeCell *pCell){
|
|
}
|
|
|
|
static RtreeDValue cellOverlap(
|
|
- Rtree *pRtree,
|
|
- RtreeCell *p,
|
|
- RtreeCell *aCell,
|
|
+ Rtree *pRtree,
|
|
+ RtreeCell *p,
|
|
+ RtreeCell *aCell,
|
|
int nCell
|
|
){
|
|
int ii;
|
|
@@ -188214,7 +203726,7 @@ static int ChooseLeaf(
|
|
|
|
int nCell = NCELL(pNode);
|
|
RtreeCell cell;
|
|
- RtreeNode *pChild;
|
|
+ RtreeNode *pChild = 0;
|
|
|
|
RtreeCell *aCell = 0;
|
|
|
|
@@ -188261,12 +203773,19 @@ static int AdjustTree(
|
|
){
|
|
RtreeNode *p = pNode;
|
|
int cnt = 0;
|
|
+ int rc;
|
|
while( p->pParent ){
|
|
RtreeNode *pParent = p->pParent;
|
|
RtreeCell cell;
|
|
int iCell;
|
|
|
|
- if( (++cnt)>1000 || nodeParentIndex(pRtree, p, &iCell) ){
|
|
+ cnt++;
|
|
+ if( NEVER(cnt>100) ){
|
|
+ RTREE_IS_CORRUPT(pRtree);
|
|
+ return SQLITE_CORRUPT_VTAB;
|
|
+ }
|
|
+ rc = nodeParentIndex(pRtree, p, &iCell);
|
|
+ if( NEVER(rc!=SQLITE_OK) ){
|
|
RTREE_IS_CORRUPT(pRtree);
|
|
return SQLITE_CORRUPT_VTAB;
|
|
}
|
|
@@ -188276,7 +203795,7 @@ static int AdjustTree(
|
|
cellUnion(pRtree, &cell, pCell);
|
|
nodeOverwriteCell(pRtree, pParent, &cell, iCell);
|
|
}
|
|
-
|
|
+
|
|
p = pParent;
|
|
}
|
|
return SQLITE_OK;
|
|
@@ -188307,7 +203826,7 @@ static int rtreeInsertCell(Rtree *, RtreeNode *, RtreeCell *, int);
|
|
|
|
/*
|
|
** Arguments aIdx, aDistance and aSpare all point to arrays of size
|
|
-** nIdx. The aIdx array contains the set of integers from 0 to
|
|
+** nIdx. The aIdx array contains the set of integers from 0 to
|
|
** (nIdx-1) in no particular order. This function sorts the values
|
|
** in aIdx according to the indexed values in aDistance. For
|
|
** example, assuming the inputs:
|
|
@@ -188323,9 +203842,9 @@ static int rtreeInsertCell(Rtree *, RtreeNode *, RtreeCell *, int);
|
|
** sorting algorithm.
|
|
*/
|
|
static void SortByDistance(
|
|
- int *aIdx,
|
|
- int nIdx,
|
|
- RtreeDValue *aDistance,
|
|
+ int *aIdx,
|
|
+ int nIdx,
|
|
+ RtreeDValue *aDistance,
|
|
int *aSpare
|
|
){
|
|
if( nIdx>1 ){
|
|
@@ -188379,7 +203898,7 @@ static void SortByDistance(
|
|
|
|
/*
|
|
** Arguments aIdx, aCell and aSpare all point to arrays of size
|
|
-** nIdx. The aIdx array contains the set of integers from 0 to
|
|
+** nIdx. The aIdx array contains the set of integers from 0 to
|
|
** (nIdx-1) in no particular order. This function sorts the values
|
|
** in aIdx according to dimension iDim of the cells in aCell. The
|
|
** minimum value of dimension iDim is considered first, the
|
|
@@ -188390,10 +203909,10 @@ static void SortByDistance(
|
|
*/
|
|
static void SortByDimension(
|
|
Rtree *pRtree,
|
|
- int *aIdx,
|
|
- int nIdx,
|
|
- int iDim,
|
|
- RtreeCell *aCell,
|
|
+ int *aIdx,
|
|
+ int nIdx,
|
|
+ int iDim,
|
|
+ RtreeCell *aCell,
|
|
int *aSpare
|
|
){
|
|
if( nIdx>1 ){
|
|
@@ -188490,8 +204009,8 @@ static int splitNodeStartree(
|
|
int nLeft;
|
|
|
|
for(
|
|
- nLeft=RTREE_MINCELLS(pRtree);
|
|
- nLeft<=(nCell-RTREE_MINCELLS(pRtree));
|
|
+ nLeft=RTREE_MINCELLS(pRtree);
|
|
+ nLeft<=(nCell-RTREE_MINCELLS(pRtree));
|
|
nLeft++
|
|
){
|
|
RtreeCell left;
|
|
@@ -188546,21 +204065,26 @@ static int splitNodeStartree(
|
|
|
|
|
|
static int updateMapping(
|
|
- Rtree *pRtree,
|
|
- i64 iRowid,
|
|
- RtreeNode *pNode,
|
|
+ Rtree *pRtree,
|
|
+ i64 iRowid,
|
|
+ RtreeNode *pNode,
|
|
int iHeight
|
|
){
|
|
int (*xSetMapping)(Rtree *, sqlite3_int64, sqlite3_int64);
|
|
xSetMapping = ((iHeight==0)?rowidWrite:parentWrite);
|
|
if( iHeight>0 ){
|
|
RtreeNode *pChild = nodeHashLookup(pRtree, iRowid);
|
|
+ RtreeNode *p;
|
|
+ for(p=pNode; p; p=p->pParent){
|
|
+ if( p==pChild ) return SQLITE_CORRUPT_VTAB;
|
|
+ }
|
|
if( pChild ){
|
|
nodeRelease(pRtree, pChild->pParent);
|
|
nodeReference(pNode);
|
|
pChild->pParent = pNode;
|
|
}
|
|
}
|
|
+ if( NEVER(pNode==0) ) return SQLITE_ERROR;
|
|
return xSetMapping(pRtree, iRowid, pNode->iNode);
|
|
}
|
|
|
|
@@ -188584,7 +204108,7 @@ static int SplitNode(
|
|
RtreeCell leftbbox;
|
|
RtreeCell rightbbox;
|
|
|
|
- /* Allocate an array and populate it with a copy of pCell and
|
|
+ /* Allocate an array and populate it with a copy of pCell and
|
|
** all cells from node pLeft. Then zero the original node.
|
|
*/
|
|
aCell = sqlite3_malloc64((sizeof(RtreeCell)+sizeof(int))*(nCell+1));
|
|
@@ -188650,11 +204174,12 @@ static int SplitNode(
|
|
RtreeNode *pParent = pLeft->pParent;
|
|
int iCell;
|
|
rc = nodeParentIndex(pRtree, pLeft, &iCell);
|
|
- if( rc==SQLITE_OK ){
|
|
+ if( ALWAYS(rc==SQLITE_OK) ){
|
|
nodeOverwriteCell(pRtree, pParent, &leftbbox, iCell);
|
|
rc = AdjustTree(pRtree, pParent, &leftbbox);
|
|
+ assert( rc==SQLITE_OK );
|
|
}
|
|
- if( rc!=SQLITE_OK ){
|
|
+ if( NEVER(rc!=SQLITE_OK) ){
|
|
goto splitnode_out;
|
|
}
|
|
}
|
|
@@ -188701,14 +204226,14 @@ static int SplitNode(
|
|
}
|
|
|
|
/*
|
|
-** If node pLeaf is not the root of the r-tree and its pParent pointer is
|
|
+** If node pLeaf is not the root of the r-tree and its pParent pointer is
|
|
** still NULL, load all ancestor nodes of pLeaf into memory and populate
|
|
** the pLeaf->pParent chain all the way up to the root node.
|
|
**
|
|
** This operation is required when a row is deleted (or updated - an update
|
|
** is implemented as a delete followed by an insert). SQLite provides the
|
|
** rowid of the row to delete, which can be used to find the leaf on which
|
|
-** the entry resides (argument pLeaf). Once the leaf is located, this
|
|
+** the entry resides (argument pLeaf). Once the leaf is located, this
|
|
** function is called to determine its ancestry.
|
|
*/
|
|
static int fixLeafParent(Rtree *pRtree, RtreeNode *pLeaf){
|
|
@@ -188729,7 +204254,7 @@ static int fixLeafParent(Rtree *pRtree, RtreeNode *pLeaf){
|
|
*/
|
|
iNode = sqlite3_column_int64(pRtree->pReadParent, 0);
|
|
for(pTest=pLeaf; pTest && pTest->iNode!=iNode; pTest=pTest->pParent);
|
|
- if( !pTest ){
|
|
+ if( pTest==0 ){
|
|
rc2 = nodeAcquire(pRtree, iNode, 0, &pChild->pParent);
|
|
}
|
|
}
|
|
@@ -188760,6 +204285,7 @@ static int removeNode(Rtree *pRtree, RtreeNode *pNode, int iHeight){
|
|
pParent = pNode->pParent;
|
|
pNode->pParent = 0;
|
|
rc = deleteCell(pRtree, pParent, iCell, iHeight+1);
|
|
+ testcase( rc!=SQLITE_OK );
|
|
}
|
|
rc2 = nodeRelease(pRtree, pParent);
|
|
if( rc==SQLITE_OK ){
|
|
@@ -188782,7 +204308,7 @@ static int removeNode(Rtree *pRtree, RtreeNode *pNode, int iHeight){
|
|
if( SQLITE_OK!=(rc = sqlite3_reset(pRtree->pDeleteParent)) ){
|
|
return rc;
|
|
}
|
|
-
|
|
+
|
|
/* Remove the node from the in-memory hash table and link it into
|
|
** the Rtree.pDeleted list. Its contents will be re-inserted later on.
|
|
*/
|
|
@@ -188797,9 +204323,9 @@ static int removeNode(Rtree *pRtree, RtreeNode *pNode, int iHeight){
|
|
|
|
static int fixBoundingBox(Rtree *pRtree, RtreeNode *pNode){
|
|
RtreeNode *pParent = pNode->pParent;
|
|
- int rc = SQLITE_OK;
|
|
+ int rc = SQLITE_OK;
|
|
if( pParent ){
|
|
- int ii;
|
|
+ int ii;
|
|
int nCell = NCELL(pNode);
|
|
RtreeCell box; /* Bounding box for pNode */
|
|
nodeGetCell(pRtree, pNode, 0, &box);
|
|
@@ -188854,9 +204380,9 @@ static int deleteCell(Rtree *pRtree, RtreeNode *pNode, int iCell, int iHeight){
|
|
}
|
|
|
|
static int Reinsert(
|
|
- Rtree *pRtree,
|
|
- RtreeNode *pNode,
|
|
- RtreeCell *pCell,
|
|
+ Rtree *pRtree,
|
|
+ RtreeNode *pNode,
|
|
+ RtreeCell *pCell,
|
|
int iHeight
|
|
){
|
|
int *aOrder;
|
|
@@ -188910,7 +204436,7 @@ static int Reinsert(
|
|
for(ii=0; ii<nCell; ii++){
|
|
aDistance[ii] = RTREE_ZERO;
|
|
for(iDim=0; iDim<pRtree->nDim; iDim++){
|
|
- RtreeDValue coord = (DCOORD(aCell[ii].aCoord[iDim*2+1]) -
|
|
+ RtreeDValue coord = (DCOORD(aCell[ii].aCoord[iDim*2+1]) -
|
|
DCOORD(aCell[ii].aCoord[iDim*2]));
|
|
aDistance[ii] += (coord-aCenterCoord[iDim])*(coord-aCenterCoord[iDim]);
|
|
}
|
|
@@ -188955,7 +204481,7 @@ static int Reinsert(
|
|
}
|
|
|
|
/*
|
|
-** Insert cell pCell into node pNode. Node pNode is the head of a
|
|
+** Insert cell pCell into node pNode. Node pNode is the head of a
|
|
** subtree iHeight high (leaf nodes have iHeight==0).
|
|
*/
|
|
static int rtreeInsertCell(
|
|
@@ -188982,7 +204508,7 @@ static int rtreeInsertCell(
|
|
}
|
|
}else{
|
|
rc = AdjustTree(pRtree, pNode, pCell);
|
|
- if( rc==SQLITE_OK ){
|
|
+ if( ALWAYS(rc==SQLITE_OK) ){
|
|
if( iHeight==0 ){
|
|
rc = rowidWrite(pRtree, pCell->iRowid, pNode->iNode);
|
|
}else{
|
|
@@ -189045,8 +204571,8 @@ static int rtreeDeleteRowid(Rtree *pRtree, sqlite3_int64 iDelete){
|
|
/* Obtain a reference to the root node to initialize Rtree.iDepth */
|
|
rc = nodeAcquire(pRtree, 1, 0, &pRoot);
|
|
|
|
- /* Obtain a reference to the leaf node that contains the entry
|
|
- ** about to be deleted.
|
|
+ /* Obtain a reference to the leaf node that contains the entry
|
|
+ ** about to be deleted.
|
|
*/
|
|
if( rc==SQLITE_OK ){
|
|
rc = findLeafNode(pRtree, iDelete, &pLeaf, 0);
|
|
@@ -189077,18 +204603,18 @@ static int rtreeDeleteRowid(Rtree *pRtree, sqlite3_int64 iDelete){
|
|
}
|
|
|
|
/* Check if the root node now has exactly one child. If so, remove
|
|
- ** it, schedule the contents of the child for reinsertion and
|
|
+ ** it, schedule the contents of the child for reinsertion and
|
|
** reduce the tree height by one.
|
|
**
|
|
** This is equivalent to copying the contents of the child into
|
|
- ** the root node (the operation that Gutman's paper says to perform
|
|
+ ** the root node (the operation that Gutman's paper says to perform
|
|
** in this scenario).
|
|
*/
|
|
if( rc==SQLITE_OK && pRtree->iDepth>0 && NCELL(pRoot)==1 ){
|
|
int rc2;
|
|
RtreeNode *pChild = 0;
|
|
i64 iChild = nodeGetRowid(pRtree, pRoot, 0);
|
|
- rc = nodeAcquire(pRtree, iChild, pRoot, &pChild);
|
|
+ rc = nodeAcquire(pRtree, iChild, pRoot, &pChild); /* tag-20210916a */
|
|
if( rc==SQLITE_OK ){
|
|
rc = removeNode(pRtree, pChild, pRtree->iDepth-1);
|
|
}
|
|
@@ -189151,8 +204677,8 @@ static RtreeValue rtreeValueUp(sqlite3_value *v){
|
|
#endif /* !defined(SQLITE_RTREE_INT_ONLY) */
|
|
|
|
/*
|
|
-** A constraint has failed while inserting a row into an rtree table.
|
|
-** Assuming no OOM error occurs, this function sets the error message
|
|
+** A constraint has failed while inserting a row into an rtree table.
|
|
+** Assuming no OOM error occurs, this function sets the error message
|
|
** (at pRtree->base.zErrMsg) to an appropriate value and returns
|
|
** SQLITE_CONSTRAINT.
|
|
**
|
|
@@ -189165,7 +204691,7 @@ static RtreeValue rtreeValueUp(sqlite3_value *v){
|
|
*/
|
|
static int rtreeConstraintError(Rtree *pRtree, int iCol){
|
|
sqlite3_stmt *pStmt = 0;
|
|
- char *zSql;
|
|
+ char *zSql;
|
|
int rc;
|
|
|
|
assert( iCol==0 || iCol%2 );
|
|
@@ -189202,9 +204728,9 @@ static int rtreeConstraintError(Rtree *pRtree, int iCol){
|
|
** The xUpdate method for rtree module virtual tables.
|
|
*/
|
|
static int rtreeUpdate(
|
|
- sqlite3_vtab *pVtab,
|
|
- int nData,
|
|
- sqlite3_value **aData,
|
|
+ sqlite3_vtab *pVtab,
|
|
+ int nData,
|
|
+ sqlite3_value **aData,
|
|
sqlite_int64 *pRowid
|
|
){
|
|
Rtree *pRtree = (Rtree *)pVtab;
|
|
@@ -189221,7 +204747,7 @@ static int rtreeUpdate(
|
|
rtreeReference(pRtree);
|
|
assert(nData>=1);
|
|
|
|
- cell.iRowid = 0; /* Used only to suppress a compiler warning */
|
|
+ memset(&cell, 0, sizeof(cell));
|
|
|
|
/* Constraint handling. A write operation on an r-tree table may return
|
|
** SQLITE_CONSTRAINT for two reasons:
|
|
@@ -189271,7 +204797,7 @@ static int rtreeUpdate(
|
|
}
|
|
}
|
|
|
|
- /* If a rowid value was supplied, check if it is already present in
|
|
+ /* If a rowid value was supplied, check if it is already present in
|
|
** the table. If so, the constraint has failed. */
|
|
if( sqlite3_value_type(aData[2])!=SQLITE_NULL ){
|
|
cell.iRowid = sqlite3_value_int64(aData[2]);
|
|
@@ -189377,8 +204903,8 @@ static int rtreeRename(sqlite3_vtab *pVtab, const char *zNewName){
|
|
"ALTER TABLE %Q.'%q_node' RENAME TO \"%w_node\";"
|
|
"ALTER TABLE %Q.'%q_parent' RENAME TO \"%w_parent\";"
|
|
"ALTER TABLE %Q.'%q_rowid' RENAME TO \"%w_rowid\";"
|
|
- , pRtree->zDb, pRtree->zName, zNewName
|
|
- , pRtree->zDb, pRtree->zName, zNewName
|
|
+ , pRtree->zDb, pRtree->zName, zNewName
|
|
+ , pRtree->zDb, pRtree->zName, zNewName
|
|
, pRtree->zDb, pRtree->zName, zNewName
|
|
);
|
|
if( zSql ){
|
|
@@ -189393,8 +204919,8 @@ static int rtreeRename(sqlite3_vtab *pVtab, const char *zNewName){
|
|
** The xSavepoint method.
|
|
**
|
|
** This module does not need to do anything to support savepoints. However,
|
|
-** it uses this hook to close any open blob handle. This is done because a
|
|
-** DROP TABLE command - which fortunately always opens a savepoint - cannot
|
|
+** it uses this hook to close any open blob handle. This is done because a
|
|
+** DROP TABLE command - which fortunately always opens a savepoint - cannot
|
|
** succeed if there are any open blob handles. i.e. if the blob handle were
|
|
** not closed here, the following would fail:
|
|
**
|
|
@@ -189423,7 +204949,7 @@ static int rtreeQueryStat1(sqlite3 *db, Rtree *pRtree){
|
|
char *zSql;
|
|
sqlite3_stmt *p;
|
|
int rc;
|
|
- i64 nRow = 0;
|
|
+ i64 nRow = RTREE_MIN_ROWEST;
|
|
|
|
rc = sqlite3_table_column_metadata(
|
|
db, pRtree->zDb, "sqlite_stat1",0,0,0,0,0,0
|
|
@@ -189440,20 +204966,10 @@ static int rtreeQueryStat1(sqlite3 *db, Rtree *pRtree){
|
|
if( rc==SQLITE_OK ){
|
|
if( sqlite3_step(p)==SQLITE_ROW ) nRow = sqlite3_column_int64(p, 0);
|
|
rc = sqlite3_finalize(p);
|
|
- }else if( rc!=SQLITE_NOMEM ){
|
|
- rc = SQLITE_OK;
|
|
- }
|
|
-
|
|
- if( rc==SQLITE_OK ){
|
|
- if( nRow==0 ){
|
|
- pRtree->nRowEst = RTREE_DEFAULT_ROWEST;
|
|
- }else{
|
|
- pRtree->nRowEst = MAX(nRow, RTREE_MIN_ROWEST);
|
|
- }
|
|
}
|
|
sqlite3_free(zSql);
|
|
}
|
|
-
|
|
+ pRtree->nRowEst = MAX(nRow, RTREE_MIN_ROWEST);
|
|
return rc;
|
|
}
|
|
|
|
@@ -189501,10 +205017,10 @@ static sqlite3_module rtreeModule = {
|
|
};
|
|
|
|
static int rtreeSqlInit(
|
|
- Rtree *pRtree,
|
|
- sqlite3 *db,
|
|
- const char *zDb,
|
|
- const char *zPrefix,
|
|
+ Rtree *pRtree,
|
|
+ sqlite3 *db,
|
|
+ const char *zDb,
|
|
+ const char *zPrefix,
|
|
int isCreate
|
|
){
|
|
int rc = SQLITE_OK;
|
|
@@ -189584,7 +205100,7 @@ static int rtreeSqlInit(
|
|
}
|
|
zSql = sqlite3_mprintf(zFormat, zDb, zPrefix);
|
|
if( zSql ){
|
|
- rc = sqlite3_prepare_v3(db, zSql, -1, f, appStmt[i], 0);
|
|
+ rc = sqlite3_prepare_v3(db, zSql, -1, f, appStmt[i], 0);
|
|
}else{
|
|
rc = SQLITE_NOMEM;
|
|
}
|
|
@@ -189603,9 +205119,12 @@ static int rtreeSqlInit(
|
|
sqlite3_str_appendf(p, "UPDATE \"%w\".\"%w_rowid\"SET ", zDb, zPrefix);
|
|
for(ii=0; ii<pRtree->nAux; ii++){
|
|
if( ii ) sqlite3_str_append(p, ",", 1);
|
|
+#ifdef SQLITE_ENABLE_GEOPOLY
|
|
if( ii<pRtree->nAuxNotNull ){
|
|
sqlite3_str_appendf(p,"a%d=coalesce(?%d,a%d)",ii,ii+2,ii);
|
|
- }else{
|
|
+ }else
|
|
+#endif
|
|
+ {
|
|
sqlite3_str_appendf(p,"a%d=?%d",ii,ii+2);
|
|
}
|
|
}
|
|
@@ -189614,7 +205133,7 @@ static int rtreeSqlInit(
|
|
if( zSql==0 ){
|
|
rc = SQLITE_NOMEM;
|
|
}else{
|
|
- rc = sqlite3_prepare_v3(db, zSql, -1, f, &pRtree->pWriteAux, 0);
|
|
+ rc = sqlite3_prepare_v3(db, zSql, -1, f, &pRtree->pWriteAux, 0);
|
|
sqlite3_free(zSql);
|
|
}
|
|
}
|
|
@@ -189655,9 +205174,9 @@ static int getIntFromStmt(sqlite3 *db, const char *zSql, int *piVal){
|
|
** table already exists. In this case the node-size is determined by inspecting
|
|
** the root node of the tree.
|
|
**
|
|
-** Otherwise, for an xCreate(), use 64 bytes less than the database page-size.
|
|
-** This ensures that each node is stored on a single database page. If the
|
|
-** database page-size is so large that more than RTREE_MAXCELLS entries
|
|
+** Otherwise, for an xCreate(), use 64 bytes less than the database page-size.
|
|
+** This ensures that each node is stored on a single database page. If the
|
|
+** database page-size is so large that more than RTREE_MAXCELLS entries
|
|
** would fit in a single node, use a smaller node-size.
|
|
*/
|
|
static int getNodeSize(
|
|
@@ -189708,7 +205227,7 @@ static int rtreeTokenLength(const char *z){
|
|
return sqlite3GetToken((const unsigned char*)z,&dummy);
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** This function is the implementation of both the xConnect and xCreate
|
|
** methods of the r-tree virtual table.
|
|
**
|
|
@@ -189773,7 +205292,7 @@ static int rtreeInit(
|
|
** the r-tree table schema.
|
|
*/
|
|
pSql = sqlite3_str_new(db);
|
|
- sqlite3_str_appendf(pSql, "CREATE TABLE x(%.*s INT",
|
|
+ sqlite3_str_appendf(pSql, "CREATE TABLE x(%.*s INT",
|
|
rtreeTokenLength(argv[3]), argv[3]);
|
|
for(ii=4; ii<argc; ii++){
|
|
const char *zArg = argv[ii];
|
|
@@ -189783,8 +205302,10 @@ static int rtreeInit(
|
|
}else if( pRtree->nAux>0 ){
|
|
break;
|
|
}else{
|
|
+ static const char *azFormat[] = {",%.*s REAL", ",%.*s INT"};
|
|
pRtree->nDim2++;
|
|
- sqlite3_str_appendf(pSql, ",%.*s NUM", rtreeTokenLength(zArg), zArg);
|
|
+ sqlite3_str_appendf(pSql, azFormat[eCoordType],
|
|
+ rtreeTokenLength(zArg), zArg);
|
|
}
|
|
}
|
|
sqlite3_str_appendf(pSql, ");");
|
|
@@ -189849,7 +205370,7 @@ static int rtreeInit(
|
|
**
|
|
** The human readable string takes the form of a Tcl list with one
|
|
** entry for each cell in the r-tree node. Each entry is itself a
|
|
-** list, containing the 8-byte rowid/pageno followed by the
|
|
+** list, containing the 8-byte rowid/pageno followed by the
|
|
** <num-dimension>*2 coordinates.
|
|
*/
|
|
static void rtreenode(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){
|
|
@@ -189868,6 +205389,7 @@ static void rtreenode(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){
|
|
tree.nDim2 = tree.nDim*2;
|
|
tree.nBytesPerCell = 8 + 8 * tree.nDim;
|
|
node.zData = (u8 *)sqlite3_value_blob(apArg[1]);
|
|
+ if( node.zData==0 ) return;
|
|
nData = sqlite3_value_bytes(apArg[1]);
|
|
if( nData<4 ) return;
|
|
if( nData<NCELL(&node)*tree.nBytesPerCell ) return;
|
|
@@ -189905,13 +205427,18 @@ static void rtreenode(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){
|
|
*/
|
|
static void rtreedepth(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){
|
|
UNUSED_PARAMETER(nArg);
|
|
- if( sqlite3_value_type(apArg[0])!=SQLITE_BLOB
|
|
+ if( sqlite3_value_type(apArg[0])!=SQLITE_BLOB
|
|
|| sqlite3_value_bytes(apArg[0])<2
|
|
+
|
|
){
|
|
- sqlite3_result_error(ctx, "Invalid argument to rtreedepth()", -1);
|
|
+ sqlite3_result_error(ctx, "Invalid argument to rtreedepth()", -1);
|
|
}else{
|
|
u8 *zBlob = (u8 *)sqlite3_value_blob(apArg[0]);
|
|
- sqlite3_result_int(ctx, readInt16(zBlob));
|
|
+ if( zBlob ){
|
|
+ sqlite3_result_int(ctx, readInt16(zBlob));
|
|
+ }else{
|
|
+ sqlite3_result_error_nomem(ctx);
|
|
+ }
|
|
}
|
|
}
|
|
|
|
@@ -189991,7 +205518,7 @@ static void rtreeCheckAppendMsg(RtreeCheck *pCheck, const char *zFmt, ...){
|
|
if( z==0 ){
|
|
pCheck->rc = SQLITE_NOMEM;
|
|
}else{
|
|
- pCheck->zReport = sqlite3_mprintf("%z%s%z",
|
|
+ pCheck->zReport = sqlite3_mprintf("%z%s%z",
|
|
pCheck->zReport, (pCheck->zReport ? "\n" : ""), z
|
|
);
|
|
if( pCheck->zReport==0 ){
|
|
@@ -190022,7 +205549,7 @@ static u8 *rtreeCheckGetNode(RtreeCheck *pCheck, i64 iNode, int *pnNode){
|
|
|
|
if( pCheck->rc==SQLITE_OK && pCheck->pGetNode==0 ){
|
|
pCheck->pGetNode = rtreeCheckPrepare(pCheck,
|
|
- "SELECT data FROM %Q.'%q_node' WHERE nodeno=?",
|
|
+ "SELECT data FROM %Q.'%q_node' WHERE nodeno=?",
|
|
pCheck->zDb, pCheck->zTab
|
|
);
|
|
}
|
|
@@ -190092,7 +205619,7 @@ static void rtreeCheckMapping(
|
|
}else if( rc==SQLITE_ROW ){
|
|
i64 ii = sqlite3_column_int64(pStmt, 0);
|
|
if( ii!=iVal ){
|
|
- rtreeCheckAppendMsg(pCheck,
|
|
+ rtreeCheckAppendMsg(pCheck,
|
|
"Found (%lld -> %lld) in %s table, expected (%lld -> %lld)",
|
|
iKey, ii, (bLeaf ? "%_rowid" : "%_parent"), iKey, iVal
|
|
);
|
|
@@ -190108,13 +205635,13 @@ static void rtreeCheckMapping(
|
|
** if they are not.
|
|
**
|
|
** Additionally, if pParent is not NULL, then it is assumed to point to
|
|
-** the array of coordinates on the parent page that bound the page
|
|
+** the array of coordinates on the parent page that bound the page
|
|
** containing pCell. In this case it is also verified that the two
|
|
** sets of coordinates are mutually consistent and an error message added
|
|
** to the RtreeCheck object if they are not.
|
|
*/
|
|
static void rtreeCheckCellCoord(
|
|
- RtreeCheck *pCheck,
|
|
+ RtreeCheck *pCheck,
|
|
i64 iNode, /* Node id to use in error messages */
|
|
int iCell, /* Cell number to use in error messages */
|
|
u8 *pCell, /* Pointer to cell coordinates */
|
|
@@ -190130,7 +205657,7 @@ static void rtreeCheckCellCoord(
|
|
|
|
/* printf("%e, %e\n", c1.u.f, c2.u.f); */
|
|
if( pCheck->bInt ? c1.i>c2.i : c1.f>c2.f ){
|
|
- rtreeCheckAppendMsg(pCheck,
|
|
+ rtreeCheckAppendMsg(pCheck,
|
|
"Dimension %d of cell %d on node %lld is corrupt", i, iCell, iNode
|
|
);
|
|
}
|
|
@@ -190139,10 +205666,10 @@ static void rtreeCheckCellCoord(
|
|
readCoord(&pParent[4*2*i], &p1);
|
|
readCoord(&pParent[4*(2*i + 1)], &p2);
|
|
|
|
- if( (pCheck->bInt ? c1.i<p1.i : c1.f<p1.f)
|
|
+ if( (pCheck->bInt ? c1.i<p1.i : c1.f<p1.f)
|
|
|| (pCheck->bInt ? c2.i>p2.i : c2.f>p2.f)
|
|
){
|
|
- rtreeCheckAppendMsg(pCheck,
|
|
+ rtreeCheckAppendMsg(pCheck,
|
|
"Dimension %d of cell %d on node %lld is corrupt relative to parent"
|
|
, i, iCell, iNode
|
|
);
|
|
@@ -190174,7 +205701,7 @@ static void rtreeCheckNode(
|
|
aNode = rtreeCheckGetNode(pCheck, iNode, &nNode);
|
|
if( aNode ){
|
|
if( nNode<4 ){
|
|
- rtreeCheckAppendMsg(pCheck,
|
|
+ rtreeCheckAppendMsg(pCheck,
|
|
"Node %lld is too small (%d bytes)", iNode, nNode
|
|
);
|
|
}else{
|
|
@@ -190190,8 +205717,8 @@ static void rtreeCheckNode(
|
|
}
|
|
nCell = readInt16(&aNode[2]);
|
|
if( (4 + nCell*(8 + pCheck->nDim*2*4))>nNode ){
|
|
- rtreeCheckAppendMsg(pCheck,
|
|
- "Node %lld is too small for cell count of %d (%d bytes)",
|
|
+ rtreeCheckAppendMsg(pCheck,
|
|
+ "Node %lld is too small for cell count of %d (%d bytes)",
|
|
iNode, nCell, nNode
|
|
);
|
|
}else{
|
|
@@ -190277,8 +205804,10 @@ static int rtreeCheckTable(
|
|
if( pStmt ){
|
|
nAux = sqlite3_column_count(pStmt) - 2;
|
|
sqlite3_finalize(pStmt);
|
|
+ }else
|
|
+ if( check.rc!=SQLITE_NOMEM ){
|
|
+ check.rc = SQLITE_OK;
|
|
}
|
|
- check.rc = SQLITE_OK;
|
|
}
|
|
|
|
/* Find number of dimensions in the rtree table. */
|
|
@@ -190334,11 +205863,11 @@ static int rtreeCheckTable(
|
|
** b) unless the cell is on the root node, that the cell is bounded
|
|
** by the parent cell on the parent node.
|
|
**
|
|
-** c) for leaf nodes, that there is an entry in the %_rowid
|
|
-** table corresponding to the cell's rowid value that
|
|
+** c) for leaf nodes, that there is an entry in the %_rowid
|
|
+** table corresponding to the cell's rowid value that
|
|
** points to the correct node.
|
|
**
|
|
-** d) for cells on non-leaf nodes, that there is an entry in the
|
|
+** d) for cells on non-leaf nodes, that there is an entry in the
|
|
** %_parent table mapping from the cell's child node to the
|
|
** node that it resides on.
|
|
**
|
|
@@ -190347,17 +205876,17 @@ static int rtreeCheckTable(
|
|
** is a leaf cell that corresponds to each entry in the %_rowid table.
|
|
**
|
|
** 3. That there are the same number of entries in the %_parent table
|
|
-** as there are non-leaf cells in the r-tree structure, and that
|
|
-** there is a non-leaf cell that corresponds to each entry in the
|
|
+** as there are non-leaf cells in the r-tree structure, and that
|
|
+** there is a non-leaf cell that corresponds to each entry in the
|
|
** %_parent table.
|
|
*/
|
|
static void rtreecheck(
|
|
- sqlite3_context *ctx,
|
|
- int nArg,
|
|
+ sqlite3_context *ctx,
|
|
+ int nArg,
|
|
sqlite3_value **apArg
|
|
){
|
|
if( nArg!=1 && nArg!=2 ){
|
|
- sqlite3_result_error(ctx,
|
|
+ sqlite3_result_error(ctx,
|
|
"wrong number of arguments to function rtreecheck()", -1
|
|
);
|
|
}else{
|
|
@@ -190413,11 +205942,7 @@ static void rtreecheck(
|
|
# define GEODEBUG(X)
|
|
#endif
|
|
|
|
-#ifndef JSON_NULL /* The following stuff repeats things found in json1 */
|
|
-/*
|
|
-** Versions of isspace(), isalnum() and isdigit() to which it is safe
|
|
-** to pass signed char values.
|
|
-*/
|
|
+/* Character class routines */
|
|
#ifdef sqlite3Isdigit
|
|
/* Use the SQLite core versions if this routine is part of the
|
|
** SQLite amalgamation */
|
|
@@ -190432,6 +205957,7 @@ static void rtreecheck(
|
|
# define safe_isxdigit(x) isxdigit((unsigned char)(x))
|
|
#endif
|
|
|
|
+#ifndef JSON_NULL /* The following stuff repeats things found in json1 */
|
|
/*
|
|
** Growing our own isspace() routine this way is twice as fast as
|
|
** the library isspace() function.
|
|
@@ -190454,7 +205980,7 @@ static const char geopolyIsSpace[] = {
|
|
0, 0, 0, 0, 0, 0, 0, 0, 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 safe_isspace(x) (geopolyIsSpace[(unsigned char)x])
|
|
+#define fast_isspace(x) (geopolyIsSpace[(unsigned char)x])
|
|
#endif /* JSON NULL - back to original code */
|
|
|
|
/* Compiler and version */
|
|
@@ -190543,7 +206069,7 @@ static void geopolySwab32(unsigned char *a){
|
|
|
|
/* Skip whitespace. Return the next non-whitespace character. */
|
|
static char geopolySkipSpace(GeoParse *p){
|
|
- while( safe_isspace(p->z[0]) ) p->z++;
|
|
+ while( fast_isspace(p->z[0]) ) p->z++;
|
|
return p->z[0];
|
|
}
|
|
|
|
@@ -190692,11 +206218,16 @@ static GeoPoly *geopolyFuncParam(
|
|
){
|
|
GeoPoly *p = 0;
|
|
int nByte;
|
|
+ testcase( pCtx==0 );
|
|
if( sqlite3_value_type(pVal)==SQLITE_BLOB
|
|
- && (nByte = sqlite3_value_bytes(pVal))>=(4+6*sizeof(GeoCoord))
|
|
+ && (nByte = sqlite3_value_bytes(pVal))>=(int)(4+6*sizeof(GeoCoord))
|
|
){
|
|
const unsigned char *a = sqlite3_value_blob(pVal);
|
|
int nVertex;
|
|
+ if( a==0 ){
|
|
+ if( pCtx ) sqlite3_result_error_nomem(pCtx);
|
|
+ return 0;
|
|
+ }
|
|
nVertex = (a[1]<<16) + (a[2]<<8) + a[3];
|
|
if( (a[0]==0 || a[0]==1)
|
|
&& (nVertex*2*sizeof(GeoCoord) + 4)==(unsigned int)nByte
|
|
@@ -190747,8 +206278,9 @@ static void geopolyBlobFunc(
|
|
sqlite3_value **argv
|
|
){
|
|
GeoPoly *p = geopolyFuncParam(context, argv[0], 0);
|
|
+ (void)argc;
|
|
if( p ){
|
|
- sqlite3_result_blob(context, p->hdr,
|
|
+ sqlite3_result_blob(context, p->hdr,
|
|
4+8*p->nVertex, SQLITE_TRANSIENT);
|
|
sqlite3_free(p);
|
|
}
|
|
@@ -190766,6 +206298,7 @@ static void geopolyJsonFunc(
|
|
sqlite3_value **argv
|
|
){
|
|
GeoPoly *p = geopolyFuncParam(context, argv[0], 0);
|
|
+ (void)argc;
|
|
if( p ){
|
|
sqlite3 *db = sqlite3_context_db_handle(context);
|
|
sqlite3_str *x = sqlite3_str_new(db);
|
|
@@ -190847,6 +206380,7 @@ static void geopolyXformFunc(
|
|
double F = sqlite3_value_double(argv[6]);
|
|
GeoCoord x1, y1, x0, y0;
|
|
int ii;
|
|
+ (void)argc;
|
|
if( p ){
|
|
for(ii=0; ii<p->nVertex; ii++){
|
|
x0 = GeoX(p,ii);
|
|
@@ -190856,7 +206390,7 @@ static void geopolyXformFunc(
|
|
GeoX(p,ii) = x1;
|
|
GeoY(p,ii) = y1;
|
|
}
|
|
- sqlite3_result_blob(context, p->hdr,
|
|
+ sqlite3_result_blob(context, p->hdr,
|
|
4+8*p->nVertex, SQLITE_TRANSIENT);
|
|
sqlite3_free(p);
|
|
}
|
|
@@ -190897,10 +206431,11 @@ static void geopolyAreaFunc(
|
|
sqlite3_value **argv
|
|
){
|
|
GeoPoly *p = geopolyFuncParam(context, argv[0], 0);
|
|
+ (void)argc;
|
|
if( p ){
|
|
sqlite3_result_double(context, geopolyArea(p));
|
|
sqlite3_free(p);
|
|
- }
|
|
+ }
|
|
}
|
|
|
|
/*
|
|
@@ -190908,7 +206443,7 @@ static void geopolyAreaFunc(
|
|
**
|
|
** If the rotation of polygon X is clockwise (incorrect) instead of
|
|
** counter-clockwise (the correct winding order according to RFC7946)
|
|
-** then reverse the order of the vertexes in polygon X.
|
|
+** then reverse the order of the vertexes in polygon X.
|
|
**
|
|
** In other words, this routine returns a CCW polygon regardless of the
|
|
** winding order of its input.
|
|
@@ -190922,6 +206457,7 @@ static void geopolyCcwFunc(
|
|
sqlite3_value **argv
|
|
){
|
|
GeoPoly *p = geopolyFuncParam(context, argv[0], 0);
|
|
+ (void)argc;
|
|
if( p ){
|
|
if( geopolyArea(p)<0.0 ){
|
|
int ii, jj;
|
|
@@ -190934,10 +206470,10 @@ static void geopolyCcwFunc(
|
|
GeoY(p,jj) = t;
|
|
}
|
|
}
|
|
- sqlite3_result_blob(context, p->hdr,
|
|
+ sqlite3_result_blob(context, p->hdr,
|
|
4+8*p->nVertex, SQLITE_TRANSIENT);
|
|
sqlite3_free(p);
|
|
- }
|
|
+ }
|
|
}
|
|
|
|
#define GEOPOLY_PI 3.1415926535897932385
|
|
@@ -190976,6 +206512,7 @@ static void geopolyRegularFunc(
|
|
int n = sqlite3_value_int(argv[3]);
|
|
int i;
|
|
GeoPoly *p;
|
|
+ (void)argc;
|
|
|
|
if( n<3 || r<=0.0 ) return;
|
|
if( n>1000 ) n = 1000;
|
|
@@ -191070,6 +206607,8 @@ static GeoPoly *geopolyBBox(
|
|
aCoord[2].f = mnY;
|
|
aCoord[3].f = mxY;
|
|
}
|
|
+ }else if( aCoord ){
|
|
+ memset(aCoord, 0, sizeof(RtreeCoord)*4);
|
|
}
|
|
return pOut;
|
|
}
|
|
@@ -191083,8 +206622,9 @@ static void geopolyBBoxFunc(
|
|
sqlite3_value **argv
|
|
){
|
|
GeoPoly *p = geopolyBBox(context, argv[0], 0, 0);
|
|
+ (void)argc;
|
|
if( p ){
|
|
- sqlite3_result_blob(context, p->hdr,
|
|
+ sqlite3_result_blob(context, p->hdr,
|
|
4+8*p->nVertex, SQLITE_TRANSIENT);
|
|
sqlite3_free(p);
|
|
}
|
|
@@ -191110,6 +206650,7 @@ static void geopolyBBoxStep(
|
|
){
|
|
RtreeCoord a[4];
|
|
int rc = SQLITE_OK;
|
|
+ (void)argc;
|
|
(void)geopolyBBox(context, argv[0], a, &rc);
|
|
if( rc==SQLITE_OK ){
|
|
GeoBBox *pBBox;
|
|
@@ -191135,7 +206676,7 @@ static void geopolyBBoxFinal(
|
|
if( pBBox==0 ) return;
|
|
p = geopolyBBox(context, 0, pBBox->a, 0);
|
|
if( p ){
|
|
- sqlite3_result_blob(context, p->hdr,
|
|
+ sqlite3_result_blob(context, p->hdr,
|
|
4+8*p->nVertex, SQLITE_TRANSIENT);
|
|
sqlite3_free(p);
|
|
}
|
|
@@ -191198,6 +206739,8 @@ static void geopolyContainsPointFunc(
|
|
int v = 0;
|
|
int cnt = 0;
|
|
int ii;
|
|
+ (void)argc;
|
|
+
|
|
if( p1==0 ) return;
|
|
for(ii=0; ii<p1->nVertex-1; ii++){
|
|
v = pointBeneathLine(x0,y0,GeoX(p1,ii), GeoY(p1,ii),
|
|
@@ -191237,6 +206780,7 @@ static void geopolyWithinFunc(
|
|
){
|
|
GeoPoly *p1 = geopolyFuncParam(context, argv[0], 0);
|
|
GeoPoly *p2 = geopolyFuncParam(context, argv[1], 0);
|
|
+ (void)argc;
|
|
if( p1 && p2 ){
|
|
int x = geopolyOverlap(p1, p2);
|
|
if( x<0 ){
|
|
@@ -191315,7 +206859,7 @@ static void geopolyAddOneSegment(
|
|
pEvent->eType = 1;
|
|
pEvent->pSeg = pSeg;
|
|
}
|
|
-
|
|
+
|
|
|
|
|
|
/*
|
|
@@ -191355,7 +206899,7 @@ static GeoEvent *geopolyEventMerge(GeoEvent *pLeft, GeoEvent *pRight){
|
|
}
|
|
}
|
|
pLast->pNext = pRight ? pRight : pLeft;
|
|
- return head.pNext;
|
|
+ return head.pNext;
|
|
}
|
|
|
|
/*
|
|
@@ -191404,7 +206948,7 @@ static GeoSegment *geopolySegmentMerge(GeoSegment *pLeft, GeoSegment *pRight){
|
|
}
|
|
}
|
|
pLast->pNext = pRight ? pRight : pLeft;
|
|
- return head.pNext;
|
|
+ return head.pNext;
|
|
}
|
|
|
|
/*
|
|
@@ -191449,8 +206993,8 @@ static int geopolyOverlap(GeoPoly *p1, GeoPoly *p2){
|
|
GeoSegment *pSeg;
|
|
unsigned char aOverlap[4];
|
|
|
|
- nByte = sizeof(GeoEvent)*nVertex*2
|
|
- + sizeof(GeoSegment)*nVertex
|
|
+ nByte = sizeof(GeoEvent)*nVertex*2
|
|
+ + sizeof(GeoSegment)*nVertex
|
|
+ sizeof(GeoOverlap);
|
|
p = sqlite3_malloc64( nByte );
|
|
if( p==0 ) return -1;
|
|
@@ -191460,7 +207004,7 @@ static int geopolyOverlap(GeoPoly *p1, GeoPoly *p2){
|
|
geopolyAddSegments(p, p1, 1);
|
|
geopolyAddSegments(p, p2, 2);
|
|
pThisEvent = geopolySortEventsByX(p->aEvent, p->nEvent);
|
|
- rX = pThisEvent->x==0.0 ? -1.0 : 0.0;
|
|
+ rX = pThisEvent && pThisEvent->x==0.0 ? -1.0 : 0.0;
|
|
memset(aOverlap, 0, sizeof(aOverlap));
|
|
while( pThisEvent ){
|
|
if( pThisEvent->x!=rX ){
|
|
@@ -191519,11 +207063,11 @@ static int geopolyOverlap(GeoPoly *p1, GeoPoly *p2){
|
|
}else{
|
|
/* Remove a segment */
|
|
if( pActive==pThisEvent->pSeg ){
|
|
- pActive = pActive->pNext;
|
|
+ pActive = ALWAYS(pActive) ? pActive->pNext : 0;
|
|
}else{
|
|
for(pSeg=pActive; pSeg; pSeg=pSeg->pNext){
|
|
if( pSeg->pNext==pThisEvent->pSeg ){
|
|
- pSeg->pNext = pSeg->pNext->pNext;
|
|
+ pSeg->pNext = ALWAYS(pSeg->pNext) ? pSeg->pNext->pNext : 0;
|
|
break;
|
|
}
|
|
}
|
|
@@ -191567,6 +207111,7 @@ static void geopolyOverlapFunc(
|
|
){
|
|
GeoPoly *p1 = geopolyFuncParam(context, argv[0], 0);
|
|
GeoPoly *p2 = geopolyFuncParam(context, argv[1], 0);
|
|
+ (void)argc;
|
|
if( p1 && p2 ){
|
|
int x = geopolyOverlap(p1, p2);
|
|
if( x<0 ){
|
|
@@ -191587,12 +207132,16 @@ static void geopolyDebugFunc(
|
|
int argc,
|
|
sqlite3_value **argv
|
|
){
|
|
+ (void)context;
|
|
+ (void)argc;
|
|
#ifdef GEOPOLY_ENABLE_DEBUG
|
|
geo_debug = sqlite3_value_int(argv[0]);
|
|
+#else
|
|
+ (void)argv;
|
|
#endif
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** This function is the implementation of both the xConnect and xCreate
|
|
** methods of the geopoly virtual table.
|
|
**
|
|
@@ -191616,6 +207165,7 @@ static int geopolyInit(
|
|
sqlite3_str *pSql;
|
|
char *zSql;
|
|
int ii;
|
|
+ (void)pAux;
|
|
|
|
sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1);
|
|
|
|
@@ -191682,7 +207232,7 @@ static int geopolyInit(
|
|
}
|
|
|
|
|
|
-/*
|
|
+/*
|
|
** GEOPOLY virtual table module xCreate method.
|
|
*/
|
|
static int geopolyCreate(
|
|
@@ -191695,7 +207245,7 @@ static int geopolyCreate(
|
|
return geopolyInit(db, pAux, argc, argv, ppVtab, pzErr, 1);
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** GEOPOLY virtual table module xConnect method.
|
|
*/
|
|
static int geopolyConnect(
|
|
@@ -191709,7 +207259,7 @@ static int geopolyConnect(
|
|
}
|
|
|
|
|
|
-/*
|
|
+/*
|
|
** GEOPOLY virtual table module xFilter method.
|
|
**
|
|
** Query plans:
|
|
@@ -191732,6 +207282,7 @@ static int geopolyFilter(
|
|
RtreeNode *pRoot = 0;
|
|
int rc = SQLITE_OK;
|
|
int iCell = 0;
|
|
+ (void)idxStr;
|
|
|
|
rtreeReference(pRtree);
|
|
|
|
@@ -191759,14 +207310,15 @@ static int geopolyFilter(
|
|
pCsr->atEOF = 1;
|
|
}
|
|
}else{
|
|
- /* Normal case - r-tree scan. Set up the RtreeCursor.aConstraint array
|
|
- ** with the configured constraints.
|
|
+ /* Normal case - r-tree scan. Set up the RtreeCursor.aConstraint array
|
|
+ ** with the configured constraints.
|
|
*/
|
|
rc = nodeAcquire(pRtree, 1, 0, &pRoot);
|
|
if( rc==SQLITE_OK && idxNum<=3 ){
|
|
RtreeCoord bbox[4];
|
|
RtreeConstraint *p;
|
|
assert( argc==1 );
|
|
+ assert( argv[0]!=0 );
|
|
geopolyBBox(0, argv[0], bbox, &rc);
|
|
if( rc ){
|
|
goto geopoly_filter_end;
|
|
@@ -191841,7 +207393,7 @@ static int geopolyFilter(
|
|
|
|
/*
|
|
** Rtree virtual table module xBestIndex method. There are three
|
|
-** table scan strategies to choose from (in order from most to
|
|
+** table scan strategies to choose from (in order from most to
|
|
** least desirable):
|
|
**
|
|
** idxNum idxStr Strategy
|
|
@@ -191857,6 +207409,7 @@ static int geopolyBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
|
|
int iRowidTerm = -1;
|
|
int iFuncTerm = -1;
|
|
int idxNum = 0;
|
|
+ (void)tab;
|
|
|
|
for(ii=0; ii<pIdxInfo->nConstraint; ii++){
|
|
struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[ii];
|
|
@@ -191901,7 +207454,7 @@ static int geopolyBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
|
|
}
|
|
|
|
|
|
-/*
|
|
+/*
|
|
** GEOPOLY virtual table module xColumn method.
|
|
*/
|
|
static int geopolyColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
|
|
@@ -191921,7 +207474,7 @@ static int geopolyColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
|
|
&pCsr->pReadAux, 0);
|
|
if( rc ) return rc;
|
|
}
|
|
- sqlite3_bind_int64(pCsr->pReadAux, 1,
|
|
+ sqlite3_bind_int64(pCsr->pReadAux, 1,
|
|
nodeGetRowid(pRtree, pNode, p->iCell));
|
|
rc = sqlite3_step(pCsr->pReadAux);
|
|
if( rc==SQLITE_ROW ){
|
|
@@ -191960,9 +207513,9 @@ static int geopolyColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
|
|
** argv[3] = new value for first application-defined column....
|
|
*/
|
|
static int geopolyUpdate(
|
|
- sqlite3_vtab *pVtab,
|
|
- int nData,
|
|
- sqlite3_value **aData,
|
|
+ sqlite3_vtab *pVtab,
|
|
+ int nData,
|
|
+ sqlite3_value **aData,
|
|
sqlite_int64 *pRowid
|
|
){
|
|
Rtree *pRtree = (Rtree *)pVtab;
|
|
@@ -191994,6 +207547,7 @@ static int geopolyUpdate(
|
|
|| !sqlite3_value_nochange(aData[2]) /* UPDATE _shape */
|
|
|| oldRowid!=newRowid) /* Rowid change */
|
|
){
|
|
+ assert( aData[2]!=0 );
|
|
geopolyBBox(0, aData[2], cell.aCoord, &rc);
|
|
if( rc ){
|
|
if( rc==SQLITE_ERROR ){
|
|
@@ -192004,7 +207558,7 @@ static int geopolyUpdate(
|
|
}
|
|
coordChange = 1;
|
|
|
|
- /* If a rowid value was supplied, check if it is already present in
|
|
+ /* If a rowid value was supplied, check if it is already present in
|
|
** the table. If so, the constraint has failed. */
|
|
if( newRowidValid && (!oldRowidValid || oldRowid!=newRowid) ){
|
|
int steprc;
|
|
@@ -192076,7 +207630,7 @@ static int geopolyUpdate(
|
|
sqlite3_free(p);
|
|
nChange = 1;
|
|
}
|
|
- for(jj=1; jj<pRtree->nAux; jj++){
|
|
+ for(jj=1; jj<nData-2; jj++){
|
|
nChange++;
|
|
sqlite3_bind_value(pUp, jj+2, aData[jj+2]);
|
|
}
|
|
@@ -192102,6 +207656,8 @@ static int geopolyFindFunction(
|
|
void (**pxFunc)(sqlite3_context*,int,sqlite3_value**),
|
|
void **ppArg
|
|
){
|
|
+ (void)pVtab;
|
|
+ (void)nArg;
|
|
if( sqlite3_stricmp(zName, "geopoly_overlap")==0 ){
|
|
*pxFunc = geopolyOverlapFunc;
|
|
*ppArg = 0;
|
|
@@ -192171,7 +207727,7 @@ static int sqlite3_geopoly_init(sqlite3 *db){
|
|
} aAgg[] = {
|
|
{ geopolyBBoxStep, geopolyBBoxFinal, "geopoly_group_bbox" },
|
|
};
|
|
- int i;
|
|
+ unsigned int i;
|
|
for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){
|
|
int enc;
|
|
if( aFunc[i].bPure ){
|
|
@@ -192184,7 +207740,7 @@ static int sqlite3_geopoly_init(sqlite3 *db){
|
|
aFunc[i].xFunc, 0, 0);
|
|
}
|
|
for(i=0; i<sizeof(aAgg)/sizeof(aAgg[0]) && rc==SQLITE_OK; i++){
|
|
- rc = sqlite3_create_function(db, aAgg[i].zName, 1,
|
|
+ rc = sqlite3_create_function(db, aAgg[i].zName, 1,
|
|
SQLITE_UTF8|SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS, 0,
|
|
0, aAgg[i].xStep, aAgg[i].xFinal);
|
|
}
|
|
@@ -192200,7 +207756,7 @@ static int sqlite3_geopoly_init(sqlite3 *db){
|
|
|
|
/*
|
|
** Register the r-tree module with database handle db. This creates the
|
|
-** virtual table module "rtree" and the debugging/analysis scalar
|
|
+** virtual table module "rtree" and the debugging/analysis scalar
|
|
** function "rtreenode".
|
|
*/
|
|
SQLITE_PRIVATE int sqlite3RtreeInit(sqlite3 *db){
|
|
@@ -192327,7 +207883,7 @@ SQLITE_API int sqlite3_rtree_geometry_callback(
|
|
pGeomCtx->xQueryFunc = 0;
|
|
pGeomCtx->xDestructor = 0;
|
|
pGeomCtx->pContext = pContext;
|
|
- return sqlite3_create_function_v2(db, zGeom, -1, SQLITE_ANY,
|
|
+ return sqlite3_create_function_v2(db, zGeom, -1, SQLITE_ANY,
|
|
(void *)pGeomCtx, geomCallback, 0, 0, rtreeFreeCallback
|
|
);
|
|
}
|
|
@@ -192347,12 +207903,15 @@ SQLITE_API int sqlite3_rtree_query_callback(
|
|
|
|
/* Allocate and populate the context object. */
|
|
pGeomCtx = (RtreeGeomCallback *)sqlite3_malloc(sizeof(RtreeGeomCallback));
|
|
- if( !pGeomCtx ) return SQLITE_NOMEM;
|
|
+ if( !pGeomCtx ){
|
|
+ if( xDestructor ) xDestructor(pContext);
|
|
+ return SQLITE_NOMEM;
|
|
+ }
|
|
pGeomCtx->xGeom = 0;
|
|
pGeomCtx->xQueryFunc = xQueryFunc;
|
|
pGeomCtx->xDestructor = xDestructor;
|
|
pGeomCtx->pContext = pContext;
|
|
- return sqlite3_create_function_v2(db, zQueryFunc, -1, SQLITE_ANY,
|
|
+ return sqlite3_create_function_v2(db, zQueryFunc, -1, SQLITE_ANY,
|
|
(void *)pGeomCtx, geomCallback, 0, 0, rtreeFreeCallback
|
|
);
|
|
}
|
|
@@ -192388,9 +207947,9 @@ SQLITE_API int sqlite3_rtree_init(
|
|
*************************************************************************
|
|
** $Id: icu.c,v 1.7 2007/12/13 21:54:11 drh Exp $
|
|
**
|
|
-** This file implements an integration between the ICU library
|
|
-** ("International Components for Unicode", an open-source library
|
|
-** for handling unicode data) and SQLite. The integration uses
|
|
+** This file implements an integration between the ICU library
|
|
+** ("International Components for Unicode", an open-source library
|
|
+** for handling unicode data) and SQLite. The integration uses
|
|
** ICU to provide the following to SQLite:
|
|
**
|
|
** * An implementation of the SQL regexp() function (and hence REGEXP
|
|
@@ -192401,7 +207960,7 @@ SQLITE_API int sqlite3_rtree_init(
|
|
**
|
|
** * Integration of ICU and SQLite collation sequences.
|
|
**
|
|
-** * An implementation of the LIKE operator that uses ICU to
|
|
+** * An implementation of the LIKE operator that uses ICU to
|
|
** provide case-independent matching.
|
|
*/
|
|
|
|
@@ -192428,7 +207987,7 @@ SQLITE_API int sqlite3_rtree_init(
|
|
** This function is called when an ICU function called from within
|
|
** the implementation of an SQL scalar function returns an error.
|
|
**
|
|
-** The scalar function context passed as the first argument is
|
|
+** The scalar function context passed as the first argument is
|
|
** loaded with an error message based on the following two args.
|
|
*/
|
|
static void icuFunctionError(
|
|
@@ -192493,7 +208052,7 @@ static const unsigned char icuUtf8Trans1[] = {
|
|
|
|
/*
|
|
** Compare two UTF-8 strings for equality where the first string is
|
|
-** a "LIKE" expression. Return true (1) if they are the same and
|
|
+** a "LIKE" expression. Return true (1) if they are the same and
|
|
** false (0) if they are different.
|
|
*/
|
|
static int icuLikeCompare(
|
|
@@ -192520,12 +208079,12 @@ static int icuLikeCompare(
|
|
** 3. uPattern is an unescaped escape character, or
|
|
** 4. uPattern is to be handled as an ordinary character
|
|
*/
|
|
- if( !prevEscape && uPattern==MATCH_ALL ){
|
|
+ if( uPattern==MATCH_ALL && !prevEscape && uPattern!=(uint32_t)uEsc ){
|
|
/* Case 1. */
|
|
uint8_t c;
|
|
|
|
/* Skip any MATCH_ALL or MATCH_ONE characters that follow a
|
|
- ** MATCH_ALL. For each MATCH_ONE, skip one character in the
|
|
+ ** MATCH_ALL. For each MATCH_ONE, skip one character in the
|
|
** test string.
|
|
*/
|
|
while( (c=*zPattern) == MATCH_ALL || c == MATCH_ONE ){
|
|
@@ -192546,12 +208105,12 @@ static int icuLikeCompare(
|
|
}
|
|
return 0;
|
|
|
|
- }else if( !prevEscape && uPattern==MATCH_ONE ){
|
|
+ }else if( uPattern==MATCH_ONE && !prevEscape && uPattern!=(uint32_t)uEsc ){
|
|
/* Case 2. */
|
|
if( *zString==0 ) return 0;
|
|
SQLITE_ICU_SKIP_UTF8(zString);
|
|
|
|
- }else if( !prevEscape && uPattern==(uint32_t)uEsc){
|
|
+ }else if( uPattern==(uint32_t)uEsc && !prevEscape ){
|
|
/* Case 3. */
|
|
prevEscape = 1;
|
|
|
|
@@ -192578,15 +208137,15 @@ static int icuLikeCompare(
|
|
**
|
|
** A LIKE B
|
|
**
|
|
-** is implemented as like(B, A). If there is an escape character E,
|
|
+** is implemented as like(B, A). If there is an escape character E,
|
|
**
|
|
** A LIKE B ESCAPE E
|
|
**
|
|
** is mapped to like(B, A, E).
|
|
*/
|
|
static void icuLikeFunc(
|
|
- sqlite3_context *context,
|
|
- int argc,
|
|
+ sqlite3_context *context,
|
|
+ int argc,
|
|
sqlite3_value **argv
|
|
){
|
|
const unsigned char *zA = sqlite3_value_text(argv[0]);
|
|
@@ -192612,7 +208171,7 @@ static void icuLikeFunc(
|
|
if( zE==0 ) return;
|
|
U8_NEXT(zE, i, nE, uEsc);
|
|
if( i!=nE){
|
|
- sqlite3_result_error(context,
|
|
+ sqlite3_result_error(context,
|
|
"ESCAPE expression must be a single character", -1);
|
|
return;
|
|
}
|
|
@@ -192635,7 +208194,7 @@ static void icuRegexpDelete(void *p){
|
|
/*
|
|
** Implementation of SQLite REGEXP operator. This scalar function takes
|
|
** two arguments. The first is a regular expression pattern to compile
|
|
-** the second is a string to match against that pattern. If either
|
|
+** the second is a string to match against that pattern. If either
|
|
** argument is an SQL NULL, then NULL Is returned. Otherwise, the result
|
|
** is 1 if the string matches the pattern, or 0 otherwise.
|
|
**
|
|
@@ -192659,8 +208218,8 @@ static void icuRegexpFunc(sqlite3_context *p, int nArg, sqlite3_value **apArg){
|
|
|
|
(void)nArg; /* Unused parameter */
|
|
|
|
- /* If the left hand side of the regexp operator is NULL,
|
|
- ** then the result is also NULL.
|
|
+ /* If the left hand side of the regexp operator is NULL,
|
|
+ ** then the result is also NULL.
|
|
*/
|
|
if( !zString ){
|
|
return;
|
|
@@ -192676,8 +208235,9 @@ static void icuRegexpFunc(sqlite3_context *p, int nArg, sqlite3_value **apArg){
|
|
|
|
if( U_SUCCESS(status) ){
|
|
sqlite3_set_auxdata(p, 0, pExpr, icuRegexpDelete);
|
|
- }else{
|
|
- assert(!pExpr);
|
|
+ pExpr = sqlite3_get_auxdata(p, 0);
|
|
+ }
|
|
+ if( !pExpr ){
|
|
icuFunctionError(p, "uregex_open", status);
|
|
return;
|
|
}
|
|
@@ -192698,7 +208258,7 @@ static void icuRegexpFunc(sqlite3_context *p, int nArg, sqlite3_value **apArg){
|
|
}
|
|
|
|
/* Set the text that the regular expression operates on to a NULL
|
|
- ** pointer. This is not really necessary, but it is tidier than
|
|
+ ** pointer. This is not really necessary, but it is tidier than
|
|
** leaving the regular expression object configured with an invalid
|
|
** pointer after this function returns.
|
|
*/
|
|
@@ -192709,7 +208269,7 @@ static void icuRegexpFunc(sqlite3_context *p, int nArg, sqlite3_value **apArg){
|
|
}
|
|
|
|
/*
|
|
-** Implementations of scalar functions for case mapping - upper() and
|
|
+** Implementations of scalar functions for case mapping - upper() and
|
|
** lower(). Function upper() converts its input to upper-case (ABC).
|
|
** Function lower() converts to lower-case (abc).
|
|
**
|
|
@@ -192717,7 +208277,7 @@ static void icuRegexpFunc(sqlite3_context *p, int nArg, sqlite3_value **apArg){
|
|
** "language specific". Refer to ICU documentation for the differences
|
|
** between the two.
|
|
**
|
|
-** To utilise "general" case mapping, the upper() or lower() scalar
|
|
+** To utilise "general" case mapping, the upper() or lower() scalar
|
|
** functions are invoked with one argument:
|
|
**
|
|
** upper('ABC') -> 'abc'
|
|
@@ -192825,7 +208385,7 @@ static int icuCollationColl(
|
|
/*
|
|
** Implementation of the scalar function icu_load_collation().
|
|
**
|
|
-** This scalar function is used to add ICU collation based collation
|
|
+** This scalar function is used to add ICU collation based collation
|
|
** types to an SQLite database connection. It is intended to be called
|
|
** as follows:
|
|
**
|
|
@@ -192836,8 +208396,8 @@ static int icuCollationColl(
|
|
** collation sequence to create.
|
|
*/
|
|
static void icuLoadCollation(
|
|
- sqlite3_context *p,
|
|
- int nArg,
|
|
+ sqlite3_context *p,
|
|
+ int nArg,
|
|
sqlite3_value **apArg
|
|
){
|
|
sqlite3 *db = (sqlite3 *)sqlite3_user_data(p);
|
|
@@ -192863,7 +208423,7 @@ static void icuLoadCollation(
|
|
}
|
|
assert(p);
|
|
|
|
- rc = sqlite3_create_collation_v2(db, zName, SQLITE_UTF16, (void *)pUCollator,
|
|
+ rc = sqlite3_create_collation_v2(db, zName, SQLITE_UTF16, (void *)pUCollator,
|
|
icuCollationColl, icuCollationDel
|
|
);
|
|
if( rc!=SQLITE_OK ){
|
|
@@ -192901,11 +208461,11 @@ SQLITE_PRIVATE int sqlite3IcuInit(sqlite3 *db){
|
|
};
|
|
int rc = SQLITE_OK;
|
|
int i;
|
|
-
|
|
+
|
|
for(i=0; rc==SQLITE_OK && i<(int)(sizeof(scalars)/sizeof(scalars[0])); i++){
|
|
const struct IcuScalar *p = &scalars[i];
|
|
rc = sqlite3_create_function(
|
|
- db, p->zName, p->nArg, p->enc,
|
|
+ db, p->zName, p->nArg, p->enc,
|
|
p->iContext ? (void*)db : (void*)0,
|
|
p->xFunc, 0, 0
|
|
);
|
|
@@ -192919,7 +208479,7 @@ SQLITE_PRIVATE int sqlite3IcuInit(sqlite3 *db){
|
|
__declspec(dllexport)
|
|
#endif
|
|
SQLITE_API int sqlite3_icu_init(
|
|
- sqlite3 *db,
|
|
+ sqlite3 *db,
|
|
char **pzErrMsg,
|
|
const sqlite3_api_routines *pApi
|
|
){
|
|
@@ -193022,7 +208582,7 @@ static int icuDestroy(sqlite3_tokenizer *pTokenizer){
|
|
/*
|
|
** Prepare to begin tokenizing a particular string. The input
|
|
** string to be tokenized is pInput[0..nBytes-1]. A cursor
|
|
-** used to incrementally tokenize this string is returned in
|
|
+** used to incrementally tokenize this string is returned in
|
|
** *ppCursor.
|
|
*/
|
|
static int icuOpen(
|
|
@@ -193064,7 +208624,7 @@ static int icuOpen(
|
|
pCsr->aOffset = (int *)&pCsr->aChar[(nChar+3)&~3];
|
|
|
|
pCsr->aOffset[iOut] = iInput;
|
|
- U8_NEXT(zInput, iInput, nInput, c);
|
|
+ U8_NEXT(zInput, iInput, nInput, c);
|
|
while( c>0 ){
|
|
int isError = 0;
|
|
c = u_foldCase(c, opt);
|
|
@@ -193210,7 +208770,7 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(
|
|
*************************************************************************
|
|
**
|
|
**
|
|
-** OVERVIEW
|
|
+** OVERVIEW
|
|
**
|
|
** The RBU extension requires that the RBU update be packaged as an
|
|
** SQLite database. The tables it expects to find are described in
|
|
@@ -193218,34 +208778,34 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(
|
|
** that the user wishes to write to, a corresponding data_xyz table is
|
|
** created in the RBU database and populated with one row for each row to
|
|
** update, insert or delete from the target table.
|
|
-**
|
|
+**
|
|
** The update proceeds in three stages:
|
|
-**
|
|
+**
|
|
** 1) The database is updated. The modified database pages are written
|
|
** to a *-oal file. A *-oal file is just like a *-wal file, except
|
|
** that it is named "<database>-oal" instead of "<database>-wal".
|
|
** Because regular SQLite clients do not look for file named
|
|
** "<database>-oal", they go on using the original database in
|
|
** rollback mode while the *-oal file is being generated.
|
|
-**
|
|
+**
|
|
** During this stage RBU does not update the database by writing
|
|
** directly to the target tables. Instead it creates "imposter"
|
|
** tables using the SQLITE_TESTCTRL_IMPOSTER interface that it uses
|
|
** to update each b-tree individually. All updates required by each
|
|
** b-tree are completed before moving on to the next, and all
|
|
** updates are done in sorted key order.
|
|
-**
|
|
+**
|
|
** 2) The "<database>-oal" file is moved to the equivalent "<database>-wal"
|
|
** location using a call to rename(2). Before doing this the RBU
|
|
** module takes an EXCLUSIVE lock on the database file, ensuring
|
|
** that there are no other active readers.
|
|
-**
|
|
+**
|
|
** Once the EXCLUSIVE lock is released, any other database readers
|
|
** detect the new *-wal file and read the database in wal mode. At
|
|
** this point they see the new version of the database - including
|
|
** the updates made as part of the RBU update.
|
|
-**
|
|
-** 3) The new *-wal file is checkpointed. This proceeds in the same way
|
|
+**
|
|
+** 3) The new *-wal file is checkpointed. This proceeds in the same way
|
|
** as a regular database checkpoint, except that a single frame is
|
|
** checkpointed each time sqlite3rbu_step() is called. If the RBU
|
|
** handle is closed before the entire *-wal file is checkpointed,
|
|
@@ -193254,7 +208814,7 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(
|
|
** the future.
|
|
**
|
|
** POTENTIAL PROBLEMS
|
|
-**
|
|
+**
|
|
** The rename() call might not be portable. And RBU is not currently
|
|
** syncing the directory after renaming the file.
|
|
**
|
|
@@ -193276,7 +208836,7 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(
|
|
** fields are collected. This means we're probably writing a lot more
|
|
** data to disk when saving the state of an ongoing update to the RBU
|
|
** update database than is strictly necessary.
|
|
-**
|
|
+**
|
|
*/
|
|
|
|
/* #include <assert.h> */
|
|
@@ -193300,42 +208860,42 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(
|
|
**
|
|
*************************************************************************
|
|
**
|
|
-** This file contains the public interface for the RBU extension.
|
|
+** This file contains the public interface for the RBU extension.
|
|
*/
|
|
|
|
/*
|
|
** SUMMARY
|
|
**
|
|
-** Writing a transaction containing a large number of operations on
|
|
+** Writing a transaction containing a large number of operations on
|
|
** b-tree indexes that are collectively larger than the available cache
|
|
-** memory can be very inefficient.
|
|
+** memory can be very inefficient.
|
|
**
|
|
** The problem is that in order to update a b-tree, the leaf page (at least)
|
|
** containing the entry being inserted or deleted must be modified. If the
|
|
-** working set of leaves is larger than the available cache memory, then a
|
|
-** single leaf that is modified more than once as part of the transaction
|
|
+** working set of leaves is larger than the available cache memory, then a
|
|
+** single leaf that is modified more than once as part of the transaction
|
|
** may be loaded from or written to the persistent media multiple times.
|
|
** Additionally, because the index updates are likely to be applied in
|
|
-** random order, access to pages within the database is also likely to be in
|
|
+** random order, access to pages within the database is also likely to be in
|
|
** random order, which is itself quite inefficient.
|
|
**
|
|
** One way to improve the situation is to sort the operations on each index
|
|
** by index key before applying them to the b-tree. This leads to an IO
|
|
** pattern that resembles a single linear scan through the index b-tree,
|
|
-** and all but guarantees each modified leaf page is loaded and stored
|
|
+** and all but guarantees each modified leaf page is loaded and stored
|
|
** exactly once. SQLite uses this trick to improve the performance of
|
|
** CREATE INDEX commands. This extension allows it to be used to improve
|
|
** the performance of large transactions on existing databases.
|
|
**
|
|
-** Additionally, this extension allows the work involved in writing the
|
|
-** large transaction to be broken down into sub-transactions performed
|
|
-** sequentially by separate processes. This is useful if the system cannot
|
|
-** guarantee that a single update process will run for long enough to apply
|
|
-** the entire update, for example because the update is being applied on a
|
|
-** mobile device that is frequently rebooted. Even after the writer process
|
|
+** Additionally, this extension allows the work involved in writing the
|
|
+** large transaction to be broken down into sub-transactions performed
|
|
+** sequentially by separate processes. This is useful if the system cannot
|
|
+** guarantee that a single update process will run for long enough to apply
|
|
+** the entire update, for example because the update is being applied on a
|
|
+** mobile device that is frequently rebooted. Even after the writer process
|
|
** has committed one or more sub-transactions, other database clients continue
|
|
-** to read from the original database snapshot. In other words, partially
|
|
-** applied transactions are not visible to other clients.
|
|
+** to read from the original database snapshot. In other words, partially
|
|
+** applied transactions are not visible to other clients.
|
|
**
|
|
** "RBU" stands for "Resumable Bulk Update". As in a large database update
|
|
** transmitted via a wireless network to a mobile device. A transaction
|
|
@@ -193351,9 +208911,9 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(
|
|
**
|
|
** * INSERT statements may not use any default values.
|
|
**
|
|
-** * UPDATE and DELETE statements must identify their target rows by
|
|
+** * UPDATE and DELETE statements must identify their target rows by
|
|
** non-NULL PRIMARY KEY values. Rows with NULL values stored in PRIMARY
|
|
-** KEY fields may not be updated or deleted. If the table being written
|
|
+** KEY fields may not be updated or deleted. If the table being written
|
|
** has no PRIMARY KEY, affected rows must be identified by rowid.
|
|
**
|
|
** * UPDATE statements may not modify PRIMARY KEY columns.
|
|
@@ -193370,10 +208930,10 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(
|
|
** PREPARATION
|
|
**
|
|
** An "RBU update" is stored as a separate SQLite database. A database
|
|
-** containing an RBU update is an "RBU database". For each table in the
|
|
+** containing an RBU update is an "RBU database". For each table in the
|
|
** target database to be updated, the RBU database should contain a table
|
|
** named "data_<target name>" containing the same set of columns as the
|
|
-** target table, and one more - "rbu_control". The data_% table should
|
|
+** target table, and one more - "rbu_control". The data_% table should
|
|
** have no PRIMARY KEY or UNIQUE constraints, but each column should have
|
|
** the same type as the corresponding column in the target database.
|
|
** The "rbu_control" column should have no type at all. For example, if
|
|
@@ -193388,22 +208948,22 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(
|
|
** The order of the columns in the data_% table does not matter.
|
|
**
|
|
** Instead of a regular table, the RBU database may also contain virtual
|
|
-** tables or view named using the data_<target> naming scheme.
|
|
+** tables or views named using the data_<target> naming scheme.
|
|
**
|
|
-** Instead of the plain data_<target> naming scheme, RBU database tables
|
|
+** Instead of the plain data_<target> naming scheme, RBU database tables
|
|
** may also be named data<integer>_<target>, where <integer> is any sequence
|
|
** of zero or more numeric characters (0-9). This can be significant because
|
|
-** tables within the RBU database are always processed in order sorted by
|
|
+** tables within the RBU database are always processed in order sorted by
|
|
** name. By judicious selection of the <integer> portion of the names
|
|
** of the RBU tables the user can therefore control the order in which they
|
|
** are processed. This can be useful, for example, to ensure that "external
|
|
** content" FTS4 tables are updated before their underlying content tables.
|
|
**
|
|
** If the target database table is a virtual table or a table that has no
|
|
-** PRIMARY KEY declaration, the data_% table must also contain a column
|
|
-** named "rbu_rowid". This column is mapped to the tables implicit primary
|
|
-** key column - "rowid". Virtual tables for which the "rowid" column does
|
|
-** not function like a primary key value cannot be updated using RBU. For
|
|
+** PRIMARY KEY declaration, the data_% table must also contain a column
|
|
+** named "rbu_rowid". This column is mapped to the table's implicit primary
|
|
+** key column - "rowid". Virtual tables for which the "rowid" column does
|
|
+** not function like a primary key value cannot be updated using RBU. For
|
|
** example, if the target db contains either of the following:
|
|
**
|
|
** CREATE VIRTUAL TABLE x1 USING fts3(a, b);
|
|
@@ -193426,35 +208986,35 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(
|
|
** CREATE TABLE data_ft1(a, b, langid, rbu_rowid, rbu_control);
|
|
** CREATE TABLE data_ft1(a, b, rbu_rowid, rbu_control);
|
|
**
|
|
-** For each row to INSERT into the target database as part of the RBU
|
|
+** For each row to INSERT into the target database as part of the RBU
|
|
** update, the corresponding data_% table should contain a single record
|
|
** with the "rbu_control" column set to contain integer value 0. The
|
|
-** other columns should be set to the values that make up the new record
|
|
-** to insert.
|
|
+** other columns should be set to the values that make up the new record
|
|
+** to insert.
|
|
**
|
|
-** If the target database table has an INTEGER PRIMARY KEY, it is not
|
|
-** possible to insert a NULL value into the IPK column. Attempting to
|
|
+** If the target database table has an INTEGER PRIMARY KEY, it is not
|
|
+** possible to insert a NULL value into the IPK column. Attempting to
|
|
** do so results in an SQLITE_MISMATCH error.
|
|
**
|
|
-** For each row to DELETE from the target database as part of the RBU
|
|
+** For each row to DELETE from the target database as part of the RBU
|
|
** update, the corresponding data_% table should contain a single record
|
|
** with the "rbu_control" column set to contain integer value 1. The
|
|
** real primary key values of the row to delete should be stored in the
|
|
** corresponding columns of the data_% table. The values stored in the
|
|
** other columns are not used.
|
|
**
|
|
-** For each row to UPDATE from the target database as part of the RBU
|
|
+** For each row to UPDATE from the target database as part of the RBU
|
|
** update, the corresponding data_% table should contain a single record
|
|
** with the "rbu_control" column set to contain a value of type text.
|
|
-** The real primary key values identifying the row to update should be
|
|
+** The real primary key values identifying the row to update should be
|
|
** stored in the corresponding columns of the data_% table row, as should
|
|
-** the new values of all columns being update. The text value in the
|
|
+** the new values of all columns being update. The text value in the
|
|
** "rbu_control" column must contain the same number of characters as
|
|
** there are columns in the target database table, and must consist entirely
|
|
-** of 'x' and '.' characters (or in some special cases 'd' - see below). For
|
|
+** of 'x' and '.' characters (or in some special cases 'd' - see below). For
|
|
** each column that is being updated, the corresponding character is set to
|
|
** 'x'. For those that remain as they are, the corresponding character of the
|
|
-** rbu_control value should be set to '.'. For example, given the tables
|
|
+** rbu_control value should be set to '.'. For example, given the tables
|
|
** above, the update statement:
|
|
**
|
|
** UPDATE t1 SET c = 'usa' WHERE a = 4;
|
|
@@ -193468,30 +209028,30 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(
|
|
** target table with the value stored in the corresponding data_% column, the
|
|
** user-defined SQL function "rbu_delta()" is invoked and the result stored in
|
|
** the target table column. rbu_delta() is invoked with two arguments - the
|
|
-** original value currently stored in the target table column and the
|
|
+** original value currently stored in the target table column and the
|
|
** value specified in the data_xxx table.
|
|
**
|
|
** For example, this row:
|
|
**
|
|
** INSERT INTO data_t1(a, b, c, rbu_control) VALUES(4, NULL, 'usa', '..d');
|
|
**
|
|
-** is similar to an UPDATE statement such as:
|
|
+** is similar to an UPDATE statement such as:
|
|
**
|
|
** UPDATE t1 SET c = rbu_delta(c, 'usa') WHERE a = 4;
|
|
**
|
|
-** Finally, if an 'f' character appears in place of a 'd' or 's' in an
|
|
+** Finally, if an 'f' character appears in place of a 'd' or 's' in an
|
|
** ota_control string, the contents of the data_xxx table column is assumed
|
|
** to be a "fossil delta" - a patch to be applied to a blob value in the
|
|
** format used by the fossil source-code management system. In this case
|
|
-** the existing value within the target database table must be of type BLOB.
|
|
+** the existing value within the target database table must be of type BLOB.
|
|
** It is replaced by the result of applying the specified fossil delta to
|
|
** itself.
|
|
**
|
|
** If the target database table is a virtual table or a table with no PRIMARY
|
|
-** KEY, the rbu_control value should not include a character corresponding
|
|
+** KEY, the rbu_control value should not include a character corresponding
|
|
** to the rbu_rowid value. For example, this:
|
|
**
|
|
-** INSERT INTO data_ft1(a, b, rbu_rowid, rbu_control)
|
|
+** INSERT INTO data_ft1(a, b, rbu_rowid, rbu_control)
|
|
** VALUES(NULL, 'usa', 12, '.x');
|
|
**
|
|
** causes a result similar to:
|
|
@@ -193501,14 +209061,14 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(
|
|
** The data_xxx tables themselves should have no PRIMARY KEY declarations.
|
|
** However, RBU is more efficient if reading the rows in from each data_xxx
|
|
** table in "rowid" order is roughly the same as reading them sorted by
|
|
-** the PRIMARY KEY of the corresponding target database table. In other
|
|
-** words, rows should be sorted using the destination table PRIMARY KEY
|
|
+** the PRIMARY KEY of the corresponding target database table. In other
|
|
+** words, rows should be sorted using the destination table PRIMARY KEY
|
|
** fields before they are inserted into the data_xxx tables.
|
|
**
|
|
** USAGE
|
|
**
|
|
-** The API declared below allows an application to apply an RBU update
|
|
-** stored on disk to an existing target database. Essentially, the
|
|
+** The API declared below allows an application to apply an RBU update
|
|
+** stored on disk to an existing target database. Essentially, the
|
|
** application:
|
|
**
|
|
** 1) Opens an RBU handle using the sqlite3rbu_open() function.
|
|
@@ -193519,24 +209079,24 @@ SQLITE_PRIVATE void sqlite3Fts3IcuTokenizerModule(
|
|
**
|
|
** 3) Calls the sqlite3rbu_step() function one or more times on
|
|
** the new handle. Each call to sqlite3rbu_step() performs a single
|
|
-** b-tree operation, so thousands of calls may be required to apply
|
|
+** b-tree operation, so thousands of calls may be required to apply
|
|
** a complete update.
|
|
**
|
|
** 4) Calls sqlite3rbu_close() to close the RBU update handle. If
|
|
** sqlite3rbu_step() has been called enough times to completely
|
|
** apply the update to the target database, then the RBU database
|
|
-** is marked as fully applied. Otherwise, the state of the RBU
|
|
-** update application is saved in the RBU database for later
|
|
+** is marked as fully applied. Otherwise, the state of the RBU
|
|
+** update application is saved in the RBU database for later
|
|
** resumption.
|
|
**
|
|
** See comments below for more detail on APIs.
|
|
**
|
|
** If an update is only partially applied to the target database by the
|
|
-** time sqlite3rbu_close() is called, various state information is saved
|
|
+** time sqlite3rbu_close() is called, various state information is saved
|
|
** within the RBU database. This allows subsequent processes to automatically
|
|
** resume the RBU update from where it left off.
|
|
**
|
|
-** To remove all RBU extension state information, returning an RBU database
|
|
+** To remove all RBU extension state information, returning an RBU database
|
|
** to its original contents, it is sufficient to drop all tables that begin
|
|
** with the prefix "rbu_"
|
|
**
|
|
@@ -193572,21 +209132,21 @@ typedef struct sqlite3rbu sqlite3rbu;
|
|
** the path to the RBU database. Each call to this function must be matched
|
|
** by a call to sqlite3rbu_close(). When opening the databases, RBU passes
|
|
** the SQLITE_CONFIG_URI flag to sqlite3_open_v2(). So if either zTarget
|
|
-** or zRbu begin with "file:", it will be interpreted as an SQLite
|
|
+** or zRbu begin with "file:", it will be interpreted as an SQLite
|
|
** database URI, not a regular file name.
|
|
**
|
|
-** If the zState argument is passed a NULL value, the RBU extension stores
|
|
-** the current state of the update (how many rows have been updated, which
|
|
+** If the zState argument is passed a NULL value, the RBU extension stores
|
|
+** the current state of the update (how many rows have been updated, which
|
|
** indexes are yet to be updated etc.) within the RBU database itself. This
|
|
** can be convenient, as it means that the RBU application does not need to
|
|
-** organize removing a separate state file after the update is concluded.
|
|
-** Or, if zState is non-NULL, it must be a path to a database file in which
|
|
+** organize removing a separate state file after the update is concluded.
|
|
+** Or, if zState is non-NULL, it must be a path to a database file in which
|
|
** the RBU extension can store the state of the update.
|
|
**
|
|
** When resuming an RBU update, the zState argument must be passed the same
|
|
** value as when the RBU update was started.
|
|
**
|
|
-** Once the RBU update is finished, the RBU extension does not
|
|
+** Once the RBU update is finished, the RBU extension does not
|
|
** automatically remove any zState database file, even if it created it.
|
|
**
|
|
** By default, RBU uses the default VFS to access the files on disk. To
|
|
@@ -193599,7 +209159,7 @@ typedef struct sqlite3rbu sqlite3rbu;
|
|
** the zipvfs_create_vfs() API below for details on using RBU with zipvfs.
|
|
*/
|
|
SQLITE_API sqlite3rbu *sqlite3rbu_open(
|
|
- const char *zTarget,
|
|
+ const char *zTarget,
|
|
const char *zRbu,
|
|
const char *zState
|
|
);
|
|
@@ -193609,13 +209169,13 @@ SQLITE_API sqlite3rbu *sqlite3rbu_open(
|
|
** An RBU vacuum is similar to SQLite's built-in VACUUM command, except
|
|
** that it can be suspended and resumed like an RBU update.
|
|
**
|
|
-** The second argument to this function identifies a database in which
|
|
-** to store the state of the RBU vacuum operation if it is suspended. The
|
|
+** The second argument to this function identifies a database in which
|
|
+** to store the state of the RBU vacuum operation if it is suspended. The
|
|
** first time sqlite3rbu_vacuum() is called, to start an RBU vacuum
|
|
** operation, the state database should either not exist or be empty
|
|
-** (contain no tables). If an RBU vacuum is suspended by calling
|
|
+** (contain no tables). If an RBU vacuum is suspended by calling
|
|
** sqlite3rbu_close() on the RBU handle before sqlite3rbu_step() has
|
|
-** returned SQLITE_DONE, the vacuum state is stored in the state database.
|
|
+** returned SQLITE_DONE, the vacuum state is stored in the state database.
|
|
** The vacuum can be resumed by calling this function to open a new RBU
|
|
** handle specifying the same target and state databases.
|
|
**
|
|
@@ -193623,26 +209183,26 @@ SQLITE_API sqlite3rbu *sqlite3rbu_open(
|
|
** name of the state database is "<database>-vacuum", where <database>
|
|
** is the name of the target database file. In this case, on UNIX, if the
|
|
** state database is not already present in the file-system, it is created
|
|
-** with the same permissions as the target db is made.
|
|
+** with the same permissions as the target db is made.
|
|
**
|
|
-** With an RBU vacuum, it is an SQLITE_MISUSE error if the name of the
|
|
-** state database ends with "-vactmp". This name is reserved for internal
|
|
+** With an RBU vacuum, it is an SQLITE_MISUSE error if the name of the
|
|
+** state database ends with "-vactmp". This name is reserved for internal
|
|
** use.
|
|
**
|
|
** This function does not delete the state database after an RBU vacuum
|
|
** is completed, even if it created it. However, if the call to
|
|
** sqlite3rbu_close() returns any value other than SQLITE_OK, the contents
|
|
** of the state tables within the state database are zeroed. This way,
|
|
-** the next call to sqlite3rbu_vacuum() opens a handle that starts a
|
|
+** the next call to sqlite3rbu_vacuum() opens a handle that starts a
|
|
** new RBU vacuum operation.
|
|
**
|
|
** As with sqlite3rbu_open(), Zipvfs users should rever to the comment
|
|
-** describing the sqlite3rbu_create_vfs() API function below for
|
|
-** a description of the complications associated with using RBU with
|
|
+** describing the sqlite3rbu_create_vfs() API function below for
|
|
+** a description of the complications associated with using RBU with
|
|
** zipvfs databases.
|
|
*/
|
|
SQLITE_API sqlite3rbu *sqlite3rbu_vacuum(
|
|
- const char *zTarget,
|
|
+ const char *zTarget,
|
|
const char *zState
|
|
);
|
|
|
|
@@ -193654,7 +209214,7 @@ SQLITE_API sqlite3rbu *sqlite3rbu_vacuum(
|
|
** is removed entirely. If the second parameter is negative, the limit is
|
|
** not modified (this is useful for querying the current limit).
|
|
**
|
|
-** In all cases the returned value is the current limit in bytes (zero
|
|
+** In all cases the returned value is the current limit in bytes (zero
|
|
** indicates unlimited).
|
|
**
|
|
** If the temp space limit is exceeded during operation, an SQLITE_FULL
|
|
@@ -193663,13 +209223,13 @@ SQLITE_API sqlite3rbu *sqlite3rbu_vacuum(
|
|
SQLITE_API sqlite3_int64 sqlite3rbu_temp_size_limit(sqlite3rbu*, sqlite3_int64);
|
|
|
|
/*
|
|
-** Return the current amount of temp file space, in bytes, currently used by
|
|
+** Return the current amount of temp file space, in bytes, currently used by
|
|
** the RBU handle passed as the only argument.
|
|
*/
|
|
SQLITE_API sqlite3_int64 sqlite3rbu_temp_size(sqlite3rbu*);
|
|
|
|
/*
|
|
-** Internally, each RBU connection uses a separate SQLite database
|
|
+** Internally, each RBU connection uses a separate SQLite database
|
|
** connection to access the target and rbu update databases. This
|
|
** API allows the application direct access to these database handles.
|
|
**
|
|
@@ -193680,10 +209240,10 @@ SQLITE_API sqlite3_int64 sqlite3rbu_temp_size(sqlite3rbu*);
|
|
** following scenarios:
|
|
**
|
|
** * If any target tables are virtual tables, it may be necessary to
|
|
-** call sqlite3_create_module() on the target database handle to
|
|
+** call sqlite3_create_module() on the target database handle to
|
|
** register the required virtual table implementations.
|
|
**
|
|
-** * If the data_xxx tables in the RBU source database are virtual
|
|
+** * If the data_xxx tables in the RBU source database are virtual
|
|
** tables, the application may need to call sqlite3_create_module() on
|
|
** the rbu update db handle to any required virtual table
|
|
** implementations.
|
|
@@ -193702,12 +209262,12 @@ SQLITE_API sqlite3_int64 sqlite3rbu_temp_size(sqlite3rbu*);
|
|
SQLITE_API sqlite3 *sqlite3rbu_db(sqlite3rbu*, int bRbu);
|
|
|
|
/*
|
|
-** Do some work towards applying the RBU update to the target db.
|
|
+** Do some work towards applying the RBU update to the target db.
|
|
**
|
|
-** Return SQLITE_DONE if the update has been completely applied, or
|
|
+** Return SQLITE_DONE if the update has been completely applied, or
|
|
** SQLITE_OK if no error occurs but there remains work to do to apply
|
|
-** the RBU update. If an error does occur, some other error code is
|
|
-** returned.
|
|
+** the RBU update. If an error does occur, some other error code is
|
|
+** returned.
|
|
**
|
|
** Once a call to sqlite3rbu_step() has returned a value other than
|
|
** SQLITE_OK, all subsequent calls on the same RBU handle are no-ops
|
|
@@ -193720,7 +209280,7 @@ SQLITE_API int sqlite3rbu_step(sqlite3rbu *pRbu);
|
|
**
|
|
** If a power failure or application crash occurs during an update, following
|
|
** system recovery RBU may resume the update from the point at which the state
|
|
-** was last saved. In other words, from the most recent successful call to
|
|
+** was last saved. In other words, from the most recent successful call to
|
|
** sqlite3rbu_close() or this function.
|
|
**
|
|
** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
|
|
@@ -193728,7 +209288,7 @@ SQLITE_API int sqlite3rbu_step(sqlite3rbu *pRbu);
|
|
SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *pRbu);
|
|
|
|
/*
|
|
-** Close an RBU handle.
|
|
+** Close an RBU handle.
|
|
**
|
|
** If the RBU update has been completely applied, mark the RBU database
|
|
** as fully applied. Otherwise, assuming no error has occurred, save the
|
|
@@ -193742,20 +209302,20 @@ SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *pRbu);
|
|
** eventually free any such buffer using sqlite3_free().
|
|
**
|
|
** Otherwise, if no error occurs, this function returns SQLITE_OK if the
|
|
-** update has been partially applied, or SQLITE_DONE if it has been
|
|
+** update has been partially applied, or SQLITE_DONE if it has been
|
|
** completely applied.
|
|
*/
|
|
SQLITE_API int sqlite3rbu_close(sqlite3rbu *pRbu, char **pzErrmsg);
|
|
|
|
/*
|
|
-** Return the total number of key-value operations (inserts, deletes or
|
|
+** Return the total number of key-value operations (inserts, deletes or
|
|
** updates) that have been performed on the target database since the
|
|
** current RBU update was started.
|
|
*/
|
|
SQLITE_API sqlite3_int64 sqlite3rbu_progress(sqlite3rbu *pRbu);
|
|
|
|
/*
|
|
-** Obtain permyriadage (permyriadage is to 10000 as percentage is to 100)
|
|
+** Obtain permyriadage (permyriadage is to 10000 as percentage is to 100)
|
|
** progress indications for the two stages of an RBU update. This API may
|
|
** be useful for driving GUI progress indicators and similar.
|
|
**
|
|
@@ -193768,16 +209328,16 @@ SQLITE_API sqlite3_int64 sqlite3rbu_progress(sqlite3rbu *pRbu);
|
|
** The update is visible to non-RBU clients during stage 2. During stage 1
|
|
** non-RBU reader clients may see the original database.
|
|
**
|
|
-** If this API is called during stage 2 of the update, output variable
|
|
+** If this API is called during stage 2 of the update, output variable
|
|
** (*pnOne) is set to 10000 to indicate that stage 1 has finished and (*pnTwo)
|
|
** to a value between 0 and 10000 to indicate the permyriadage progress of
|
|
-** stage 2. A value of 5000 indicates that stage 2 is half finished,
|
|
+** stage 2. A value of 5000 indicates that stage 2 is half finished,
|
|
** 9000 indicates that it is 90% finished, and so on.
|
|
**
|
|
-** If this API is called during stage 1 of the update, output variable
|
|
+** If this API is called during stage 1 of the update, output variable
|
|
** (*pnTwo) is set to 0 to indicate that stage 2 has not yet started. The
|
|
-** value to which (*pnOne) is set depends on whether or not the RBU
|
|
-** database contains an "rbu_count" table. The rbu_count table, if it
|
|
+** value to which (*pnOne) is set depends on whether or not the RBU
|
|
+** database contains an "rbu_count" table. The rbu_count table, if it
|
|
** exists, must contain the same columns as the following:
|
|
**
|
|
** CREATE TABLE rbu_count(tbl TEXT PRIMARY KEY, cnt INTEGER) WITHOUT ROWID;
|
|
@@ -193834,22 +209394,50 @@ SQLITE_API void sqlite3rbu_bp_progress(sqlite3rbu *pRbu, int *pnOne, int*pnTwo);
|
|
|
|
SQLITE_API int sqlite3rbu_state(sqlite3rbu *pRbu);
|
|
|
|
+/*
|
|
+** As part of applying an RBU update or performing an RBU vacuum operation,
|
|
+** the system must at one point move the *-oal file to the equivalent *-wal
|
|
+** path. Normally, it does this by invoking POSIX function rename(2) directly.
|
|
+** Except on WINCE platforms, where it uses win32 API MoveFileW(). This
|
|
+** function may be used to register a callback that the RBU module will invoke
|
|
+** instead of one of these APIs.
|
|
+**
|
|
+** If a callback is registered with an RBU handle, it invokes it instead
|
|
+** of rename(2) when it needs to move a file within the file-system. The
|
|
+** first argument passed to the xRename() callback is a copy of the second
|
|
+** argument (pArg) passed to this function. The second is the full path
|
|
+** to the file to move and the third the full path to which it should be
|
|
+** moved. The callback function should return SQLITE_OK to indicate
|
|
+** success. If an error occurs, it should return an SQLite error code.
|
|
+** In this case the RBU operation will be abandoned and the error returned
|
|
+** to the RBU user.
|
|
+**
|
|
+** Passing a NULL pointer in place of the xRename argument to this function
|
|
+** restores the default behaviour.
|
|
+*/
|
|
+SQLITE_API void sqlite3rbu_rename_handler(
|
|
+ sqlite3rbu *pRbu,
|
|
+ void *pArg,
|
|
+ int (*xRename)(void *pArg, const char *zOld, const char *zNew)
|
|
+);
|
|
+
|
|
+
|
|
/*
|
|
** Create an RBU VFS named zName that accesses the underlying file-system
|
|
-** via existing VFS zParent. Or, if the zParent parameter is passed NULL,
|
|
+** via existing VFS zParent. Or, if the zParent parameter is passed NULL,
|
|
** then the new RBU VFS uses the default system VFS to access the file-system.
|
|
-** The new object is registered as a non-default VFS with SQLite before
|
|
+** The new object is registered as a non-default VFS with SQLite before
|
|
** returning.
|
|
**
|
|
** Part of the RBU implementation uses a custom VFS object. Usually, this
|
|
-** object is created and deleted automatically by RBU.
|
|
+** object is created and deleted automatically by RBU.
|
|
**
|
|
** The exception is for applications that also use zipvfs. In this case,
|
|
** the custom VFS must be explicitly created by the user before the RBU
|
|
** handle is opened. The RBU VFS should be installed so that the zipvfs
|
|
-** VFS uses the RBU VFS, which in turn uses any other VFS layers in use
|
|
+** VFS uses the RBU VFS, which in turn uses any other VFS layers in use
|
|
** (for example multiplexor) to access the file-system. For example,
|
|
-** to assemble an RBU enabled VFS stack that uses both zipvfs and
|
|
+** to assemble an RBU enabled VFS stack that uses both zipvfs and
|
|
** multiplexor (error checking omitted):
|
|
**
|
|
** // Create a VFS named "multiplex" (not the default).
|
|
@@ -193871,9 +209459,9 @@ SQLITE_API int sqlite3rbu_state(sqlite3rbu *pRbu);
|
|
** may be used by RBU clients. Attempting to use RBU with a zipvfs VFS stack
|
|
** that does not include the RBU layer results in an error.
|
|
**
|
|
-** The overhead of adding the "rbu" VFS to the system is negligible for
|
|
-** non-RBU users. There is no harm in an application accessing the
|
|
-** file-system via "rbu" all the time, even if it only uses RBU functionality
|
|
+** The overhead of adding the "rbu" VFS to the system is negligible for
|
|
+** non-RBU users. There is no harm in an application accessing the
|
|
+** file-system via "rbu" all the time, even if it only uses RBU functionality
|
|
** occasionally.
|
|
*/
|
|
SQLITE_API int sqlite3rbu_create_vfs(const char *zName, const char *zParent);
|
|
@@ -193918,6 +209506,13 @@ SQLITE_API void sqlite3rbu_destroy_vfs(const char *zName);
|
|
# define SWAP(TYPE,A,B) {TYPE t=A; A=B; B=t;}
|
|
#endif
|
|
|
|
+/*
|
|
+** Name of the URI option that causes RBU to take an exclusive lock as
|
|
+** part of the incremental checkpoint operation.
|
|
+*/
|
|
+#define RBU_EXCLUSIVE_CHECKPOINT "rbu_exclusive_checkpoint"
|
|
+
|
|
+
|
|
/*
|
|
** The rbu_state table is used to save the state of a partially applied
|
|
** update so that it can be resumed later. The table consists of integer
|
|
@@ -193926,17 +209521,17 @@ SQLITE_API void sqlite3rbu_destroy_vfs(const char *zName);
|
|
** RBU_STATE_STAGE:
|
|
** May be set to integer values 1, 2, 4 or 5. As follows:
|
|
** 1: the *-rbu file is currently under construction.
|
|
-** 2: the *-rbu file has been constructed, but not yet moved
|
|
+** 2: the *-rbu file has been constructed, but not yet moved
|
|
** to the *-wal path.
|
|
** 4: the checkpoint is underway.
|
|
** 5: the rbu update has been checkpointed.
|
|
**
|
|
** RBU_STATE_TBL:
|
|
-** Only valid if STAGE==1. The target database name of the table
|
|
+** Only valid if STAGE==1. The target database name of the table
|
|
** currently being written.
|
|
**
|
|
** RBU_STATE_IDX:
|
|
-** Only valid if STAGE==1. The target database name of the index
|
|
+** Only valid if STAGE==1. The target database name of the index
|
|
** currently being written, or NULL if the main table is currently being
|
|
** updated.
|
|
**
|
|
@@ -193956,14 +209551,14 @@ SQLITE_API void sqlite3rbu_destroy_vfs(const char *zName);
|
|
** be continued if this happens).
|
|
**
|
|
** RBU_STATE_COOKIE:
|
|
-** Valid if STAGE==1. The current change-counter cookie value in the
|
|
+** Valid if STAGE==1. The current change-counter cookie value in the
|
|
** target db file.
|
|
**
|
|
** RBU_STATE_OALSZ:
|
|
** Valid if STAGE==1. The size in bytes of the *-oal file.
|
|
**
|
|
** RBU_STATE_DATATBL:
|
|
-** Only valid if STAGE==1. The RBU database name of the table
|
|
+** Only valid if STAGE==1. The RBU database name of the table
|
|
** currently being read.
|
|
*/
|
|
#define RBU_STATE_STAGE 1
|
|
@@ -194045,7 +209640,7 @@ struct RbuSpan {
|
|
** the target database that require updating. For each such table, the
|
|
** iterator visits, in order:
|
|
**
|
|
-** * the table itself,
|
|
+** * the table itself,
|
|
** * each index of the table (zero or more points to visit), and
|
|
** * a special "cleanup table" state.
|
|
**
|
|
@@ -194059,7 +209654,7 @@ struct RbuSpan {
|
|
** this array set set to 1. This is because in that case, the module has
|
|
** no way to tell which fields will be required to add and remove entries
|
|
** from the partial indexes.
|
|
-**
|
|
+**
|
|
*/
|
|
struct RbuObjIter {
|
|
sqlite3_stmt *pTblIter; /* Iterate through tables */
|
|
@@ -194141,7 +209736,7 @@ struct RbuFrame {
|
|
**
|
|
** nPhaseOneStep:
|
|
** If the RBU database contains an rbu_count table, this value is set to
|
|
-** a running estimate of the number of b-tree operations required to
|
|
+** a running estimate of the number of b-tree operations required to
|
|
** finish populating the *-oal file. This allows the sqlite3_bp_progress()
|
|
** API to calculate the permyriadage progress of populating the *-oal file
|
|
** using the formula:
|
|
@@ -194161,7 +209756,7 @@ struct RbuFrame {
|
|
**
|
|
** * the RBU update contains any UPDATE operations. If the PK specified
|
|
** for an UPDATE operation does not exist in the target table, then
|
|
-** no b-tree operations are required on index b-trees. Or if the
|
|
+** no b-tree operations are required on index b-trees. Or if the
|
|
** specified PK does exist, then (nIndex*2) such operations are
|
|
** required (one delete and one insert on each index b-tree).
|
|
**
|
|
@@ -194194,6 +209789,8 @@ struct sqlite3rbu {
|
|
int nPagePerSector; /* Pages per sector for pTargetFd */
|
|
i64 iOalSz;
|
|
i64 nPhaseOneStep;
|
|
+ void *pRenameArg;
|
|
+ int (*xRename)(void*, const char*, const char*);
|
|
|
|
/* The following state variables are used as part of the incremental
|
|
** checkpoint stage (eStage==RBU_STAGE_CKPT). See comments surrounding
|
|
@@ -194518,7 +210115,7 @@ static void rbuFossilDeltaFunc(
|
|
/*
|
|
** Prepare the SQL statement in buffer zSql against database handle db.
|
|
** If successful, set *ppStmt to point to the new statement and return
|
|
-** SQLITE_OK.
|
|
+** SQLITE_OK.
|
|
**
|
|
** Otherwise, if an error does occur, set *ppStmt to NULL and return
|
|
** an SQLite error code. Additionally, set output variable *pzErrmsg to
|
|
@@ -194526,7 +210123,7 @@ static void rbuFossilDeltaFunc(
|
|
** of the caller to (eventually) free this buffer using sqlite3_free().
|
|
*/
|
|
static int prepareAndCollectError(
|
|
- sqlite3 *db,
|
|
+ sqlite3 *db,
|
|
sqlite3_stmt **ppStmt,
|
|
char **pzErrmsg,
|
|
const char *zSql
|
|
@@ -194558,9 +210155,9 @@ static int resetAndCollectError(sqlite3_stmt *pStmt, char **pzErrmsg){
|
|
/*
|
|
** Unless it is NULL, argument zSql points to a buffer allocated using
|
|
** sqlite3_malloc containing an SQL statement. This function prepares the SQL
|
|
-** statement against database db and frees the buffer. If statement
|
|
-** compilation is successful, *ppStmt is set to point to the new statement
|
|
-** handle and SQLITE_OK is returned.
|
|
+** statement against database db and frees the buffer. If statement
|
|
+** compilation is successful, *ppStmt is set to point to the new statement
|
|
+** handle and SQLITE_OK is returned.
|
|
**
|
|
** Otherwise, if an error occurs, *ppStmt is set to NULL and an error code
|
|
** returned. In this case, *pzErrmsg may also be set to point to an error
|
|
@@ -194571,7 +210168,7 @@ static int resetAndCollectError(sqlite3_stmt *pStmt, char **pzErrmsg){
|
|
** In this case SQLITE_NOMEM is returned and *ppStmt set to NULL.
|
|
*/
|
|
static int prepareFreeAndCollectError(
|
|
- sqlite3 *db,
|
|
+ sqlite3 *db,
|
|
sqlite3_stmt **ppStmt,
|
|
char **pzErrmsg,
|
|
char *zSql
|
|
@@ -194628,7 +210225,7 @@ static void rbuObjIterClearStatements(RbuObjIter *pIter){
|
|
}
|
|
sqlite3_free(pIter->aIdxCol);
|
|
sqlite3_free(pIter->zIdxSql);
|
|
-
|
|
+
|
|
pIter->pSelect = 0;
|
|
pIter->pInsert = 0;
|
|
pIter->pDelete = 0;
|
|
@@ -194655,16 +210252,16 @@ static void rbuObjIterFinalize(RbuObjIter *pIter){
|
|
/*
|
|
** Advance the iterator to the next position.
|
|
**
|
|
-** If no error occurs, SQLITE_OK is returned and the iterator is left
|
|
-** pointing to the next entry. Otherwise, an error code and message is
|
|
-** left in the RBU handle passed as the first argument. A copy of the
|
|
+** If no error occurs, SQLITE_OK is returned and the iterator is left
|
|
+** pointing to the next entry. Otherwise, an error code and message is
|
|
+** left in the RBU handle passed as the first argument. A copy of the
|
|
** error code is returned.
|
|
*/
|
|
static int rbuObjIterNext(sqlite3rbu *p, RbuObjIter *pIter){
|
|
int rc = p->rc;
|
|
if( rc==SQLITE_OK ){
|
|
|
|
- /* Free any SQLite statements used while processing the previous object */
|
|
+ /* Free any SQLite statements used while processing the previous object */
|
|
rbuObjIterClearStatements(pIter);
|
|
if( pIter->zIdx==0 ){
|
|
rc = sqlite3_exec(p->dbMain,
|
|
@@ -194723,7 +210320,7 @@ static int rbuObjIterNext(sqlite3rbu *p, RbuObjIter *pIter){
|
|
** The implementation of the rbu_target_name() SQL function. This function
|
|
** accepts one or two arguments. The first argument is the name of a table -
|
|
** the name of a table in the RBU database. The second, if it is present, is 1
|
|
-** for a view or 0 for a table.
|
|
+** for a view or 0 for a table.
|
|
**
|
|
** For a non-vacuum RBU handle, if the table name matches the pattern:
|
|
**
|
|
@@ -194771,19 +210368,19 @@ static void rbuTargetNameFunc(
|
|
/*
|
|
** Initialize the iterator structure passed as the second argument.
|
|
**
|
|
-** If no error occurs, SQLITE_OK is returned and the iterator is left
|
|
-** pointing to the first entry. Otherwise, an error code and message is
|
|
-** left in the RBU handle passed as the first argument. A copy of the
|
|
+** If no error occurs, SQLITE_OK is returned and the iterator is left
|
|
+** pointing to the first entry. Otherwise, an error code and message is
|
|
+** left in the RBU handle passed as the first argument. A copy of the
|
|
** error code is returned.
|
|
*/
|
|
static int rbuObjIterFirst(sqlite3rbu *p, RbuObjIter *pIter){
|
|
int rc;
|
|
memset(pIter, 0, sizeof(RbuObjIter));
|
|
|
|
- rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pTblIter, &p->zErrmsg,
|
|
+ rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pTblIter, &p->zErrmsg,
|
|
sqlite3_mprintf(
|
|
"SELECT rbu_target_name(name, type='view') AS target, name "
|
|
- "FROM sqlite_master "
|
|
+ "FROM sqlite_schema "
|
|
"WHERE type IN ('table', 'view') AND target IS NOT NULL "
|
|
" %s "
|
|
"ORDER BY name"
|
|
@@ -194792,7 +210389,7 @@ static int rbuObjIterFirst(sqlite3rbu *p, RbuObjIter *pIter){
|
|
if( rc==SQLITE_OK ){
|
|
rc = prepareAndCollectError(p->dbMain, &pIter->pIdxIter, &p->zErrmsg,
|
|
"SELECT name, rootpage, sql IS NULL OR substr(8, 6)=='UNIQUE' "
|
|
- " FROM main.sqlite_master "
|
|
+ " FROM main.sqlite_schema "
|
|
" WHERE type='index' AND tbl_name = ?"
|
|
);
|
|
}
|
|
@@ -194808,7 +210405,7 @@ static int rbuObjIterFirst(sqlite3rbu *p, RbuObjIter *pIter){
|
|
**
|
|
** If an error has already occurred (p->rc is already set to something other
|
|
** than SQLITE_OK), then this function returns NULL without modifying the
|
|
-** stored error code. In this case it still calls sqlite3_free() on any
|
|
+** stored error code. In this case it still calls sqlite3_free() on any
|
|
** printf() parameters associated with %z conversions.
|
|
*/
|
|
static char *rbuMPrintf(sqlite3rbu *p, const char *zFmt, ...){
|
|
@@ -194854,12 +210451,12 @@ static int rbuMPrintfExec(sqlite3rbu *p, sqlite3 *db, const char *zFmt, ...){
|
|
}
|
|
|
|
/*
|
|
-** Attempt to allocate and return a pointer to a zeroed block of nByte
|
|
-** bytes.
|
|
+** Attempt to allocate and return a pointer to a zeroed block of nByte
|
|
+** bytes.
|
|
**
|
|
-** If an error (i.e. an OOM condition) occurs, return NULL and leave an
|
|
-** error code in the rbu handle passed as the first argument. Or, if an
|
|
-** error has already occurred when this function is called, return NULL
|
|
+** If an error (i.e. an OOM condition) occurs, return NULL and leave an
|
|
+** error code in the rbu handle passed as the first argument. Or, if an
|
|
+** error has already occurred when this function is called, return NULL
|
|
** immediately without attempting the allocation or modifying the stored
|
|
** error code.
|
|
*/
|
|
@@ -194956,7 +210553,7 @@ static void rbuFinalize(sqlite3rbu *p, sqlite3_stmt *pStmt){
|
|
** RBU_PK_VTAB: Table is a virtual table.
|
|
**
|
|
** Argument *piPk is also of type (int*), and also points to an output
|
|
-** parameter. Unless the table has an external primary key index
|
|
+** parameter. Unless the table has an external primary key index
|
|
** (i.e. unless *peType is set to 3), then *piPk is set to zero. Or,
|
|
** if the table does have an external primary key index, then *piPk
|
|
** is set to the root page number of the primary key index before
|
|
@@ -194964,12 +210561,12 @@ static void rbuFinalize(sqlite3rbu *p, sqlite3_stmt *pStmt){
|
|
**
|
|
** ALGORITHM:
|
|
**
|
|
-** if( no entry exists in sqlite_master ){
|
|
+** if( no entry exists in sqlite_schema ){
|
|
** return RBU_PK_NOTABLE
|
|
** }else if( sql for the entry starts with "CREATE VIRTUAL" ){
|
|
** return RBU_PK_VTAB
|
|
** }else if( "PRAGMA index_list()" for the table contains a "pk" index ){
|
|
-** if( the index that is the pk exists in sqlite_master ){
|
|
+** if( the index that is the pk exists in sqlite_schema ){
|
|
** *piPK = rootpage of that index.
|
|
** return RBU_PK_EXTERNAL
|
|
** }else{
|
|
@@ -194989,9 +210586,9 @@ static void rbuTableType(
|
|
int *piPk
|
|
){
|
|
/*
|
|
- ** 0) SELECT count(*) FROM sqlite_master where name=%Q AND IsVirtual(%Q)
|
|
+ ** 0) SELECT count(*) FROM sqlite_schema where name=%Q AND IsVirtual(%Q)
|
|
** 1) PRAGMA index_list = ?
|
|
- ** 2) SELECT count(*) FROM sqlite_master where name=%Q
|
|
+ ** 2) SELECT count(*) FROM sqlite_schema where name=%Q
|
|
** 3) PRAGMA table_info = ?
|
|
*/
|
|
sqlite3_stmt *aStmt[4] = {0, 0, 0, 0};
|
|
@@ -195000,10 +210597,12 @@ static void rbuTableType(
|
|
*piPk = 0;
|
|
|
|
assert( p->rc==SQLITE_OK );
|
|
- p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[0], &p->zErrmsg,
|
|
+ p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[0], &p->zErrmsg,
|
|
sqlite3_mprintf(
|
|
- "SELECT (sql LIKE 'create virtual%%'), rootpage"
|
|
- " FROM sqlite_master"
|
|
+ "SELECT "
|
|
+ " (sql COLLATE nocase BETWEEN 'CREATE VIRTUAL' AND 'CREATE VIRTUAM'),"
|
|
+ " rootpage"
|
|
+ " FROM sqlite_schema"
|
|
" WHERE name=%Q", zTab
|
|
));
|
|
if( p->rc!=SQLITE_OK || sqlite3_step(aStmt[0])!=SQLITE_ROW ){
|
|
@@ -195016,7 +210615,7 @@ static void rbuTableType(
|
|
}
|
|
*piTnum = sqlite3_column_int(aStmt[0], 1);
|
|
|
|
- p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[1], &p->zErrmsg,
|
|
+ p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[1], &p->zErrmsg,
|
|
sqlite3_mprintf("PRAGMA index_list=%Q",zTab)
|
|
);
|
|
if( p->rc ) goto rbuTableType_end;
|
|
@@ -195024,9 +210623,9 @@ static void rbuTableType(
|
|
const u8 *zOrig = sqlite3_column_text(aStmt[1], 3);
|
|
const u8 *zIdx = sqlite3_column_text(aStmt[1], 1);
|
|
if( zOrig && zIdx && zOrig[0]=='p' ){
|
|
- p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[2], &p->zErrmsg,
|
|
+ p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[2], &p->zErrmsg,
|
|
sqlite3_mprintf(
|
|
- "SELECT rootpage FROM sqlite_master WHERE name = %Q", zIdx
|
|
+ "SELECT rootpage FROM sqlite_schema WHERE name = %Q", zIdx
|
|
));
|
|
if( p->rc==SQLITE_OK ){
|
|
if( sqlite3_step(aStmt[2])==SQLITE_ROW ){
|
|
@@ -195040,7 +210639,7 @@ static void rbuTableType(
|
|
}
|
|
}
|
|
|
|
- p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[3], &p->zErrmsg,
|
|
+ p->rc = prepareFreeAndCollectError(p->dbMain, &aStmt[3], &p->zErrmsg,
|
|
sqlite3_mprintf("PRAGMA table_info=%Q",zTab)
|
|
);
|
|
if( p->rc==SQLITE_OK ){
|
|
@@ -195116,7 +210715,7 @@ static void rbuObjIterCacheIndexedCols(sqlite3rbu *p, RbuObjIter *pIter){
|
|
** the table (not index) that the iterator currently points to.
|
|
**
|
|
** Return SQLITE_OK if successful, or an SQLite error code otherwise. If
|
|
-** an error does occur, an error code and error message are also left in
|
|
+** an error does occur, an error code and error message are also left in
|
|
** the RBU handle.
|
|
*/
|
|
static int rbuObjIterCacheTableInfo(sqlite3rbu *p, RbuObjIter *pIter){
|
|
@@ -195138,7 +210737,7 @@ static int rbuObjIterCacheTableInfo(sqlite3rbu *p, RbuObjIter *pIter){
|
|
if( p->rc ) return p->rc;
|
|
if( pIter->zIdx==0 ) pIter->iTnum = iTnum;
|
|
|
|
- assert( pIter->eType==RBU_PK_NONE || pIter->eType==RBU_PK_IPK
|
|
+ assert( pIter->eType==RBU_PK_NONE || pIter->eType==RBU_PK_IPK
|
|
|| pIter->eType==RBU_PK_EXTERNAL || pIter->eType==RBU_PK_WITHOUT_ROWID
|
|
|| pIter->eType==RBU_PK_VTAB
|
|
);
|
|
@@ -195146,7 +210745,7 @@ static int rbuObjIterCacheTableInfo(sqlite3rbu *p, RbuObjIter *pIter){
|
|
/* Populate the azTblCol[] and nTblCol variables based on the columns
|
|
** of the input table. Ignore any input table columns that begin with
|
|
** "rbu_". */
|
|
- p->rc = prepareFreeAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg,
|
|
+ p->rc = prepareFreeAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg,
|
|
sqlite3_mprintf("SELECT * FROM '%q'", pIter->zDataTbl)
|
|
);
|
|
if( p->rc==SQLITE_OK ){
|
|
@@ -195182,7 +210781,7 @@ static int rbuObjIterCacheTableInfo(sqlite3rbu *p, RbuObjIter *pIter){
|
|
** present in the input table. Populate the abTblPk[], azTblType[] and
|
|
** aiTblOrder[] arrays at the same time. */
|
|
if( p->rc==SQLITE_OK ){
|
|
- p->rc = prepareFreeAndCollectError(p->dbMain, &pStmt, &p->zErrmsg,
|
|
+ p->rc = prepareFreeAndCollectError(p->dbMain, &pStmt, &p->zErrmsg,
|
|
sqlite3_mprintf("PRAGMA table_info(%Q)", pIter->zTbl)
|
|
);
|
|
}
|
|
@@ -195225,8 +210824,8 @@ static int rbuObjIterCacheTableInfo(sqlite3rbu *p, RbuObjIter *pIter){
|
|
}
|
|
|
|
/*
|
|
-** This function constructs and returns a pointer to a nul-terminated
|
|
-** string containing some SQL clause or list based on one or more of the
|
|
+** This function constructs and returns a pointer to a nul-terminated
|
|
+** string containing some SQL clause or list based on one or more of the
|
|
** column names currently stored in the pIter->azTblCol[] array.
|
|
*/
|
|
static char *rbuObjIterGetCollist(
|
|
@@ -195277,10 +210876,10 @@ static char *rbuObjIterGetPkList(
|
|
}
|
|
|
|
/*
|
|
-** This function is called as part of restarting an RBU vacuum within
|
|
+** This function is called as part of restarting an RBU vacuum within
|
|
** stage 1 of the process (while the *-oal file is being built) while
|
|
** updating a table (not an index). The table may be a rowid table or
|
|
-** a WITHOUT ROWID table. It queries the target database to find the
|
|
+** a WITHOUT ROWID table. It queries the target database to find the
|
|
** largest key that has already been written to the target table and
|
|
** constructs a WHERE clause that can be used to extract the remaining
|
|
** rows from the source table. For a rowid table, the WHERE clause
|
|
@@ -195304,7 +210903,7 @@ static char *rbuVacuumTableStart(
|
|
sqlite3_stmt *pMax = 0;
|
|
char *zRet = 0;
|
|
if( bRowid ){
|
|
- p->rc = prepareFreeAndCollectError(p->dbMain, &pMax, &p->zErrmsg,
|
|
+ p->rc = prepareFreeAndCollectError(p->dbMain, &pMax, &p->zErrmsg,
|
|
sqlite3_mprintf(
|
|
"SELECT max(_rowid_) FROM \"%s%w\"", zWrite, pIter->zTbl
|
|
)
|
|
@@ -195320,9 +210919,9 @@ static char *rbuVacuumTableStart(
|
|
char *zList = rbuObjIterGetPkList(p, pIter, "", ", ", "");
|
|
|
|
if( p->rc==SQLITE_OK ){
|
|
- p->rc = prepareFreeAndCollectError(p->dbMain, &pMax, &p->zErrmsg,
|
|
+ p->rc = prepareFreeAndCollectError(p->dbMain, &pMax, &p->zErrmsg,
|
|
sqlite3_mprintf(
|
|
- "SELECT %s FROM \"%s%w\" ORDER BY %s LIMIT 1",
|
|
+ "SELECT %s FROM \"%s%w\" ORDER BY %s LIMIT 1",
|
|
zSelect, zWrite, pIter->zTbl, zOrder
|
|
)
|
|
);
|
|
@@ -195344,12 +210943,12 @@ static char *rbuVacuumTableStart(
|
|
** This function is called as part of restating an RBU vacuum when the
|
|
** current operation is writing content to an index. If possible, it
|
|
** queries the target index b-tree for the largest key already written to
|
|
-** it, then composes and returns an expression that can be used in a WHERE
|
|
-** clause to select the remaining required rows from the source table.
|
|
+** it, then composes and returns an expression that can be used in a WHERE
|
|
+** clause to select the remaining required rows from the source table.
|
|
** It is only possible to return such an expression if:
|
|
**
|
|
** * The index contains no DESC columns, and
|
|
-** * The last key written to the index before the operation was
|
|
+** * The last key written to the index before the operation was
|
|
** suspended does not contain any NULL values.
|
|
**
|
|
** The expression is of the form:
|
|
@@ -195359,10 +210958,10 @@ static char *rbuVacuumTableStart(
|
|
** except that the "?" placeholders are replaced with literal values.
|
|
**
|
|
** If the expression cannot be created, NULL is returned. In this case,
|
|
-** the caller has to use an OFFSET clause to extract only the required
|
|
+** the caller has to use an OFFSET clause to extract only the required
|
|
** rows from the sourct table, just as it does for an RBU update operation.
|
|
*/
|
|
-char *rbuVacuumIndexStart(
|
|
+static char *rbuVacuumIndexStart(
|
|
sqlite3rbu *p, /* RBU handle */
|
|
RbuObjIter *pIter /* RBU iterator object */
|
|
){
|
|
@@ -195428,7 +211027,9 @@ char *rbuVacuumIndexStart(
|
|
zSep = "";
|
|
for(iCol=0; iCol<pIter->nCol; iCol++){
|
|
const char *zQuoted = (const char*)sqlite3_column_text(pSel, iCol);
|
|
- if( zQuoted[0]=='N' ){
|
|
+ if( zQuoted==0 ){
|
|
+ p->rc = SQLITE_NOMEM;
|
|
+ }else if( zQuoted[0]=='N' ){
|
|
bFailed = 1;
|
|
break;
|
|
}
|
|
@@ -195452,23 +211053,23 @@ char *rbuVacuumIndexStart(
|
|
}
|
|
|
|
/*
|
|
-** This function is used to create a SELECT list (the list of SQL
|
|
-** expressions that follows a SELECT keyword) for a SELECT statement
|
|
-** used to read from an data_xxx or rbu_tmp_xxx table while updating the
|
|
-** index object currently indicated by the iterator object passed as the
|
|
-** second argument. A "PRAGMA index_xinfo = <idxname>" statement is used
|
|
+** This function is used to create a SELECT list (the list of SQL
|
|
+** expressions that follows a SELECT keyword) for a SELECT statement
|
|
+** used to read from an data_xxx or rbu_tmp_xxx table while updating the
|
|
+** index object currently indicated by the iterator object passed as the
|
|
+** second argument. A "PRAGMA index_xinfo = <idxname>" statement is used
|
|
** to obtain the required information.
|
|
**
|
|
** If the index is of the following form:
|
|
**
|
|
** CREATE INDEX i1 ON t1(c, b COLLATE nocase);
|
|
**
|
|
-** and "t1" is a table with an explicit INTEGER PRIMARY KEY column
|
|
+** and "t1" is a table with an explicit INTEGER PRIMARY KEY column
|
|
** "ipk", the returned string is:
|
|
**
|
|
** "`c` COLLATE 'BINARY', `b` COLLATE 'NOCASE', `ipk` COLLATE 'BINARY'"
|
|
**
|
|
-** As well as the returned string, three other malloc'd strings are
|
|
+** As well as the returned string, three other malloc'd strings are
|
|
** returned via output parameters. As follows:
|
|
**
|
|
** pzImposterCols: ...
|
|
@@ -195538,11 +211139,11 @@ static char *rbuObjIterGetIndexCols(
|
|
|
|
if( pIter->bUnique==0 || sqlite3_column_int(pXInfo, 5) ){
|
|
const char *zOrder = (bDesc ? " DESC" : "");
|
|
- zImpPK = sqlite3_mprintf("%z%s\"rbu_imp_%d%w\"%s",
|
|
+ zImpPK = sqlite3_mprintf("%z%s\"rbu_imp_%d%w\"%s",
|
|
zImpPK, zCom, nBind, zCol, zOrder
|
|
);
|
|
}
|
|
- zImpCols = sqlite3_mprintf("%z%s\"rbu_imp_%d%w\" %s COLLATE %Q",
|
|
+ zImpCols = sqlite3_mprintf("%z%s\"rbu_imp_%d%w\" %s COLLATE %Q",
|
|
zImpCols, zCom, nBind, zCol, zType, zCollate
|
|
);
|
|
zWhere = sqlite3_mprintf(
|
|
@@ -195588,7 +211189,7 @@ static char *rbuObjIterGetIndexCols(
|
|
** the text ", old._rowid_" to the returned value.
|
|
*/
|
|
static char *rbuObjIterGetOldlist(
|
|
- sqlite3rbu *p,
|
|
+ sqlite3rbu *p,
|
|
RbuObjIter *pIter,
|
|
const char *zObj
|
|
){
|
|
@@ -195629,7 +211230,7 @@ static char *rbuObjIterGetOldlist(
|
|
** "b = ?1 AND c = ?2"
|
|
*/
|
|
static char *rbuObjIterGetWhere(
|
|
- sqlite3rbu *p,
|
|
+ sqlite3rbu *p,
|
|
RbuObjIter *pIter
|
|
){
|
|
char *zList = 0;
|
|
@@ -195644,7 +211245,7 @@ static char *rbuObjIterGetWhere(
|
|
zSep = " AND ";
|
|
}
|
|
}
|
|
- zList = rbuMPrintf(p,
|
|
+ zList = rbuMPrintf(p,
|
|
"_rowid_ = (SELECT id FROM rbu_imposter2 WHERE %z)", zList
|
|
);
|
|
|
|
@@ -195684,7 +211285,7 @@ static void rbuBadControlError(sqlite3rbu *p){
|
|
**
|
|
** The memory for the returned string is obtained from sqlite3_malloc().
|
|
** It is the responsibility of the caller to eventually free it using
|
|
-** sqlite3_free().
|
|
+** sqlite3_free().
|
|
**
|
|
** If an OOM error is encountered when allocating space for the new
|
|
** string, an error code is left in the rbu handle passed as the first
|
|
@@ -195708,19 +211309,19 @@ static char *rbuObjIterGetSetlist(
|
|
for(i=0; i<pIter->nTblCol; i++){
|
|
char c = zMask[pIter->aiSrcOrder[i]];
|
|
if( c=='x' ){
|
|
- zList = rbuMPrintf(p, "%z%s\"%w\"=?%d",
|
|
+ zList = rbuMPrintf(p, "%z%s\"%w\"=?%d",
|
|
zList, zSep, pIter->azTblCol[i], i+1
|
|
);
|
|
zSep = ", ";
|
|
}
|
|
else if( c=='d' ){
|
|
- zList = rbuMPrintf(p, "%z%s\"%w\"=rbu_delta(\"%w\", ?%d)",
|
|
+ zList = rbuMPrintf(p, "%z%s\"%w\"=rbu_delta(\"%w\", ?%d)",
|
|
zList, zSep, pIter->azTblCol[i], pIter->azTblCol[i], i+1
|
|
);
|
|
zSep = ", ";
|
|
}
|
|
else if( c=='f' ){
|
|
- zList = rbuMPrintf(p, "%z%s\"%w\"=rbu_fossil_delta(\"%w\", ?%d)",
|
|
+ zList = rbuMPrintf(p, "%z%s\"%w\"=rbu_fossil_delta(\"%w\", ?%d)",
|
|
zList, zSep, pIter->azTblCol[i], pIter->azTblCol[i], i+1
|
|
);
|
|
zSep = ", ";
|
|
@@ -195738,7 +211339,7 @@ static char *rbuObjIterGetSetlist(
|
|
**
|
|
** The memory for the returned string is obtained from sqlite3_malloc().
|
|
** It is the responsibility of the caller to eventually free it using
|
|
-** sqlite3_free().
|
|
+** sqlite3_free().
|
|
**
|
|
** If an OOM error is encountered when allocating space for the new
|
|
** string, an error code is left in the rbu handle passed as the first
|
|
@@ -195762,8 +211363,8 @@ static char *rbuObjIterGetBindlist(sqlite3rbu *p, int nBind){
|
|
}
|
|
|
|
/*
|
|
-** The iterator currently points to a table (not index) of type
|
|
-** RBU_PK_WITHOUT_ROWID. This function creates the PRIMARY KEY
|
|
+** The iterator currently points to a table (not index) of type
|
|
+** RBU_PK_WITHOUT_ROWID. This function creates the PRIMARY KEY
|
|
** declaration for the corresponding imposter table. For example,
|
|
** if the iterator points to a table created as:
|
|
**
|
|
@@ -195780,7 +211381,7 @@ static char *rbuWithoutRowidPK(sqlite3rbu *p, RbuObjIter *pIter){
|
|
const char *zSep = "PRIMARY KEY(";
|
|
sqlite3_stmt *pXList = 0; /* PRAGMA index_list = (pIter->zTbl) */
|
|
sqlite3_stmt *pXInfo = 0; /* PRAGMA index_xinfo = <pk-index> */
|
|
-
|
|
+
|
|
p->rc = prepareFreeAndCollectError(p->dbMain, &pXList, &p->zErrmsg,
|
|
sqlite3_mprintf("PRAGMA main.index_list = %Q", pIter->zTbl)
|
|
);
|
|
@@ -195818,7 +211419,7 @@ static char *rbuWithoutRowidPK(sqlite3rbu *p, RbuObjIter *pIter){
|
|
** a table b-tree where the table has an external primary key. If the
|
|
** iterator passed as the second argument does not currently point to
|
|
** a table (not index) with an external primary key, this function is a
|
|
-** no-op.
|
|
+** no-op.
|
|
**
|
|
** Assuming the iterator does point to a table with an external PK, this
|
|
** function creates a WITHOUT ROWID imposter table named "rbu_imposter2"
|
|
@@ -195845,8 +211446,8 @@ static void rbuCreateImposterTable2(sqlite3rbu *p, RbuObjIter *pIter){
|
|
/* Figure out the name of the primary key index for the current table.
|
|
** This is needed for the argument to "PRAGMA index_xinfo". Set
|
|
** zIdx to point to a nul-terminated string containing this name. */
|
|
- p->rc = prepareAndCollectError(p->dbMain, &pQuery, &p->zErrmsg,
|
|
- "SELECT name FROM sqlite_master WHERE rootpage = ?"
|
|
+ p->rc = prepareAndCollectError(p->dbMain, &pQuery, &p->zErrmsg,
|
|
+ "SELECT name FROM sqlite_schema WHERE rootpage = ?"
|
|
);
|
|
if( p->rc==SQLITE_OK ){
|
|
sqlite3_bind_int(pQuery, 1, tnum);
|
|
@@ -195867,7 +211468,7 @@ static void rbuCreateImposterTable2(sqlite3rbu *p, RbuObjIter *pIter){
|
|
int iCid = sqlite3_column_int(pXInfo, 1);
|
|
int bDesc = sqlite3_column_int(pXInfo, 3);
|
|
const char *zCollate = (const char*)sqlite3_column_text(pXInfo, 4);
|
|
- zCols = rbuMPrintf(p, "%z%sc%d %s COLLATE %Q", zCols, zComma,
|
|
+ zCols = rbuMPrintf(p, "%z%sc%d %s COLLATE %Q", zCols, zComma,
|
|
iCid, pIter->azTblType[iCid], zCollate
|
|
);
|
|
zPk = rbuMPrintf(p, "%z%sc%d%s", zPk, zComma, iCid, bDesc?" DESC":"");
|
|
@@ -195879,7 +211480,7 @@ static void rbuCreateImposterTable2(sqlite3rbu *p, RbuObjIter *pIter){
|
|
|
|
sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 1, tnum);
|
|
rbuMPrintfExec(p, p->dbMain,
|
|
- "CREATE TABLE rbu_imposter2(%z, PRIMARY KEY(%z)) WITHOUT ROWID",
|
|
+ "CREATE TABLE rbu_imposter2(%z, PRIMARY KEY(%z)) WITHOUT ROWID",
|
|
zCols, zPk
|
|
);
|
|
sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 0, 0);
|
|
@@ -195887,7 +211488,7 @@ static void rbuCreateImposterTable2(sqlite3rbu *p, RbuObjIter *pIter){
|
|
}
|
|
|
|
/*
|
|
-** If an error has already occurred when this function is called, it
|
|
+** If an error has already occurred when this function is called, it
|
|
** immediately returns zero (without doing any work). Or, if an error
|
|
** occurs during the execution of this function, it sets the error code
|
|
** in the sqlite3rbu object indicated by the first argument and returns
|
|
@@ -195900,9 +211501,9 @@ static void rbuCreateImposterTable2(sqlite3rbu *p, RbuObjIter *pIter){
|
|
** an imposter table are created, or zero otherwise.
|
|
**
|
|
** An imposter table is required in all cases except RBU_PK_VTAB. Only
|
|
-** virtual tables are written to directly. The imposter table has the
|
|
-** same schema as the actual target table (less any UNIQUE constraints).
|
|
-** More precisely, the "same schema" means the same columns, types,
|
|
+** virtual tables are written to directly. The imposter table has the
|
|
+** same schema as the actual target table (less any UNIQUE constraints).
|
|
+** More precisely, the "same schema" means the same columns, types,
|
|
** collation sequences. For tables that do not have an external PRIMARY
|
|
** KEY, it also means the same PRIMARY KEY declaration.
|
|
*/
|
|
@@ -195928,7 +211529,7 @@ static void rbuCreateImposterTable(sqlite3rbu *p, RbuObjIter *pIter){
|
|
** "PRIMARY KEY" to the imposter table column declaration. */
|
|
zPk = "PRIMARY KEY ";
|
|
}
|
|
- zSql = rbuMPrintf(p, "%z%s\"%w\" %s %sCOLLATE %Q%s",
|
|
+ zSql = rbuMPrintf(p, "%z%s\"%w\" %s %sCOLLATE %Q%s",
|
|
zSql, zComma, zCol, pIter->azTblType[iCol], zPk, zColl,
|
|
(pIter->abNotNull[iCol] ? " NOT NULL" : "")
|
|
);
|
|
@@ -195943,8 +211544,8 @@ static void rbuCreateImposterTable(sqlite3rbu *p, RbuObjIter *pIter){
|
|
}
|
|
|
|
sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 1, tnum);
|
|
- rbuMPrintfExec(p, p->dbMain, "CREATE TABLE \"rbu_imp_%w\"(%z)%s",
|
|
- pIter->zTbl, zSql,
|
|
+ rbuMPrintfExec(p, p->dbMain, "CREATE TABLE \"rbu_imp_%w\"(%z)%s",
|
|
+ pIter->zTbl, zSql,
|
|
(pIter->eType==RBU_PK_WITHOUT_ROWID ? " WITHOUT ROWID" : "")
|
|
);
|
|
sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 0, 0);
|
|
@@ -195958,12 +211559,12 @@ static void rbuCreateImposterTable(sqlite3rbu *p, RbuObjIter *pIter){
|
|
** INSERT INTO rbu_tmp_xxx VALUES(?, ?, ? ...);
|
|
**
|
|
** The number of bound variables is equal to the number of columns in
|
|
-** the target table, plus one (for the rbu_control column), plus one more
|
|
-** (for the rbu_rowid column) if the target table is an implicit IPK or
|
|
+** the target table, plus one (for the rbu_control column), plus one more
|
|
+** (for the rbu_rowid column) if the target table is an implicit IPK or
|
|
** virtual table.
|
|
*/
|
|
static void rbuObjIterPrepareTmpInsert(
|
|
- sqlite3rbu *p,
|
|
+ sqlite3rbu *p,
|
|
RbuObjIter *pIter,
|
|
const char *zCollist,
|
|
const char *zRbuRowid
|
|
@@ -195974,14 +211575,14 @@ static void rbuObjIterPrepareTmpInsert(
|
|
assert( pIter->pTmpInsert==0 );
|
|
p->rc = prepareFreeAndCollectError(
|
|
p->dbRbu, &pIter->pTmpInsert, &p->zErrmsg, sqlite3_mprintf(
|
|
- "INSERT INTO %s.'rbu_tmp_%q'(rbu_control,%s%s) VALUES(%z)",
|
|
+ "INSERT INTO %s.'rbu_tmp_%q'(rbu_control,%s%s) VALUES(%z)",
|
|
p->zStateDb, pIter->zDataTbl, zCollist, zRbuRowid, zBind
|
|
));
|
|
}
|
|
}
|
|
|
|
static void rbuTmpInsertFunc(
|
|
- sqlite3_context *pCtx,
|
|
+ sqlite3_context *pCtx,
|
|
int nVal,
|
|
sqlite3_value **apVal
|
|
){
|
|
@@ -195990,8 +211591,8 @@ static void rbuTmpInsertFunc(
|
|
int i;
|
|
|
|
assert( sqlite3_value_int(apVal[0])!=0
|
|
- || p->objiter.eType==RBU_PK_EXTERNAL
|
|
- || p->objiter.eType==RBU_PK_NONE
|
|
+ || p->objiter.eType==RBU_PK_EXTERNAL
|
|
+ || p->objiter.eType==RBU_PK_NONE
|
|
);
|
|
if( sqlite3_value_int(apVal[0])!=0 ){
|
|
p->nPhaseOneStep += p->objiter.nIndex;
|
|
@@ -196019,7 +211620,7 @@ static char *rbuObjIterGetIndexWhere(sqlite3rbu *p, RbuObjIter *pIter){
|
|
|
|
if( rc==SQLITE_OK ){
|
|
rc = prepareAndCollectError(p->dbMain, &pStmt, &p->zErrmsg,
|
|
- "SELECT trim(sql) FROM sqlite_master WHERE type='index' AND name=?"
|
|
+ "SELECT trim(sql) FROM sqlite_schema WHERE type='index' AND name=?"
|
|
);
|
|
}
|
|
if( rc==SQLITE_OK ){
|
|
@@ -196106,12 +211707,12 @@ static char *rbuObjIterGetIndexWhere(sqlite3rbu *p, RbuObjIter *pIter){
|
|
}
|
|
|
|
/*
|
|
-** Ensure that the SQLite statement handles required to update the
|
|
-** target database object currently indicated by the iterator passed
|
|
+** Ensure that the SQLite statement handles required to update the
|
|
+** target database object currently indicated by the iterator passed
|
|
** as the second argument are available.
|
|
*/
|
|
static int rbuObjIterPrepareAll(
|
|
- sqlite3rbu *p,
|
|
+ sqlite3rbu *p,
|
|
RbuObjIter *pIter,
|
|
int nOffset /* Add "LIMIT -1 OFFSET $nOffset" to SELECT */
|
|
){
|
|
@@ -196185,9 +211786,9 @@ static int rbuObjIterPrepareAll(
|
|
|
|
zSql = sqlite3_mprintf(
|
|
"SELECT %s, 0 AS rbu_control FROM '%q' %s %s %s ORDER BY %s%s",
|
|
- zCollist,
|
|
+ zCollist,
|
|
pIter->zDataTbl,
|
|
- zPart,
|
|
+ zPart,
|
|
(zStart ? (zPart ? "AND" : "WHERE") : ""), zStart,
|
|
zCollist, zLimit
|
|
);
|
|
@@ -196208,7 +211809,7 @@ static int rbuObjIterPrepareAll(
|
|
"%s %s typeof(rbu_control)='integer' AND rbu_control!=1 "
|
|
"ORDER BY %s%s",
|
|
zCollist, p->zStateDb, pIter->zDataTbl, zPart,
|
|
- zCollist, pIter->zDataTbl,
|
|
+ zCollist, pIter->zDataTbl,
|
|
zPart,
|
|
(zPart ? "AND" : "WHERE"),
|
|
zCollist, zLimit
|
|
@@ -196250,7 +211851,7 @@ static int rbuObjIterPrepareAll(
|
|
if( p->rc==SQLITE_OK ){
|
|
p->rc = prepareFreeAndCollectError(p->dbMain, &pIter->pInsert, pz,
|
|
sqlite3_mprintf(
|
|
- "INSERT INTO \"%s%w\"(%s%s) VALUES(%s)",
|
|
+ "INSERT INTO \"%s%w\"(%s%s) VALUES(%s)",
|
|
zWrite, zTbl, zCollist, (bRbuRowid ? ", _rowid_" : ""), zBindings
|
|
)
|
|
);
|
|
@@ -196343,10 +211944,10 @@ static int rbuObjIterPrepareAll(
|
|
p->rc = prepareFreeAndCollectError(p->dbRbu, &pIter->pSelect, pz,
|
|
sqlite3_mprintf(
|
|
"SELECT %s,%s rbu_control%s FROM '%q'%s %s %s %s",
|
|
- zCollist,
|
|
+ zCollist,
|
|
(rbuIsVacuum(p) ? "0 AS " : ""),
|
|
zRbuRowid,
|
|
- pIter->zDataTbl, (zStart ? zStart : ""),
|
|
+ pIter->zDataTbl, (zStart ? zStart : ""),
|
|
(zOrder ? "ORDER BY" : ""), zOrder,
|
|
zLimit
|
|
)
|
|
@@ -196364,16 +211965,16 @@ static int rbuObjIterPrepareAll(
|
|
sqlite3_free(zCollist);
|
|
sqlite3_free(zLimit);
|
|
}
|
|
-
|
|
+
|
|
return p->rc;
|
|
}
|
|
|
|
/*
|
|
** Set output variable *ppStmt to point to an UPDATE statement that may
|
|
** be used to update the imposter table for the main table b-tree of the
|
|
-** table object that pIter currently points to, assuming that the
|
|
+** table object that pIter currently points to, assuming that the
|
|
** rbu_control column of the data_xyz table contains zMask.
|
|
-**
|
|
+**
|
|
** If the zMask string does not specify any columns to update, then this
|
|
** is not an error. Output variable *ppStmt is set to NULL in this case.
|
|
*/
|
|
@@ -196400,7 +212001,7 @@ static int rbuGetUpdateStmt(
|
|
*pp = pUp->pNext;
|
|
pUp->pNext = pIter->pRbuUpdate;
|
|
pIter->pRbuUpdate = pUp;
|
|
- *ppStmt = pUp->pUpdate;
|
|
+ *ppStmt = pUp->pUpdate;
|
|
return SQLITE_OK;
|
|
}
|
|
nUp++;
|
|
@@ -196430,7 +212031,7 @@ static int rbuGetUpdateStmt(
|
|
const char *zPrefix = "";
|
|
|
|
if( pIter->eType!=RBU_PK_VTAB ) zPrefix = "rbu_imp_";
|
|
- zUpdate = sqlite3_mprintf("UPDATE \"%s%w\" SET %s WHERE %s",
|
|
+ zUpdate = sqlite3_mprintf("UPDATE \"%s%w\" SET %s WHERE %s",
|
|
zPrefix, pIter->zTbl, zSet, zWhere
|
|
);
|
|
p->rc = prepareFreeAndCollectError(
|
|
@@ -196446,8 +212047,8 @@ static int rbuGetUpdateStmt(
|
|
}
|
|
|
|
static sqlite3 *rbuOpenDbhandle(
|
|
- sqlite3rbu *p,
|
|
- const char *zName,
|
|
+ sqlite3rbu *p,
|
|
+ const char *zName,
|
|
int bUseVfs
|
|
){
|
|
sqlite3 *db = 0;
|
|
@@ -196476,8 +212077,8 @@ static void rbuFreeState(RbuState *p){
|
|
}
|
|
|
|
/*
|
|
-** Allocate an RbuState object and load the contents of the rbu_state
|
|
-** table into it. Return a pointer to the new object. It is the
|
|
+** Allocate an RbuState object and load the contents of the rbu_state
|
|
+** table into it. Return a pointer to the new object. It is the
|
|
** responsibility of the caller to eventually free the object using
|
|
** sqlite3_free().
|
|
**
|
|
@@ -196493,7 +212094,7 @@ static RbuState *rbuLoadState(sqlite3rbu *p){
|
|
pRet = (RbuState*)rbuMalloc(p, sizeof(RbuState));
|
|
if( pRet==0 ) return 0;
|
|
|
|
- rc = prepareFreeAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg,
|
|
+ rc = prepareFreeAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg,
|
|
sqlite3_mprintf("SELECT k, v FROM %s.rbu_state", p->zStateDb)
|
|
);
|
|
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
|
|
@@ -196533,7 +212134,7 @@ static RbuState *rbuLoadState(sqlite3rbu *p){
|
|
break;
|
|
|
|
case RBU_STATE_OALSZ:
|
|
- pRet->iOalSz = (u32)sqlite3_column_int64(pStmt, 1);
|
|
+ pRet->iOalSz = sqlite3_column_int64(pStmt, 1);
|
|
break;
|
|
|
|
case RBU_STATE_PHASEONESTEP:
|
|
@@ -196560,19 +212161,25 @@ static RbuState *rbuLoadState(sqlite3rbu *p){
|
|
/*
|
|
** Open the database handle and attach the RBU database as "rbu". If an
|
|
** error occurs, leave an error code and message in the RBU handle.
|
|
+**
|
|
+** If argument dbMain is not NULL, then it is a database handle already
|
|
+** open on the target database. Use this handle instead of opening a new
|
|
+** one.
|
|
*/
|
|
-static void rbuOpenDatabase(sqlite3rbu *p, int *pbRetry){
|
|
+static void rbuOpenDatabase(sqlite3rbu *p, sqlite3 *dbMain, int *pbRetry){
|
|
assert( p->rc || (p->dbMain==0 && p->dbRbu==0) );
|
|
assert( p->rc || rbuIsVacuum(p) || p->zTarget!=0 );
|
|
+ assert( dbMain==0 || rbuIsVacuum(p)==0 );
|
|
|
|
/* Open the RBU database */
|
|
p->dbRbu = rbuOpenDbhandle(p, p->zRbu, 1);
|
|
+ p->dbMain = dbMain;
|
|
|
|
if( p->rc==SQLITE_OK && rbuIsVacuum(p) ){
|
|
sqlite3_file_control(p->dbRbu, "main", SQLITE_FCNTL_RBUCNT, (void*)p);
|
|
if( p->zState==0 ){
|
|
const char *zFile = sqlite3_db_filename(p->dbRbu, "main");
|
|
- p->zState = rbuMPrintf(p, "file://%s-vacuum?modeof=%s", zFile, zFile);
|
|
+ p->zState = rbuMPrintf(p, "file:///%s-vacuum?modeof=%s", zFile, zFile);
|
|
}
|
|
}
|
|
|
|
@@ -196601,9 +212208,9 @@ static void rbuOpenDatabase(sqlite3rbu *p, int *pbRetry){
|
|
int bOk = 0;
|
|
sqlite3_stmt *pCnt = 0;
|
|
p->rc = prepareAndCollectError(p->dbRbu, &pCnt, &p->zErrmsg,
|
|
- "SELECT count(*) FROM stat.sqlite_master"
|
|
+ "SELECT count(*) FROM stat.sqlite_schema"
|
|
);
|
|
- if( p->rc==SQLITE_OK
|
|
+ if( p->rc==SQLITE_OK
|
|
&& sqlite3_step(pCnt)==SQLITE_ROW
|
|
&& 1==sqlite3_column_int(pCnt, 0)
|
|
){
|
|
@@ -196616,7 +212223,7 @@ static void rbuOpenDatabase(sqlite3rbu *p, int *pbRetry){
|
|
p->rc = SQLITE_ERROR;
|
|
p->zErrmsg = sqlite3_mprintf("invalid state database");
|
|
}
|
|
-
|
|
+
|
|
if( p->rc==SQLITE_OK ){
|
|
p->rc = sqlite3_exec(p->dbRbu, "COMMIT", 0, 0, 0);
|
|
}
|
|
@@ -196670,7 +212277,7 @@ static void rbuOpenDatabase(sqlite3rbu *p, int *pbRetry){
|
|
if( *zExtra=='\0' ) zExtra = 0;
|
|
}
|
|
|
|
- zTarget = sqlite3_mprintf("file:%s-vactmp?rbu_memory=1%s%s",
|
|
+ zTarget = sqlite3_mprintf("file:%s-vactmp?rbu_memory=1%s%s",
|
|
sqlite3_db_filename(p->dbRbu, "main"),
|
|
(zExtra==0 ? "" : "&"), (zExtra==0 ? "" : zExtra)
|
|
);
|
|
@@ -196685,19 +212292,19 @@ static void rbuOpenDatabase(sqlite3rbu *p, int *pbRetry){
|
|
}
|
|
|
|
if( p->rc==SQLITE_OK ){
|
|
- p->rc = sqlite3_create_function(p->dbMain,
|
|
+ p->rc = sqlite3_create_function(p->dbMain,
|
|
"rbu_tmp_insert", -1, SQLITE_UTF8, (void*)p, rbuTmpInsertFunc, 0, 0
|
|
);
|
|
}
|
|
|
|
if( p->rc==SQLITE_OK ){
|
|
- p->rc = sqlite3_create_function(p->dbMain,
|
|
+ p->rc = sqlite3_create_function(p->dbMain,
|
|
"rbu_fossil_delta", 2, SQLITE_UTF8, 0, rbuFossilDeltaFunc, 0, 0
|
|
);
|
|
}
|
|
|
|
if( p->rc==SQLITE_OK ){
|
|
- p->rc = sqlite3_create_function(p->dbRbu,
|
|
+ p->rc = sqlite3_create_function(p->dbRbu,
|
|
"rbu_target_name", -1, SQLITE_UTF8, (void*)p, rbuTargetNameFunc, 0, 0
|
|
);
|
|
}
|
|
@@ -196705,9 +212312,9 @@ static void rbuOpenDatabase(sqlite3rbu *p, int *pbRetry){
|
|
if( p->rc==SQLITE_OK ){
|
|
p->rc = sqlite3_file_control(p->dbMain, "main", SQLITE_FCNTL_RBU, (void*)p);
|
|
}
|
|
- rbuMPrintfExec(p, p->dbMain, "SELECT * FROM sqlite_master");
|
|
+ rbuMPrintfExec(p, p->dbMain, "SELECT * FROM sqlite_schema");
|
|
|
|
- /* Mark the database file just opened as an RBU target database. If
|
|
+ /* Mark the database file just opened as an RBU target database. If
|
|
** this call returns SQLITE_NOTFOUND, then the RBU vfs is not in use.
|
|
** This is an error. */
|
|
if( p->rc==SQLITE_OK ){
|
|
@@ -196755,10 +212362,10 @@ static void rbuFileSuffix3(const char *zBase, char *z){
|
|
}
|
|
|
|
/*
|
|
-** Return the current wal-index header checksum for the target database
|
|
+** Return the current wal-index header checksum for the target database
|
|
** as a 64-bit integer.
|
|
**
|
|
-** The checksum is store in the first page of xShmMap memory as an 8-byte
|
|
+** The checksum is store in the first page of xShmMap memory as an 8-byte
|
|
** blob starting at byte offset 40.
|
|
*/
|
|
static i64 rbuShmChecksum(sqlite3rbu *p){
|
|
@@ -196776,11 +212383,11 @@ static i64 rbuShmChecksum(sqlite3rbu *p){
|
|
|
|
/*
|
|
** This function is called as part of initializing or reinitializing an
|
|
-** incremental checkpoint.
|
|
+** incremental checkpoint.
|
|
**
|
|
-** It populates the sqlite3rbu.aFrame[] array with the set of
|
|
-** (wal frame -> db page) copy operations required to checkpoint the
|
|
-** current wal file, and obtains the set of shm locks required to safely
|
|
+** It populates the sqlite3rbu.aFrame[] array with the set of
|
|
+** (wal frame -> db page) copy operations required to checkpoint the
|
|
+** current wal file, and obtains the set of shm locks required to safely
|
|
** perform the copy operations directly on the file-system.
|
|
**
|
|
** If argument pState is not NULL, then the incremental checkpoint is
|
|
@@ -196798,7 +212405,7 @@ static void rbuSetupCheckpoint(sqlite3rbu *p, RbuState *pState){
|
|
if( pState==0 ){
|
|
p->eStage = 0;
|
|
if( p->rc==SQLITE_OK ){
|
|
- p->rc = sqlite3_exec(p->dbMain, "SELECT * FROM sqlite_master", 0, 0, 0);
|
|
+ p->rc = sqlite3_exec(p->dbMain, "SELECT * FROM sqlite_schema", 0, 0, 0);
|
|
}
|
|
}
|
|
|
|
@@ -196815,26 +212422,26 @@ static void rbuSetupCheckpoint(sqlite3rbu *p, RbuState *pState){
|
|
** would be read/written are recorded in the sqlite3rbu.aFrame[]
|
|
** array.
|
|
**
|
|
- ** * Calls to xShmLock(UNLOCK) to release the exclusive shm WRITER,
|
|
+ ** * Calls to xShmLock(UNLOCK) to release the exclusive shm WRITER,
|
|
** READ0 and CHECKPOINT locks taken as part of the checkpoint are
|
|
** no-ops. These locks will not be released until the connection
|
|
** is closed.
|
|
**
|
|
- ** * Attempting to xSync() the database file causes an SQLITE_INTERNAL
|
|
+ ** * Attempting to xSync() the database file causes an SQLITE_NOTICE
|
|
** error.
|
|
**
|
|
** As a result, unless an error (i.e. OOM or SQLITE_BUSY) occurs, the
|
|
- ** checkpoint below fails with SQLITE_INTERNAL, and leaves the aFrame[]
|
|
- ** array populated with a set of (frame -> page) mappings. Because the
|
|
- ** WRITER, CHECKPOINT and READ0 locks are still held, it is safe to copy
|
|
- ** data from the wal file into the database file according to the
|
|
+ ** checkpoint below fails with SQLITE_NOTICE, and leaves the aFrame[]
|
|
+ ** array populated with a set of (frame -> page) mappings. Because the
|
|
+ ** WRITER, CHECKPOINT and READ0 locks are still held, it is safe to copy
|
|
+ ** data from the wal file into the database file according to the
|
|
** contents of aFrame[].
|
|
*/
|
|
if( p->rc==SQLITE_OK ){
|
|
int rc2;
|
|
p->eStage = RBU_STAGE_CAPTURE;
|
|
rc2 = sqlite3_exec(p->dbMain, "PRAGMA main.wal_checkpoint=restart", 0, 0,0);
|
|
- if( rc2!=SQLITE_INTERNAL ) p->rc = rc2;
|
|
+ if( rc2!=SQLITE_NOTICE ) p->rc = rc2;
|
|
}
|
|
|
|
if( p->rc==SQLITE_OK && p->nFrame>0 ){
|
|
@@ -196860,9 +212467,9 @@ static void rbuSetupCheckpoint(sqlite3rbu *p, RbuState *pState){
|
|
p->nPagePerSector = 1;
|
|
}
|
|
|
|
- /* Call xSync() on the wal file. This causes SQLite to sync the
|
|
- ** directory in which the target database and the wal file reside, in
|
|
- ** case it has not been synced since the rename() call in
|
|
+ /* Call xSync() on the wal file. This causes SQLite to sync the
|
|
+ ** directory in which the target database and the wal file reside, in
|
|
+ ** case it has not been synced since the rename() call in
|
|
** rbuMoveOalFile(). */
|
|
p->rc = pWal->pMethods->xSync(pWal, SQLITE_SYNC_NORMAL);
|
|
}
|
|
@@ -196880,7 +212487,7 @@ static int rbuCaptureWalRead(sqlite3rbu *pRbu, i64 iOff, int iAmt){
|
|
|
|
if( pRbu->mLock!=mReq ){
|
|
pRbu->rc = SQLITE_BUSY;
|
|
- return SQLITE_INTERNAL;
|
|
+ return SQLITE_NOTICE_RBU;
|
|
}
|
|
|
|
pRbu->pgsz = iAmt;
|
|
@@ -196903,7 +212510,7 @@ static int rbuCaptureWalRead(sqlite3rbu *pRbu, i64 iOff, int iAmt){
|
|
|
|
/*
|
|
** Called when a page of data is written to offset iOff of the database
|
|
-** file while the rbu handle is in capture mode. Record the page number
|
|
+** file while the rbu handle is in capture mode. Record the page number
|
|
** of the page being written in the aFrame[] array.
|
|
*/
|
|
static int rbuCaptureDbWrite(sqlite3rbu *pRbu, i64 iOff){
|
|
@@ -196932,15 +212539,31 @@ static void rbuCheckpointFrame(sqlite3rbu *p, RbuFrame *pFrame){
|
|
|
|
|
|
/*
|
|
-** Take an EXCLUSIVE lock on the database file.
|
|
+** Take an EXCLUSIVE lock on the database file. Return SQLITE_OK if
|
|
+** successful, or an SQLite error code otherwise.
|
|
*/
|
|
-static void rbuLockDatabase(sqlite3rbu *p){
|
|
- sqlite3_file *pReal = p->pTargetFd->pReal;
|
|
- assert( p->rc==SQLITE_OK );
|
|
- p->rc = pReal->pMethods->xLock(pReal, SQLITE_LOCK_SHARED);
|
|
- if( p->rc==SQLITE_OK ){
|
|
- p->rc = pReal->pMethods->xLock(pReal, SQLITE_LOCK_EXCLUSIVE);
|
|
+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 ){
|
|
+ rc = fd->pMethods->xLock(fd, SQLITE_LOCK_SHARED);
|
|
+ if( rc==SQLITE_OK ){
|
|
+ rc = fd->pMethods->xLock(fd, SQLITE_LOCK_EXCLUSIVE);
|
|
+ }
|
|
}
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Return true if the database handle passed as the only argument
|
|
+** was opened with the rbu_exclusive_checkpoint=1 URI parameter
|
|
+** specified. Or false otherwise.
|
|
+*/
|
|
+static int rbuExclusiveCheckpoint(sqlite3 *db){
|
|
+ const char *zUri = sqlite3_db_filename(db, 0);
|
|
+ return sqlite3_uri_boolean(zUri, RBU_EXCLUSIVE_CHECKPOINT, 0);
|
|
}
|
|
|
|
#if defined(_WIN32_WCE)
|
|
@@ -196971,7 +212594,7 @@ static LPWSTR rbuWinUtf8ToUnicode(const char *zFilename){
|
|
** The RBU handle is currently in RBU_STAGE_OAL state, with a SHARED lock
|
|
** on the database file. This proc moves the *-oal file to the *-wal path,
|
|
** then reopens the database file (this time in vanilla, non-oal, WAL mode).
|
|
-** If an error occurs, leave an error code and error message in the rbu
|
|
+** If an error occurs, leave an error code and error message in the rbu
|
|
** handle.
|
|
*/
|
|
static void rbuMoveOalFile(sqlite3rbu *p){
|
|
@@ -196993,54 +212616,43 @@ static void rbuMoveOalFile(sqlite3rbu *p){
|
|
}else{
|
|
/* Move the *-oal file to *-wal. At this point connection p->db is
|
|
** holding a SHARED lock on the target database file (because it is
|
|
- ** in WAL mode). So no other connection may be writing the db.
|
|
+ ** in WAL mode). So no other connection may be writing the db.
|
|
**
|
|
** In order to ensure that there are no database readers, an EXCLUSIVE
|
|
** lock is obtained here before the *-oal is moved to *-wal.
|
|
*/
|
|
- rbuLockDatabase(p);
|
|
- if( p->rc==SQLITE_OK ){
|
|
- rbuFileSuffix3(zBase, zWal);
|
|
- rbuFileSuffix3(zBase, zOal);
|
|
+ sqlite3 *dbMain = 0;
|
|
+ rbuFileSuffix3(zBase, zWal);
|
|
+ rbuFileSuffix3(zBase, zOal);
|
|
|
|
- /* Re-open the databases. */
|
|
- rbuObjIterFinalize(&p->objiter);
|
|
- sqlite3_close(p->dbRbu);
|
|
- sqlite3_close(p->dbMain);
|
|
- p->dbMain = 0;
|
|
- p->dbRbu = 0;
|
|
+ /* Re-open the databases. */
|
|
+ rbuObjIterFinalize(&p->objiter);
|
|
+ sqlite3_close(p->dbRbu);
|
|
+ sqlite3_close(p->dbMain);
|
|
+ p->dbMain = 0;
|
|
+ p->dbRbu = 0;
|
|
|
|
-#if defined(_WIN32_WCE)
|
|
- {
|
|
- LPWSTR zWideOal;
|
|
- LPWSTR zWideWal;
|
|
-
|
|
- zWideOal = rbuWinUtf8ToUnicode(zOal);
|
|
- if( zWideOal ){
|
|
- zWideWal = rbuWinUtf8ToUnicode(zWal);
|
|
- if( zWideWal ){
|
|
- if( MoveFileW(zWideOal, zWideWal) ){
|
|
- p->rc = SQLITE_OK;
|
|
- }else{
|
|
- p->rc = SQLITE_IOERR;
|
|
- }
|
|
- sqlite3_free(zWideWal);
|
|
- }else{
|
|
- p->rc = SQLITE_IOERR_NOMEM;
|
|
- }
|
|
- sqlite3_free(zWideOal);
|
|
- }else{
|
|
- p->rc = SQLITE_IOERR_NOMEM;
|
|
- }
|
|
- }
|
|
-#else
|
|
- p->rc = rename(zOal, zWal) ? SQLITE_IOERR : SQLITE_OK;
|
|
-#endif
|
|
+ dbMain = rbuOpenDbhandle(p, p->zTarget, 1);
|
|
+ if( dbMain ){
|
|
+ assert( p->rc==SQLITE_OK );
|
|
+ p->rc = rbuLockDatabase(dbMain);
|
|
+ }
|
|
|
|
- if( p->rc==SQLITE_OK ){
|
|
- rbuOpenDatabase(p, 0);
|
|
- rbuSetupCheckpoint(p, 0);
|
|
- }
|
|
+ if( p->rc==SQLITE_OK ){
|
|
+ p->rc = p->xRename(p->pRenameArg, zOal, zWal);
|
|
+ }
|
|
+
|
|
+ if( p->rc!=SQLITE_OK
|
|
+ || rbuIsVacuum(p)
|
|
+ || rbuExclusiveCheckpoint(dbMain)==0
|
|
+ ){
|
|
+ sqlite3_close(dbMain);
|
|
+ dbMain = 0;
|
|
+ }
|
|
+
|
|
+ if( p->rc==SQLITE_OK ){
|
|
+ rbuOpenDatabase(p, dbMain, 0);
|
|
+ rbuSetupCheckpoint(p, 0);
|
|
}
|
|
}
|
|
|
|
@@ -197151,8 +212763,8 @@ static void rbuStepOneOp(sqlite3rbu *p, int eType){
|
|
/* If this is an INSERT into a table b-tree and the table has an
|
|
** explicit INTEGER PRIMARY KEY, check that this is not an attempt
|
|
** to write a NULL into the IPK column. That is not permitted. */
|
|
- if( eType==RBU_INSERT
|
|
- && pIter->zIdx==0 && pIter->eType==RBU_PK_IPK && pIter->abTblPk[i]
|
|
+ if( eType==RBU_INSERT
|
|
+ && pIter->zIdx==0 && pIter->eType==RBU_PK_IPK && pIter->abTblPk[i]
|
|
&& sqlite3_column_type(pIter->pSelect, i)==SQLITE_NULL
|
|
){
|
|
p->rc = SQLITE_MISMATCH;
|
|
@@ -197169,18 +212781,18 @@ static void rbuStepOneOp(sqlite3rbu *p, int eType){
|
|
if( p->rc ) return;
|
|
}
|
|
if( pIter->zIdx==0 ){
|
|
- if( pIter->eType==RBU_PK_VTAB
|
|
- || pIter->eType==RBU_PK_NONE
|
|
- || (pIter->eType==RBU_PK_EXTERNAL && rbuIsVacuum(p))
|
|
+ if( pIter->eType==RBU_PK_VTAB
|
|
+ || pIter->eType==RBU_PK_NONE
|
|
+ || (pIter->eType==RBU_PK_EXTERNAL && rbuIsVacuum(p))
|
|
){
|
|
- /* For a virtual table, or a table with no primary key, the
|
|
+ /* For a virtual table, or a table with no primary key, the
|
|
** SELECT statement is:
|
|
**
|
|
** SELECT <cols>, rbu_control, rbu_rowid FROM ....
|
|
**
|
|
** Hence column_value(pIter->nCol+1).
|
|
*/
|
|
- assertColumnName(pIter->pSelect, pIter->nCol+1,
|
|
+ assertColumnName(pIter->pSelect, pIter->nCol+1,
|
|
rbuIsVacuum(p) ? "rowid" : "rbu_rowid"
|
|
);
|
|
pVal = sqlite3_column_value(pIter->pSelect, pIter->nCol+1);
|
|
@@ -197244,8 +212856,8 @@ static int rbuStep(sqlite3rbu *p){
|
|
p->rc = sqlite3_bind_value(pUpdate, i+1, pVal);
|
|
}
|
|
}
|
|
- if( p->rc==SQLITE_OK
|
|
- && (pIter->eType==RBU_PK_VTAB || pIter->eType==RBU_PK_NONE)
|
|
+ if( p->rc==SQLITE_OK
|
|
+ && (pIter->eType==RBU_PK_VTAB || pIter->eType==RBU_PK_NONE)
|
|
){
|
|
/* Bind the rbu_rowid value to column _rowid_ */
|
|
assertColumnName(pIter->pSelect, pIter->nCol+1, "rbu_rowid");
|
|
@@ -197275,7 +212887,7 @@ static void rbuIncrSchemaCookie(sqlite3rbu *p){
|
|
int iCookie = 1000000;
|
|
sqlite3_stmt *pStmt;
|
|
|
|
- p->rc = prepareAndCollectError(dbread, &pStmt, &p->zErrmsg,
|
|
+ p->rc = prepareAndCollectError(dbread, &pStmt, &p->zErrmsg,
|
|
"PRAGMA schema_version"
|
|
);
|
|
if( p->rc==SQLITE_OK ){
|
|
@@ -197307,7 +212919,7 @@ static void rbuSaveState(sqlite3rbu *p, int eStage){
|
|
int rc;
|
|
|
|
assert( p->zErrmsg==0 );
|
|
- rc = prepareFreeAndCollectError(p->dbRbu, &pInsert, &p->zErrmsg,
|
|
+ rc = prepareFreeAndCollectError(p->dbRbu, &pInsert, &p->zErrmsg,
|
|
sqlite3_mprintf(
|
|
"INSERT OR REPLACE INTO %s.rbu_state(k, v) VALUES "
|
|
"(%d, %d), "
|
|
@@ -197322,9 +212934,9 @@ static void rbuSaveState(sqlite3rbu *p, int eStage){
|
|
"(%d, %Q) ",
|
|
p->zStateDb,
|
|
RBU_STATE_STAGE, eStage,
|
|
- RBU_STATE_TBL, p->objiter.zTbl,
|
|
- RBU_STATE_IDX, p->objiter.zIdx,
|
|
- RBU_STATE_ROW, p->nStep,
|
|
+ RBU_STATE_TBL, p->objiter.zTbl,
|
|
+ RBU_STATE_IDX, p->objiter.zIdx,
|
|
+ RBU_STATE_ROW, p->nStep,
|
|
RBU_STATE_PROGRESS, p->nProgress,
|
|
RBU_STATE_CKPT, p->iWalCksum,
|
|
RBU_STATE_COOKIE, (i64)pFd->iCookie,
|
|
@@ -197345,7 +212957,7 @@ static void rbuSaveState(sqlite3rbu *p, int eStage){
|
|
|
|
|
|
/*
|
|
-** The second argument passed to this function is the name of a PRAGMA
|
|
+** The second argument passed to this function is the name of a PRAGMA
|
|
** setting - "page_size", "auto_vacuum", "user_version" or "application_id".
|
|
** This function executes the following on sqlite3rbu.dbRbu:
|
|
**
|
|
@@ -197364,7 +212976,7 @@ static void rbuSaveState(sqlite3rbu *p, int eStage){
|
|
static void rbuCopyPragma(sqlite3rbu *p, const char *zPragma){
|
|
if( p->rc==SQLITE_OK ){
|
|
sqlite3_stmt *pPragma = 0;
|
|
- p->rc = prepareFreeAndCollectError(p->dbRbu, &pPragma, &p->zErrmsg,
|
|
+ p->rc = prepareFreeAndCollectError(p->dbRbu, &pPragma, &p->zErrmsg,
|
|
sqlite3_mprintf("PRAGMA main.%s", zPragma)
|
|
);
|
|
if( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pPragma) ){
|
|
@@ -197377,7 +212989,7 @@ static void rbuCopyPragma(sqlite3rbu *p, const char *zPragma){
|
|
}
|
|
|
|
/*
|
|
-** The RBU handle passed as the only argument has just been opened and
|
|
+** The RBU handle passed as the only argument has just been opened and
|
|
** the state database is empty. If this RBU handle was opened for an
|
|
** RBU vacuum operation, create the schema in the target db.
|
|
*/
|
|
@@ -197388,8 +213000,8 @@ static void rbuCreateTargetSchema(sqlite3rbu *p){
|
|
assert( rbuIsVacuum(p) );
|
|
p->rc = sqlite3_exec(p->dbMain, "PRAGMA writable_schema=1", 0,0, &p->zErrmsg);
|
|
if( p->rc==SQLITE_OK ){
|
|
- p->rc = prepareAndCollectError(p->dbRbu, &pSql, &p->zErrmsg,
|
|
- "SELECT sql FROM sqlite_master WHERE sql!='' AND rootpage!=0"
|
|
+ p->rc = prepareAndCollectError(p->dbRbu, &pSql, &p->zErrmsg,
|
|
+ "SELECT sql FROM sqlite_schema WHERE sql!='' AND rootpage!=0"
|
|
" AND name!='sqlite_sequence' "
|
|
" ORDER BY type DESC"
|
|
);
|
|
@@ -197403,14 +213015,14 @@ static void rbuCreateTargetSchema(sqlite3rbu *p){
|
|
if( p->rc!=SQLITE_OK ) return;
|
|
|
|
if( p->rc==SQLITE_OK ){
|
|
- p->rc = prepareAndCollectError(p->dbRbu, &pSql, &p->zErrmsg,
|
|
- "SELECT * FROM sqlite_master WHERE rootpage=0 OR rootpage IS NULL"
|
|
+ p->rc = prepareAndCollectError(p->dbRbu, &pSql, &p->zErrmsg,
|
|
+ "SELECT * FROM sqlite_schema WHERE rootpage=0 OR rootpage IS NULL"
|
|
);
|
|
}
|
|
|
|
if( p->rc==SQLITE_OK ){
|
|
- p->rc = prepareAndCollectError(p->dbMain, &pInsert, &p->zErrmsg,
|
|
- "INSERT INTO sqlite_master VALUES(?,?,?,?,?)"
|
|
+ p->rc = prepareAndCollectError(p->dbMain, &pInsert, &p->zErrmsg,
|
|
+ "INSERT INTO sqlite_schema VALUES(?,?,?,?,?)"
|
|
);
|
|
}
|
|
|
|
@@ -197450,11 +213062,11 @@ SQLITE_API int sqlite3rbu_step(sqlite3rbu *p){
|
|
while( p->rc==SQLITE_OK && pIter->zTbl ){
|
|
|
|
if( pIter->bCleanup ){
|
|
- /* Clean up the rbu_tmp_xxx table for the previous table. It
|
|
+ /* Clean up the rbu_tmp_xxx table for the previous table. It
|
|
** cannot be dropped as there are currently active SQL statements.
|
|
** But the contents can be deleted. */
|
|
if( rbuIsVacuum(p)==0 && pIter->abIndexed ){
|
|
- rbuMPrintfExec(p, p->dbRbu,
|
|
+ rbuMPrintfExec(p, p->dbRbu,
|
|
"DELETE FROM %s.'rbu_tmp_%q'", p->zStateDb, pIter->zDataTbl
|
|
);
|
|
}
|
|
@@ -197504,10 +213116,10 @@ SQLITE_API int sqlite3rbu_step(sqlite3rbu *p){
|
|
if( p->rc==SQLITE_OK ){
|
|
if( p->nStep>=p->nFrame ){
|
|
sqlite3_file *pDb = p->pTargetFd->pReal;
|
|
-
|
|
+
|
|
/* Sync the db file */
|
|
p->rc = pDb->pMethods->xSync(pDb, SQLITE_SYNC_NORMAL);
|
|
-
|
|
+
|
|
/* Update nBackfill */
|
|
if( p->rc==SQLITE_OK ){
|
|
void volatile *ptr;
|
|
@@ -197516,7 +213128,7 @@ SQLITE_API int sqlite3rbu_step(sqlite3rbu *p){
|
|
((u32 volatile*)ptr)[24] = p->iMaxFrame;
|
|
}
|
|
}
|
|
-
|
|
+
|
|
if( p->rc==SQLITE_OK ){
|
|
p->eStage = RBU_STAGE_DONE;
|
|
p->rc = SQLITE_DONE;
|
|
@@ -197524,7 +213136,7 @@ SQLITE_API int sqlite3rbu_step(sqlite3rbu *p){
|
|
}else{
|
|
/* At one point the following block copied a single frame from the
|
|
** wal file to the database file. So that one call to sqlite3rbu_step()
|
|
- ** checkpointed a single frame.
|
|
+ ** checkpointed a single frame.
|
|
**
|
|
** However, if the sector-size is larger than the page-size, and the
|
|
** application calls sqlite3rbu_savestate() or close() immediately
|
|
@@ -197538,7 +213150,7 @@ SQLITE_API int sqlite3rbu_step(sqlite3rbu *p){
|
|
iSector = (pFrame->iDbPage-1) / p->nPagePerSector;
|
|
rbuCheckpointFrame(p, pFrame);
|
|
p->nStep++;
|
|
- }while( p->nStep<p->nFrame
|
|
+ }while( p->nStep<p->nFrame
|
|
&& iSector==((p->aFrame[p->nStep].iDbPage-1) / p->nPagePerSector)
|
|
&& p->rc==SQLITE_OK
|
|
);
|
|
@@ -197584,7 +213196,7 @@ static void rbuSetupOal(sqlite3rbu *p, RbuState *pState){
|
|
RbuObjIter *pIter = &p->objiter;
|
|
int rc = SQLITE_OK;
|
|
|
|
- while( rc==SQLITE_OK && pIter->zTbl && (pIter->bCleanup
|
|
+ while( rc==SQLITE_OK && pIter->zTbl && (pIter->bCleanup
|
|
|| rbuStrCompare(pIter->zIdx, pState->zIdx)
|
|
|| (pState->zDataTbl==0 && rbuStrCompare(pIter->zTbl, pState->zTbl))
|
|
|| (pState->zDataTbl && rbuStrCompare(pIter->zDataTbl, pState->zDataTbl))
|
|
@@ -197614,7 +213226,8 @@ static void rbuSetupOal(sqlite3rbu *p, RbuState *pState){
|
|
static void rbuDeleteOalFile(sqlite3rbu *p){
|
|
char *zOal = rbuMPrintf(p, "%s-oal", p->zTarget);
|
|
if( zOal ){
|
|
- sqlite3_vfs *pVfs = sqlite3_vfs_find(0);
|
|
+ sqlite3_vfs *pVfs = 0;
|
|
+ sqlite3_file_control(p->dbMain, "main", SQLITE_FCNTL_VFS_POINTER, &pVfs);
|
|
assert( pVfs && p->rc==SQLITE_OK && p->zErrmsg==0 );
|
|
pVfs->xDelete(pVfs, zOal, 0);
|
|
sqlite3_free(zOal);
|
|
@@ -197660,7 +213273,7 @@ static void rbuDeleteVfs(sqlite3rbu *p){
|
|
** the number of auxilliary indexes on the table.
|
|
*/
|
|
static void rbuIndexCntFunc(
|
|
- sqlite3_context *pCtx,
|
|
+ sqlite3_context *pCtx,
|
|
int nVal,
|
|
sqlite3_value **apVal
|
|
){
|
|
@@ -197671,9 +213284,9 @@ static void rbuIndexCntFunc(
|
|
sqlite3 *db = (rbuIsVacuum(p) ? p->dbRbu : p->dbMain);
|
|
|
|
assert( nVal==1 );
|
|
-
|
|
- rc = prepareFreeAndCollectError(db, &pStmt, &zErrmsg,
|
|
- sqlite3_mprintf("SELECT count(*) FROM sqlite_master "
|
|
+
|
|
+ rc = prepareFreeAndCollectError(db, &pStmt, &zErrmsg,
|
|
+ sqlite3_mprintf("SELECT count(*) FROM sqlite_schema "
|
|
"WHERE type='index' AND tbl_name = %Q", sqlite3_value_text(apVal[0]))
|
|
);
|
|
if( rc!=SQLITE_OK ){
|
|
@@ -197706,7 +213319,7 @@ static void rbuIndexCntFunc(
|
|
** and the cnt column the number of rows it contains.
|
|
**
|
|
** sqlite3rbu.nPhaseOneStep is initialized to the sum of (1 + nIndex) * cnt
|
|
-** for all rows in the rbu_count table, where nIndex is the number of
|
|
+** for all rows in the rbu_count table, where nIndex is the number of
|
|
** indexes on the corresponding target database table.
|
|
*/
|
|
static void rbuInitPhaseOneSteps(sqlite3rbu *p){
|
|
@@ -197716,15 +213329,15 @@ static void rbuInitPhaseOneSteps(sqlite3rbu *p){
|
|
|
|
p->nPhaseOneStep = -1;
|
|
|
|
- p->rc = sqlite3_create_function(p->dbRbu,
|
|
+ p->rc = sqlite3_create_function(p->dbRbu,
|
|
"rbu_index_cnt", 1, SQLITE_UTF8, (void*)p, rbuIndexCntFunc, 0, 0
|
|
);
|
|
-
|
|
+
|
|
/* Check for the rbu_count table. If it does not exist, or if an error
|
|
** occurs, nPhaseOneStep will be left set to -1. */
|
|
if( p->rc==SQLITE_OK ){
|
|
p->rc = prepareAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg,
|
|
- "SELECT 1 FROM sqlite_master WHERE tbl_name = 'rbu_count'"
|
|
+ "SELECT 1 FROM sqlite_schema WHERE tbl_name = 'rbu_count'"
|
|
);
|
|
}
|
|
if( p->rc==SQLITE_OK ){
|
|
@@ -197733,7 +213346,7 @@ static void rbuInitPhaseOneSteps(sqlite3rbu *p){
|
|
}
|
|
p->rc = sqlite3_finalize(pStmt);
|
|
}
|
|
-
|
|
+
|
|
if( p->rc==SQLITE_OK && bExists ){
|
|
p->rc = prepareAndCollectError(p->dbRbu, &pStmt, &p->zErrmsg,
|
|
"SELECT sum(cnt * (1 + rbu_index_cnt(rbu_target_name(tbl))))"
|
|
@@ -197751,7 +213364,7 @@ static void rbuInitPhaseOneSteps(sqlite3rbu *p){
|
|
|
|
|
|
static sqlite3rbu *openRbuHandle(
|
|
- const char *zTarget,
|
|
+ const char *zTarget,
|
|
const char *zRbu,
|
|
const char *zState
|
|
){
|
|
@@ -197766,6 +213379,7 @@ static sqlite3rbu *openRbuHandle(
|
|
|
|
/* Create the custom VFS. */
|
|
memset(p, 0, sizeof(sqlite3rbu));
|
|
+ sqlite3rbu_rename_handler(p, 0, 0);
|
|
rbuCreateVfs(p);
|
|
|
|
/* Open the target, RBU and state databases */
|
|
@@ -197789,11 +213403,11 @@ static sqlite3rbu *openRbuHandle(
|
|
** to be a wal-mode db. But, this may have happened due to an earlier
|
|
** RBU vacuum operation leaving an old wal file in the directory.
|
|
** If this is the case, it will have been checkpointed and deleted
|
|
- ** when the handle was closed and a second attempt to open the
|
|
+ ** when the handle was closed and a second attempt to open the
|
|
** database may succeed. */
|
|
- rbuOpenDatabase(p, &bRetry);
|
|
+ rbuOpenDatabase(p, 0, &bRetry);
|
|
if( bRetry ){
|
|
- rbuOpenDatabase(p, 0);
|
|
+ rbuOpenDatabase(p, 0, 0);
|
|
}
|
|
}
|
|
|
|
@@ -197802,7 +213416,7 @@ static sqlite3rbu *openRbuHandle(
|
|
assert( pState || p->rc!=SQLITE_OK );
|
|
if( p->rc==SQLITE_OK ){
|
|
|
|
- if( pState->eStage==0 ){
|
|
+ if( pState->eStage==0 ){
|
|
rbuDeleteOalFile(p);
|
|
rbuInitPhaseOneSteps(p);
|
|
p->eStage = RBU_STAGE_OAL;
|
|
@@ -197826,15 +213440,15 @@ static sqlite3rbu *openRbuHandle(
|
|
}
|
|
}
|
|
|
|
- if( p->rc==SQLITE_OK
|
|
+ if( p->rc==SQLITE_OK
|
|
&& (p->eStage==RBU_STAGE_OAL || p->eStage==RBU_STAGE_MOVE)
|
|
&& pState->eStage!=0
|
|
){
|
|
rbu_file *pFd = (rbuIsVacuum(p) ? p->pRbuFd : p->pTargetFd);
|
|
- if( pFd->iCookie!=pState->iCookie ){
|
|
+ if( pFd->iCookie!=pState->iCookie ){
|
|
/* At this point (pTargetFd->iCookie) contains the value of the
|
|
- ** change-counter cookie (the thing that gets incremented when a
|
|
- ** transaction is committed in rollback mode) currently stored on
|
|
+ ** change-counter cookie (the thing that gets incremented when a
|
|
+ ** transaction is committed in rollback mode) currently stored on
|
|
** page 1 of the database file. */
|
|
p->rc = SQLITE_BUSY;
|
|
p->zErrmsg = sqlite3_mprintf("database modified during rbu %s",
|
|
@@ -197871,7 +213485,7 @@ static sqlite3rbu *openRbuHandle(
|
|
}
|
|
|
|
/* Check if the main database is a zipvfs db. If it is, set the upper
|
|
- ** level pager to use "journal_mode=off". This prevents it from
|
|
+ ** level pager to use "journal_mode=off". This prevents it from
|
|
** generating a large journal using a temp file. */
|
|
if( p->rc==SQLITE_OK ){
|
|
int frc = sqlite3_file_control(db, "main", SQLITE_FCNTL_ZIPVFS, 0);
|
|
@@ -197888,6 +213502,14 @@ static sqlite3rbu *openRbuHandle(
|
|
}else if( p->eStage==RBU_STAGE_MOVE ){
|
|
/* no-op */
|
|
}else if( p->eStage==RBU_STAGE_CKPT ){
|
|
+ if( !rbuIsVacuum(p) && rbuExclusiveCheckpoint(p->dbMain) ){
|
|
+ /* If the rbu_exclusive_checkpoint=1 URI parameter was specified
|
|
+ ** and an incremental checkpoint is being resumed, attempt an
|
|
+ ** exclusive lock on the db file. If this fails, so be it. */
|
|
+ p->eStage = RBU_STAGE_DONE;
|
|
+ rbuLockDatabase(p->dbMain);
|
|
+ p->eStage = RBU_STAGE_CKPT;
|
|
+ }
|
|
rbuSetupCheckpoint(p, pState);
|
|
}else if( p->eStage==RBU_STAGE_DONE ){
|
|
p->rc = SQLITE_DONE;
|
|
@@ -197917,15 +213539,14 @@ static sqlite3rbu *rbuMisuseError(void){
|
|
}
|
|
|
|
/*
|
|
-** Open and return a new RBU handle.
|
|
+** Open and return a new RBU handle.
|
|
*/
|
|
SQLITE_API sqlite3rbu *sqlite3rbu_open(
|
|
- const char *zTarget,
|
|
+ const char *zTarget,
|
|
const char *zRbu,
|
|
const char *zState
|
|
){
|
|
if( zTarget==0 || zRbu==0 ){ return rbuMisuseError(); }
|
|
- /* TODO: Check that zTarget and zRbu are non-NULL */
|
|
return openRbuHandle(zTarget, zRbu, zState);
|
|
}
|
|
|
|
@@ -197933,7 +213554,7 @@ SQLITE_API sqlite3rbu *sqlite3rbu_open(
|
|
** Open a handle to begin or resume an RBU VACUUM operation.
|
|
*/
|
|
SQLITE_API sqlite3rbu *sqlite3rbu_vacuum(
|
|
- const char *zTarget,
|
|
+ const char *zTarget,
|
|
const char *zState
|
|
){
|
|
if( zTarget==0 ){ return rbuMisuseError(); }
|
|
@@ -198007,8 +213628,8 @@ SQLITE_API int sqlite3rbu_close(sqlite3rbu *p, char **pzErrmsg){
|
|
rbuObjIterFinalize(&p->objiter);
|
|
|
|
/* If this is an RBU vacuum handle and the vacuum has either finished
|
|
- ** successfully or encountered an error, delete the contents of the
|
|
- ** state table. This causes the next call to sqlite3rbu_vacuum()
|
|
+ ** successfully or encountered an error, delete the contents of the
|
|
+ ** state table. This causes the next call to sqlite3rbu_vacuum()
|
|
** specifying the current target and state databases to start a new
|
|
** vacuum from scratch. */
|
|
if( rbuIsVacuum(p) && p->rc!=SQLITE_OK && p->dbRbu ){
|
|
@@ -198041,7 +213662,7 @@ SQLITE_API int sqlite3rbu_close(sqlite3rbu *p, char **pzErrmsg){
|
|
}
|
|
|
|
/*
|
|
-** Return the total number of key-value operations (inserts, deletes or
|
|
+** Return the total number of key-value operations (inserts, deletes or
|
|
** updates) that have been performed on the target database since the
|
|
** current RBU update was started.
|
|
*/
|
|
@@ -198139,7 +213760,7 @@ SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *p){
|
|
if( p->eStage==RBU_STAGE_OAL ){
|
|
assert( rc!=SQLITE_DONE );
|
|
if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbRbu, "COMMIT", 0, 0, 0);
|
|
- if( rc==SQLITE_OK ){
|
|
+ if( rc==SQLITE_OK ){
|
|
const char *zBegin = rbuIsVacuum(p) ? "BEGIN" : "BEGIN IMMEDIATE";
|
|
rc = sqlite3_exec(p->dbRbu, zBegin, 0, 0, 0);
|
|
}
|
|
@@ -198150,11 +213771,59 @@ SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *p){
|
|
return rc;
|
|
}
|
|
|
|
+/*
|
|
+** Default xRename callback for RBU.
|
|
+*/
|
|
+static int xDefaultRename(void *pArg, const char *zOld, const char *zNew){
|
|
+ int rc = SQLITE_OK;
|
|
+#if defined(_WIN32_WCE)
|
|
+ {
|
|
+ LPWSTR zWideOld;
|
|
+ LPWSTR zWideNew;
|
|
+
|
|
+ zWideOld = rbuWinUtf8ToUnicode(zOld);
|
|
+ if( zWideOld ){
|
|
+ zWideNew = rbuWinUtf8ToUnicode(zNew);
|
|
+ if( zWideNew ){
|
|
+ if( MoveFileW(zWideOld, zWideNew) ){
|
|
+ rc = SQLITE_OK;
|
|
+ }else{
|
|
+ rc = SQLITE_IOERR;
|
|
+ }
|
|
+ sqlite3_free(zWideNew);
|
|
+ }else{
|
|
+ rc = SQLITE_IOERR_NOMEM;
|
|
+ }
|
|
+ sqlite3_free(zWideOld);
|
|
+ }else{
|
|
+ rc = SQLITE_IOERR_NOMEM;
|
|
+ }
|
|
+ }
|
|
+#else
|
|
+ rc = rename(zOld, zNew) ? SQLITE_IOERR : SQLITE_OK;
|
|
+#endif
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+SQLITE_API void sqlite3rbu_rename_handler(
|
|
+ sqlite3rbu *pRbu,
|
|
+ void *pArg,
|
|
+ int (*xRename)(void *pArg, const char *zOld, const char *zNew)
|
|
+){
|
|
+ if( xRename ){
|
|
+ pRbu->xRename = xRename;
|
|
+ pRbu->pRenameArg = pArg;
|
|
+ }else{
|
|
+ pRbu->xRename = xDefaultRename;
|
|
+ pRbu->pRenameArg = 0;
|
|
+ }
|
|
+}
|
|
+
|
|
/**************************************************************************
|
|
** Beginning of RBU VFS shim methods. The VFS shim modifies the behaviour
|
|
** of a standard VFS in the following ways:
|
|
**
|
|
-** 1. Whenever the first page of a main database file is read or
|
|
+** 1. Whenever the first page of a main database file is read or
|
|
** written, the value of the change-counter cookie is stored in
|
|
** rbu_file.iCookie. Similarly, the value of the "write-version"
|
|
** database header field is stored in rbu_file.iWriteVer. This ensures
|
|
@@ -198162,15 +213831,15 @@ SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *p){
|
|
**
|
|
** 2. Whenever an SQLITE_OPEN_WAL file is opened, the (rbu_file.pWalFd)
|
|
** member variable of the associated database file descriptor is set
|
|
-** to point to the new file. A mutex protected linked list of all main
|
|
-** db fds opened using a particular RBU VFS is maintained at
|
|
+** to point to the new file. A mutex protected linked list of all main
|
|
+** db fds opened using a particular RBU VFS is maintained at
|
|
** rbu_vfs.pMain to facilitate this.
|
|
**
|
|
-** 3. Using a new file-control "SQLITE_FCNTL_RBU", a main db rbu_file
|
|
+** 3. Using a new file-control "SQLITE_FCNTL_RBU", a main db rbu_file
|
|
** object can be marked as the target database of an RBU update. This
|
|
** turns on the following extra special behaviour:
|
|
**
|
|
-** 3a. If xAccess() is called to check if there exists a *-wal file
|
|
+** 3a. If xAccess() is called to check if there exists a *-wal file
|
|
** associated with an RBU target database currently in RBU_STAGE_OAL
|
|
** stage (preparing the *-oal file), the following special handling
|
|
** applies:
|
|
@@ -198183,30 +213852,30 @@ SQLITE_API int sqlite3rbu_savestate(sqlite3rbu *p){
|
|
**
|
|
** Then, when xOpen() is called to open the *-wal file associated with
|
|
** the RBU target in RBU_STAGE_OAL stage, instead of opening the *-wal
|
|
-** file, the rbu vfs opens the corresponding *-oal file instead.
|
|
+** file, the rbu vfs opens the corresponding *-oal file instead.
|
|
**
|
|
** 3b. The *-shm pages returned by xShmMap() for a target db file in
|
|
** RBU_STAGE_OAL mode are actually stored in heap memory. This is to
|
|
** avoid creating a *-shm file on disk. Additionally, xShmLock() calls
|
|
** are no-ops on target database files in RBU_STAGE_OAL mode. This is
|
|
-** because assert() statements in some VFS implementations fail if
|
|
+** because assert() statements in some VFS implementations fail if
|
|
** xShmLock() is called before xShmMap().
|
|
**
|
|
** 3c. If an EXCLUSIVE lock is attempted on a target database file in any
|
|
-** mode except RBU_STAGE_DONE (all work completed and checkpointed), it
|
|
+** mode except RBU_STAGE_DONE (all work completed and checkpointed), it
|
|
** fails with an SQLITE_BUSY error. This is to stop RBU connections
|
|
** from automatically checkpointing a *-wal (or *-oal) file from within
|
|
** sqlite3_close().
|
|
**
|
|
** 3d. In RBU_STAGE_CAPTURE mode, all xRead() calls on the wal file, and
|
|
-** all xWrite() calls on the target database file perform no IO.
|
|
+** all xWrite() calls on the target database file perform no IO.
|
|
** Instead the frame and page numbers that would be read and written
|
|
** are recorded. Additionally, successful attempts to obtain exclusive
|
|
-** xShmLock() WRITER, CHECKPOINTER and READ0 locks on the target
|
|
+** xShmLock() WRITER, CHECKPOINTER and READ0 locks on the target
|
|
** database file are recorded. xShmLock() calls to unlock the same
|
|
** locks are no-ops (so that once obtained, these locks are never
|
|
** relinquished). Finally, calls to xSync() on the target database
|
|
-** file fail with SQLITE_INTERNAL errors.
|
|
+** file fail with SQLITE_NOTICE errors.
|
|
*/
|
|
|
|
static void rbuUnlockShm(rbu_file *p){
|
|
@@ -198278,7 +213947,7 @@ static void rbuMainlistRemove(rbu_file *p){
|
|
}
|
|
|
|
/*
|
|
-** Given that zWal points to a buffer containing a wal file name passed to
|
|
+** Given that zWal points to a buffer containing a wal file name passed to
|
|
** either the xOpen() or xAccess() VFS method, search the main-db list for
|
|
** a file-handle opened by the same database connection on the corresponding
|
|
** database file.
|
|
@@ -198315,9 +213984,12 @@ static int rbuVfsClose(sqlite3_file *pFile){
|
|
sqlite3_free(p->zDel);
|
|
|
|
if( p->openFlags & SQLITE_OPEN_MAIN_DB ){
|
|
+ const sqlite3_io_methods *pMeth = p->pReal->pMethods;
|
|
rbuMainlistRemove(p);
|
|
rbuUnlockShm(p);
|
|
- p->pReal->pMethods->xShmUnmap(p->pReal, 0);
|
|
+ if( pMeth->iVersion>1 && pMeth->xShmUnmap ){
|
|
+ pMeth->xShmUnmap(p->pReal, 0);
|
|
+ }
|
|
}
|
|
else if( (p->openFlags & SQLITE_OPEN_DELETEONCLOSE) && p->pRbu ){
|
|
rbuUpdateTempSize(p, 0);
|
|
@@ -198331,7 +214003,7 @@ static int rbuVfsClose(sqlite3_file *pFile){
|
|
|
|
|
|
/*
|
|
-** Read and return an unsigned 32-bit big-endian integer from the buffer
|
|
+** Read and return an unsigned 32-bit big-endian integer from the buffer
|
|
** passed as the only argument.
|
|
*/
|
|
static u32 rbuGetU32(u8 *aBuf){
|
|
@@ -198361,9 +214033,9 @@ static void rbuPutU16(u8 *aBuf, u16 iVal){
|
|
** Read data from an rbuVfs-file.
|
|
*/
|
|
static int rbuVfsRead(
|
|
- sqlite3_file *pFile,
|
|
- void *zBuf,
|
|
- int iAmt,
|
|
+ sqlite3_file *pFile,
|
|
+ void *zBuf,
|
|
+ int iAmt,
|
|
sqlite_int64 iOfst
|
|
){
|
|
rbu_file *p = (rbu_file*)pFile;
|
|
@@ -198374,20 +214046,20 @@ static int rbuVfsRead(
|
|
assert( p->openFlags & SQLITE_OPEN_WAL );
|
|
rc = rbuCaptureWalRead(p->pRbu, iOfst, iAmt);
|
|
}else{
|
|
- if( pRbu && pRbu->eStage==RBU_STAGE_OAL
|
|
- && (p->openFlags & SQLITE_OPEN_WAL)
|
|
- && iOfst>=pRbu->iOalSz
|
|
+ if( pRbu && pRbu->eStage==RBU_STAGE_OAL
|
|
+ && (p->openFlags & SQLITE_OPEN_WAL)
|
|
+ && iOfst>=pRbu->iOalSz
|
|
){
|
|
rc = SQLITE_OK;
|
|
memset(zBuf, 0, iAmt);
|
|
}else{
|
|
rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst);
|
|
#if 1
|
|
- /* If this is being called to read the first page of the target
|
|
- ** database as part of an rbu vacuum operation, synthesize the
|
|
+ /* If this is being called to read the first page of the target
|
|
+ ** database as part of an rbu vacuum operation, synthesize the
|
|
** contents of the first page if it does not yet exist. Otherwise,
|
|
** SQLite will not check for a *-wal file. */
|
|
- if( pRbu && rbuIsVacuum(pRbu)
|
|
+ if( pRbu && rbuIsVacuum(pRbu)
|
|
&& rc==SQLITE_IOERR_SHORT_READ && iOfst==0
|
|
&& (p->openFlags & SQLITE_OPEN_MAIN_DB)
|
|
&& pRbu->rc==SQLITE_OK
|
|
@@ -198427,9 +214099,9 @@ static int rbuVfsRead(
|
|
** Write data to an rbuVfs-file.
|
|
*/
|
|
static int rbuVfsWrite(
|
|
- sqlite3_file *pFile,
|
|
- const void *zBuf,
|
|
- int iAmt,
|
|
+ sqlite3_file *pFile,
|
|
+ const void *zBuf,
|
|
+ int iAmt,
|
|
sqlite_int64 iOfst
|
|
){
|
|
rbu_file *p = (rbu_file*)pFile;
|
|
@@ -198441,8 +214113,8 @@ static int rbuVfsWrite(
|
|
rc = rbuCaptureDbWrite(p->pRbu, iOfst);
|
|
}else{
|
|
if( pRbu ){
|
|
- if( pRbu->eStage==RBU_STAGE_OAL
|
|
- && (p->openFlags & SQLITE_OPEN_WAL)
|
|
+ if( pRbu->eStage==RBU_STAGE_OAL
|
|
+ && (p->openFlags & SQLITE_OPEN_WAL)
|
|
&& iOfst>=pRbu->iOalSz
|
|
){
|
|
pRbu->iOalSz = iAmt + iOfst;
|
|
@@ -198485,7 +214157,7 @@ static int rbuVfsSync(sqlite3_file *pFile, int flags){
|
|
rbu_file *p = (rbu_file *)pFile;
|
|
if( p->pRbu && p->pRbu->eStage==RBU_STAGE_CAPTURE ){
|
|
if( p->openFlags & SQLITE_OPEN_MAIN_DB ){
|
|
- return SQLITE_INTERNAL;
|
|
+ return SQLITE_NOTICE_RBU;
|
|
}
|
|
return SQLITE_OK;
|
|
}
|
|
@@ -198502,10 +214174,10 @@ static int rbuVfsFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
|
|
|
|
/* If this is an RBU vacuum operation and this is the target database,
|
|
** pretend that it has at least one page. Otherwise, SQLite will not
|
|
- ** check for the existance of a *-wal file. rbuVfsRead() contains
|
|
+ ** check for the existance of a *-wal file. rbuVfsRead() contains
|
|
** similar logic. */
|
|
- if( rc==SQLITE_OK && *pSize==0
|
|
- && p->pRbu && rbuIsVacuum(p->pRbu)
|
|
+ if( rc==SQLITE_OK && *pSize==0
|
|
+ && p->pRbu && rbuIsVacuum(p->pRbu)
|
|
&& (p->openFlags & SQLITE_OPEN_MAIN_DB)
|
|
){
|
|
*pSize = 1024;
|
|
@@ -198522,10 +214194,10 @@ static int rbuVfsLock(sqlite3_file *pFile, int eLock){
|
|
int rc = SQLITE_OK;
|
|
|
|
assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) );
|
|
- if( eLock==SQLITE_LOCK_EXCLUSIVE
|
|
+ if( eLock==SQLITE_LOCK_EXCLUSIVE
|
|
&& (p->bNolock || (pRbu && pRbu->eStage!=RBU_STAGE_DONE))
|
|
){
|
|
- /* Do not allow EXCLUSIVE locks. Preventing SQLite from taking this
|
|
+ /* Do not allow EXCLUSIVE locks. Preventing SQLite from taking this
|
|
** prevents it from checkpointing the database from sqlite3_close(). */
|
|
rc = SQLITE_BUSY;
|
|
}else{
|
|
@@ -198636,22 +214308,24 @@ static int rbuVfsShmLock(sqlite3_file *pFile, int ofst, int n, int flags){
|
|
#endif
|
|
|
|
assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) );
|
|
- if( pRbu && (pRbu->eStage==RBU_STAGE_OAL || pRbu->eStage==RBU_STAGE_MOVE) ){
|
|
- /* Magic number 1 is the WAL_CKPT_LOCK lock. Preventing SQLite from
|
|
- ** taking this lock also prevents any checkpoints from occurring.
|
|
- ** todo: really, it's not clear why this might occur, as
|
|
- ** wal_autocheckpoint ought to be turned off. */
|
|
+ if( pRbu && (
|
|
+ pRbu->eStage==RBU_STAGE_OAL
|
|
+ || pRbu->eStage==RBU_STAGE_MOVE
|
|
+ || pRbu->eStage==RBU_STAGE_DONE
|
|
+ )){
|
|
+ /* Prevent SQLite from taking a shm-lock on the target file when it
|
|
+ ** is supplying heap memory to the upper layer in place of *-shm
|
|
+ ** segments. */
|
|
if( ofst==WAL_LOCK_CKPT && n==1 ) rc = SQLITE_BUSY;
|
|
}else{
|
|
int bCapture = 0;
|
|
if( pRbu && pRbu->eStage==RBU_STAGE_CAPTURE ){
|
|
bCapture = 1;
|
|
}
|
|
-
|
|
if( bCapture==0 || 0==(flags & SQLITE_SHM_UNLOCK) ){
|
|
rc = p->pReal->pMethods->xShmLock(p->pReal, ofst, n, flags);
|
|
if( bCapture && rc==SQLITE_OK ){
|
|
- pRbu->mLock |= (1 << ofst);
|
|
+ pRbu->mLock |= ((1<<n) - 1) << ofst;
|
|
}
|
|
}
|
|
}
|
|
@@ -198663,10 +214337,10 @@ static int rbuVfsShmLock(sqlite3_file *pFile, int ofst, int n, int flags){
|
|
** Obtain a pointer to a mapping of a single 32KiB page of the *-shm file.
|
|
*/
|
|
static int rbuVfsShmMap(
|
|
- sqlite3_file *pFile,
|
|
- int iRegion,
|
|
- int szRegion,
|
|
- int isWrite,
|
|
+ sqlite3_file *pFile,
|
|
+ int iRegion,
|
|
+ int szRegion,
|
|
+ int isWrite,
|
|
void volatile **pp
|
|
){
|
|
rbu_file *p = (rbu_file*)pFile;
|
|
@@ -198674,7 +214348,7 @@ static int rbuVfsShmMap(
|
|
int eStage = (p->pRbu ? p->pRbu->eStage : 0);
|
|
|
|
/* If not in RBU_STAGE_OAL, allow this call to pass through. Or, if this
|
|
- ** rbu is in the RBU_STAGE_OAL state, use heap memory for *-shm space
|
|
+ ** rbu is in the RBU_STAGE_OAL state, use heap memory for *-shm space
|
|
** instead of a file on disk. */
|
|
assert( p->openFlags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_TEMP_DB) );
|
|
if( eStage==RBU_STAGE_OAL ){
|
|
@@ -198774,6 +214448,25 @@ static int rbuVfsOpen(
|
|
rbuVfsShmUnmap, /* xShmUnmap */
|
|
0, 0 /* xFetch, xUnfetch */
|
|
};
|
|
+ static sqlite3_io_methods rbuvfs_io_methods1 = {
|
|
+ 1, /* iVersion */
|
|
+ rbuVfsClose, /* xClose */
|
|
+ rbuVfsRead, /* xRead */
|
|
+ rbuVfsWrite, /* xWrite */
|
|
+ rbuVfsTruncate, /* xTruncate */
|
|
+ rbuVfsSync, /* xSync */
|
|
+ rbuVfsFileSize, /* xFileSize */
|
|
+ rbuVfsLock, /* xLock */
|
|
+ rbuVfsUnlock, /* xUnlock */
|
|
+ rbuVfsCheckReservedLock, /* xCheckReservedLock */
|
|
+ rbuVfsFileControl, /* xFileControl */
|
|
+ rbuVfsSectorSize, /* xSectorSize */
|
|
+ rbuVfsDeviceCharacteristics, /* xDeviceCharacteristics */
|
|
+ 0, 0, 0, 0, 0, 0
|
|
+ };
|
|
+
|
|
+
|
|
+
|
|
rbu_vfs *pRbuVfs = (rbu_vfs*)pVfs;
|
|
sqlite3_vfs *pRealVfs = pRbuVfs->pRealVfs;
|
|
rbu_file *pFd = (rbu_file *)pFile;
|
|
@@ -198798,28 +214491,14 @@ static int rbuVfsOpen(
|
|
rbu_file *pDb = rbuFindMaindb(pRbuVfs, zName, 0);
|
|
if( pDb ){
|
|
if( pDb->pRbu && pDb->pRbu->eStage==RBU_STAGE_OAL ){
|
|
- /* This call is to open a *-wal file. Intead, open the *-oal. This
|
|
- ** code ensures that the string passed to xOpen() is terminated by a
|
|
- ** pair of '\0' bytes in case the VFS attempts to extract a URI
|
|
- ** parameter from it. */
|
|
- const char *zBase = zName;
|
|
- size_t nCopy;
|
|
- char *zCopy;
|
|
+ /* This call is to open a *-wal file. Intead, open the *-oal. */
|
|
+ size_t nOpen;
|
|
if( rbuIsVacuum(pDb->pRbu) ){
|
|
- zBase = sqlite3_db_filename(pDb->pRbu->dbRbu, "main");
|
|
- zBase = sqlite3_filename_wal(zBase);
|
|
- }
|
|
- nCopy = strlen(zBase);
|
|
- zCopy = sqlite3_malloc64(nCopy+2);
|
|
- if( zCopy ){
|
|
- memcpy(zCopy, zBase, nCopy);
|
|
- zCopy[nCopy-3] = 'o';
|
|
- zCopy[nCopy] = '\0';
|
|
- zCopy[nCopy+1] = '\0';
|
|
- zOpen = (const char*)(pFd->zDel = zCopy);
|
|
- }else{
|
|
- rc = SQLITE_NOMEM;
|
|
+ zOpen = sqlite3_db_filename(pDb->pRbu->dbRbu, "main");
|
|
+ zOpen = sqlite3_filename_wal(zOpen);
|
|
}
|
|
+ nOpen = strlen(zOpen);
|
|
+ ((char*)zOpen)[nOpen-3] = 'o';
|
|
pFd->pRbu = pDb->pRbu;
|
|
}
|
|
pDb->pWalFd = pFd;
|
|
@@ -198829,8 +214508,8 @@ static int rbuVfsOpen(
|
|
pFd->pRbu = pRbuVfs->pRbu;
|
|
}
|
|
|
|
- if( oflags & SQLITE_OPEN_MAIN_DB
|
|
- && sqlite3_uri_boolean(zName, "rbu_memory", 0)
|
|
+ if( oflags & SQLITE_OPEN_MAIN_DB
|
|
+ && sqlite3_uri_boolean(zName, "rbu_memory", 0)
|
|
){
|
|
assert( oflags & SQLITE_OPEN_MAIN_DB );
|
|
oflags = SQLITE_OPEN_TEMP_DB | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE |
|
|
@@ -198842,10 +214521,15 @@ static int rbuVfsOpen(
|
|
rc = pRealVfs->xOpen(pRealVfs, zOpen, pFd->pReal, oflags, pOutFlags);
|
|
}
|
|
if( pFd->pReal->pMethods ){
|
|
+ const sqlite3_io_methods *pMeth = pFd->pReal->pMethods;
|
|
/* The xOpen() operation has succeeded. Set the sqlite3_file.pMethods
|
|
** pointer and, if the file is a main database file, link it into the
|
|
** mutex protected linked list of all such files. */
|
|
- pFile->pMethods = &rbuvfs_io_methods;
|
|
+ if( pMeth->iVersion<2 || pMeth->xShmLock==0 ){
|
|
+ pFile->pMethods = &rbuvfs_io_methods1;
|
|
+ }else{
|
|
+ pFile->pMethods = &rbuvfs_io_methods;
|
|
+ }
|
|
if( flags & SQLITE_OPEN_MAIN_DB ){
|
|
rbuMainlistAdd(pFd);
|
|
}
|
|
@@ -198869,9 +214553,9 @@ static int rbuVfsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
|
|
** is available, or false otherwise.
|
|
*/
|
|
static int rbuVfsAccess(
|
|
- sqlite3_vfs *pVfs,
|
|
- const char *zPath,
|
|
- int flags,
|
|
+ sqlite3_vfs *pVfs,
|
|
+ const char *zPath,
|
|
+ int flags,
|
|
int *pResOut
|
|
){
|
|
rbu_vfs *pRbuVfs = (rbu_vfs*)pVfs;
|
|
@@ -198887,7 +214571,7 @@ static int rbuVfsAccess(
|
|
** a) if the *-wal file does exist, return SQLITE_CANTOPEN. This
|
|
** ensures that the RBU extension never tries to update a database
|
|
** in wal mode, even if the first page of the database file has
|
|
- ** been damaged.
|
|
+ ** been damaged.
|
|
**
|
|
** b) if the *-wal file does not exist, claim that it does anyway,
|
|
** causing SQLite to call xOpen() to open it. This call will also
|
|
@@ -198917,9 +214601,9 @@ static int rbuVfsAccess(
|
|
** of at least (DEVSYM_MAX_PATHNAME+1) bytes.
|
|
*/
|
|
static int rbuVfsFullPathname(
|
|
- sqlite3_vfs *pVfs,
|
|
- const char *zPath,
|
|
- int nOut,
|
|
+ sqlite3_vfs *pVfs,
|
|
+ const char *zPath,
|
|
+ int nOut,
|
|
char *zOut
|
|
){
|
|
sqlite3_vfs *pRealVfs = ((rbu_vfs*)pVfs)->pRealVfs;
|
|
@@ -198937,7 +214621,7 @@ static void *rbuVfsDlOpen(sqlite3_vfs *pVfs, const char *zPath){
|
|
|
|
/*
|
|
** Populate the buffer zErrMsg (size nByte bytes) with a human readable
|
|
-** utf-8 string describing the most recent error encountered associated
|
|
+** utf-8 string describing the most recent error encountered associated
|
|
** with dynamic libraries.
|
|
*/
|
|
static void rbuVfsDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
|
|
@@ -198949,8 +214633,8 @@ static void rbuVfsDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
|
|
** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
|
|
*/
|
|
static void (*rbuVfsDlSym(
|
|
- sqlite3_vfs *pVfs,
|
|
- void *pArg,
|
|
+ sqlite3_vfs *pVfs,
|
|
+ void *pArg,
|
|
const char *zSym
|
|
))(void){
|
|
sqlite3_vfs *pRealVfs = ((rbu_vfs*)pVfs)->pRealVfs;
|
|
@@ -198967,7 +214651,7 @@ static void rbuVfsDlClose(sqlite3_vfs *pVfs, void *pHandle){
|
|
#endif /* SQLITE_OMIT_LOAD_EXTENSION */
|
|
|
|
/*
|
|
-** Populate the buffer pointed to by zBufOut with nByte bytes of
|
|
+** Populate the buffer pointed to by zBufOut with nByte bytes of
|
|
** random data.
|
|
*/
|
|
static int rbuVfsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
|
|
@@ -198976,7 +214660,7 @@ static int rbuVfsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
|
|
}
|
|
|
|
/*
|
|
-** Sleep for nMicro microseconds. Return the number of microseconds
|
|
+** Sleep for nMicro microseconds. Return the number of microseconds
|
|
** actually slept.
|
|
*/
|
|
static int rbuVfsSleep(sqlite3_vfs *pVfs, int nMicro){
|
|
@@ -199140,24 +214824,33 @@ SQLITE_API sqlite3_int64 sqlite3rbu_temp_size(sqlite3rbu *pRbu){
|
|
#if (defined(SQLITE_ENABLE_DBSTAT_VTAB) || defined(SQLITE_TEST)) \
|
|
&& !defined(SQLITE_OMIT_VIRTUALTABLE)
|
|
|
|
+/*
|
|
+** The pager and btree modules arrange objects in memory so that there are
|
|
+** always approximately 200 bytes of addressable memory following each page
|
|
+** buffer. This way small buffer overreads caused by corrupt database pages
|
|
+** do not cause undefined behaviour. This module pads each page buffer
|
|
+** by the following number of bytes for the same purpose.
|
|
+*/
|
|
+#define DBSTAT_PAGE_PADDING_BYTES 256
|
|
+
|
|
/*
|
|
** Page paths:
|
|
-**
|
|
-** The value of the 'path' column describes the path taken from the
|
|
-** root-node of the b-tree structure to each page. The value of the
|
|
+**
|
|
+** The value of the 'path' column describes the path taken from the
|
|
+** root-node of the b-tree structure to each page. The value of the
|
|
** root-node path is '/'.
|
|
**
|
|
** The value of the path for the left-most child page of the root of
|
|
** a b-tree is '/000/'. (Btrees store content ordered from left to right
|
|
** so the pages to the left have smaller keys than the pages to the right.)
|
|
** The next to left-most child of the root page is
|
|
-** '/001', and so on, each sibling page identified by a 3-digit hex
|
|
+** '/001', and so on, each sibling page identified by a 3-digit hex
|
|
** value. The children of the 451st left-most sibling have paths such
|
|
** as '/1c2/000/, '/1c2/001/' etc.
|
|
**
|
|
-** Overflow pages are specified by appending a '+' character and a
|
|
+** Overflow pages are specified by appending a '+' character and a
|
|
** six-digit hexadecimal value to the path to the cell they are linked
|
|
-** from. For example, the three overflow pages in a chain linked from
|
|
+** from. For example, the three overflow pages in a chain linked from
|
|
** the left-most cell of the 450th child of the root page are identified
|
|
** by the paths:
|
|
**
|
|
@@ -199171,7 +214864,7 @@ SQLITE_API sqlite3_int64 sqlite3rbu_temp_size(sqlite3rbu *pRbu){
|
|
**
|
|
** '/1c2/000/' // Left-most child of 451st child of root
|
|
*/
|
|
-static const char zDbstatSchema[] =
|
|
+static const char zDbstatSchema[] =
|
|
"CREATE TABLE x("
|
|
" name TEXT," /* 0 Name of table or index */
|
|
" path TEXT," /* 1 Path to page from root (NULL for agg) */
|
|
@@ -199207,9 +214900,8 @@ struct StatCell {
|
|
/* Size information for a single btree page */
|
|
struct StatPage {
|
|
u32 iPgno; /* Page number */
|
|
- DbPage *pPg; /* Page content */
|
|
+ u8 *aPg; /* Page buffer from sqlite3_malloc() */
|
|
int iCell; /* Current cell */
|
|
-
|
|
char *zPath; /* Path to this page */
|
|
|
|
/* Variables populated by statDecodePage(): */
|
|
@@ -199270,6 +214962,7 @@ static int statConnect(
|
|
StatTable *pTab = 0;
|
|
int rc = SQLITE_OK;
|
|
int iDb;
|
|
+ (void)pAux;
|
|
|
|
if( argc>=4 ){
|
|
Token nm;
|
|
@@ -199323,6 +215016,7 @@ static int statBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
|
|
int iSchema = -1;
|
|
int iName = -1;
|
|
int iAgg = -1;
|
|
+ (void)tab;
|
|
|
|
/* Look for a valid schema=? constraint. If found, change the idxNum to
|
|
** 1 and request the value of that constraint be sent to xFilter. And
|
|
@@ -199353,6 +215047,7 @@ static int statBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
|
|
i = 0;
|
|
if( iSchema>=0 ){
|
|
pIdxInfo->aConstraintUsage[iSchema].argvIndex = ++i;
|
|
+ pIdxInfo->aConstraintUsage[iSchema].omit = 1;
|
|
pIdxInfo->idxNum |= 0x01;
|
|
}
|
|
if( iName>=0 ){
|
|
@@ -199365,8 +215060,8 @@ static int statBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
|
|
}
|
|
pIdxInfo->estimatedCost = 1.0;
|
|
|
|
- /* Records are always returned in ascending order of (name, path).
|
|
- ** If this will satisfy the client, set the orderByConsumed flag so that
|
|
+ /* Records are always returned in ascending order of (name, path).
|
|
+ ** If this will satisfy the client, set the orderByConsumed flag so that
|
|
** SQLite does not do an external sort.
|
|
*/
|
|
if( ( pIdxInfo->nOrderBy==1
|
|
@@ -199420,18 +215115,25 @@ static void statClearCells(StatPage *p){
|
|
}
|
|
|
|
static void statClearPage(StatPage *p){
|
|
+ u8 *aPg = p->aPg;
|
|
statClearCells(p);
|
|
- sqlite3PagerUnref(p->pPg);
|
|
sqlite3_free(p->zPath);
|
|
memset(p, 0, sizeof(StatPage));
|
|
+ p->aPg = aPg;
|
|
}
|
|
|
|
static void statResetCsr(StatCursor *pCsr){
|
|
int i;
|
|
- sqlite3_reset(pCsr->pStmt);
|
|
+ /* In some circumstances, specifically if an OOM has occurred, the call
|
|
+ ** to sqlite3_reset() may cause the pager to be reset (emptied). It is
|
|
+ ** important that statClearPage() is called to free any page refs before
|
|
+ ** this happens. dbsqlfuzz 9ed3e4e3816219d3509d711636c38542bf3f40b1. */
|
|
for(i=0; i<ArraySize(pCsr->aPage); i++){
|
|
statClearPage(&pCsr->aPage[i]);
|
|
+ sqlite3_free(pCsr->aPage[i].aPg);
|
|
+ pCsr->aPage[i].aPg = 0;
|
|
}
|
|
+ sqlite3_reset(pCsr->pStmt);
|
|
pCsr->iPage = 0;
|
|
sqlite3_free(pCsr->zPath);
|
|
pCsr->zPath = 0;
|
|
@@ -199472,7 +215174,7 @@ static int getLocalPayload(
|
|
int nLocal;
|
|
int nMinLocal;
|
|
int nMaxLocal;
|
|
-
|
|
+
|
|
if( flags==0x0D ){ /* Table leaf node */
|
|
nMinLocal = (nUsable - 12) * 32 / 255 - 23;
|
|
nMaxLocal = nUsable - 35;
|
|
@@ -199496,7 +215198,7 @@ static int statDecodePage(Btree *pBt, StatPage *p){
|
|
int isLeaf;
|
|
int szPage;
|
|
|
|
- u8 *aData = sqlite3PagerGetData(p->pPg);
|
|
+ u8 *aData = p->aPg;
|
|
u8 *aHdr = &aData[p->iPgno==1 ? 100 : 0];
|
|
|
|
p->flags = aHdr[0];
|
|
@@ -199567,7 +215269,9 @@ static int statDecodePage(Btree *pBt, StatPage *p){
|
|
if( nPayload>(u32)nLocal ){
|
|
int j;
|
|
int nOvfl = ((nPayload - nLocal) + nUsable-4 - 1) / (nUsable - 4);
|
|
- if( iOff+nLocal>nUsable ) goto statPageIsCorrupt;
|
|
+ if( iOff+nLocal+4>nUsable || nPayload>0x7fffffff ){
|
|
+ goto statPageIsCorrupt;
|
|
+ }
|
|
pCell->nLastOvfl = (nPayload-nLocal) - (nOvfl-1) * (nUsable-4);
|
|
pCell->nOvfl = nOvfl;
|
|
pCell->aOvfl = sqlite3_malloc64(sizeof(u32)*nOvfl);
|
|
@@ -199581,7 +215285,7 @@ static int statDecodePage(Btree *pBt, StatPage *p){
|
|
if( rc!=SQLITE_OK ){
|
|
assert( pPg==0 );
|
|
return rc;
|
|
- }
|
|
+ }
|
|
pCell->aOvfl[j] = sqlite3Get4byte(sqlite3PagerGetData(pPg));
|
|
sqlite3PagerUnref(pPg);
|
|
}
|
|
@@ -199624,6 +215328,38 @@ static void statSizeAndOffset(StatCursor *pCsr){
|
|
}
|
|
}
|
|
|
|
+/*
|
|
+** Load a copy of the page data for page iPg into the buffer belonging
|
|
+** to page object pPg. Allocate the buffer if necessary. Return SQLITE_OK
|
|
+** if successful, or an SQLite error code otherwise.
|
|
+*/
|
|
+static int statGetPage(
|
|
+ Btree *pBt, /* Load page from this b-tree */
|
|
+ u32 iPg, /* Page number to load */
|
|
+ StatPage *pPg /* Load page into this object */
|
|
+){
|
|
+ int pgsz = sqlite3BtreeGetPageSize(pBt);
|
|
+ DbPage *pDbPage = 0;
|
|
+ int rc;
|
|
+
|
|
+ if( pPg->aPg==0 ){
|
|
+ pPg->aPg = (u8*)sqlite3_malloc(pgsz + DBSTAT_PAGE_PADDING_BYTES);
|
|
+ if( pPg->aPg==0 ){
|
|
+ return SQLITE_NOMEM_BKPT;
|
|
+ }
|
|
+ memset(&pPg->aPg[pgsz], 0, DBSTAT_PAGE_PADDING_BYTES);
|
|
+ }
|
|
+
|
|
+ rc = sqlite3PagerGet(sqlite3BtreePager(pBt), iPg, &pDbPage, 0);
|
|
+ if( rc==SQLITE_OK ){
|
|
+ const u8 *a = sqlite3PagerGetData(pDbPage);
|
|
+ memcpy(pPg->aPg, a, pgsz);
|
|
+ sqlite3PagerUnref(pDbPage);
|
|
+ }
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
/*
|
|
** Move a DBSTAT cursor to the next entry. Normally, the next
|
|
** entry will be the next page, but in aggregated mode (pCsr->isAgg!=0),
|
|
@@ -199642,7 +215378,7 @@ static int statNext(sqlite3_vtab_cursor *pCursor){
|
|
pCsr->zPath = 0;
|
|
|
|
statNextRestart:
|
|
- if( pCsr->aPage[0].pPg==0 ){
|
|
+ if( pCsr->iPage<0 ){
|
|
/* Start measuring space on the next btree */
|
|
statResetCounts(pCsr);
|
|
rc = sqlite3_step(pCsr->pStmt);
|
|
@@ -199654,7 +215390,7 @@ static int statNext(sqlite3_vtab_cursor *pCursor){
|
|
pCsr->isEof = 1;
|
|
return sqlite3_reset(pCsr->pStmt);
|
|
}
|
|
- rc = sqlite3PagerGet(pPager, iRoot, &pCsr->aPage[0].pPg, 0);
|
|
+ rc = statGetPage(pBt, iRoot, &pCsr->aPage[0]);
|
|
pCsr->aPage[0].iPgno = iRoot;
|
|
pCsr->aPage[0].iCell = 0;
|
|
if( !pCsr->isAgg ){
|
|
@@ -199676,7 +215412,7 @@ static int statNext(sqlite3_vtab_cursor *pCursor){
|
|
while( pCell->iOvfl<pCell->nOvfl ){
|
|
int nUsable, iOvfl;
|
|
sqlite3BtreeEnter(pBt);
|
|
- nUsable = sqlite3BtreeGetPageSize(pBt) -
|
|
+ nUsable = sqlite3BtreeGetPageSize(pBt) -
|
|
sqlite3BtreeGetReserveNoMutex(pBt);
|
|
sqlite3BtreeLeave(pBt);
|
|
pCsr->nPage++;
|
|
@@ -199705,9 +215441,8 @@ static int statNext(sqlite3_vtab_cursor *pCursor){
|
|
|
|
if( !p->iRightChildPg || p->iCell>p->nCell ){
|
|
statClearPage(p);
|
|
- if( pCsr->iPage>0 ){
|
|
- pCsr->iPage--;
|
|
- }else if( pCsr->isAgg ){
|
|
+ pCsr->iPage--;
|
|
+ if( pCsr->isAgg && pCsr->iPage<0 ){
|
|
/* label-statNext-done: When computing aggregate space usage over
|
|
** an entire btree, this is the exit point from this function */
|
|
return SQLITE_OK;
|
|
@@ -199726,7 +215461,7 @@ static int statNext(sqlite3_vtab_cursor *pCursor){
|
|
}else{
|
|
p[1].iPgno = p->aCell[p->iCell].iChildPg;
|
|
}
|
|
- rc = sqlite3PagerGet(pPager, p[1].iPgno, &p[1].pPg, 0);
|
|
+ rc = statGetPage(pBt, p[1].iPgno, &p[1]);
|
|
pCsr->nPage++;
|
|
p[1].iCell = 0;
|
|
if( !pCsr->isAgg ){
|
|
@@ -199796,7 +215531,7 @@ static int statEof(sqlite3_vtab_cursor *pCursor){
|
|
** meaning of the bits in idxNum.
|
|
*/
|
|
static int statFilter(
|
|
- sqlite3_vtab_cursor *pCursor,
|
|
+ sqlite3_vtab_cursor *pCursor,
|
|
int idxNum, const char *idxStr,
|
|
int argc, sqlite3_value **argv
|
|
){
|
|
@@ -199807,6 +215542,8 @@ static int statFilter(
|
|
int iArg = 0; /* Count of argv[] parameters used so far */
|
|
int rc = SQLITE_OK; /* Result of this operation */
|
|
const char *zName = 0; /* Only provide analysis of this table */
|
|
+ (void)argc;
|
|
+ (void)idxStr;
|
|
|
|
statResetCsr(pCsr);
|
|
sqlite3_finalize(pCsr->pStmt);
|
|
@@ -199836,10 +215573,10 @@ static int statFilter(
|
|
pSql = sqlite3_str_new(pTab->db);
|
|
sqlite3_str_appendf(pSql,
|
|
"SELECT * FROM ("
|
|
- "SELECT 'sqlite_master' AS name,1 AS rootpage,'table' AS type"
|
|
+ "SELECT 'sqlite_schema' AS name,1 AS rootpage,'table' AS type"
|
|
" UNION ALL "
|
|
"SELECT name,rootpage,type"
|
|
- " FROM \"%w\".sqlite_master WHERE rootpage!=0)",
|
|
+ " FROM \"%w\".sqlite_schema WHERE rootpage!=0)",
|
|
pTab->db->aDb[pCsr->iDb].zDbSName);
|
|
if( zName ){
|
|
sqlite3_str_appendf(pSql, "WHERE name=%Q", zName);
|
|
@@ -199856,14 +215593,15 @@ static int statFilter(
|
|
}
|
|
|
|
if( rc==SQLITE_OK ){
|
|
+ pCsr->iPage = -1;
|
|
rc = statNext(pCursor);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
static int statColumn(
|
|
- sqlite3_vtab_cursor *pCursor,
|
|
- sqlite3_context *ctx,
|
|
+ sqlite3_vtab_cursor *pCursor,
|
|
+ sqlite3_context *ctx,
|
|
int i
|
|
){
|
|
StatCursor *pCsr = (StatCursor *)pCursor;
|
|
@@ -199889,16 +215627,16 @@ static int statColumn(
|
|
}
|
|
break;
|
|
case 4: /* ncell */
|
|
- sqlite3_result_int(ctx, pCsr->nCell);
|
|
+ sqlite3_result_int64(ctx, pCsr->nCell);
|
|
break;
|
|
case 5: /* payload */
|
|
- sqlite3_result_int(ctx, pCsr->nPayload);
|
|
+ sqlite3_result_int64(ctx, pCsr->nPayload);
|
|
break;
|
|
case 6: /* unused */
|
|
- sqlite3_result_int(ctx, pCsr->nUnused);
|
|
+ sqlite3_result_int64(ctx, pCsr->nUnused);
|
|
break;
|
|
case 7: /* mx_payload */
|
|
- sqlite3_result_int(ctx, pCsr->nMxPayload);
|
|
+ sqlite3_result_int64(ctx, pCsr->nMxPayload);
|
|
break;
|
|
case 8: /* pgoffset */
|
|
if( !pCsr->isAgg ){
|
|
@@ -199906,7 +215644,7 @@ static int statColumn(
|
|
}
|
|
break;
|
|
case 9: /* pgsize */
|
|
- sqlite3_result_int(ctx, pCsr->szPage);
|
|
+ sqlite3_result_int64(ctx, pCsr->szPage);
|
|
break;
|
|
case 10: { /* schema */
|
|
sqlite3 *db = sqlite3_context_db_handle(ctx);
|
|
@@ -199981,7 +215719,7 @@ SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3 *db){ return SQLITE_OK; }
|
|
** This file contains an implementation of the "sqlite_dbpage" virtual table.
|
|
**
|
|
** The sqlite_dbpage virtual table is used to read or write whole raw
|
|
-** pages of the database file. The pager interface is used so that
|
|
+** pages of the database file. The pager interface is used so that
|
|
** uncommitted changes and changes recorded in the WAL file are correctly
|
|
** retrieved.
|
|
**
|
|
@@ -200040,9 +215778,13 @@ static int dbpageConnect(
|
|
){
|
|
DbpageTable *pTab = 0;
|
|
int rc = SQLITE_OK;
|
|
+ (void)pAux;
|
|
+ (void)argc;
|
|
+ (void)argv;
|
|
+ (void)pzErr;
|
|
|
|
sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY);
|
|
- rc = sqlite3_declare_vtab(db,
|
|
+ rc = sqlite3_declare_vtab(db,
|
|
"CREATE TABLE x(pgno INTEGER PRIMARY KEY, data BLOB, schema HIDDEN)");
|
|
if( rc==SQLITE_OK ){
|
|
pTab = (DbpageTable *)sqlite3_malloc64(sizeof(DbpageTable));
|
|
@@ -200078,6 +215820,7 @@ static int dbpageDisconnect(sqlite3_vtab *pVtab){
|
|
static int dbpageBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
|
|
int i;
|
|
int iPlan = 0;
|
|
+ (void)tab;
|
|
|
|
/* If there is a schema= constraint, it must be honored. Report a
|
|
** ridiculously large estimated cost if the schema= constraint is
|
|
@@ -200124,6 +215867,7 @@ static int dbpageBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
|
|
){
|
|
pIdxInfo->orderByConsumed = 1;
|
|
}
|
|
+ sqlite3VtabUsesAllSchemas(pIdxInfo);
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
@@ -200182,7 +215926,7 @@ static int dbpageEof(sqlite3_vtab_cursor *pCursor){
|
|
** idxStr is not used
|
|
*/
|
|
static int dbpageFilter(
|
|
- sqlite3_vtab_cursor *pCursor,
|
|
+ sqlite3_vtab_cursor *pCursor,
|
|
int idxNum, const char *idxStr,
|
|
int argc, sqlite3_value **argv
|
|
){
|
|
@@ -200192,8 +215936,10 @@ static int dbpageFilter(
|
|
sqlite3 *db = pTab->db;
|
|
Btree *pBt;
|
|
|
|
+ (void)idxStr;
|
|
+
|
|
/* Default setting is no rows of result */
|
|
- pCsr->pgno = 1;
|
|
+ pCsr->pgno = 1;
|
|
pCsr->mxPgno = 0;
|
|
|
|
if( idxNum & 2 ){
|
|
@@ -200206,7 +215952,7 @@ static int dbpageFilter(
|
|
pCsr->iDb = 0;
|
|
}
|
|
pBt = db->aDb[pCsr->iDb].pBt;
|
|
- if( pBt==0 ) return SQLITE_OK;
|
|
+ if( NEVER(pBt==0) ) return SQLITE_OK;
|
|
pCsr->pPager = sqlite3BtreePager(pBt);
|
|
pCsr->szPage = sqlite3BtreeGetPageSize(pBt);
|
|
pCsr->mxPgno = sqlite3BtreeLastPage(pBt);
|
|
@@ -200228,8 +215974,8 @@ static int dbpageFilter(
|
|
}
|
|
|
|
static int dbpageColumn(
|
|
- sqlite3_vtab_cursor *pCursor,
|
|
- sqlite3_context *ctx,
|
|
+ sqlite3_vtab_cursor *pCursor,
|
|
+ sqlite3_context *ctx,
|
|
int i
|
|
){
|
|
DbpageCursor *pCsr = (DbpageCursor *)pCursor;
|
|
@@ -200241,12 +215987,18 @@ static int dbpageColumn(
|
|
}
|
|
case 1: { /* data */
|
|
DbPage *pDbPage = 0;
|
|
- rc = sqlite3PagerGet(pCsr->pPager, pCsr->pgno, (DbPage**)&pDbPage, 0);
|
|
- if( rc==SQLITE_OK ){
|
|
- sqlite3_result_blob(ctx, sqlite3PagerGetData(pDbPage), pCsr->szPage,
|
|
- SQLITE_TRANSIENT);
|
|
+ if( pCsr->pgno==((PENDING_BYTE/pCsr->szPage)+1) ){
|
|
+ /* The pending byte page. Assume it is zeroed out. Attempting to
|
|
+ ** request this page from the page is an SQLITE_CORRUPT error. */
|
|
+ sqlite3_result_zeroblob(ctx, pCsr->szPage);
|
|
+ }else{
|
|
+ rc = sqlite3PagerGet(pCsr->pPager, pCsr->pgno, (DbPage**)&pDbPage, 0);
|
|
+ if( rc==SQLITE_OK ){
|
|
+ sqlite3_result_blob(ctx, sqlite3PagerGetData(pDbPage), pCsr->szPage,
|
|
+ SQLITE_TRANSIENT);
|
|
+ }
|
|
+ sqlite3PagerUnref(pDbPage);
|
|
}
|
|
- sqlite3PagerUnref(pDbPage);
|
|
break;
|
|
}
|
|
default: { /* schema */
|
|
@@ -200255,7 +216007,7 @@ static int dbpageColumn(
|
|
break;
|
|
}
|
|
}
|
|
- return SQLITE_OK;
|
|
+ return rc;
|
|
}
|
|
|
|
static int dbpageRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
|
|
@@ -200281,6 +216033,7 @@ static int dbpageUpdate(
|
|
Pager *pPager;
|
|
int szPage;
|
|
|
|
+ (void)pRowid;
|
|
if( pTab->db->flags & SQLITE_Defensive ){
|
|
zErr = "read-only";
|
|
goto update_fail;
|
|
@@ -200290,23 +216043,25 @@ static int dbpageUpdate(
|
|
goto update_fail;
|
|
}
|
|
pgno = sqlite3_value_int(argv[0]);
|
|
- if( (Pgno)sqlite3_value_int(argv[1])!=pgno ){
|
|
+ if( sqlite3_value_type(argv[0])==SQLITE_NULL
|
|
+ || (Pgno)sqlite3_value_int(argv[1])!=pgno
|
|
+ ){
|
|
zErr = "cannot insert";
|
|
goto update_fail;
|
|
}
|
|
zSchema = (const char*)sqlite3_value_text(argv[4]);
|
|
- iDb = zSchema ? sqlite3FindDbName(pTab->db, zSchema) : -1;
|
|
- if( iDb<0 ){
|
|
+ iDb = ALWAYS(zSchema) ? sqlite3FindDbName(pTab->db, zSchema) : -1;
|
|
+ if( NEVER(iDb<0) ){
|
|
zErr = "no such schema";
|
|
goto update_fail;
|
|
}
|
|
pBt = pTab->db->aDb[iDb].pBt;
|
|
- if( pgno<1 || pBt==0 || pgno>(int)sqlite3BtreeLastPage(pBt) ){
|
|
+ if( NEVER(pgno<1) || NEVER(pBt==0) || NEVER(pgno>sqlite3BtreeLastPage(pBt)) ){
|
|
zErr = "bad page number";
|
|
goto update_fail;
|
|
}
|
|
szPage = sqlite3BtreeGetPageSize(pBt);
|
|
- if( sqlite3_value_type(argv[3])!=SQLITE_BLOB
|
|
+ if( sqlite3_value_type(argv[3])!=SQLITE_BLOB
|
|
|| sqlite3_value_bytes(argv[3])!=szPage
|
|
){
|
|
zErr = "bad page value";
|
|
@@ -200315,11 +216070,12 @@ static int dbpageUpdate(
|
|
pPager = sqlite3BtreePager(pBt);
|
|
rc = sqlite3PagerGet(pPager, pgno, (DbPage**)&pDbPage, 0);
|
|
if( rc==SQLITE_OK ){
|
|
- rc = sqlite3PagerWrite(pDbPage);
|
|
- if( rc==SQLITE_OK ){
|
|
- memcpy(sqlite3PagerGetData(pDbPage),
|
|
- sqlite3_value_blob(argv[3]),
|
|
- szPage);
|
|
+ const void *pData = sqlite3_value_blob(argv[3]);
|
|
+ assert( pData!=0 || pTab->db->mallocFailed );
|
|
+ if( pData
|
|
+ && (rc = sqlite3PagerWrite(pDbPage))==SQLITE_OK
|
|
+ ){
|
|
+ memcpy(sqlite3PagerGetData(pDbPage), pData, szPage);
|
|
}
|
|
}
|
|
sqlite3PagerUnref(pDbPage);
|
|
@@ -200341,7 +216097,7 @@ static int dbpageBegin(sqlite3_vtab *pVtab){
|
|
int i;
|
|
for(i=0; i<db->nDb; i++){
|
|
Btree *pBt = db->aDb[i].pBt;
|
|
- if( pBt ) sqlite3BtreeBeginTrans(pBt, 1, 0);
|
|
+ if( pBt ) (void)sqlite3BtreeBeginTrans(pBt, 1, 0);
|
|
}
|
|
return SQLITE_OK;
|
|
}
|
|
@@ -200429,12 +216185,15 @@ struct SessionHook {
|
|
struct sqlite3_session {
|
|
sqlite3 *db; /* Database handle session is attached to */
|
|
char *zDb; /* Name of database session is attached to */
|
|
+ int bEnableSize; /* True if changeset_size() enabled */
|
|
int bEnable; /* True if currently recording */
|
|
int bIndirect; /* True if all changes are indirect */
|
|
int bAutoAttach; /* True to auto-attach tables */
|
|
int rc; /* Non-zero if an error has occurred */
|
|
void *pFilterCtx; /* First argument to pass to xTableFilter */
|
|
int (*xTableFilter)(void *pCtx, const char *zTab);
|
|
+ i64 nMalloc; /* Number of bytes of data allocated */
|
|
+ i64 nMaxChangesetSize;
|
|
sqlite3_value *pZeroBlob; /* Value containing X'' */
|
|
sqlite3_session *pNext; /* Next session object on same db. */
|
|
SessionTable *pTable; /* List of attached tables */
|
|
@@ -200451,7 +216210,7 @@ struct SessionBuffer {
|
|
};
|
|
|
|
/*
|
|
-** An object of this type is used internally as an abstraction for
|
|
+** An object of this type is used internally as an abstraction for
|
|
** input data. Input data may be supplied either as a single large buffer
|
|
** (e.g. sqlite3changeset_start()) or using a stream function (e.g.
|
|
** sqlite3changeset_start_strm()).
|
|
@@ -200477,6 +216236,7 @@ struct sqlite3_changeset_iter {
|
|
SessionBuffer tblhdr; /* Buffer to hold apValue/zTab/abPK/ */
|
|
int bPatchset; /* True if this is a patchset */
|
|
int bInvert; /* True to invert changeset */
|
|
+ int bSkipEmpty; /* Skip noop UPDATE changes */
|
|
int rc; /* Iterator error code */
|
|
sqlite3_stmt *pConflict; /* Points to conflicting row, if any */
|
|
char *zTab; /* Current table */
|
|
@@ -200512,11 +216272,11 @@ struct SessionTable {
|
|
SessionChange **apChange; /* Hash table buckets */
|
|
};
|
|
|
|
-/*
|
|
+/*
|
|
** RECORD FORMAT:
|
|
**
|
|
-** The following record format is similar to (but not compatible with) that
|
|
-** used in SQLite database files. This format is used as part of the
|
|
+** The following record format is similar to (but not compatible with) that
|
|
+** used in SQLite database files. This format is used as part of the
|
|
** change-set binary format, and so must be architecture independent.
|
|
**
|
|
** Unlike the SQLite database record format, each field is self-contained -
|
|
@@ -200550,7 +216310,7 @@ struct SessionTable {
|
|
** Real values:
|
|
** An 8-byte big-endian IEEE 754-2008 real value.
|
|
**
|
|
-** Varint values are encoded in the same way as varints in the SQLite
|
|
+** Varint values are encoded in the same way as varints in the SQLite
|
|
** record format.
|
|
**
|
|
** CHANGESET FORMAT:
|
|
@@ -200582,7 +216342,7 @@ struct SessionTable {
|
|
**
|
|
** The new.* record that is part of each INSERT change contains the values
|
|
** that make up the new row. Similarly, the old.* record that is part of each
|
|
-** DELETE change contains the values that made up the row that was deleted
|
|
+** DELETE change contains the values that made up the row that was deleted
|
|
** from the database. In the changeset format, the records that are part
|
|
** of INSERT or DELETE changes never contain any undefined (type byte 0x00)
|
|
** fields.
|
|
@@ -200591,8 +216351,8 @@ struct SessionTable {
|
|
** associated with table columns that are not PRIMARY KEY columns and are
|
|
** not modified by the UPDATE change are set to "undefined". Other fields
|
|
** are set to the values that made up the row before the UPDATE that the
|
|
-** change records took place. Within the new.* record, fields associated
|
|
-** with table columns modified by the UPDATE change contain the new
|
|
+** change records took place. Within the new.* record, fields associated
|
|
+** with table columns modified by the UPDATE change contain the new
|
|
** values. Fields associated with table columns that are not modified
|
|
** are set to "undefined".
|
|
**
|
|
@@ -200618,7 +216378,7 @@ struct SessionTable {
|
|
**
|
|
** As in the changeset format, each field of the single record that is part
|
|
** of a patchset change is associated with the correspondingly positioned
|
|
-** table column, counting from left to right within the CREATE TABLE
|
|
+** table column, counting from left to right within the CREATE TABLE
|
|
** statement.
|
|
**
|
|
** For a DELETE change, all fields within the record except those associated
|
|
@@ -200636,7 +216396,7 @@ struct SessionTable {
|
|
**
|
|
** REBASE BLOB FORMAT:
|
|
**
|
|
-** A rebase blob may be output by sqlite3changeset_apply_v2() and its
|
|
+** A rebase blob may be output by sqlite3changeset_apply_v2() and its
|
|
** streaming equivalent for use with the sqlite3_rebaser APIs to rebase
|
|
** existing changesets. A rebase blob contains one entry for each conflict
|
|
** resolved using either the OMIT or REPLACE strategies within the apply_v2()
|
|
@@ -200660,7 +216420,7 @@ struct SessionTable {
|
|
**
|
|
** In a rebase blob, the first field is set to SQLITE_INSERT if the change
|
|
** that caused the conflict was an INSERT or UPDATE, or to SQLITE_DELETE if
|
|
-** it was a DELETE. The second field is set to 0x01 if the conflict
|
|
+** it was a DELETE. The second field is set to 0x01 if the conflict
|
|
** resolution strategy was REPLACE, or 0x00 if it was OMIT.
|
|
**
|
|
** If the change that caused the conflict was a DELETE, then the single
|
|
@@ -200676,15 +216436,16 @@ struct SessionTable {
|
|
** this structure stored in a SessionTable.aChange[] hash table.
|
|
*/
|
|
struct SessionChange {
|
|
- int op; /* One of UPDATE, DELETE, INSERT */
|
|
- int bIndirect; /* True if this change is "indirect" */
|
|
+ u8 op; /* One of UPDATE, DELETE, INSERT */
|
|
+ u8 bIndirect; /* True if this change is "indirect" */
|
|
+ int nMaxSize; /* Max size of eventual changeset record */
|
|
int nRecord; /* Number of bytes in buffer aRecord[] */
|
|
u8 *aRecord; /* Buffer containing old.* record */
|
|
SessionChange *pNext; /* For hash-table collisions */
|
|
};
|
|
|
|
/*
|
|
-** Write a varint with value iVal into the buffer at aBuf. Return the
|
|
+** Write a varint with value iVal into the buffer at aBuf. Return the
|
|
** number of bytes written.
|
|
*/
|
|
static int sessionVarintPut(u8 *aBuf, int iVal){
|
|
@@ -200699,7 +216460,7 @@ static int sessionVarintLen(int iVal){
|
|
}
|
|
|
|
/*
|
|
-** Read a varint value from aBuf[] into *piVal. Return the number of
|
|
+** Read a varint value from aBuf[] into *piVal. Return the number of
|
|
** bytes read.
|
|
*/
|
|
static int sessionVarintGet(u8 *aBuf, int *piVal){
|
|
@@ -200738,13 +216499,13 @@ static void sessionPutI64(u8 *aBuf, sqlite3_int64 i){
|
|
** This function is used to serialize the contents of value pValue (see
|
|
** comment titled "RECORD FORMAT" above).
|
|
**
|
|
-** If it is non-NULL, the serialized form of the value is written to
|
|
+** If it is non-NULL, the serialized form of the value is written to
|
|
** buffer aBuf. *pnWrite is set to the number of bytes written before
|
|
** returning. Or, if aBuf is NULL, the only thing this function does is
|
|
** set *pnWrite.
|
|
**
|
|
** If no error occurs, SQLITE_OK is returned. Or, if an OOM error occurs
|
|
-** within a call to sqlite3_value_text() (may fail if the db is utf-16))
|
|
+** within a call to sqlite3_value_text() (may fail if the db is utf-16))
|
|
** SQLITE_NOMEM is returned.
|
|
*/
|
|
static int sessionSerializeValue(
|
|
@@ -200756,16 +216517,16 @@ static int sessionSerializeValue(
|
|
|
|
if( pValue ){
|
|
int eType; /* Value type (SQLITE_NULL, TEXT etc.) */
|
|
-
|
|
+
|
|
eType = sqlite3_value_type(pValue);
|
|
if( aBuf ) aBuf[0] = eType;
|
|
-
|
|
+
|
|
switch( eType ){
|
|
- case SQLITE_NULL:
|
|
+ case SQLITE_NULL:
|
|
nByte = 1;
|
|
break;
|
|
-
|
|
- case SQLITE_INTEGER:
|
|
+
|
|
+ case SQLITE_INTEGER:
|
|
case SQLITE_FLOAT:
|
|
if( aBuf ){
|
|
/* TODO: SQLite does something special to deal with mixed-endian
|
|
@@ -200782,14 +216543,14 @@ static int sessionSerializeValue(
|
|
}
|
|
sessionPutI64(&aBuf[1], i);
|
|
}
|
|
- nByte = 9;
|
|
+ nByte = 9;
|
|
break;
|
|
-
|
|
+
|
|
default: {
|
|
u8 *z;
|
|
int n;
|
|
int nVarint;
|
|
-
|
|
+
|
|
assert( eType==SQLITE_TEXT || eType==SQLITE_BLOB );
|
|
if( eType==SQLITE_TEXT ){
|
|
z = (u8 *)sqlite3_value_text(pValue);
|
|
@@ -200799,12 +216560,12 @@ static int sessionSerializeValue(
|
|
n = sqlite3_value_bytes(pValue);
|
|
if( z==0 && (eType!=SQLITE_BLOB || n>0) ) return SQLITE_NOMEM;
|
|
nVarint = sessionVarintLen(n);
|
|
-
|
|
+
|
|
if( aBuf ){
|
|
sessionVarintPut(&aBuf[1], n);
|
|
- if( n ) memcpy(&aBuf[nVarint + 1], z, n);
|
|
+ if( n>0 ) memcpy(&aBuf[nVarint + 1], z, n);
|
|
}
|
|
-
|
|
+
|
|
nByte = 1 + nVarint + n;
|
|
break;
|
|
}
|
|
@@ -200818,6 +216579,26 @@ static int sessionSerializeValue(
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
+/*
|
|
+** Allocate and return a pointer to a buffer nByte bytes in size. If
|
|
+** pSession is not NULL, increase the sqlite3_session.nMalloc variable
|
|
+** by the number of bytes allocated.
|
|
+*/
|
|
+static void *sessionMalloc64(sqlite3_session *pSession, i64 nByte){
|
|
+ void *pRet = sqlite3_malloc64(nByte);
|
|
+ if( pSession ) pSession->nMalloc += sqlite3_msize(pRet);
|
|
+ return pRet;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Free buffer pFree, which must have been allocated by an earlier
|
|
+** call to sessionMalloc64(). If pSession is not NULL, decrease the
|
|
+** sqlite3_session.nMalloc counter by the number of bytes freed.
|
|
+*/
|
|
+static void sessionFree(sqlite3_session *pSession, void *pFree){
|
|
+ if( pSession ) pSession->nMalloc -= sqlite3_msize(pFree);
|
|
+ sqlite3_free(pFree);
|
|
+}
|
|
|
|
/*
|
|
** This macro is used to calculate hash key values for data structures. In
|
|
@@ -200846,7 +216627,7 @@ static unsigned int sessionHashAppendI64(unsigned int h, i64 i){
|
|
}
|
|
|
|
/*
|
|
-** Append the hash of the blob passed via the second and third arguments to
|
|
+** Append the hash of the blob passed via the second and third arguments to
|
|
** the hash-key value passed as the first. Return the new hash-key value.
|
|
*/
|
|
static unsigned int sessionHashAppendBlob(unsigned int h, int n, const u8 *z){
|
|
@@ -200865,7 +216646,7 @@ static unsigned int sessionHashAppendType(unsigned int h, int eType){
|
|
|
|
/*
|
|
** This function may only be called from within a pre-update callback.
|
|
-** It calculates a hash based on the primary key values of the old.* or
|
|
+** It calculates a hash based on the primary key values of the old.* or
|
|
** new.* row currently available and, assuming no error occurs, writes it to
|
|
** *piHash before returning. If the primary key contains one or more NULL
|
|
** values, *pbNullPK is set to true before returning.
|
|
@@ -200972,12 +216753,12 @@ static unsigned int sessionChangeHash(
|
|
int isPK = pTab->abPK[i];
|
|
if( bPkOnly && isPK==0 ) continue;
|
|
|
|
- /* It is not possible for eType to be SQLITE_NULL here. The session
|
|
+ /* It is not possible for eType to be SQLITE_NULL here. The session
|
|
** module does not record changes for rows with NULL values stored in
|
|
** primary key columns. */
|
|
- assert( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT
|
|
- || eType==SQLITE_TEXT || eType==SQLITE_BLOB
|
|
- || eType==SQLITE_NULL || eType==0
|
|
+ assert( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT
|
|
+ || eType==SQLITE_TEXT || eType==SQLITE_BLOB
|
|
+ || eType==SQLITE_NULL || eType==0
|
|
);
|
|
assert( !isPK || (eType!=0 && eType!=SQLITE_NULL) );
|
|
|
|
@@ -200988,7 +216769,7 @@ static unsigned int sessionChangeHash(
|
|
h = sessionHashAppendI64(h, sessionGetI64(a));
|
|
a += 8;
|
|
}else{
|
|
- int n;
|
|
+ int n;
|
|
a += sessionVarintGet(a, &n);
|
|
h = sessionHashAppendBlob(h, n, a);
|
|
a += n;
|
|
@@ -201003,7 +216784,7 @@ static unsigned int sessionChangeHash(
|
|
/*
|
|
** Arguments aLeft and aRight are pointers to change records for table pTab.
|
|
** This function returns true if the two records apply to the same row (i.e.
|
|
-** have the same values stored in the primary key columns), or false
|
|
+** have the same values stored in the primary key columns), or false
|
|
** otherwise.
|
|
*/
|
|
static int sessionChangeEqual(
|
|
@@ -201040,17 +216821,17 @@ static int sessionChangeEqual(
|
|
** Arguments aLeft and aRight both point to buffers containing change
|
|
** records with nCol columns. This function "merges" the two records into
|
|
** a single records which is written to the buffer at *paOut. *paOut is
|
|
-** then set to point to one byte after the last byte written before
|
|
+** then set to point to one byte after the last byte written before
|
|
** returning.
|
|
**
|
|
-** The merging of records is done as follows: For each column, if the
|
|
+** The merging of records is done as follows: For each column, if the
|
|
** aRight record contains a value for the column, copy the value from
|
|
** their. Otherwise, if aLeft contains a value, copy it. If neither
|
|
** record contains a value for a given column, then neither does the
|
|
** output record.
|
|
*/
|
|
static void sessionMergeRecord(
|
|
- u8 **paOut,
|
|
+ u8 **paOut,
|
|
int nCol,
|
|
u8 *aLeft,
|
|
u8 *aRight
|
|
@@ -201080,13 +216861,13 @@ static void sessionMergeRecord(
|
|
/*
|
|
** This is a helper function used by sessionMergeUpdate().
|
|
**
|
|
-** When this function is called, both *paOne and *paTwo point to a value
|
|
-** within a change record. Before it returns, both have been advanced so
|
|
+** When this function is called, both *paOne and *paTwo point to a value
|
|
+** within a change record. Before it returns, both have been advanced so
|
|
** as to point to the next value in the record.
|
|
**
|
|
** If, when this function is called, *paTwo points to a valid value (i.e.
|
|
** *paTwo[0] is not 0x00 - the "no value" placeholder), a copy of the *paTwo
|
|
-** pointer is returned and *pnVal is set to the number of bytes in the
|
|
+** pointer is returned and *pnVal is set to the number of bytes in the
|
|
** serialized value. Otherwise, a copy of *paOne is returned and *pnVal
|
|
** set to the number of bytes in the value at *paOne. If *paOne points
|
|
** to the "no value" placeholder, *pnVal is set to 1. In other words:
|
|
@@ -201185,8 +216966,8 @@ static int sessionMergeUpdate(
|
|
|
|
aOld = sessionMergeValue(&aOld1, &aOld2, &nOld);
|
|
aNew = sessionMergeValue(&aNew1, &aNew2, &nNew);
|
|
- if( bPatchset==0
|
|
- && (pTab->abPK[i] || (nOld==nNew && 0==memcmp(aOld, aNew, nNew)))
|
|
+ if( bPatchset==0
|
|
+ && (pTab->abPK[i] || (nOld==nNew && 0==memcmp(aOld, aNew, nNew)))
|
|
){
|
|
*(aOut++) = '\0';
|
|
}else{
|
|
@@ -201275,7 +217056,7 @@ static int sessionPreupdateEqual(
|
|
}
|
|
|
|
/*
|
|
-** If required, grow the hash table used to store changes on table pTab
|
|
+** If required, grow the hash table used to store changes on table pTab
|
|
** (part of the session pSession). If a fatal OOM error occurs, set the
|
|
** session object to failed and return SQLITE_ERROR. Otherwise, return
|
|
** SQLITE_OK.
|
|
@@ -201285,13 +217066,19 @@ static int sessionPreupdateEqual(
|
|
** Growing the hash table in this case is a performance optimization only,
|
|
** it is not required for correct operation.
|
|
*/
|
|
-static int sessionGrowHash(int bPatchset, SessionTable *pTab){
|
|
+static int sessionGrowHash(
|
|
+ sqlite3_session *pSession, /* For memory accounting. May be NULL */
|
|
+ int bPatchset,
|
|
+ SessionTable *pTab
|
|
+){
|
|
if( pTab->nChange==0 || pTab->nEntry>=(pTab->nChange/2) ){
|
|
int i;
|
|
SessionChange **apNew;
|
|
sqlite3_int64 nNew = 2*(sqlite3_int64)(pTab->nChange ? pTab->nChange : 128);
|
|
|
|
- apNew = (SessionChange **)sqlite3_malloc64(sizeof(SessionChange *) * nNew);
|
|
+ apNew = (SessionChange**)sessionMalloc64(
|
|
+ pSession, sizeof(SessionChange*) * nNew
|
|
+ );
|
|
if( apNew==0 ){
|
|
if( pTab->nChange==0 ){
|
|
return SQLITE_ERROR;
|
|
@@ -201312,7 +217099,7 @@ static int sessionGrowHash(int bPatchset, SessionTable *pTab){
|
|
}
|
|
}
|
|
|
|
- sqlite3_free(pTab->apChange);
|
|
+ sessionFree(pSession, pTab->apChange);
|
|
pTab->nChange = nNew;
|
|
pTab->apChange = apNew;
|
|
}
|
|
@@ -201346,6 +217133,7 @@ static int sessionGrowHash(int bPatchset, SessionTable *pTab){
|
|
** be freed using sqlite3_free() by the caller
|
|
*/
|
|
static int sessionTableInfo(
|
|
+ sqlite3_session *pSession, /* For memory accounting. May be NULL */
|
|
sqlite3 *db, /* Database connection */
|
|
const char *zDb, /* Name of attached database (e.g. "main") */
|
|
const char *zThis, /* Table name */
|
|
@@ -201380,16 +217168,32 @@ 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 ) return SQLITE_NOMEM;
|
|
+ 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 ) return rc;
|
|
+ if( rc!=SQLITE_OK ){
|
|
+ *pazCol = 0;
|
|
+ *pabPK = 0;
|
|
+ *pnCol = 0;
|
|
+ if( pzTab ) *pzTab = 0;
|
|
+ return rc;
|
|
+ }
|
|
|
|
nByte = nThis + 1;
|
|
while( SQLITE_ROW==sqlite3_step(pStmt) ){
|
|
@@ -201400,7 +217204,7 @@ static int sessionTableInfo(
|
|
|
|
if( rc==SQLITE_OK ){
|
|
nByte += nDbCol * (sizeof(const char *) + sizeof(u8) + 1);
|
|
- pAlloc = sqlite3_malloc64(nByte);
|
|
+ pAlloc = sessionMalloc64(pSession, nByte);
|
|
if( pAlloc==0 ){
|
|
rc = SQLITE_NOMEM;
|
|
}
|
|
@@ -201415,7 +217219,7 @@ static int sessionTableInfo(
|
|
*pzTab = (char *)pAlloc;
|
|
pAlloc += nThis+1;
|
|
}
|
|
-
|
|
+
|
|
i = 0;
|
|
while( SQLITE_ROW==sqlite3_step(pStmt) ){
|
|
int nName = sqlite3_column_bytes(pStmt, 1);
|
|
@@ -201428,7 +217232,7 @@ static int sessionTableInfo(
|
|
i++;
|
|
}
|
|
rc = sqlite3_reset(pStmt);
|
|
-
|
|
+
|
|
}
|
|
|
|
/* If successful, populate the output variables. Otherwise, zero them and
|
|
@@ -201443,7 +217247,7 @@ static int sessionTableInfo(
|
|
*pabPK = 0;
|
|
*pnCol = 0;
|
|
if( pzTab ) *pzTab = 0;
|
|
- sqlite3_free(azCol);
|
|
+ sessionFree(pSession, azCol);
|
|
}
|
|
sqlite3_finalize(pStmt);
|
|
return rc;
|
|
@@ -201458,14 +217262,14 @@ static int sessionTableInfo(
|
|
** 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
|
|
** key, sqlite3_session.rc is left set to SQLITE_OK and non-zero returned to
|
|
-** indicate that updates on this table should be ignored. SessionTable.abPK
|
|
+** 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){
|
|
if( pTab->nCol==0 ){
|
|
u8 *abPK;
|
|
assert( pTab->azCol==0 || pTab->abPK==0 );
|
|
- pSession->rc = sessionTableInfo(pSession->db, pSession->zDb,
|
|
+ pSession->rc = sessionTableInfo(pSession, pSession->db, pSession->zDb,
|
|
pTab->zName, &pTab->nCol, 0, &pTab->azCol, &abPK
|
|
);
|
|
if( pSession->rc==SQLITE_OK ){
|
|
@@ -201479,6 +217283,12 @@ static int sessionInitTable(sqlite3_session *pSession, SessionTable *pTab){
|
|
if( 0==sqlite3_stricmp("sqlite_stat1", pTab->zName) ){
|
|
pTab->bStat1 = 1;
|
|
}
|
|
+
|
|
+ if( pSession->bEnableSize ){
|
|
+ pSession->nMaxChangesetSize += (
|
|
+ 1 + sessionVarintLen(pTab->nCol) + pTab->nCol + strlen(pTab->zName)+1
|
|
+ );
|
|
+ }
|
|
}
|
|
}
|
|
return (pSession->rc || pTab->abPK==0);
|
|
@@ -201524,9 +217334,106 @@ static int sessionStat1Depth(void *pCtx){
|
|
return p->hook.xDepth(p->hook.pCtx);
|
|
}
|
|
|
|
+static int sessionUpdateMaxSize(
|
|
+ int op,
|
|
+ sqlite3_session *pSession, /* Session object pTab is attached to */
|
|
+ SessionTable *pTab, /* Table that change applies to */
|
|
+ SessionChange *pC /* Update pC->nMaxSize */
|
|
+){
|
|
+ i64 nNew = 2;
|
|
+ if( pC->op==SQLITE_INSERT ){
|
|
+ if( op!=SQLITE_DELETE ){
|
|
+ int ii;
|
|
+ for(ii=0; ii<pTab->nCol; ii++){
|
|
+ sqlite3_value *p = 0;
|
|
+ pSession->hook.xNew(pSession->hook.pCtx, ii, &p);
|
|
+ sessionSerializeValue(0, p, &nNew);
|
|
+ }
|
|
+ }
|
|
+ }else if( op==SQLITE_DELETE ){
|
|
+ nNew += pC->nRecord;
|
|
+ if( sqlite3_preupdate_blobwrite(pSession->db)>=0 ){
|
|
+ nNew += pC->nRecord;
|
|
+ }
|
|
+ }else{
|
|
+ int ii;
|
|
+ u8 *pCsr = pC->aRecord;
|
|
+ for(ii=0; ii<pTab->nCol; ii++){
|
|
+ int bChanged = 1;
|
|
+ int nOld = 0;
|
|
+ int eType;
|
|
+ sqlite3_value *p = 0;
|
|
+ pSession->hook.xNew(pSession->hook.pCtx, ii, &p);
|
|
+ if( p==0 ){
|
|
+ return SQLITE_NOMEM;
|
|
+ }
|
|
+
|
|
+ eType = *pCsr++;
|
|
+ switch( eType ){
|
|
+ case SQLITE_NULL:
|
|
+ bChanged = sqlite3_value_type(p)!=SQLITE_NULL;
|
|
+ break;
|
|
+
|
|
+ case SQLITE_FLOAT:
|
|
+ case SQLITE_INTEGER: {
|
|
+ if( eType==sqlite3_value_type(p) ){
|
|
+ sqlite3_int64 iVal = sessionGetI64(pCsr);
|
|
+ if( eType==SQLITE_INTEGER ){
|
|
+ bChanged = (iVal!=sqlite3_value_int64(p));
|
|
+ }else{
|
|
+ double dVal;
|
|
+ memcpy(&dVal, &iVal, 8);
|
|
+ bChanged = (dVal!=sqlite3_value_double(p));
|
|
+ }
|
|
+ }
|
|
+ nOld = 8;
|
|
+ pCsr += 8;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ default: {
|
|
+ int nByte;
|
|
+ nOld = sessionVarintGet(pCsr, &nByte);
|
|
+ pCsr += nOld;
|
|
+ nOld += nByte;
|
|
+ assert( eType==SQLITE_TEXT || eType==SQLITE_BLOB );
|
|
+ if( eType==sqlite3_value_type(p)
|
|
+ && nByte==sqlite3_value_bytes(p)
|
|
+ && (nByte==0 || 0==memcmp(pCsr, sqlite3_value_blob(p), nByte))
|
|
+ ){
|
|
+ bChanged = 0;
|
|
+ }
|
|
+ pCsr += nByte;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if( bChanged && pTab->abPK[ii] ){
|
|
+ nNew = pC->nRecord + 2;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if( bChanged ){
|
|
+ nNew += 1 + nOld;
|
|
+ sessionSerializeValue(0, p, &nNew);
|
|
+ }else if( pTab->abPK[ii] ){
|
|
+ nNew += 2 + nOld;
|
|
+ }else{
|
|
+ nNew += 2;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if( nNew>pC->nMaxSize ){
|
|
+ int nIncr = nNew - pC->nMaxSize;
|
|
+ pC->nMaxSize = nNew;
|
|
+ pSession->nMaxChangesetSize += nIncr;
|
|
+ }
|
|
+ return SQLITE_OK;
|
|
+}
|
|
|
|
/*
|
|
-** This function is only called from with a pre-update-hook reporting a
|
|
+** This function is only called from with a pre-update-hook reporting a
|
|
** change on table pTab (attached to session pSession). The type of change
|
|
** (UPDATE, INSERT, DELETE) is specified by the first argument.
|
|
**
|
|
@@ -201538,8 +217445,8 @@ static void sessionPreupdateOneChange(
|
|
sqlite3_session *pSession, /* Session object pTab is attached to */
|
|
SessionTable *pTab /* Table that change applies to */
|
|
){
|
|
- int iHash;
|
|
- int bNull = 0;
|
|
+ int iHash;
|
|
+ int bNull = 0;
|
|
int rc = SQLITE_OK;
|
|
SessionStat1Ctx stat1 = {{0,0,0,0,0},0};
|
|
|
|
@@ -201548,7 +217455,7 @@ static void sessionPreupdateOneChange(
|
|
/* Load table details if required */
|
|
if( sessionInitTable(pSession, pTab) ) return;
|
|
|
|
- /* Check the number of columns in this xPreUpdate call matches the
|
|
+ /* 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) ){
|
|
pSession->rc = SQLITE_SCHEMA;
|
|
@@ -201556,7 +217463,7 @@ static void sessionPreupdateOneChange(
|
|
}
|
|
|
|
/* Grow the hash table if required */
|
|
- if( sessionGrowHash(0, pTab) ){
|
|
+ if( sessionGrowHash(pSession, 0, pTab) ){
|
|
pSession->rc = SQLITE_NOMEM;
|
|
return;
|
|
}
|
|
@@ -201597,13 +217504,12 @@ static void sessionPreupdateOneChange(
|
|
/* Create a new change object containing all the old values (if
|
|
** this is an SQLITE_UPDATE or SQLITE_DELETE), or just the PK
|
|
** values (if this is an INSERT). */
|
|
- SessionChange *pChange; /* New change object */
|
|
sqlite3_int64 nByte; /* Number of bytes to allocate */
|
|
int i; /* Used to iterate through columns */
|
|
-
|
|
+
|
|
assert( rc==SQLITE_OK );
|
|
pTab->nEntry++;
|
|
-
|
|
+
|
|
/* Figure out how large an allocation is required */
|
|
nByte = sizeof(SessionChange);
|
|
for(i=0; i<pTab->nCol; i++){
|
|
@@ -201621,17 +217527,17 @@ static void sessionPreupdateOneChange(
|
|
rc = sessionSerializeValue(0, p, &nByte);
|
|
if( rc!=SQLITE_OK ) goto error_out;
|
|
}
|
|
-
|
|
+
|
|
/* Allocate the change object */
|
|
- pChange = (SessionChange *)sqlite3_malloc64(nByte);
|
|
- if( !pChange ){
|
|
+ pC = (SessionChange *)sessionMalloc64(pSession, nByte);
|
|
+ if( !pC ){
|
|
rc = SQLITE_NOMEM;
|
|
goto error_out;
|
|
}else{
|
|
- memset(pChange, 0, sizeof(SessionChange));
|
|
- pChange->aRecord = (u8 *)&pChange[1];
|
|
+ memset(pC, 0, sizeof(SessionChange));
|
|
+ pC->aRecord = (u8 *)&pC[1];
|
|
}
|
|
-
|
|
+
|
|
/* Populate the change object. None of the preupdate_old(),
|
|
** preupdate_new() or SerializeValue() calls below may fail as all
|
|
** required values and encodings have already been cached in memory.
|
|
@@ -201644,29 +217550,35 @@ static void sessionPreupdateOneChange(
|
|
}else if( pTab->abPK[i] ){
|
|
pSession->hook.xNew(pSession->hook.pCtx, i, &p);
|
|
}
|
|
- sessionSerializeValue(&pChange->aRecord[nByte], p, &nByte);
|
|
+ sessionSerializeValue(&pC->aRecord[nByte], p, &nByte);
|
|
}
|
|
|
|
/* Add the change to the hash-table */
|
|
if( pSession->bIndirect || pSession->hook.xDepth(pSession->hook.pCtx) ){
|
|
- pChange->bIndirect = 1;
|
|
+ pC->bIndirect = 1;
|
|
}
|
|
- pChange->nRecord = nByte;
|
|
- pChange->op = op;
|
|
- pChange->pNext = pTab->apChange[iHash];
|
|
- pTab->apChange[iHash] = pChange;
|
|
+ pC->nRecord = nByte;
|
|
+ pC->op = op;
|
|
+ pC->pNext = pTab->apChange[iHash];
|
|
+ pTab->apChange[iHash] = pC;
|
|
|
|
}else if( pC->bIndirect ){
|
|
/* If the existing change is considered "indirect", but this current
|
|
** change is "direct", mark the change object as direct. */
|
|
- if( pSession->hook.xDepth(pSession->hook.pCtx)==0
|
|
- && pSession->bIndirect==0
|
|
+ if( pSession->hook.xDepth(pSession->hook.pCtx)==0
|
|
+ && pSession->bIndirect==0
|
|
){
|
|
pC->bIndirect = 0;
|
|
}
|
|
}
|
|
+
|
|
+ assert( rc==SQLITE_OK );
|
|
+ if( pSession->bEnableSize ){
|
|
+ rc = sessionUpdateMaxSize(op, pSession, pTab, pC);
|
|
+ }
|
|
}
|
|
|
|
+
|
|
/* If an error has occurred, mark the session object as failed. */
|
|
error_out:
|
|
if( pTab->bStat1 ){
|
|
@@ -201678,7 +217590,7 @@ static void sessionPreupdateOneChange(
|
|
}
|
|
|
|
static int sessionFindTable(
|
|
- sqlite3_session *pSession,
|
|
+ sqlite3_session *pSession,
|
|
const char *zName,
|
|
SessionTable **ppTab
|
|
){
|
|
@@ -201695,11 +217607,15 @@ static int sessionFindTable(
|
|
/* If there is a table-filter configured, invoke it. If it returns 0,
|
|
** do not automatically add the new table. */
|
|
if( pSession->xTableFilter==0
|
|
- || pSession->xTableFilter(pSession->pFilterCtx, zName)
|
|
+ || pSession->xTableFilter(pSession->pFilterCtx, zName)
|
|
){
|
|
rc = sqlite3session_attach(pSession, zName);
|
|
if( rc==SQLITE_OK ){
|
|
- for(pRet=pSession->pTable; pRet->pNext; pRet=pRet->pNext);
|
|
+ pRet = pSession->pTable;
|
|
+ while( ALWAYS(pRet) && pRet->pNext ){
|
|
+ pRet = pRet->pNext;
|
|
+ }
|
|
+ assert( pRet!=0 );
|
|
assert( 0==sqlite3_strnicmp(pRet->zName, zName, nName+1) );
|
|
}
|
|
}
|
|
@@ -201726,12 +217642,14 @@ static void xPreUpdate(
|
|
int nDb = sqlite3Strlen30(zDb);
|
|
|
|
assert( sqlite3_mutex_held(db->mutex) );
|
|
+ (void)iKey1;
|
|
+ (void)iKey2;
|
|
|
|
for(pSession=(sqlite3_session *)pCtx; pSession; pSession=pSession->pNext){
|
|
SessionTable *pTab;
|
|
|
|
- /* If this session is attached to a different database ("main", "temp"
|
|
- ** etc.), or if it is not currently enabled, there is nothing to do. Skip
|
|
+ /* If this session is attached to a different database ("main", "temp"
|
|
+ ** etc.), or if it is not currently enabled, there is nothing to do. Skip
|
|
** to the next session object attached to this database. */
|
|
if( pSession->bEnable==0 ) continue;
|
|
if( pSession->rc ) continue;
|
|
@@ -201802,6 +217720,7 @@ static int sessionDiffCount(void *pCtx){
|
|
return p->nOldOff ? p->nOldOff : sqlite3_column_count(p->pStmt);
|
|
}
|
|
static int sessionDiffDepth(void *pCtx){
|
|
+ (void)pCtx;
|
|
return 0;
|
|
}
|
|
|
|
@@ -201822,7 +217741,7 @@ static void sessionDiffHooks(
|
|
|
|
static char *sessionExprComparePK(
|
|
int nCol,
|
|
- const char *zDb1, const char *zDb2,
|
|
+ const char *zDb1, const char *zDb2,
|
|
const char *zTab,
|
|
const char **azCol, u8 *abPK
|
|
){
|
|
@@ -201845,7 +217764,7 @@ static char *sessionExprComparePK(
|
|
|
|
static char *sessionExprCompareOther(
|
|
int nCol,
|
|
- const char *zDb1, const char *zDb2,
|
|
+ const char *zDb1, const char *zDb2,
|
|
const char *zTab,
|
|
const char **azCol, u8 *abPK
|
|
){
|
|
@@ -201875,7 +217794,6 @@ static char *sessionExprCompareOther(
|
|
}
|
|
|
|
static char *sessionSelectFindNew(
|
|
- int nCol,
|
|
const char *zDb1, /* Pick rows in this db only */
|
|
const char *zDb2, /* But not in this one */
|
|
const char *zTbl, /* Table name */
|
|
@@ -201899,7 +217817,7 @@ static int sessionDiffFindNew(
|
|
char *zExpr
|
|
){
|
|
int rc = SQLITE_OK;
|
|
- char *zStmt = sessionSelectFindNew(pTab->nCol, zDb1, zDb2, pTab->zName,zExpr);
|
|
+ char *zStmt = sessionSelectFindNew(zDb1, zDb2, pTab->zName,zExpr);
|
|
|
|
if( zStmt==0 ){
|
|
rc = SQLITE_NOMEM;
|
|
@@ -201922,9 +217840,9 @@ static int sessionDiffFindNew(
|
|
}
|
|
|
|
static int sessionDiffFindModified(
|
|
- sqlite3_session *pSession,
|
|
- SessionTable *pTab,
|
|
- const char *zFrom,
|
|
+ sqlite3_session *pSession,
|
|
+ SessionTable *pTab,
|
|
+ const char *zFrom,
|
|
const char *zExpr
|
|
){
|
|
int rc = SQLITE_OK;
|
|
@@ -201996,7 +217914,7 @@ SQLITE_API int sqlite3session_diff(
|
|
int nCol; /* Columns in zFrom.zTbl */
|
|
u8 *abPK;
|
|
const char **azCol = 0;
|
|
- rc = sessionTableInfo(db, zFrom, zTbl, &nCol, 0, &azCol, &abPK);
|
|
+ rc = sessionTableInfo(0, db, zFrom, zTbl, &nCol, 0, &azCol, &abPK);
|
|
if( rc==SQLITE_OK ){
|
|
if( pTo->nCol!=nCol ){
|
|
bMismatch = 1;
|
|
@@ -202023,7 +217941,7 @@ SQLITE_API int sqlite3session_diff(
|
|
}
|
|
|
|
if( rc==SQLITE_OK ){
|
|
- zExpr = sessionExprComparePK(pTo->nCol,
|
|
+ zExpr = sessionExprComparePK(pTo->nCol,
|
|
zDb, zFrom, pTo->zName, pTo->azCol, pTo->abPK
|
|
);
|
|
}
|
|
@@ -202078,7 +217996,7 @@ SQLITE_API int sqlite3session_create(
|
|
memcpy(pNew->zDb, zDb, nDb+1);
|
|
sessionPreupdateHooks(pNew);
|
|
|
|
- /* Add the new session object to the linked list of session objects
|
|
+ /* Add the new session object to the linked list of session objects
|
|
** attached to database handle $db. Do this under the cover of the db
|
|
** handle mutex. */
|
|
sqlite3_mutex_enter(sqlite3_db_mutex(db));
|
|
@@ -202094,7 +218012,7 @@ SQLITE_API int sqlite3session_create(
|
|
** Free the list of table objects passed as the first argument. The contents
|
|
** of the changed-rows hash tables are also deleted.
|
|
*/
|
|
-static void sessionDeleteTable(SessionTable *pList){
|
|
+static void sessionDeleteTable(sqlite3_session *pSession, SessionTable *pList){
|
|
SessionTable *pNext;
|
|
SessionTable *pTab;
|
|
|
|
@@ -202106,12 +218024,12 @@ static void sessionDeleteTable(SessionTable *pList){
|
|
SessionChange *pNextChange;
|
|
for(p=pTab->apChange[i]; p; p=pNextChange){
|
|
pNextChange = p->pNext;
|
|
- sqlite3_free(p);
|
|
+ sessionFree(pSession, p);
|
|
}
|
|
}
|
|
- sqlite3_free((char*)pTab->azCol); /* cast works around VC++ bug */
|
|
- sqlite3_free(pTab->apChange);
|
|
- sqlite3_free(pTab);
|
|
+ sessionFree(pSession, (char*)pTab->azCol); /* cast works around VC++ bug */
|
|
+ sessionFree(pSession, pTab->apChange);
|
|
+ sessionFree(pSession, pTab);
|
|
}
|
|
}
|
|
|
|
@@ -202137,11 +218055,13 @@ SQLITE_API void sqlite3session_delete(sqlite3_session *pSession){
|
|
sqlite3_mutex_leave(sqlite3_db_mutex(db));
|
|
sqlite3ValueFree(pSession->pZeroBlob);
|
|
|
|
- /* Delete all attached table objects. And the contents of their
|
|
+ /* Delete all attached table objects. And the contents of their
|
|
** associated hash-tables. */
|
|
- sessionDeleteTable(pSession->pTable);
|
|
+ sessionDeleteTable(pSession, pSession->pTable);
|
|
|
|
- /* Free the session object itself. */
|
|
+ /* Assert that all allocations have been freed and then free the
|
|
+ ** session object itself. */
|
|
+ assert( pSession->nMalloc==0 );
|
|
sqlite3_free(pSession);
|
|
}
|
|
|
|
@@ -202149,7 +218069,7 @@ SQLITE_API void sqlite3session_delete(sqlite3_session *pSession){
|
|
** Set a table filter on a Session Object.
|
|
*/
|
|
SQLITE_API void sqlite3session_table_filter(
|
|
- sqlite3_session *pSession,
|
|
+ sqlite3_session *pSession,
|
|
int(*xFilter)(void*, const char*),
|
|
void *pCtx /* First argument passed to xFilter */
|
|
){
|
|
@@ -202188,12 +218108,13 @@ SQLITE_API int sqlite3session_attach(
|
|
|
|
if( !pTab ){
|
|
/* Allocate new SessionTable object. */
|
|
- pTab = (SessionTable *)sqlite3_malloc64(sizeof(SessionTable) + nName + 1);
|
|
+ int nByte = sizeof(SessionTable) + nName + 1;
|
|
+ pTab = (SessionTable*)sessionMalloc64(pSession, nByte);
|
|
if( !pTab ){
|
|
rc = SQLITE_NOMEM;
|
|
}else{
|
|
/* Populate the new SessionTable object and link it into the list.
|
|
- ** The new object must be linked onto the end of the list, not
|
|
+ ** The new object must be linked onto the end of the list, not
|
|
** simply added to the start of it in order to ensure that tables
|
|
** appear in the correct order when a changeset or patchset is
|
|
** eventually generated. */
|
|
@@ -202218,13 +218139,29 @@ SQLITE_API int sqlite3session_attach(
|
|
** 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, size_t nByte, int *pRc){
|
|
- if( *pRc==SQLITE_OK && (size_t)(p->nAlloc-p->nBuf)<nByte ){
|
|
+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( (size_t)(nNew-p->nBuf)<nByte );
|
|
+ }while( nNew<nReq );
|
|
+
|
|
+ /* The value of SESSION_MAX_BUFFER_SZ is copied from the implementation
|
|
+ ** of sqlite3_realloc64(). Allocations greater than this size in bytes
|
|
+ ** always fail. It is used here to ensure that this routine can always
|
|
+ ** allocate up to this limit - instead of up to the largest power of
|
|
+ ** two smaller than the limit. */
|
|
+ if( nNew>SESSION_MAX_BUFFER_SZ ){
|
|
+ nNew = SESSION_MAX_BUFFER_SZ;
|
|
+ if( nNew<nReq ){
|
|
+ *pRc = SQLITE_NOMEM;
|
|
+ return 1;
|
|
+ }
|
|
+ }
|
|
|
|
aNew = (u8 *)sqlite3_realloc64(p->aBuf, nNew);
|
|
if( 0==aNew ){
|
|
@@ -202261,8 +218198,8 @@ static void sessionAppendValue(SessionBuffer *p, sqlite3_value *pVal, int *pRc){
|
|
}
|
|
|
|
/*
|
|
-** This function is a no-op if *pRc is other than SQLITE_OK when it is
|
|
-** called. Otherwise, append a single byte to the buffer.
|
|
+** This function is a no-op if *pRc is other than SQLITE_OK when it is
|
|
+** called. Otherwise, append a single byte to the buffer.
|
|
**
|
|
** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
|
|
** returning.
|
|
@@ -202274,8 +218211,8 @@ static void sessionAppendByte(SessionBuffer *p, u8 v, int *pRc){
|
|
}
|
|
|
|
/*
|
|
-** This function is a no-op if *pRc is other than SQLITE_OK when it is
|
|
-** called. Otherwise, append a single varint to the buffer.
|
|
+** This function is a no-op if *pRc is other than SQLITE_OK when it is
|
|
+** called. Otherwise, append a single varint to the buffer.
|
|
**
|
|
** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
|
|
** returning.
|
|
@@ -202287,16 +218224,16 @@ static void sessionAppendVarint(SessionBuffer *p, int v, int *pRc){
|
|
}
|
|
|
|
/*
|
|
-** This function is a no-op if *pRc is other than SQLITE_OK when it is
|
|
-** called. Otherwise, append a blob of data to the buffer.
|
|
+** This function is a no-op if *pRc is other than SQLITE_OK when it is
|
|
+** called. Otherwise, append a blob of data to the buffer.
|
|
**
|
|
** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
|
|
** returning.
|
|
*/
|
|
static void sessionAppendBlob(
|
|
- SessionBuffer *p,
|
|
- const u8 *aBlob,
|
|
- int nBlob,
|
|
+ SessionBuffer *p,
|
|
+ const u8 *aBlob,
|
|
+ int nBlob,
|
|
int *pRc
|
|
){
|
|
if( nBlob>0 && 0==sessionBufferGrow(p, nBlob, pRc) ){
|
|
@@ -202306,7 +218243,7 @@ static void sessionAppendBlob(
|
|
}
|
|
|
|
/*
|
|
-** This function is a no-op if *pRc is other than SQLITE_OK when it is
|
|
+** 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.
|
|
**
|
|
@@ -202314,8 +218251,8 @@ static void sessionAppendBlob(
|
|
** returning.
|
|
*/
|
|
static void sessionAppendStr(
|
|
- SessionBuffer *p,
|
|
- const char *zStr,
|
|
+ SessionBuffer *p,
|
|
+ const char *zStr,
|
|
int *pRc
|
|
){
|
|
int nStr = sqlite3Strlen30(zStr);
|
|
@@ -202326,7 +218263,7 @@ static void sessionAppendStr(
|
|
}
|
|
|
|
/*
|
|
-** This function is a no-op if *pRc is other than SQLITE_OK when it is
|
|
+** 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
|
|
** to the buffer. No nul-terminator is written.
|
|
**
|
|
@@ -202344,9 +218281,9 @@ static void sessionAppendInteger(
|
|
}
|
|
|
|
/*
|
|
-** This function is a no-op if *pRc is other than SQLITE_OK when it is
|
|
+** 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
|
|
-** with any embedded quote characters escaped to the buffer. No
|
|
+** with any embedded quote characters escaped to the buffer. No
|
|
** nul-terminator byte is written.
|
|
**
|
|
** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
|
|
@@ -202419,8 +218356,8 @@ static void sessionAppendCol(
|
|
|
|
/*
|
|
**
|
|
-** This function appends an update change to the buffer (see the comments
|
|
-** under "CHANGESET FORMAT" at the top of the file). An update change
|
|
+** This function appends an update change to the buffer (see the comments
|
|
+** under "CHANGESET FORMAT" at the top of the file). An update change
|
|
** consists of:
|
|
**
|
|
** 1 byte: SQLITE_UPDATE (0x17)
|
|
@@ -202435,10 +218372,10 @@ static void sessionAppendCol(
|
|
** If all of the old.* values are equal to their corresponding new.* value
|
|
** (i.e. nothing has changed), then no data at all is appended to the buffer.
|
|
**
|
|
-** Otherwise, the old.* record contains all primary key values and the
|
|
-** original values of any fields that have been modified. The new.* record
|
|
+** Otherwise, the old.* record contains all primary key values and the
|
|
+** original values of any fields that have been modified. The new.* record
|
|
** contains the new values of only those fields that have been modified.
|
|
-*/
|
|
+*/
|
|
static int sessionAppendUpdate(
|
|
SessionBuffer *pBuf, /* Buffer to append to */
|
|
int bPatchset, /* True for "patchset", 0 for "changeset" */
|
|
@@ -202453,6 +218390,7 @@ static int sessionAppendUpdate(
|
|
int i; /* Used to iterate through columns */
|
|
u8 *pCsr = p->aRecord; /* Used to iterate through old.* values */
|
|
|
|
+ assert( abPK!=0 );
|
|
sessionAppendByte(pBuf, SQLITE_UPDATE, &rc);
|
|
sessionAppendByte(pBuf, p->bIndirect, &rc);
|
|
for(i=0; i<sqlite3_column_count(pStmt); i++){
|
|
@@ -202489,8 +218427,8 @@ static int sessionAppendUpdate(
|
|
int nHdr = 1 + sessionVarintGet(&pCsr[1], &n);
|
|
assert( eType==SQLITE_TEXT || eType==SQLITE_BLOB );
|
|
nAdvance = nHdr + n;
|
|
- if( eType==sqlite3_column_type(pStmt, i)
|
|
- && n==sqlite3_column_bytes(pStmt, i)
|
|
+ if( eType==sqlite3_column_type(pStmt, i)
|
|
+ && n==sqlite3_column_bytes(pStmt, i)
|
|
&& (n==0 || 0==memcmp(&pCsr[nHdr], sqlite3_column_blob(pStmt, i), n))
|
|
){
|
|
break;
|
|
@@ -202717,7 +218655,7 @@ static int sessionSelectBind(
|
|
|
|
/*
|
|
** This function is a no-op if *pRc is set to other than SQLITE_OK when it
|
|
-** is called. Otherwise, append a serialized table header (part of the binary
|
|
+** is called. Otherwise, append a serialized table header (part of the binary
|
|
** changeset format) to buffer *pBuf. If an error occurs, set *pRc to an
|
|
** SQLite error code before returning.
|
|
*/
|
|
@@ -202741,7 +218679,7 @@ static void sessionAppendTableHdr(
|
|
**
|
|
** If no error occurs, SQLITE_OK is returned and the new changeset/patchset
|
|
** stored in output variables *pnChangeset and *ppChangeset. Or, if an error
|
|
-** occurs, an SQLite error code is returned and both output variables set
|
|
+** occurs, an SQLite error code is returned and both output variables set
|
|
** to 0.
|
|
*/
|
|
static int sessionGenerateChangeset(
|
|
@@ -202757,12 +218695,14 @@ static int sessionGenerateChangeset(
|
|
SessionBuffer buf = {0,0,0}; /* Buffer in which to accumlate changeset */
|
|
int rc; /* Return code */
|
|
|
|
- assert( xOutput==0 || (pnChangeset==0 && ppChangeset==0 ) );
|
|
+ assert( xOutput==0 || (pnChangeset==0 && ppChangeset==0) );
|
|
+ assert( xOutput!=0 || (pnChangeset!=0 && ppChangeset!=0) );
|
|
|
|
/* Zero the output variables in case an error occurs. If this session
|
|
** object is already in the error state (sqlite3_session.rc != SQLITE_OK),
|
|
** this call will be a no-op. */
|
|
if( xOutput==0 ){
|
|
+ assert( pnChangeset!=0 && ppChangeset!=0 );
|
|
*pnChangeset = 0;
|
|
*ppChangeset = 0;
|
|
}
|
|
@@ -202776,8 +218716,8 @@ static int sessionGenerateChangeset(
|
|
for(pTab=pSession->pTable; rc==SQLITE_OK && pTab; pTab=pTab->pNext){
|
|
if( pTab->nEntry ){
|
|
const char *zName = pTab->zName;
|
|
- int nCol; /* Number of columns in table */
|
|
- u8 *abPK; /* Primary key array */
|
|
+ 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 */
|
|
@@ -202785,7 +218725,7 @@ static int sessionGenerateChangeset(
|
|
int nNoop; /* Size of buffer after writing tbl header */
|
|
|
|
/* Check the table schema is still Ok. */
|
|
- rc = sessionTableInfo(db, pSession->zDb, zName, &nCol, 0, &azCol, &abPK);
|
|
+ rc = sessionTableInfo(0, db, pSession->zDb, zName, &nCol, 0,&azCol,&abPK);
|
|
if( !rc && (pTab->nCol!=nCol || memcmp(abPK, pTab->abPK, nCol)) ){
|
|
rc = SQLITE_SCHEMA;
|
|
}
|
|
@@ -202815,6 +218755,7 @@ static int sessionGenerateChangeset(
|
|
sessionAppendCol(&buf, pSel, iCol, &rc);
|
|
}
|
|
}else{
|
|
+ assert( abPK!=0 ); /* Because sessionSelectStmt() returned ok */
|
|
rc = sessionAppendUpdate(&buf, bPatchset, pSel, p, abPK);
|
|
}
|
|
}else if( p->op!=SQLITE_INSERT ){
|
|
@@ -202826,10 +218767,10 @@ static int sessionGenerateChangeset(
|
|
|
|
/* If the buffer is now larger than sessions_strm_chunk_size, pass
|
|
** its contents to the xOutput() callback. */
|
|
- if( xOutput
|
|
- && rc==SQLITE_OK
|
|
- && buf.nBuf>nNoop
|
|
- && buf.nBuf>sessions_strm_chunk_size
|
|
+ if( xOutput
|
|
+ && rc==SQLITE_OK
|
|
+ && buf.nBuf>nNoop
|
|
+ && buf.nBuf>sessions_strm_chunk_size
|
|
){
|
|
rc = xOutput(pOut, (void*)buf.aBuf, buf.nBuf);
|
|
nNoop = -1;
|
|
@@ -202864,10 +218805,10 @@ static int sessionGenerateChangeset(
|
|
}
|
|
|
|
/*
|
|
-** Obtain a changeset object containing all changes recorded by the
|
|
+** Obtain a changeset object containing all changes recorded by the
|
|
** session object passed as the first argument.
|
|
**
|
|
-** It is the responsibility of the caller to eventually free the buffer
|
|
+** It is the responsibility of the caller to eventually free the buffer
|
|
** using sqlite3_free().
|
|
*/
|
|
SQLITE_API int sqlite3session_changeset(
|
|
@@ -202875,7 +218816,14 @@ SQLITE_API int sqlite3session_changeset(
|
|
int *pnChangeset, /* OUT: Size of buffer at *ppChangeset */
|
|
void **ppChangeset /* OUT: Buffer containing changeset */
|
|
){
|
|
- return sessionGenerateChangeset(pSession, 0, 0, 0, pnChangeset, ppChangeset);
|
|
+ int rc;
|
|
+
|
|
+ if( pnChangeset==0 || ppChangeset==0 ) return SQLITE_MISUSE;
|
|
+ rc = sessionGenerateChangeset(pSession, 0, 0, 0, pnChangeset,ppChangeset);
|
|
+ assert( rc || pnChangeset==0
|
|
+ || pSession->bEnableSize==0 || *pnChangeset<=pSession->nMaxChangesetSize
|
|
+ );
|
|
+ return rc;
|
|
}
|
|
|
|
/*
|
|
@@ -202886,6 +218834,7 @@ SQLITE_API int sqlite3session_changeset_strm(
|
|
int (*xOutput)(void *pOut, const void *pData, int nData),
|
|
void *pOut
|
|
){
|
|
+ if( xOutput==0 ) return SQLITE_MISUSE;
|
|
return sessionGenerateChangeset(pSession, 0, xOutput, pOut, 0, 0);
|
|
}
|
|
|
|
@@ -202897,14 +218846,15 @@ SQLITE_API int sqlite3session_patchset_strm(
|
|
int (*xOutput)(void *pOut, const void *pData, int nData),
|
|
void *pOut
|
|
){
|
|
+ if( xOutput==0 ) return SQLITE_MISUSE;
|
|
return sessionGenerateChangeset(pSession, 1, xOutput, pOut, 0, 0);
|
|
}
|
|
|
|
/*
|
|
-** Obtain a patchset object containing all changes recorded by the
|
|
+** Obtain a patchset object containing all changes recorded by the
|
|
** session object passed as the first argument.
|
|
**
|
|
-** It is the responsibility of the caller to eventually free the buffer
|
|
+** It is the responsibility of the caller to eventually free the buffer
|
|
** using sqlite3_free().
|
|
*/
|
|
SQLITE_API int sqlite3session_patchset(
|
|
@@ -202912,6 +218862,7 @@ SQLITE_API int sqlite3session_patchset(
|
|
int *pnPatchset, /* OUT: Size of buffer at *ppChangeset */
|
|
void **ppPatchset /* OUT: Buffer containing changeset */
|
|
){
|
|
+ if( pnPatchset==0 || ppPatchset==0 ) return SQLITE_MISUSE;
|
|
return sessionGenerateChangeset(pSession, 1, 0, 0, pnPatchset, ppPatchset);
|
|
}
|
|
|
|
@@ -202960,6 +218911,46 @@ SQLITE_API int sqlite3session_isempty(sqlite3_session *pSession){
|
|
return (ret==0);
|
|
}
|
|
|
|
+/*
|
|
+** Return the amount of heap memory in use.
|
|
+*/
|
|
+SQLITE_API sqlite3_int64 sqlite3session_memory_used(sqlite3_session *pSession){
|
|
+ return pSession->nMalloc;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Configure the session object passed as the first argument.
|
|
+*/
|
|
+SQLITE_API int sqlite3session_object_config(sqlite3_session *pSession, int op, void *pArg){
|
|
+ int rc = SQLITE_OK;
|
|
+ switch( op ){
|
|
+ case SQLITE_SESSION_OBJCONFIG_SIZE: {
|
|
+ int iArg = *(int*)pArg;
|
|
+ if( iArg>=0 ){
|
|
+ if( pSession->pTable ){
|
|
+ rc = SQLITE_MISUSE;
|
|
+ }else{
|
|
+ pSession->bEnableSize = (iArg!=0);
|
|
+ }
|
|
+ }
|
|
+ *(int*)pArg = pSession->bEnableSize;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ default:
|
|
+ rc = SQLITE_MISUSE;
|
|
+ }
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Return the maximum size of sqlite3session_changeset() output.
|
|
+*/
|
|
+SQLITE_API sqlite3_int64 sqlite3session_changeset_size(sqlite3_session *pSession){
|
|
+ return pSession->nMaxChangesetSize;
|
|
+}
|
|
+
|
|
/*
|
|
** Do the work for either sqlite3changeset_start() or start_strm().
|
|
*/
|
|
@@ -202969,7 +218960,8 @@ static int sessionChangesetStart(
|
|
void *pIn,
|
|
int nChangeset, /* Size of buffer pChangeset in bytes */
|
|
void *pChangeset, /* Pointer to buffer containing changeset */
|
|
- int bInvert /* True to invert changeset */
|
|
+ int bInvert, /* True to invert changeset */
|
|
+ int bSkipEmpty /* True to skip empty UPDATE changes */
|
|
){
|
|
sqlite3_changeset_iter *pRet; /* Iterator to return */
|
|
int nByte; /* Number of bytes to allocate for iterator */
|
|
@@ -202990,6 +218982,7 @@ static int sessionChangesetStart(
|
|
pRet->in.pIn = pIn;
|
|
pRet->in.bEof = (xInput ? 0 : 1);
|
|
pRet->bInvert = bInvert;
|
|
+ pRet->bSkipEmpty = bSkipEmpty;
|
|
|
|
/* Populate the output variable and return success. */
|
|
*pp = pRet;
|
|
@@ -203004,7 +218997,7 @@ SQLITE_API int sqlite3changeset_start(
|
|
int nChangeset, /* Size of buffer pChangeset in bytes */
|
|
void *pChangeset /* Pointer to buffer containing changeset */
|
|
){
|
|
- return sessionChangesetStart(pp, 0, 0, nChangeset, pChangeset, 0);
|
|
+ return sessionChangesetStart(pp, 0, 0, nChangeset, pChangeset, 0, 0);
|
|
}
|
|
SQLITE_API int sqlite3changeset_start_v2(
|
|
sqlite3_changeset_iter **pp, /* OUT: Changeset iterator handle */
|
|
@@ -203013,7 +219006,7 @@ SQLITE_API int sqlite3changeset_start_v2(
|
|
int flags
|
|
){
|
|
int bInvert = !!(flags & SQLITE_CHANGESETSTART_INVERT);
|
|
- return sessionChangesetStart(pp, 0, 0, nChangeset, pChangeset, bInvert);
|
|
+ return sessionChangesetStart(pp, 0, 0, nChangeset, pChangeset, bInvert, 0);
|
|
}
|
|
|
|
/*
|
|
@@ -203024,7 +219017,7 @@ SQLITE_API int sqlite3changeset_start_strm(
|
|
int (*xInput)(void *pIn, void *pData, int *pnData),
|
|
void *pIn
|
|
){
|
|
- return sessionChangesetStart(pp, xInput, pIn, 0, 0, 0);
|
|
+ return sessionChangesetStart(pp, xInput, pIn, 0, 0, 0, 0);
|
|
}
|
|
SQLITE_API int sqlite3changeset_start_v2_strm(
|
|
sqlite3_changeset_iter **pp, /* OUT: Changeset iterator handle */
|
|
@@ -203033,7 +219026,7 @@ SQLITE_API int sqlite3changeset_start_v2_strm(
|
|
int flags
|
|
){
|
|
int bInvert = !!(flags & SQLITE_CHANGESETSTART_INVERT);
|
|
- return sessionChangesetStart(pp, xInput, pIn, 0, 0, bInvert);
|
|
+ return sessionChangesetStart(pp, xInput, pIn, 0, 0, bInvert, 0);
|
|
}
|
|
|
|
/*
|
|
@@ -203110,7 +219103,7 @@ static void sessionSkipRecord(
|
|
|
|
/*
|
|
** This function sets the value of the sqlite3_value object passed as the
|
|
-** first argument to a copy of the string or blob held in the aData[]
|
|
+** first argument to a copy of the string or blob held in the aData[]
|
|
** buffer. SQLITE_OK is returned if successful, or SQLITE_NOMEM if an OOM
|
|
** error occurs.
|
|
*/
|
|
@@ -203121,7 +219114,7 @@ static int sessionValueSetStr(
|
|
u8 enc /* String encoding (0 for blobs) */
|
|
){
|
|
/* In theory this code could just pass SQLITE_TRANSIENT as the final
|
|
- ** argument to sqlite3ValueSetStr() and have the copy created
|
|
+ ** argument to sqlite3ValueSetStr() and have the copy created
|
|
** automatically. But doing so makes it difficult to detect any OOM
|
|
** error. Hence the code to create the copy externally. */
|
|
u8 *aCopy = sqlite3_malloc64((sqlite3_int64)nData+1);
|
|
@@ -203159,11 +219152,14 @@ static int sessionReadRecord(
|
|
SessionInput *pIn, /* Input data */
|
|
int nCol, /* Number of values in record */
|
|
u8 *abPK, /* Array of primary key flags, or NULL */
|
|
- sqlite3_value **apOut /* Write values to this array */
|
|
+ sqlite3_value **apOut, /* Write values to this array */
|
|
+ int *pbEmpty
|
|
){
|
|
int i; /* Used to iterate through columns */
|
|
int rc = SQLITE_OK;
|
|
|
|
+ assert( pbEmpty==0 || *pbEmpty==0 );
|
|
+ if( pbEmpty ) *pbEmpty = 1;
|
|
for(i=0; i<nCol && rc==SQLITE_OK; i++){
|
|
int eType = 0; /* Type of value (SQLITE_NULL, TEXT etc.) */
|
|
if( abPK && abPK[i]==0 ) continue;
|
|
@@ -203175,6 +219171,7 @@ static int sessionReadRecord(
|
|
eType = pIn->aData[pIn->iNext++];
|
|
assert( apOut[i]==0 );
|
|
if( eType ){
|
|
+ if( pbEmpty ) *pbEmpty = 0;
|
|
apOut[i] = sqlite3ValueNew(0);
|
|
if( !apOut[i] ) rc = SQLITE_NOMEM;
|
|
}
|
|
@@ -203222,7 +219219,7 @@ static int sessionReadRecord(
|
|
** + array of PK flags (1 byte per column),
|
|
** + table name (nul terminated).
|
|
**
|
|
-** This function ensures that all of the above is present in the input
|
|
+** This function ensures that all of the above is present in the input
|
|
** buffer (i.e. that it can be accessed without any calls to xInput()).
|
|
** If successful, SQLITE_OK is returned. Otherwise, an SQLite error code.
|
|
** The input pointer is not moved.
|
|
@@ -203236,11 +219233,11 @@ static int sessionChangesetBufferTblhdr(SessionInput *pIn, int *pnByte){
|
|
if( rc==SQLITE_OK ){
|
|
nRead += sessionVarintGet(&pIn->aData[pIn->iNext + nRead], &nCol);
|
|
/* The hard upper limit for the number of columns in an SQLite
|
|
- ** database table is, according to sqliteLimit.h, 32676. So
|
|
- ** consider any table-header that purports to have more than 65536
|
|
- ** columns to be corrupt. This is convenient because otherwise,
|
|
- ** if the (nCol>65536) condition below were omitted, a sufficiently
|
|
- ** large value for nCol may cause nRead to wrap around and become
|
|
+ ** database table is, according to sqliteLimit.h, 32676. So
|
|
+ ** consider any table-header that purports to have more than 65536
|
|
+ ** columns to be corrupt. This is convenient because otherwise,
|
|
+ ** if the (nCol>65536) condition below were omitted, a sufficiently
|
|
+ ** large value for nCol may cause nRead to wrap around and become
|
|
** negative. Leading to a crash. */
|
|
if( nCol<0 || nCol>65536 ){
|
|
rc = SQLITE_CORRUPT_BKPT;
|
|
@@ -203305,8 +219302,8 @@ static int sessionChangesetBufferRecord(
|
|
** + array of PK flags (1 byte per column),
|
|
** + table name (nul terminated).
|
|
**
|
|
-** This function decodes the table-header and populates the p->nCol,
|
|
-** p->zTab and p->abPK[] variables accordingly. The p->apValue[] array is
|
|
+** This function decodes the table-header and populates the p->nCol,
|
|
+** p->zTab and p->abPK[] variables accordingly. The p->apValue[] array is
|
|
** also allocated or resized according to the new value of p->nCol. The
|
|
** input pointer is left pointing to the byte following the table header.
|
|
**
|
|
@@ -203343,37 +219340,38 @@ static int sessionChangesetReadTblhdr(sqlite3_changeset_iter *p){
|
|
}
|
|
|
|
p->apValue = (sqlite3_value**)p->tblhdr.aBuf;
|
|
- p->abPK = (u8*)&p->apValue[p->nCol*2];
|
|
- p->zTab = (char*)&p->abPK[p->nCol];
|
|
+ if( p->apValue==0 ){
|
|
+ p->abPK = 0;
|
|
+ p->zTab = 0;
|
|
+ }else{
|
|
+ p->abPK = (u8*)&p->apValue[p->nCol*2];
|
|
+ p->zTab = p->abPK ? (char*)&p->abPK[p->nCol] : 0;
|
|
+ }
|
|
return (p->rc = rc);
|
|
}
|
|
|
|
/*
|
|
-** Advance the changeset iterator to the next change.
|
|
-**
|
|
-** If both paRec and pnRec are NULL, then this function works like the public
|
|
-** API sqlite3changeset_next(). If SQLITE_ROW is returned, then the
|
|
-** sqlite3changeset_new() and old() APIs may be used to query for values.
|
|
+** Advance the changeset iterator to the next change. The differences between
|
|
+** this function and sessionChangesetNext() are that
|
|
**
|
|
-** Otherwise, if paRec and pnRec are not NULL, then a pointer to the change
|
|
-** record is written to *paRec before returning and the number of bytes in
|
|
-** the record to *pnRec.
|
|
+** * If pbEmpty is not NULL and the change is a no-op UPDATE (an UPDATE
|
|
+** that modifies no columns), this function sets (*pbEmpty) to 1.
|
|
**
|
|
-** Either way, this function returns SQLITE_ROW if the iterator is
|
|
-** successfully advanced to the next change in the changeset, an SQLite
|
|
-** error code if an error occurs, or SQLITE_DONE if there are no further
|
|
-** changes in the changeset.
|
|
+** * If the iterator is configured to skip no-op UPDATEs,
|
|
+** sessionChangesetNext() does that. This function does not.
|
|
*/
|
|
-static int sessionChangesetNext(
|
|
+static int sessionChangesetNextOne(
|
|
sqlite3_changeset_iter *p, /* Changeset iterator */
|
|
u8 **paRec, /* If non-NULL, store record pointer here */
|
|
int *pnRec, /* If non-NULL, store size of record here */
|
|
- int *pbNew /* If non-NULL, true if new table */
|
|
+ int *pbNew, /* If non-NULL, true if new table */
|
|
+ int *pbEmpty
|
|
){
|
|
int i;
|
|
u8 op;
|
|
|
|
assert( (paRec==0 && pnRec==0) || (paRec && pnRec) );
|
|
+ assert( pbEmpty==0 || *pbEmpty==0 );
|
|
|
|
/* If the iterator is in the error-state, return immediately. */
|
|
if( p->rc!=SQLITE_OK ) return p->rc;
|
|
@@ -203425,7 +219423,7 @@ static int sessionChangesetNext(
|
|
return (p->rc = SQLITE_CORRUPT_BKPT);
|
|
}
|
|
|
|
- if( paRec ){
|
|
+ if( paRec ){
|
|
int nVal; /* Number of values to buffer */
|
|
if( p->bPatchset==0 && op==SQLITE_UPDATE ){
|
|
nVal = p->nCol * 2;
|
|
@@ -203446,13 +219444,13 @@ static int sessionChangesetNext(
|
|
/* If this is an UPDATE or DELETE, read the old.* record. */
|
|
if( p->op!=SQLITE_INSERT && (p->bPatchset==0 || p->op==SQLITE_DELETE) ){
|
|
u8 *abPK = p->bPatchset ? p->abPK : 0;
|
|
- p->rc = sessionReadRecord(&p->in, p->nCol, abPK, apOld);
|
|
+ p->rc = sessionReadRecord(&p->in, p->nCol, abPK, apOld, 0);
|
|
if( p->rc!=SQLITE_OK ) return p->rc;
|
|
}
|
|
|
|
/* If this is an INSERT or UPDATE, read the new.* record. */
|
|
if( p->op!=SQLITE_DELETE ){
|
|
- p->rc = sessionReadRecord(&p->in, p->nCol, 0, apNew);
|
|
+ p->rc = sessionReadRecord(&p->in, p->nCol, 0, apNew, pbEmpty);
|
|
if( p->rc!=SQLITE_OK ) return p->rc;
|
|
}
|
|
|
|
@@ -203474,11 +219472,58 @@ static int sessionChangesetNext(
|
|
if( p->op==SQLITE_INSERT ) p->op = SQLITE_DELETE;
|
|
else if( p->op==SQLITE_DELETE ) p->op = SQLITE_INSERT;
|
|
}
|
|
+
|
|
+ /* If this is an UPDATE that is part of a changeset, then check that
|
|
+ ** there are no fields in the old.* record that are not (a) PK fields,
|
|
+ ** or (b) also present in the new.* record.
|
|
+ **
|
|
+ ** Such records are technically corrupt, but the rebaser was at one
|
|
+ ** point generating them. Under most circumstances this is benign, but
|
|
+ ** can cause spurious SQLITE_RANGE errors when applying the changeset. */
|
|
+ if( p->bPatchset==0 && p->op==SQLITE_UPDATE){
|
|
+ for(i=0; i<p->nCol; i++){
|
|
+ if( p->abPK[i]==0 && p->apValue[i+p->nCol]==0 ){
|
|
+ sqlite3ValueFree(p->apValue[i]);
|
|
+ p->apValue[i] = 0;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
}
|
|
|
|
return SQLITE_ROW;
|
|
}
|
|
|
|
+/*
|
|
+** Advance the changeset iterator to the next change.
|
|
+**
|
|
+** If both paRec and pnRec are NULL, then this function works like the public
|
|
+** API sqlite3changeset_next(). If SQLITE_ROW is returned, then the
|
|
+** sqlite3changeset_new() and old() APIs may be used to query for values.
|
|
+**
|
|
+** Otherwise, if paRec and pnRec are not NULL, then a pointer to the change
|
|
+** record is written to *paRec before returning and the number of bytes in
|
|
+** the record to *pnRec.
|
|
+**
|
|
+** Either way, this function returns SQLITE_ROW if the iterator is
|
|
+** successfully advanced to the next change in the changeset, an SQLite
|
|
+** error code if an error occurs, or SQLITE_DONE if there are no further
|
|
+** changes in the changeset.
|
|
+*/
|
|
+static int sessionChangesetNext(
|
|
+ sqlite3_changeset_iter *p, /* Changeset iterator */
|
|
+ u8 **paRec, /* If non-NULL, store record pointer here */
|
|
+ int *pnRec, /* If non-NULL, store size of record here */
|
|
+ int *pbNew /* If non-NULL, true if new table */
|
|
+){
|
|
+ int bEmpty;
|
|
+ int rc;
|
|
+ do {
|
|
+ bEmpty = 0;
|
|
+ rc = sessionChangesetNextOne(p, paRec, pnRec, pbNew, &bEmpty);
|
|
+ }while( rc==SQLITE_ROW && p->bSkipEmpty && bEmpty);
|
|
+ return rc;
|
|
+}
|
|
+
|
|
/*
|
|
** Advance an iterator created by sqlite3changeset_start() to the next
|
|
** change in the changeset. This function may return SQLITE_ROW, SQLITE_DONE
|
|
@@ -203592,7 +219637,7 @@ SQLITE_API int sqlite3changeset_new(
|
|
|
|
/*
|
|
** This function may only be called with a changeset iterator that has been
|
|
-** passed to an SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT
|
|
+** passed to an SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT
|
|
** conflict-handler function. Otherwise, SQLITE_MISUSE is returned.
|
|
**
|
|
** If successful, *ppValue is set to point to an sqlite3_value structure
|
|
@@ -203751,9 +219796,9 @@ static int sessionChangesetInvert(
|
|
|
|
/* Read the old.* and new.* records for the update change. */
|
|
pInput->iNext += 2;
|
|
- rc = sessionReadRecord(pInput, nCol, 0, &apVal[0]);
|
|
+ rc = sessionReadRecord(pInput, nCol, 0, &apVal[0], 0);
|
|
if( rc==SQLITE_OK ){
|
|
- rc = sessionReadRecord(pInput, nCol, 0, &apVal[nCol]);
|
|
+ rc = sessionReadRecord(pInput, nCol, 0, &apVal[nCol], 0);
|
|
}
|
|
|
|
/* Write the new old.* record. Consists of the PK columns from the
|
|
@@ -203797,11 +219842,11 @@ static int sessionChangesetInvert(
|
|
}
|
|
|
|
assert( rc==SQLITE_OK );
|
|
- if( pnInverted ){
|
|
+ if( pnInverted && ALWAYS(ppInverted) ){
|
|
*pnInverted = sOut.nBuf;
|
|
*ppInverted = sOut.aBuf;
|
|
sOut.aBuf = 0;
|
|
- }else if( sOut.nBuf>0 ){
|
|
+ }else if( sOut.nBuf>0 && ALWAYS(xOutput!=0) ){
|
|
rc = xOutput(pOut, sOut.aBuf, sOut.nBuf);
|
|
}
|
|
|
|
@@ -203854,24 +219899,195 @@ SQLITE_API int sqlite3changeset_invert_strm(
|
|
return rc;
|
|
}
|
|
|
|
+
|
|
+typedef struct SessionUpdate SessionUpdate;
|
|
+struct SessionUpdate {
|
|
+ sqlite3_stmt *pStmt;
|
|
+ u32 *aMask;
|
|
+ SessionUpdate *pNext;
|
|
+};
|
|
+
|
|
typedef struct SessionApplyCtx SessionApplyCtx;
|
|
struct SessionApplyCtx {
|
|
sqlite3 *db;
|
|
sqlite3_stmt *pDelete; /* DELETE statement */
|
|
- sqlite3_stmt *pUpdate; /* UPDATE statement */
|
|
sqlite3_stmt *pInsert; /* INSERT statement */
|
|
sqlite3_stmt *pSelect; /* SELECT statement */
|
|
int nCol; /* Size of azCol[] and abPK[] arrays */
|
|
const char **azCol; /* Array of column names */
|
|
u8 *abPK; /* Boolean array - true if column is in PK */
|
|
+ u32 *aUpdateMask; /* Used by sessionUpdateFind */
|
|
+ SessionUpdate *pUp;
|
|
int bStat1; /* True if table is sqlite_stat1 */
|
|
int bDeferConstraints; /* True to defer constraints */
|
|
+ int bInvertConstraints; /* Invert when iterating constraints buffer */
|
|
SessionBuffer constraints; /* Deferred constraints are stored here */
|
|
SessionBuffer rebase; /* Rebase information (if any) here */
|
|
u8 bRebaseStarted; /* If table header is already in rebase */
|
|
u8 bRebase; /* True to collect rebase information */
|
|
};
|
|
|
|
+/* Number of prepared UPDATE statements to cache. */
|
|
+#define SESSION_UPDATE_CACHE_SZ 12
|
|
+
|
|
+/*
|
|
+** Find a prepared UPDATE statement suitable for the UPDATE step currently
|
|
+** being visited by the iterator. The UPDATE is of the form:
|
|
+**
|
|
+** UPDATE tbl SET col = ?, col2 = ? WHERE pk1 IS ? AND pk2 IS ?
|
|
+*/
|
|
+static int sessionUpdateFind(
|
|
+ sqlite3_changeset_iter *pIter,
|
|
+ SessionApplyCtx *p,
|
|
+ int bPatchset,
|
|
+ sqlite3_stmt **ppStmt
|
|
+){
|
|
+ int rc = SQLITE_OK;
|
|
+ SessionUpdate *pUp = 0;
|
|
+ int nCol = pIter->nCol;
|
|
+ int nU32 = (pIter->nCol+33)/32;
|
|
+ int ii;
|
|
+
|
|
+ if( p->aUpdateMask==0 ){
|
|
+ p->aUpdateMask = sqlite3_malloc(nU32*sizeof(u32));
|
|
+ if( p->aUpdateMask==0 ){
|
|
+ rc = SQLITE_NOMEM;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if( rc==SQLITE_OK ){
|
|
+ memset(p->aUpdateMask, 0, nU32*sizeof(u32));
|
|
+ rc = SQLITE_CORRUPT;
|
|
+ for(ii=0; ii<pIter->nCol; ii++){
|
|
+ if( sessionChangesetNew(pIter, ii) ){
|
|
+ p->aUpdateMask[ii/32] |= (1<<(ii%32));
|
|
+ rc = SQLITE_OK;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if( rc==SQLITE_OK ){
|
|
+ if( bPatchset ) p->aUpdateMask[nCol/32] |= (1<<(nCol%32));
|
|
+
|
|
+ if( p->pUp ){
|
|
+ int nUp = 0;
|
|
+ SessionUpdate **pp = &p->pUp;
|
|
+ while( 1 ){
|
|
+ nUp++;
|
|
+ if( 0==memcmp(p->aUpdateMask, (*pp)->aMask, nU32*sizeof(u32)) ){
|
|
+ pUp = *pp;
|
|
+ *pp = pUp->pNext;
|
|
+ pUp->pNext = p->pUp;
|
|
+ p->pUp = pUp;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if( (*pp)->pNext ){
|
|
+ pp = &(*pp)->pNext;
|
|
+ }else{
|
|
+ if( nUp>=SESSION_UPDATE_CACHE_SZ ){
|
|
+ sqlite3_finalize((*pp)->pStmt);
|
|
+ sqlite3_free(*pp);
|
|
+ *pp = 0;
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if( pUp==0 ){
|
|
+ int nByte = sizeof(SessionUpdate) * nU32*sizeof(u32);
|
|
+ int bStat1 = (sqlite3_stricmp(pIter->zTab, "sqlite_stat1")==0);
|
|
+ pUp = (SessionUpdate*)sqlite3_malloc(nByte);
|
|
+ if( pUp==0 ){
|
|
+ rc = SQLITE_NOMEM;
|
|
+ }else{
|
|
+ const char *zSep = "";
|
|
+ SessionBuffer buf;
|
|
+
|
|
+ memset(&buf, 0, sizeof(buf));
|
|
+ pUp->aMask = (u32*)&pUp[1];
|
|
+ memcpy(pUp->aMask, p->aUpdateMask, nU32*sizeof(u32));
|
|
+
|
|
+ sessionAppendStr(&buf, "UPDATE main.", &rc);
|
|
+ sessionAppendIdent(&buf, pIter->zTab, &rc);
|
|
+ sessionAppendStr(&buf, " SET ", &rc);
|
|
+
|
|
+ /* Create the assignments part of the UPDATE */
|
|
+ for(ii=0; ii<pIter->nCol; ii++){
|
|
+ if( p->abPK[ii]==0 && sessionChangesetNew(pIter, ii) ){
|
|
+ sessionAppendStr(&buf, zSep, &rc);
|
|
+ sessionAppendIdent(&buf, p->azCol[ii], &rc);
|
|
+ sessionAppendStr(&buf, " = ?", &rc);
|
|
+ sessionAppendInteger(&buf, ii*2+1, &rc);
|
|
+ zSep = ", ";
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Create the WHERE clause part of the UPDATE */
|
|
+ zSep = "";
|
|
+ sessionAppendStr(&buf, " WHERE ", &rc);
|
|
+ for(ii=0; ii<pIter->nCol; ii++){
|
|
+ if( p->abPK[ii] || (bPatchset==0 && sessionChangesetOld(pIter, ii)) ){
|
|
+ sessionAppendStr(&buf, zSep, &rc);
|
|
+ if( bStat1 && ii==1 ){
|
|
+ assert( sqlite3_stricmp(p->azCol[ii], "idx")==0 );
|
|
+ sessionAppendStr(&buf,
|
|
+ "idx IS CASE "
|
|
+ "WHEN length(?4)=0 AND typeof(?4)='blob' THEN NULL "
|
|
+ "ELSE ?4 END ", &rc
|
|
+ );
|
|
+ }else{
|
|
+ sessionAppendIdent(&buf, p->azCol[ii], &rc);
|
|
+ sessionAppendStr(&buf, " IS ?", &rc);
|
|
+ sessionAppendInteger(&buf, ii*2+2, &rc);
|
|
+ }
|
|
+ zSep = " AND ";
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if( rc==SQLITE_OK ){
|
|
+ char *zSql = (char*)buf.aBuf;
|
|
+ rc = sqlite3_prepare_v2(p->db, zSql, buf.nBuf, &pUp->pStmt, 0);
|
|
+ }
|
|
+
|
|
+ if( rc!=SQLITE_OK ){
|
|
+ sqlite3_free(pUp);
|
|
+ pUp = 0;
|
|
+ }else{
|
|
+ pUp->pNext = p->pUp;
|
|
+ p->pUp = pUp;
|
|
+ }
|
|
+ sqlite3_free(buf.aBuf);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ assert( (rc==SQLITE_OK)==(pUp!=0) );
|
|
+ if( pUp ){
|
|
+ *ppStmt = pUp->pStmt;
|
|
+ }else{
|
|
+ *ppStmt = 0;
|
|
+ }
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Free all cached UPDATE statements.
|
|
+*/
|
|
+static void sessionUpdateFree(SessionApplyCtx *p){
|
|
+ SessionUpdate *pUp;
|
|
+ SessionUpdate *pNext;
|
|
+ for(pUp=p->pUp; pUp; pUp=pNext){
|
|
+ pNext = pUp->pNext;
|
|
+ sqlite3_finalize(pUp->pStmt);
|
|
+ sqlite3_free(pUp);
|
|
+ }
|
|
+ p->pUp = 0;
|
|
+ sqlite3_free(p->aUpdateMask);
|
|
+ p->aUpdateMask = 0;
|
|
+}
|
|
+
|
|
/*
|
|
** Formulate a statement to DELETE a row from database db. Assuming a table
|
|
** structure like this:
|
|
@@ -203900,7 +220116,7 @@ static int sessionDeleteRow(
|
|
SessionBuffer buf = {0, 0, 0};
|
|
int nPk = 0;
|
|
|
|
- sessionAppendStr(&buf, "DELETE FROM ", &rc);
|
|
+ sessionAppendStr(&buf, "DELETE FROM main.", &rc);
|
|
sessionAppendIdent(&buf, zTab, &rc);
|
|
sessionAppendStr(&buf, " WHERE ", &rc);
|
|
|
|
@@ -203941,103 +220157,6 @@ static int sessionDeleteRow(
|
|
return rc;
|
|
}
|
|
|
|
-/*
|
|
-** Formulate and prepare a statement to UPDATE a row from database db.
|
|
-** Assuming a table structure like this:
|
|
-**
|
|
-** CREATE TABLE x(a, b, c, d, PRIMARY KEY(a, c));
|
|
-**
|
|
-** The UPDATE statement looks like this:
|
|
-**
|
|
-** UPDATE x SET
|
|
-** a = CASE WHEN ?2 THEN ?3 ELSE a END,
|
|
-** b = CASE WHEN ?5 THEN ?6 ELSE b END,
|
|
-** c = CASE WHEN ?8 THEN ?9 ELSE c END,
|
|
-** d = CASE WHEN ?11 THEN ?12 ELSE d END
|
|
-** WHERE a = ?1 AND c = ?7 AND (?13 OR
|
|
-** (?5==0 OR b IS ?4) AND (?11==0 OR d IS ?10) AND
|
|
-** )
|
|
-**
|
|
-** For each column in the table, there are three variables to bind:
|
|
-**
|
|
-** ?(i*3+1) The old.* value of the column, if any.
|
|
-** ?(i*3+2) A boolean flag indicating that the value is being modified.
|
|
-** ?(i*3+3) The new.* value of the column, if any.
|
|
-**
|
|
-** Also, a boolean flag that, if set to true, causes the statement to update
|
|
-** a row even if the non-PK values do not match. This is required if the
|
|
-** conflict-handler is invoked with CHANGESET_DATA and returns
|
|
-** CHANGESET_REPLACE. This is variable "?(nCol*3+1)".
|
|
-**
|
|
-** If successful, SQLITE_OK is returned and SessionApplyCtx.pUpdate is left
|
|
-** pointing to the prepared version of the SQL statement.
|
|
-*/
|
|
-static int sessionUpdateRow(
|
|
- sqlite3 *db, /* Database handle */
|
|
- const char *zTab, /* Table name */
|
|
- SessionApplyCtx *p /* Session changeset-apply context */
|
|
-){
|
|
- int rc = SQLITE_OK;
|
|
- int i;
|
|
- const char *zSep = "";
|
|
- SessionBuffer buf = {0, 0, 0};
|
|
-
|
|
- /* Append "UPDATE tbl SET " */
|
|
- sessionAppendStr(&buf, "UPDATE ", &rc);
|
|
- sessionAppendIdent(&buf, zTab, &rc);
|
|
- sessionAppendStr(&buf, " SET ", &rc);
|
|
-
|
|
- /* Append the assignments */
|
|
- for(i=0; i<p->nCol; i++){
|
|
- sessionAppendStr(&buf, zSep, &rc);
|
|
- sessionAppendIdent(&buf, p->azCol[i], &rc);
|
|
- sessionAppendStr(&buf, " = CASE WHEN ?", &rc);
|
|
- sessionAppendInteger(&buf, i*3+2, &rc);
|
|
- sessionAppendStr(&buf, " THEN ?", &rc);
|
|
- sessionAppendInteger(&buf, i*3+3, &rc);
|
|
- sessionAppendStr(&buf, " ELSE ", &rc);
|
|
- sessionAppendIdent(&buf, p->azCol[i], &rc);
|
|
- sessionAppendStr(&buf, " END", &rc);
|
|
- zSep = ", ";
|
|
- }
|
|
-
|
|
- /* Append the PK part of the WHERE clause */
|
|
- sessionAppendStr(&buf, " WHERE ", &rc);
|
|
- for(i=0; i<p->nCol; i++){
|
|
- if( p->abPK[i] ){
|
|
- sessionAppendIdent(&buf, p->azCol[i], &rc);
|
|
- sessionAppendStr(&buf, " = ?", &rc);
|
|
- sessionAppendInteger(&buf, i*3+1, &rc);
|
|
- sessionAppendStr(&buf, " AND ", &rc);
|
|
- }
|
|
- }
|
|
-
|
|
- /* Append the non-PK part of the WHERE clause */
|
|
- sessionAppendStr(&buf, " (?", &rc);
|
|
- sessionAppendInteger(&buf, p->nCol*3+1, &rc);
|
|
- sessionAppendStr(&buf, " OR 1", &rc);
|
|
- for(i=0; i<p->nCol; i++){
|
|
- if( !p->abPK[i] ){
|
|
- sessionAppendStr(&buf, " AND (?", &rc);
|
|
- sessionAppendInteger(&buf, i*3+2, &rc);
|
|
- sessionAppendStr(&buf, "=0 OR ", &rc);
|
|
- sessionAppendIdent(&buf, p->azCol[i], &rc);
|
|
- sessionAppendStr(&buf, " IS ?", &rc);
|
|
- sessionAppendInteger(&buf, i*3+1, &rc);
|
|
- sessionAppendStr(&buf, ")", &rc);
|
|
- }
|
|
- }
|
|
- sessionAppendStr(&buf, ")", &rc);
|
|
-
|
|
- if( rc==SQLITE_OK ){
|
|
- rc = sqlite3_prepare_v2(db, (char *)buf.aBuf, buf.nBuf, &p->pUpdate, 0);
|
|
- }
|
|
- sqlite3_free(buf.aBuf);
|
|
-
|
|
- return rc;
|
|
-}
|
|
-
|
|
-
|
|
/*
|
|
** Formulate and prepare an SQL statement to query table zTab by primary
|
|
** key. Assuming the following table structure:
|
|
@@ -204106,7 +220225,7 @@ static int sessionPrepare(sqlite3 *db, sqlite3_stmt **pp, const char *zSql){
|
|
/*
|
|
** Prepare statements for applying changes to the sqlite_stat1 table.
|
|
** These are similar to those created by sessionSelectRow(),
|
|
-** sessionInsertRow(), sessionUpdateRow() and sessionDeleteRow() for
|
|
+** sessionInsertRow(), sessionUpdateRow() and sessionDeleteRow() for
|
|
** other tables.
|
|
*/
|
|
static int sessionStat1Sql(sqlite3 *db, SessionApplyCtx *p){
|
|
@@ -204118,17 +220237,6 @@ static int sessionStat1Sql(sqlite3 *db, SessionApplyCtx *p){
|
|
"?3)"
|
|
);
|
|
}
|
|
- if( rc==SQLITE_OK ){
|
|
- rc = sessionPrepare(db, &p->pUpdate,
|
|
- "UPDATE main.sqlite_stat1 SET "
|
|
- "tbl = CASE WHEN ?2 THEN ?3 ELSE tbl END, "
|
|
- "idx = CASE WHEN ?5 THEN ?6 ELSE idx END, "
|
|
- "stat = CASE WHEN ?8 THEN ?9 ELSE stat END "
|
|
- "WHERE tbl=?1 AND idx IS "
|
|
- "CASE WHEN length(?4)=0 AND typeof(?4)='blob' THEN NULL ELSE ?4 END "
|
|
- "AND (?10 OR ?8=0 OR stat IS ?7)"
|
|
- );
|
|
- }
|
|
if( rc==SQLITE_OK ){
|
|
rc = sessionPrepare(db, &p->pDelete,
|
|
"DELETE FROM main.sqlite_stat1 WHERE tbl=?1 AND idx IS "
|
|
@@ -204140,7 +220248,7 @@ static int sessionStat1Sql(sqlite3 *db, SessionApplyCtx *p){
|
|
}
|
|
|
|
/*
|
|
-** A wrapper around sqlite3_bind_value() that detects an extra problem.
|
|
+** A wrapper around sqlite3_bind_value() that detects an extra problem.
|
|
** See comments in the body of this function for details.
|
|
*/
|
|
static int sessionBindValue(
|
|
@@ -204163,15 +220271,15 @@ static int sessionBindValue(
|
|
}
|
|
|
|
/*
|
|
-** Iterator pIter must point to an SQLITE_INSERT entry. This function
|
|
+** Iterator pIter must point to an SQLITE_INSERT entry. This function
|
|
** transfers new.* values from the current iterator entry to statement
|
|
** pStmt. The table being inserted into has nCol columns.
|
|
**
|
|
-** New.* value $i from the iterator is bound to variable ($i+1) of
|
|
+** New.* value $i from the iterator is bound to variable ($i+1) of
|
|
** statement pStmt. If parameter abPK is NULL, all values from 0 to (nCol-1)
|
|
** are transfered to the statement. Otherwise, if abPK is not NULL, it points
|
|
-** to an array nCol elements in size. In this case only those values for
|
|
-** which abPK[$i] is true are read from the iterator and bound to the
|
|
+** to an array nCol elements in size. In this case only those values for
|
|
+** which abPK[$i] is true are read from the iterator and bound to the
|
|
** statement.
|
|
**
|
|
** An SQLite error code is returned if an error occurs. Otherwise, SQLITE_OK.
|
|
@@ -204187,14 +220295,14 @@ static int sessionBindRow(
|
|
int rc = SQLITE_OK;
|
|
|
|
/* Neither sqlite3changeset_old or sqlite3changeset_new can fail if the
|
|
- ** argument iterator points to a suitable entry. Make sure that xValue
|
|
- ** is one of these to guarantee that it is safe to ignore the return
|
|
+ ** argument iterator points to a suitable entry. Make sure that xValue
|
|
+ ** is one of these to guarantee that it is safe to ignore the return
|
|
** in the code below. */
|
|
assert( xValue==sqlite3changeset_old || xValue==sqlite3changeset_new );
|
|
|
|
for(i=0; rc==SQLITE_OK && i<nCol; i++){
|
|
if( !abPK || abPK[i] ){
|
|
- sqlite3_value *pVal;
|
|
+ sqlite3_value *pVal = 0;
|
|
(void)xValue(pIter, i, &pVal);
|
|
if( pVal==0 ){
|
|
/* The value in the changeset was "undefined". This indicates a
|
|
@@ -204212,21 +220320,20 @@ static int sessionBindRow(
|
|
** SQL statement pSelect is as generated by the sessionSelectRow() function.
|
|
** This function binds the primary key values from the change that changeset
|
|
** iterator pIter points to to the SELECT and attempts to seek to the table
|
|
-** entry. If a row is found, the SELECT statement left pointing at the row
|
|
+** entry. If a row is found, the SELECT statement left pointing at the row
|
|
** and SQLITE_ROW is returned. Otherwise, if no row is found and no error
|
|
** has occured, the statement is reset and SQLITE_OK is returned. If an
|
|
** error occurs, the statement is reset and an SQLite error code is returned.
|
|
**
|
|
-** If this function returns SQLITE_ROW, the caller must eventually reset()
|
|
+** If this function returns SQLITE_ROW, the caller must eventually reset()
|
|
** statement pSelect. If any other value is returned, the statement does
|
|
** not require a reset().
|
|
**
|
|
** If the iterator currently points to an INSERT record, bind values from the
|
|
** new.* record to the SELECT statement. Or, if it points to a DELETE or
|
|
-** UPDATE, bind values from the old.* record.
|
|
+** UPDATE, bind values from the old.* record.
|
|
*/
|
|
static int sessionSeekToRow(
|
|
- sqlite3 *db, /* Database handle */
|
|
sqlite3_changeset_iter *pIter, /* Changeset iterator */
|
|
u8 *abPK, /* Primary key flags array */
|
|
sqlite3_stmt *pSelect /* SELECT statement from sessionSelectRow() */
|
|
@@ -204237,7 +220344,7 @@ static int sessionSeekToRow(
|
|
const char *zDummy; /* Unused */
|
|
|
|
sqlite3changeset_op(pIter, &zDummy, &nCol, &op, 0);
|
|
- rc = sessionBindRow(pIter,
|
|
+ rc = sessionBindRow(pIter,
|
|
op==SQLITE_INSERT ? sqlite3changeset_new : sqlite3changeset_old,
|
|
nCol, abPK, pSelect
|
|
);
|
|
@@ -204254,7 +220361,7 @@ static int sessionSeekToRow(
|
|
** This function is called from within sqlite3changeset_apply_v2() when
|
|
** a conflict is encountered and resolved using conflict resolution
|
|
** mode eType (either SQLITE_CHANGESET_OMIT or SQLITE_CHANGESET_REPLACE)..
|
|
-** It adds a conflict resolution record to the buffer in
|
|
+** It adds a conflict resolution record to the buffer in
|
|
** SessionApplyCtx.rebase, which will eventually be returned to the caller
|
|
** of apply_v2() as the "rebase" buffer.
|
|
**
|
|
@@ -204282,7 +220389,7 @@ static int sessionRebaseAdd(
|
|
assert( eType==SQLITE_CHANGESET_REPLACE||eType==SQLITE_CHANGESET_OMIT );
|
|
assert( eOp==SQLITE_DELETE || eOp==SQLITE_INSERT || eOp==SQLITE_UPDATE );
|
|
|
|
- sessionAppendByte(&p->rebase,
|
|
+ sessionAppendByte(&p->rebase,
|
|
(eOp==SQLITE_DELETE ? SQLITE_DELETE : SQLITE_INSERT), &rc
|
|
);
|
|
sessionAppendByte(&p->rebase, (eType==SQLITE_CHANGESET_REPLACE), &rc);
|
|
@@ -204330,7 +220437,7 @@ static int sessionRebaseAdd(
|
|
** is set to non-zero before returning SQLITE_OK.
|
|
**
|
|
** If the conflict handler returns SQLITE_CHANGESET_ABORT, SQLITE_ABORT is
|
|
-** returned. Or, if the conflict handler returns an invalid value,
|
|
+** returned. Or, if the conflict handler returns an invalid value,
|
|
** SQLITE_MISUSE. If the conflict handler returns SQLITE_CHANGESET_OMIT,
|
|
** this function returns SQLITE_OK.
|
|
*/
|
|
@@ -204356,7 +220463,7 @@ static int sessionConflictHandler(
|
|
|
|
/* Bind the new.* PRIMARY KEY values to the SELECT statement. */
|
|
if( pbReplace ){
|
|
- rc = sessionSeekToRow(p->db, pIter, p->abPK, p->pSelect);
|
|
+ rc = sessionSeekToRow(pIter, p->abPK, p->pSelect);
|
|
}else{
|
|
rc = SQLITE_OK;
|
|
}
|
|
@@ -204420,16 +220527,16 @@ static int sessionConflictHandler(
|
|
** to true before returning. In this case the caller will invoke this function
|
|
** again, this time with pbRetry set to NULL.
|
|
**
|
|
-** If argument pbReplace is NULL and a CHANGESET_CONFLICT conflict is
|
|
+** If argument pbReplace is NULL and a CHANGESET_CONFLICT conflict is
|
|
** encountered invoke the conflict handler with CHANGESET_CONSTRAINT instead.
|
|
** Or, if pbReplace is not NULL, invoke it with CHANGESET_CONFLICT. If such
|
|
** an invocation returns SQLITE_CHANGESET_REPLACE, set *pbReplace to true
|
|
** before retrying. In this case the caller attempts to remove the conflicting
|
|
-** row before invoking this function again, this time with pbReplace set
|
|
+** row before invoking this function again, this time with pbReplace set
|
|
** to NULL.
|
|
**
|
|
** If any conflict handler returns SQLITE_CHANGESET_ABORT, this function
|
|
-** returns SQLITE_ABORT. Otherwise, if no error occurs, SQLITE_OK is
|
|
+** returns SQLITE_ABORT. Otherwise, if no error occurs, SQLITE_OK is
|
|
** returned.
|
|
*/
|
|
static int sessionApplyOneOp(
|
|
@@ -204445,7 +220552,7 @@ static int sessionApplyOneOp(
|
|
int nCol;
|
|
int rc = SQLITE_OK;
|
|
|
|
- assert( p->pDelete && p->pUpdate && p->pInsert && p->pSelect );
|
|
+ assert( p->pDelete && p->pInsert && p->pSelect );
|
|
assert( p->azCol && p->abPK );
|
|
assert( !pbReplace || *pbReplace==0 );
|
|
|
|
@@ -204485,29 +220592,28 @@ static int sessionApplyOneOp(
|
|
|
|
}else if( op==SQLITE_UPDATE ){
|
|
int i;
|
|
+ sqlite3_stmt *pUp = 0;
|
|
+ int bPatchset = (pbRetry==0 || pIter->bPatchset);
|
|
+
|
|
+ rc = sessionUpdateFind(pIter, p, bPatchset, &pUp);
|
|
|
|
/* Bind values to the UPDATE statement. */
|
|
for(i=0; rc==SQLITE_OK && i<nCol; i++){
|
|
sqlite3_value *pOld = sessionChangesetOld(pIter, i);
|
|
sqlite3_value *pNew = sessionChangesetNew(pIter, i);
|
|
-
|
|
- sqlite3_bind_int(p->pUpdate, i*3+2, !!pNew);
|
|
- if( pOld ){
|
|
- rc = sessionBindValue(p->pUpdate, i*3+1, pOld);
|
|
+ if( p->abPK[i] || (bPatchset==0 && pOld) ){
|
|
+ rc = sessionBindValue(pUp, i*2+2, pOld);
|
|
}
|
|
if( rc==SQLITE_OK && pNew ){
|
|
- rc = sessionBindValue(p->pUpdate, i*3+3, pNew);
|
|
+ rc = sessionBindValue(pUp, i*2+1, pNew);
|
|
}
|
|
}
|
|
- if( rc==SQLITE_OK ){
|
|
- sqlite3_bind_int(p->pUpdate, nCol*3+1, pbRetry==0 || pIter->bPatchset);
|
|
- }
|
|
if( rc!=SQLITE_OK ) return rc;
|
|
|
|
/* Attempt the UPDATE. In the case of a NOTFOUND or DATA conflict,
|
|
** the result will be SQLITE_OK with 0 rows modified. */
|
|
- sqlite3_step(p->pUpdate);
|
|
- rc = sqlite3_reset(p->pUpdate);
|
|
+ sqlite3_step(pUp);
|
|
+ rc = sqlite3_reset(pUp);
|
|
|
|
if( rc==SQLITE_OK && sqlite3_changes(p->db)==0 ){
|
|
/* A NOTFOUND or DATA error. Search the table to see if it contains
|
|
@@ -204529,9 +220635,9 @@ static int sessionApplyOneOp(
|
|
assert( op==SQLITE_INSERT );
|
|
if( p->bStat1 ){
|
|
/* Check if there is a conflicting row. For sqlite_stat1, this needs
|
|
- ** to be done using a SELECT, as there is no PRIMARY KEY in the
|
|
+ ** to be done using a SELECT, as there is no PRIMARY KEY in the
|
|
** database schema to throw an exception if a duplicate is inserted. */
|
|
- rc = sessionSeekToRow(p->db, pIter, p->abPK, p->pSelect);
|
|
+ rc = sessionSeekToRow(pIter, p->abPK, p->pSelect);
|
|
if( rc==SQLITE_ROW ){
|
|
rc = SQLITE_CONSTRAINT;
|
|
sqlite3_reset(p->pSelect);
|
|
@@ -204562,7 +220668,7 @@ static int sessionApplyOneOp(
|
|
** the conflict handler callback.
|
|
**
|
|
** The difference between this function and sessionApplyOne() is that this
|
|
-** function handles the case where the conflict-handler is invoked and
|
|
+** function handles the case where the conflict-handler is invoked and
|
|
** returns SQLITE_CHANGESET_REPLACE - indicating that the change should be
|
|
** retried in some manner.
|
|
*/
|
|
@@ -204582,7 +220688,7 @@ static int sessionApplyOneWithRetry(
|
|
/* If the bRetry flag is set, the change has not been applied due to an
|
|
** SQLITE_CHANGESET_DATA problem (i.e. this is an UPDATE or DELETE and
|
|
** a row with the correct PK is present in the db, but one or more other
|
|
- ** fields do not contain the expected values) and the conflict handler
|
|
+ ** fields do not contain the expected values) and the conflict handler
|
|
** returned SQLITE_CHANGESET_REPLACE. In this case retry the operation,
|
|
** but pass NULL as the final argument so that sessionApplyOneOp() ignores
|
|
** the SQLITE_CHANGESET_DATA problem. */
|
|
@@ -204600,7 +220706,7 @@ static int sessionApplyOneWithRetry(
|
|
assert( pIter->op==SQLITE_INSERT );
|
|
rc = sqlite3_exec(db, "SAVEPOINT replace_op", 0, 0, 0);
|
|
if( rc==SQLITE_OK ){
|
|
- rc = sessionBindRow(pIter,
|
|
+ rc = sessionBindRow(pIter,
|
|
sqlite3changeset_new, pApply->nCol, pApply->abPK, pApply->pDelete);
|
|
sqlite3_bind_int(pApply->pDelete, pApply->nCol+1, 1);
|
|
}
|
|
@@ -204624,7 +220730,7 @@ static int sessionApplyOneWithRetry(
|
|
** Retry the changes accumulated in the pApply->constraints buffer.
|
|
*/
|
|
static int sessionRetryConstraints(
|
|
- sqlite3 *db,
|
|
+ sqlite3 *db,
|
|
int bPatchset,
|
|
const char *zTab,
|
|
SessionApplyCtx *pApply,
|
|
@@ -204638,7 +220744,9 @@ static int sessionRetryConstraints(
|
|
SessionBuffer cons = pApply->constraints;
|
|
memset(&pApply->constraints, 0, sizeof(SessionBuffer));
|
|
|
|
- rc = sessionChangesetStart(&pIter2, 0, 0, cons.nBuf, cons.aBuf, 0);
|
|
+ rc = sessionChangesetStart(
|
|
+ &pIter2, 0, 0, cons.nBuf, cons.aBuf, pApply->bInvertConstraints, 1
|
|
+ );
|
|
if( rc==SQLITE_OK ){
|
|
size_t nByte = 2*pApply->nCol*sizeof(sqlite3_value*);
|
|
int rc2;
|
|
@@ -204672,7 +220780,7 @@ static int sessionRetryConstraints(
|
|
|
|
/*
|
|
** Argument pIter is a changeset iterator that has been initialized, but
|
|
-** not yet passed to sqlite3changeset_next(). This function applies the
|
|
+** not yet passed to sqlite3changeset_next(). This function applies the
|
|
** changeset to the main database attached to handle "db". The supplied
|
|
** conflict handler callback is invoked to resolve any conflicts encountered
|
|
** while applying the change.
|
|
@@ -204705,6 +220813,7 @@ static int sessionChangesetApply(
|
|
pIter->in.bNoDiscard = 1;
|
|
memset(&sApply, 0, sizeof(sApply));
|
|
sApply.bRebase = (ppRebase && pnRebase);
|
|
+ sApply.bInvertConstraints = !!(flags & SQLITE_CHANGESETAPPLY_INVERT);
|
|
sqlite3_mutex_enter(sqlite3_db_mutex(db));
|
|
if( (flags & SQLITE_CHANGESETAPPLY_NOSAVEPOINT)==0 ){
|
|
rc = sqlite3_exec(db, "SAVEPOINT changeset_apply", 0, 0, 0);
|
|
@@ -204716,7 +220825,7 @@ static int sessionChangesetApply(
|
|
int nCol;
|
|
int op;
|
|
const char *zNew;
|
|
-
|
|
+
|
|
sqlite3changeset_op(pIter, &zNew, &nCol, &op, 0);
|
|
|
|
if( zTab==0 || sqlite3_strnicmp(zNew, zTab, nTab+1) ){
|
|
@@ -204727,14 +220836,13 @@ static int sessionChangesetApply(
|
|
);
|
|
if( rc!=SQLITE_OK ) break;
|
|
|
|
+ sessionUpdateFree(&sApply);
|
|
sqlite3_free((char*)sApply.azCol); /* cast works around VC++ bug */
|
|
sqlite3_finalize(sApply.pDelete);
|
|
- sqlite3_finalize(sApply.pUpdate);
|
|
sqlite3_finalize(sApply.pInsert);
|
|
sqlite3_finalize(sApply.pSelect);
|
|
sApply.db = db;
|
|
sApply.pDelete = 0;
|
|
- sApply.pUpdate = 0;
|
|
sApply.pInsert = 0;
|
|
sApply.pSelect = 0;
|
|
sApply.nCol = 0;
|
|
@@ -204745,7 +220853,7 @@ static int sessionChangesetApply(
|
|
sApply.bRebaseStarted = 0;
|
|
memset(&sApply.constraints, 0, sizeof(SessionBuffer));
|
|
|
|
- /* If an xFilter() callback was specified, invoke it now. If the
|
|
+ /* If an xFilter() callback was specified, invoke it now. If the
|
|
** xFilter callback returns zero, skip this table. If it returns
|
|
** non-zero, proceed. */
|
|
schemaMismatch = (xFilter && (0==xFilter(pCtx, zNew)));
|
|
@@ -204762,25 +220870,25 @@ static int sessionChangesetApply(
|
|
int i;
|
|
|
|
sqlite3changeset_pk(pIter, &abPK, 0);
|
|
- rc = sessionTableInfo(
|
|
+ rc = sessionTableInfo(0,
|
|
db, "main", zNew, &sApply.nCol, &zTab, &sApply.azCol, &sApply.abPK
|
|
);
|
|
if( rc!=SQLITE_OK ) break;
|
|
for(i=0; i<sApply.nCol; i++){
|
|
if( sApply.abPK[i] ) nMinCol = i+1;
|
|
}
|
|
-
|
|
+
|
|
if( sApply.nCol==0 ){
|
|
schemaMismatch = 1;
|
|
- sqlite3_log(SQLITE_SCHEMA,
|
|
+ sqlite3_log(SQLITE_SCHEMA,
|
|
"sqlite3changeset_apply(): no such table: %s", zTab
|
|
);
|
|
}
|
|
else if( sApply.nCol<nCol ){
|
|
schemaMismatch = 1;
|
|
- sqlite3_log(SQLITE_SCHEMA,
|
|
+ sqlite3_log(SQLITE_SCHEMA,
|
|
"sqlite3changeset_apply(): table %s has %d columns, "
|
|
- "expected %d or more",
|
|
+ "expected %d or more",
|
|
zTab, sApply.nCol, nCol
|
|
);
|
|
}
|
|
@@ -204798,11 +220906,10 @@ static int sessionChangesetApply(
|
|
}
|
|
sApply.bStat1 = 1;
|
|
}else{
|
|
- if((rc = sessionSelectRow(db, zTab, &sApply))
|
|
- || (rc = sessionUpdateRow(db, zTab, &sApply))
|
|
- || (rc = sessionDeleteRow(db, zTab, &sApply))
|
|
- || (rc = sessionInsertRow(db, zTab, &sApply))
|
|
- ){
|
|
+ if( (rc = sessionSelectRow(db, zTab, &sApply))
|
|
+ || (rc = sessionDeleteRow(db, zTab, &sApply))
|
|
+ || (rc = sessionInsertRow(db, zTab, &sApply))
|
|
+ ){
|
|
break;
|
|
}
|
|
sApply.bStat1 = 0;
|
|
@@ -204861,9 +220968,9 @@ static int sessionChangesetApply(
|
|
*pnRebase = sApply.rebase.nBuf;
|
|
sApply.rebase.aBuf = 0;
|
|
}
|
|
+ sessionUpdateFree(&sApply);
|
|
sqlite3_finalize(sApply.pInsert);
|
|
sqlite3_finalize(sApply.pDelete);
|
|
- sqlite3_finalize(sApply.pUpdate);
|
|
sqlite3_finalize(sApply.pSelect);
|
|
sqlite3_free((char*)sApply.azCol); /* cast works around VC++ bug */
|
|
sqlite3_free((char*)sApply.constraints.aBuf);
|
|
@@ -204873,7 +220980,7 @@ static int sessionChangesetApply(
|
|
}
|
|
|
|
/*
|
|
-** Apply the changeset passed via pChangeset/nChangeset to the main
|
|
+** Apply the changeset passed via pChangeset/nChangeset to the main
|
|
** database attached to handle "db".
|
|
*/
|
|
SQLITE_API int sqlite3changeset_apply_v2(
|
|
@@ -204893,9 +221000,9 @@ SQLITE_API int sqlite3changeset_apply_v2(
|
|
void **ppRebase, int *pnRebase,
|
|
int flags
|
|
){
|
|
- sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */
|
|
- int bInverse = !!(flags & SQLITE_CHANGESETAPPLY_INVERT);
|
|
- int rc = sessionChangesetStart(&pIter, 0, 0, nChangeset, pChangeset,bInverse);
|
|
+ sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */
|
|
+ int bInv = !!(flags & SQLITE_CHANGESETAPPLY_INVERT);
|
|
+ int rc = sessionChangesetStart(&pIter, 0, 0, nChangeset, pChangeset, bInv, 1);
|
|
if( rc==SQLITE_OK ){
|
|
rc = sessionChangesetApply(
|
|
db, pIter, xFilter, xConflict, pCtx, ppRebase, pnRebase, flags
|
|
@@ -204951,9 +221058,9 @@ SQLITE_API int sqlite3changeset_apply_v2_strm(
|
|
void **ppRebase, int *pnRebase,
|
|
int flags
|
|
){
|
|
- sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */
|
|
+ sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */
|
|
int bInverse = !!(flags & SQLITE_CHANGESETAPPLY_INVERT);
|
|
- int rc = sessionChangesetStart(&pIter, xInput, pIn, 0, 0, bInverse);
|
|
+ int rc = sessionChangesetStart(&pIter, xInput, pIn, 0, 0, bInverse, 1);
|
|
if( rc==SQLITE_OK ){
|
|
rc = sessionChangesetApply(
|
|
db, pIter, xFilter, xConflict, pCtx, ppRebase, pnRebase, flags
|
|
@@ -205080,7 +221187,7 @@ static int sessionChangeMerge(
|
|
}else{
|
|
int op1 = pExist->op;
|
|
|
|
- /*
|
|
+ /*
|
|
** op1=INSERT, op2=INSERT -> Unsupported. Discard op2.
|
|
** op1=INSERT, op2=UPDATE -> INSERT.
|
|
** op1=INSERT, op2=DELETE -> (none)
|
|
@@ -205092,7 +221199,7 @@ static int sessionChangeMerge(
|
|
** op1=DELETE, op2=INSERT -> UPDATE.
|
|
** op1=DELETE, op2=UPDATE -> Unsupported. Discard op2.
|
|
** op1=DELETE, op2=DELETE -> Unsupported. Discard op2.
|
|
- */
|
|
+ */
|
|
if( (op1==SQLITE_INSERT && op2==SQLITE_INSERT)
|
|
|| (op1==SQLITE_UPDATE && op2==SQLITE_INSERT)
|
|
|| (op1==SQLITE_DELETE && op2==SQLITE_UPDATE)
|
|
@@ -205231,7 +221338,7 @@ static int sessionChangesetToHash(
|
|
|
|
/* 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
|
|
+ ** tables within the output of sqlite3changegroup_output() are in
|
|
** the right order. */
|
|
for(ppTab=&pGrp->pList; *ppTab; ppTab=&(*ppTab)->pNext);
|
|
*ppTab = pTab;
|
|
@@ -205241,7 +221348,7 @@ static int sessionChangesetToHash(
|
|
}
|
|
}
|
|
|
|
- if( sessionGrowHash(pIter->bPatchset, pTab) ){
|
|
+ if( sessionGrowHash(0, pIter->bPatchset, pTab) ){
|
|
rc = SQLITE_NOMEM;
|
|
break;
|
|
}
|
|
@@ -205249,7 +221356,7 @@ static int sessionChangesetToHash(
|
|
pTab, (pIter->bPatchset && op==SQLITE_DELETE), aRec, pTab->nChange
|
|
);
|
|
|
|
- /* Search for existing entry. If found, remove it from the hash table.
|
|
+ /* Search for existing entry. If found, remove it from the hash table.
|
|
** Code below may link it back in.
|
|
*/
|
|
for(pp=&pTab->apChange[iHash]; *pp; pp=&(*pp)->pNext){
|
|
@@ -205267,7 +221374,7 @@ static int sessionChangesetToHash(
|
|
}
|
|
}
|
|
|
|
- rc = sessionChangeMerge(pTab, bRebase,
|
|
+ rc = sessionChangeMerge(pTab, bRebase,
|
|
pIter->bPatchset, pExist, op, bIndirect, aRec, nRec, &pChange
|
|
);
|
|
if( rc ) break;
|
|
@@ -205288,7 +221395,7 @@ static int sessionChangesetToHash(
|
|
**
|
|
** If xOutput is not NULL, then the changeset/patchset is returned to the
|
|
** user via one or more calls to xOutput, as with the other streaming
|
|
-** interfaces.
|
|
+** interfaces.
|
|
**
|
|
** Or, if xOutput is NULL, then (*ppOut) is populated with a pointer to a
|
|
** buffer containing the output changeset before this function returns. In
|
|
@@ -205313,7 +221420,7 @@ static int sessionChangegroupOutput(
|
|
assert( xOutput==0 || (ppOut==0 && pnOut==0) );
|
|
|
|
/* Create the serialized output changeset based on the contents of the
|
|
- ** hash tables attached to the SessionTable objects in list p->pList.
|
|
+ ** hash tables attached to the SessionTable objects in list p->pList.
|
|
*/
|
|
for(pTab=pGrp->pList; rc==SQLITE_OK && pTab; pTab=pTab->pNext){
|
|
int i;
|
|
@@ -205337,9 +221444,9 @@ static int sessionChangegroupOutput(
|
|
if( rc==SQLITE_OK ){
|
|
if( xOutput ){
|
|
if( buf.nBuf>0 ) rc = xOutput(pOut, buf.aBuf, buf.nBuf);
|
|
- }else{
|
|
+ }else if( ppOut ){
|
|
*ppOut = buf.aBuf;
|
|
- *pnOut = buf.nBuf;
|
|
+ if( pnOut ) *pnOut = buf.nBuf;
|
|
buf.aBuf = 0;
|
|
}
|
|
}
|
|
@@ -205416,7 +221523,7 @@ SQLITE_API int sqlite3changegroup_add_strm(
|
|
*/
|
|
SQLITE_API int sqlite3changegroup_output_strm(
|
|
sqlite3_changegroup *pGrp,
|
|
- int (*xOutput)(void *pOut, const void *pData, int nData),
|
|
+ int (*xOutput)(void *pOut, const void *pData, int nData),
|
|
void *pOut
|
|
){
|
|
return sessionChangegroupOutput(pGrp, xOutput, pOut, 0, 0);
|
|
@@ -205427,12 +221534,12 @@ SQLITE_API int sqlite3changegroup_output_strm(
|
|
*/
|
|
SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup *pGrp){
|
|
if( pGrp ){
|
|
- sessionDeleteTable(pGrp->pList);
|
|
+ sessionDeleteTable(0, pGrp->pList);
|
|
sqlite3_free(pGrp);
|
|
}
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** Combine two changesets together.
|
|
*/
|
|
SQLITE_API int sqlite3changeset_concat(
|
|
@@ -205499,7 +221606,7 @@ struct sqlite3_rebaser {
|
|
|
|
/*
|
|
** Buffers a1 and a2 must both contain a sessions module record nCol
|
|
-** fields in size. This function appends an nCol sessions module
|
|
+** fields in size. This function appends an nCol sessions module
|
|
** record to buffer pBuf that is a copy of a1, except that for
|
|
** each field that is undefined in a1[], swap in the field from a2[].
|
|
*/
|
|
@@ -205534,20 +221641,20 @@ static void sessionAppendRecordMerge(
|
|
}
|
|
|
|
/*
|
|
-** This function is called when rebasing a local UPDATE change against one
|
|
+** This function is called when rebasing a local UPDATE change against one
|
|
** or more remote UPDATE changes. The aRec/nRec buffer contains the current
|
|
** old.* and new.* records for the change. The rebase buffer (a single
|
|
** record) is in aChange/nChange. The rebased change is appended to buffer
|
|
** pBuf.
|
|
**
|
|
-** Rebasing the UPDATE involves:
|
|
+** Rebasing the UPDATE involves:
|
|
**
|
|
** * Removing any changes to fields for which the corresponding field
|
|
** in the rebase buffer is set to "replaced" (type 0xFF). If this
|
|
** means the UPDATE change updates no fields, nothing is appended
|
|
** to the output buffer.
|
|
**
|
|
-** * For each field modified by the local change for which the
|
|
+** * For each field modified by the local change for which the
|
|
** corresponding field in the rebase buffer is not "undefined" (0x00)
|
|
** or "replaced" (0xFF), the old.* value is replaced by the value
|
|
** in the rebase buffer.
|
|
@@ -205573,10 +221680,10 @@ static void sessionAppendPartialUpdate(
|
|
int n1 = sessionSerialLen(a1);
|
|
int n2 = sessionSerialLen(a2);
|
|
if( pIter->abPK[i] || a2[0]==0 ){
|
|
- if( !pIter->abPK[i] ) bData = 1;
|
|
+ if( !pIter->abPK[i] && a1[0] ) bData = 1;
|
|
memcpy(pOut, a1, n1);
|
|
pOut += n1;
|
|
- }else if( a2[0]!=0xFF ){
|
|
+ }else if( a2[0]!=0xFF && a1[0] ){
|
|
bData = 1;
|
|
memcpy(pOut, a2, n2);
|
|
pOut += n2;
|
|
@@ -205606,15 +221713,15 @@ static void sessionAppendPartialUpdate(
|
|
}
|
|
|
|
/*
|
|
-** pIter is configured to iterate through a changeset. This function rebases
|
|
-** that changeset according to the current configuration of the rebaser
|
|
+** pIter is configured to iterate through a changeset. This function rebases
|
|
+** that changeset according to the current configuration of the rebaser
|
|
** object passed as the first argument. If no error occurs and argument xOutput
|
|
** is not NULL, then the changeset is returned to the caller by invoking
|
|
** xOutput zero or more times and SQLITE_OK returned. Or, if xOutput is NULL,
|
|
** then (*ppOut) is set to point to a buffer containing the rebased changeset
|
|
** before this function returns. In this case (*pnOut) is set to the size of
|
|
** the buffer in bytes. It is the responsibility of the caller to eventually
|
|
-** free the (*ppOut) buffer using sqlite3_free().
|
|
+** free the (*ppOut) buffer using sqlite3_free().
|
|
**
|
|
** If an error occurs, an SQLite error code is returned. If ppOut and
|
|
** pnOut are not NULL, then the two output parameters are set to 0 before
|
|
@@ -205692,7 +221799,7 @@ static int sessionRebase(
|
|
sessionAppendByte(&sOut, SQLITE_INSERT, &rc);
|
|
sessionAppendByte(&sOut, pIter->bIndirect, &rc);
|
|
sessionAppendRecordMerge(&sOut, pIter->nCol,
|
|
- pCsr, nRec-(pCsr-aRec),
|
|
+ pCsr, nRec-(pCsr-aRec),
|
|
pChange->aRecord, pChange->nRecord, &rc
|
|
);
|
|
}
|
|
@@ -205739,7 +221846,7 @@ static int sessionRebase(
|
|
if( sOut.nBuf>0 ){
|
|
rc = xOutput(pOut, sOut.aBuf, sOut.nBuf);
|
|
}
|
|
- }else{
|
|
+ }else if( ppOut ){
|
|
*ppOut = (void*)sOut.aBuf;
|
|
*pnOut = sOut.nBuf;
|
|
sOut.aBuf = 0;
|
|
@@ -205749,7 +221856,7 @@ static int sessionRebase(
|
|
return rc;
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** Create a new rebaser object.
|
|
*/
|
|
SQLITE_API int sqlite3rebaser_create(sqlite3_rebaser **ppNew){
|
|
@@ -205766,11 +221873,11 @@ SQLITE_API int sqlite3rebaser_create(sqlite3_rebaser **ppNew){
|
|
return rc;
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** Call this one or more times to configure a rebaser.
|
|
*/
|
|
SQLITE_API int sqlite3rebaser_configure(
|
|
- sqlite3_rebaser *p,
|
|
+ sqlite3_rebaser *p,
|
|
int nRebase, const void *pRebase
|
|
){
|
|
sqlite3_changeset_iter *pIter = 0; /* Iterator opened on pData/nData */
|
|
@@ -205783,15 +221890,15 @@ SQLITE_API int sqlite3rebaser_configure(
|
|
return rc;
|
|
}
|
|
|
|
-/*
|
|
-** Rebase a changeset according to current rebaser configuration
|
|
+/*
|
|
+** Rebase a changeset according to current rebaser configuration
|
|
*/
|
|
SQLITE_API int sqlite3rebaser_rebase(
|
|
sqlite3_rebaser *p,
|
|
- int nIn, const void *pIn,
|
|
- int *pnOut, void **ppOut
|
|
+ int nIn, const void *pIn,
|
|
+ int *pnOut, void **ppOut
|
|
){
|
|
- sqlite3_changeset_iter *pIter = 0; /* Iterator to skip through input */
|
|
+ sqlite3_changeset_iter *pIter = 0; /* Iterator to skip through input */
|
|
int rc = sqlite3changeset_start(&pIter, nIn, (void*)pIn);
|
|
|
|
if( rc==SQLITE_OK ){
|
|
@@ -205802,8 +221909,8 @@ SQLITE_API int sqlite3rebaser_rebase(
|
|
return rc;
|
|
}
|
|
|
|
-/*
|
|
-** Rebase a changeset according to current rebaser configuration
|
|
+/*
|
|
+** Rebase a changeset according to current rebaser configuration
|
|
*/
|
|
SQLITE_API int sqlite3rebaser_rebase_strm(
|
|
sqlite3_rebaser *p,
|
|
@@ -205812,7 +221919,7 @@ SQLITE_API int sqlite3rebaser_rebase_strm(
|
|
int (*xOutput)(void *pOut, const void *pData, int nData),
|
|
void *pOut
|
|
){
|
|
- sqlite3_changeset_iter *pIter = 0; /* Iterator to skip through input */
|
|
+ sqlite3_changeset_iter *pIter = 0; /* Iterator to skip through input */
|
|
int rc = sqlite3changeset_start_strm(&pIter, xInput, pIn);
|
|
|
|
if( rc==SQLITE_OK ){
|
|
@@ -205823,17 +221930,17 @@ SQLITE_API int sqlite3rebaser_rebase_strm(
|
|
return rc;
|
|
}
|
|
|
|
-/*
|
|
-** Destroy a rebaser object
|
|
+/*
|
|
+** Destroy a rebaser object
|
|
*/
|
|
SQLITE_API void sqlite3rebaser_delete(sqlite3_rebaser *p){
|
|
if( p ){
|
|
- sessionDeleteTable(p->grp.pList);
|
|
+ sessionDeleteTable(0, p->grp.pList);
|
|
sqlite3_free(p);
|
|
}
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** Global configuration
|
|
*/
|
|
SQLITE_API int sqlite3session_config(int op, void *pArg){
|
|
@@ -205860,9 +221967,9 @@ SQLITE_API int sqlite3session_config(int op, void *pArg){
|
|
/************** Begin file fts5.c ********************************************/
|
|
|
|
|
|
-#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS5)
|
|
+#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS5)
|
|
|
|
-#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
|
|
+#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
|
|
# define NDEBUG 1
|
|
#endif
|
|
#if defined(NDEBUG) && defined(SQLITE_DEBUG)
|
|
@@ -205881,7 +221988,7 @@ SQLITE_API int sqlite3session_config(int op, void *pArg){
|
|
**
|
|
******************************************************************************
|
|
**
|
|
-** Interfaces to extend FTS5. Using the interfaces defined in this file,
|
|
+** Interfaces to extend FTS5. Using the interfaces defined in this file,
|
|
** FTS5 may be extended with:
|
|
**
|
|
** * custom tokenizers, and
|
|
@@ -205926,19 +222033,19 @@ struct Fts5PhraseIter {
|
|
** EXTENSION API FUNCTIONS
|
|
**
|
|
** xUserData(pFts):
|
|
-** Return a copy of the context pointer the extension function was
|
|
+** Return a copy of the context pointer the extension function was
|
|
** registered with.
|
|
**
|
|
** xColumnTotalSize(pFts, iCol, pnToken):
|
|
** If parameter iCol is less than zero, set output variable *pnToken
|
|
** to the total number of tokens in the FTS5 table. Or, if iCol is
|
|
** non-negative but less than the number of columns in the table, return
|
|
-** the total number of tokens in column iCol, considering all rows in
|
|
+** the total number of tokens in column iCol, considering all rows in
|
|
** the FTS5 table.
|
|
**
|
|
** If parameter iCol is greater than or equal to the number of columns
|
|
** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g.
|
|
-** an OOM condition or IO error), an appropriate SQLite error code is
|
|
+** an OOM condition or IO error), an appropriate SQLite error code is
|
|
** returned.
|
|
**
|
|
** xColumnCount(pFts):
|
|
@@ -205952,7 +222059,7 @@ struct Fts5PhraseIter {
|
|
**
|
|
** If parameter iCol is greater than or equal to the number of columns
|
|
** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g.
|
|
-** an OOM condition or IO error), an appropriate SQLite error code is
|
|
+** an OOM condition or IO error), an appropriate SQLite error code is
|
|
** returned.
|
|
**
|
|
** This function may be quite inefficient if used with an FTS5 table
|
|
@@ -205979,8 +222086,8 @@ struct Fts5PhraseIter {
|
|
** an error code (i.e. SQLITE_NOMEM) if an error occurs.
|
|
**
|
|
** This API can be quite slow if used with an FTS5 table created with the
|
|
-** "detail=none" or "detail=column" option. If the FTS5 table is created
|
|
-** with either "detail=none" or "detail=column" and "content=" option
|
|
+** "detail=none" or "detail=column" option. If the FTS5 table is created
|
|
+** with either "detail=none" or "detail=column" and "content=" option
|
|
** (i.e. if it is a contentless table), then this API always returns 0.
|
|
**
|
|
** xInst:
|
|
@@ -205995,7 +222102,7 @@ struct Fts5PhraseIter {
|
|
** code (i.e. SQLITE_NOMEM) if an error occurs.
|
|
**
|
|
** This API can be quite slow if used with an FTS5 table created with the
|
|
-** "detail=none" or "detail=column" option.
|
|
+** "detail=none" or "detail=column" option.
|
|
**
|
|
** xRowid:
|
|
** Returns the rowid of the current row.
|
|
@@ -206011,11 +222118,11 @@ struct Fts5PhraseIter {
|
|
**
|
|
** with $p set to a phrase equivalent to the phrase iPhrase of the
|
|
** current query is executed. Any column filter that applies to
|
|
-** phrase iPhrase of the current query is included in $p. For each
|
|
-** row visited, the callback function passed as the fourth argument
|
|
-** is invoked. The context and API objects passed to the callback
|
|
+** phrase iPhrase of the current query is included in $p. For each
|
|
+** row visited, the callback function passed as the fourth argument
|
|
+** is invoked. The context and API objects passed to the callback
|
|
** function may be used to access the properties of each matched row.
|
|
-** Invoking Api.xUserData() returns a copy of the pointer passed as
|
|
+** Invoking Api.xUserData() returns a copy of the pointer passed as
|
|
** the third argument to pUserData.
|
|
**
|
|
** If the callback function returns any value other than SQLITE_OK, the
|
|
@@ -206030,14 +222137,14 @@ struct Fts5PhraseIter {
|
|
**
|
|
** xSetAuxdata(pFts5, pAux, xDelete)
|
|
**
|
|
-** Save the pointer passed as the second argument as the extension function's
|
|
+** Save the pointer passed as the second argument as the extension function's
|
|
** "auxiliary data". The pointer may then be retrieved by the current or any
|
|
** future invocation of the same fts5 extension function made as part of
|
|
** the same MATCH query using the xGetAuxdata() API.
|
|
**
|
|
** Each extension function is allocated a single auxiliary data slot for
|
|
-** each FTS query (MATCH expression). If the extension function is invoked
|
|
-** more than once for a single FTS query, then all invocations share a
|
|
+** each FTS query (MATCH expression). If the extension function is invoked
|
|
+** more than once for a single FTS query, then all invocations share a
|
|
** single auxiliary data context.
|
|
**
|
|
** If there is already an auxiliary data pointer when this function is
|
|
@@ -206056,7 +222163,7 @@ struct Fts5PhraseIter {
|
|
**
|
|
** xGetAuxdata(pFts5, bClear)
|
|
**
|
|
-** Returns the current auxiliary data pointer for the fts5 extension
|
|
+** Returns the current auxiliary data pointer for the fts5 extension
|
|
** function. See the xSetAuxdata() method for details.
|
|
**
|
|
** If the bClear argument is non-zero, then the auxiliary data is cleared
|
|
@@ -206076,7 +222183,7 @@ struct Fts5PhraseIter {
|
|
** method, to iterate through all instances of a single query phrase within
|
|
** the current row. This is the same information as is accessible via the
|
|
** xInstCount/xInst APIs. While the xInstCount/xInst APIs are more convenient
|
|
-** to use, this API may be faster under some circumstances. To iterate
|
|
+** to use, this API may be faster under some circumstances. To iterate
|
|
** through instances of phrase iPhrase, use the following code:
|
|
**
|
|
** Fts5PhraseIter iter;
|
|
@@ -206094,8 +222201,8 @@ struct Fts5PhraseIter {
|
|
** xPhraseFirstColumn() and xPhraseNextColumn() as illustrated below).
|
|
**
|
|
** This API can be quite slow if used with an FTS5 table created with the
|
|
-** "detail=none" or "detail=column" option. If the FTS5 table is created
|
|
-** with either "detail=none" or "detail=column" and "content=" option
|
|
+** "detail=none" or "detail=column" option. If the FTS5 table is created
|
|
+** with either "detail=none" or "detail=column" and "content=" option
|
|
** (i.e. if it is a contentless table), then this API always iterates
|
|
** through an empty set (all calls to xPhraseFirst() set iCol to -1).
|
|
**
|
|
@@ -206119,16 +222226,16 @@ struct Fts5PhraseIter {
|
|
** }
|
|
**
|
|
** This API can be quite slow if used with an FTS5 table created with the
|
|
-** "detail=none" option. If the FTS5 table is created with either
|
|
-** "detail=none" "content=" option (i.e. if it is a contentless table),
|
|
-** then this API always iterates through an empty set (all calls to
|
|
+** "detail=none" option. If the FTS5 table is created with either
|
|
+** "detail=none" "content=" option (i.e. if it is a contentless table),
|
|
+** then this API always iterates through an empty set (all calls to
|
|
** xPhraseFirstColumn() set iCol to -1).
|
|
**
|
|
** The information accessed using this API and its companion
|
|
** xPhraseFirstColumn() may also be obtained using xPhraseFirst/xPhraseNext
|
|
** (or xInst/xInstCount). The chief advantage of this API is that it is
|
|
** significantly more efficient than those alternatives when used with
|
|
-** "detail=column" tables.
|
|
+** "detail=column" tables.
|
|
**
|
|
** xPhraseNextColumn()
|
|
** See xPhraseFirstColumn above.
|
|
@@ -206142,7 +222249,7 @@ struct Fts5ExtensionApi {
|
|
int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow);
|
|
int (*xColumnTotalSize)(Fts5Context*, int iCol, sqlite3_int64 *pnToken);
|
|
|
|
- int (*xTokenize)(Fts5Context*,
|
|
+ int (*xTokenize)(Fts5Context*,
|
|
const char *pText, int nText, /* Text to tokenize */
|
|
void *pCtx, /* Context passed to xToken() */
|
|
int (*xToken)(void*, int, const char*, int, int, int) /* Callback */
|
|
@@ -206171,15 +222278,15 @@ struct Fts5ExtensionApi {
|
|
void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol);
|
|
};
|
|
|
|
-/*
|
|
+/*
|
|
** CUSTOM AUXILIARY FUNCTIONS
|
|
*************************************************************************/
|
|
|
|
/*************************************************************************
|
|
** CUSTOM TOKENIZERS
|
|
**
|
|
-** Applications may also register custom tokenizer types. A tokenizer
|
|
-** is registered by providing fts5 with a populated instance of the
|
|
+** Applications may also register custom tokenizer types. A tokenizer
|
|
+** is registered by providing fts5 with a populated instance of the
|
|
** following structure. All structure methods must be defined, setting
|
|
** any member of the fts5_tokenizer struct to NULL leads to undefined
|
|
** behaviour. The structure methods are expected to function as follows:
|
|
@@ -206190,16 +222297,16 @@ struct Fts5ExtensionApi {
|
|
**
|
|
** The first argument passed to this function is a copy of the (void*)
|
|
** pointer provided by the application when the fts5_tokenizer object
|
|
-** was registered with FTS5 (the third argument to xCreateTokenizer()).
|
|
+** was registered with FTS5 (the third argument to xCreateTokenizer()).
|
|
** The second and third arguments are an array of nul-terminated strings
|
|
** containing the tokenizer arguments, if any, specified following the
|
|
** tokenizer name as part of the CREATE VIRTUAL TABLE statement used
|
|
** to create the FTS5 table.
|
|
**
|
|
-** The final argument is an output variable. If successful, (*ppOut)
|
|
+** The final argument is an output variable. If successful, (*ppOut)
|
|
** should be set to point to the new tokenizer handle and SQLITE_OK
|
|
** returned. If an error occurs, some value other than SQLITE_OK should
|
|
-** be returned. In this case, fts5 assumes that the final value of *ppOut
|
|
+** be returned. In this case, fts5 assumes that the final value of *ppOut
|
|
** is undefined.
|
|
**
|
|
** xDelete:
|
|
@@ -206208,7 +222315,7 @@ struct Fts5ExtensionApi {
|
|
** be invoked exactly once for each successful call to xCreate().
|
|
**
|
|
** xTokenize:
|
|
-** This function is expected to tokenize the nText byte string indicated
|
|
+** This function is expected to tokenize the nText byte string indicated
|
|
** by argument pText. pText may or may not be nul-terminated. The first
|
|
** argument passed to this function is a pointer to an Fts5Tokenizer object
|
|
** returned by an earlier call to xCreate().
|
|
@@ -206222,8 +222329,8 @@ struct Fts5ExtensionApi {
|
|
** determine the set of tokens to add to (or delete from) the
|
|
** FTS index.
|
|
**
|
|
-** <li> <b>FTS5_TOKENIZE_QUERY</b> - A MATCH query is being executed
|
|
-** against the FTS index. The tokenizer is being called to tokenize
|
|
+** <li> <b>FTS5_TOKENIZE_QUERY</b> - A MATCH query is being executed
|
|
+** against the FTS index. The tokenizer is being called to tokenize
|
|
** a bareword or quoted string specified as part of the query.
|
|
**
|
|
** <li> <b>(FTS5_TOKENIZE_QUERY | FTS5_TOKENIZE_PREFIX)</b> - Same as
|
|
@@ -206231,10 +222338,10 @@ struct Fts5ExtensionApi {
|
|
** followed by a "*" character, indicating that the last token
|
|
** returned by the tokenizer will be treated as a token prefix.
|
|
**
|
|
-** <li> <b>FTS5_TOKENIZE_AUX</b> - The tokenizer is being invoked to
|
|
+** <li> <b>FTS5_TOKENIZE_AUX</b> - The tokenizer is being invoked to
|
|
** satisfy an fts5_api.xTokenize() request made by an auxiliary
|
|
** function. Or an fts5_api.xColumnSize() request made by the same
|
|
-** on a columnsize=0 database.
|
|
+** on a columnsize=0 database.
|
|
** </ul>
|
|
**
|
|
** For each token in the input string, the supplied callback xToken() must
|
|
@@ -206246,10 +222353,10 @@ struct Fts5ExtensionApi {
|
|
** which the token is derived within the input.
|
|
**
|
|
** The second argument passed to the xToken() callback ("tflags") should
|
|
-** normally be set to 0. The exception is if the tokenizer supports
|
|
+** normally be set to 0. The exception is if the tokenizer supports
|
|
** synonyms. In this case see the discussion below for details.
|
|
**
|
|
-** FTS5 assumes the xToken() callback is invoked for each token in the
|
|
+** FTS5 assumes the xToken() callback is invoked for each token in the
|
|
** order that they occur within the input text.
|
|
**
|
|
** If an xToken() callback returns any value other than SQLITE_OK, then
|
|
@@ -206263,7 +222370,7 @@ struct Fts5ExtensionApi {
|
|
** SYNONYM SUPPORT
|
|
**
|
|
** Custom tokenizers may also support synonyms. Consider a case in which a
|
|
-** user wishes to query for a phrase such as "first place". Using the
|
|
+** user wishes to query for a phrase such as "first place". Using the
|
|
** built-in tokenizers, the FTS5 query 'first + place' will match instances
|
|
** of "first place" within the document set, but not alternative forms
|
|
** such as "1st place". In some applications, it would be better to match
|
|
@@ -206283,34 +222390,34 @@ struct Fts5ExtensionApi {
|
|
**
|
|
** <li> By querying the index for all synonyms of each query term
|
|
** separately. In this case, when tokenizing query text, the
|
|
-** tokenizer may provide multiple synonyms for a single term
|
|
-** within the document. FTS5 then queries the index for each
|
|
+** tokenizer may provide multiple synonyms for a single term
|
|
+** within the document. FTS5 then queries the index for each
|
|
** synonym individually. For example, faced with the query:
|
|
**
|
|
** <codeblock>
|
|
** ... MATCH 'first place'</codeblock>
|
|
**
|
|
** the tokenizer offers both "1st" and "first" as synonyms for the
|
|
-** first token in the MATCH query and FTS5 effectively runs a query
|
|
+** first token in the MATCH query and FTS5 effectively runs a query
|
|
** similar to:
|
|
**
|
|
** <codeblock>
|
|
** ... MATCH '(first OR 1st) place'</codeblock>
|
|
**
|
|
** except that, for the purposes of auxiliary functions, the query
|
|
-** still appears to contain just two phrases - "(first OR 1st)"
|
|
+** still appears to contain just two phrases - "(first OR 1st)"
|
|
** being treated as a single phrase.
|
|
**
|
|
** <li> By adding multiple synonyms for a single term to the FTS index.
|
|
** Using this method, when tokenizing document text, the tokenizer
|
|
-** provides multiple synonyms for each token. So that when a
|
|
+** provides multiple synonyms for each token. So that when a
|
|
** document such as "I won first place" is tokenized, entries are
|
|
** added to the FTS index for "i", "won", "first", "1st" and
|
|
** "place".
|
|
**
|
|
** This way, even if the tokenizer does not provide synonyms
|
|
** when tokenizing query text (it should not - to do so would be
|
|
-** inefficient), it doesn't matter if the user queries for
|
|
+** inefficient), it doesn't matter if the user queries for
|
|
** 'first + place' or '1st + place', as there are entries in the
|
|
** FTS index corresponding to both forms of the first token.
|
|
** </ol>
|
|
@@ -206331,11 +222438,11 @@ struct Fts5ExtensionApi {
|
|
**
|
|
** It is an error to specify the FTS5_TOKEN_COLOCATED flag the first time
|
|
** xToken() is called. Multiple synonyms may be specified for a single token
|
|
-** by making multiple calls to xToken(FTS5_TOKEN_COLOCATED) in sequence.
|
|
+** by making multiple calls to xToken(FTS5_TOKEN_COLOCATED) in sequence.
|
|
** There is no limit to the number of synonyms that may be provided for a
|
|
** single token.
|
|
**
|
|
-** In many cases, method (1) above is the best approach. It does not add
|
|
+** In many cases, method (1) above is the best approach. It does not add
|
|
** extra data to the FTS index or require FTS5 to query for multiple terms,
|
|
** so it is efficient in terms of disk space and query speed. However, it
|
|
** does not support prefix queries very well. If, as suggested above, the
|
|
@@ -206347,18 +222454,18 @@ struct Fts5ExtensionApi {
|
|
** will not match documents that contain the token "1st" (as the tokenizer
|
|
** will probably not map "1s" to any prefix of "first").
|
|
**
|
|
-** For full prefix support, method (3) may be preferred. In this case,
|
|
+** For full prefix support, method (3) may be preferred. In this case,
|
|
** because the index contains entries for both "first" and "1st", prefix
|
|
** queries such as 'fi*' or '1s*' will match correctly. However, because
|
|
** extra entries are added to the FTS index, this method uses more space
|
|
** within the database.
|
|
**
|
|
** Method (2) offers a midpoint between (1) and (3). Using this method,
|
|
-** a query such as '1s*' will match documents that contain the literal
|
|
+** a query such as '1s*' will match documents that contain the literal
|
|
** token "1st", but not "first" (assuming the tokenizer is not able to
|
|
** provide synonyms for prefixes). However, a non-prefix query like '1st'
|
|
** will match against "1st" and "first". This method does not require
|
|
-** extra disk space, as no extra entries are added to the FTS index.
|
|
+** extra disk space, as no extra entries are added to the FTS index.
|
|
** On the other hand, it may require more CPU cycles to run MATCH queries,
|
|
** as separate queries of the FTS index are required for each synonym.
|
|
**
|
|
@@ -206372,10 +222479,10 @@ typedef struct fts5_tokenizer fts5_tokenizer;
|
|
struct fts5_tokenizer {
|
|
int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
|
|
void (*xDelete)(Fts5Tokenizer*);
|
|
- int (*xTokenize)(Fts5Tokenizer*,
|
|
+ int (*xTokenize)(Fts5Tokenizer*,
|
|
void *pCtx,
|
|
int flags, /* Mask of FTS5_TOKENIZE_* flags */
|
|
- const char *pText, int nText,
|
|
+ const char *pText, int nText,
|
|
int (*xToken)(
|
|
void *pCtx, /* Copy of 2nd argument to xTokenize() */
|
|
int tflags, /* Mask of FTS5_TOKEN_* flags */
|
|
@@ -206482,8 +222589,20 @@ typedef sqlite3_uint64 u64;
|
|
#endif
|
|
|
|
#define testcase(x)
|
|
-#define ALWAYS(x) 1
|
|
-#define NEVER(x) 0
|
|
+
|
|
+#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_MUTATION_TEST)
|
|
+# define SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS 1
|
|
+#endif
|
|
+#if defined(SQLITE_OMIT_AUXILIARY_SAFETY_CHECKS)
|
|
+# define ALWAYS(X) (1)
|
|
+# define NEVER(X) (0)
|
|
+#elif !defined(NDEBUG)
|
|
+# define ALWAYS(X) ((X)?1:(assert(0),0))
|
|
+# define NEVER(X) ((X)?(assert(0),1):0)
|
|
+#else
|
|
+# define ALWAYS(X) (X)
|
|
+# define NEVER(X) (X)
|
|
+#endif
|
|
|
|
#define MIN(x,y) (((x) < (y)) ? (x) : (y))
|
|
#define MAX(x,y) (((x) > (y)) ? (x) : (y))
|
|
@@ -206496,7 +222615,7 @@ typedef sqlite3_uint64 u64;
|
|
|
|
#endif
|
|
|
|
-/* Truncate very long tokens to this many bytes. Hard limit is
|
|
+/* Truncate very long tokens to this many bytes. Hard limit is
|
|
** (65536-1-1-4-9)==65521 bytes. The limiting factor is the 16-bit offset
|
|
** field that occurs at the start of each leaf page (see fts5_index.c). */
|
|
#define FTS5_MAX_TOKEN_SIZE 32768
|
|
@@ -206509,7 +222628,7 @@ typedef sqlite3_uint64 u64;
|
|
#define FTS5_MAX_PREFIX_INDEXES 31
|
|
|
|
/*
|
|
-** Maximum segments permitted in a single index
|
|
+** Maximum segments permitted in a single index
|
|
*/
|
|
#define FTS5_MAX_SEGMENT 2000
|
|
|
|
@@ -206529,7 +222648,7 @@ static int sqlite3Fts5Corrupt(void);
|
|
|
|
/*
|
|
** The assert_nc() macro is similar to the assert() macro, except that it
|
|
-** is used for assert() conditions that are true only if it can be
|
|
+** is used for assert() conditions that are true only if it can be
|
|
** guranteed that the database is not corrupt.
|
|
*/
|
|
#ifdef SQLITE_DEBUG
|
|
@@ -206543,7 +222662,7 @@ SQLITE_API extern int sqlite3_fts5_may_be_corrupt;
|
|
** A version of memcmp() that does not cause asan errors if one of the pointer
|
|
** parameters is NULL and the number of bytes to compare is zero.
|
|
*/
|
|
-#define fts5Memcmp(s1, s2, n) ((n)==0 ? 0 : memcmp((s1), (s2), (n)))
|
|
+#define fts5Memcmp(s1, s2, n) ((n)<=0 ? 0 : memcmp((s1), (s2), (n)))
|
|
|
|
/* Mark a function parameter as unused, to suppress nuisance compiler
|
|
** warnings. */
|
|
@@ -206558,7 +222677,7 @@ SQLITE_API extern int sqlite3_fts5_may_be_corrupt;
|
|
typedef struct Fts5Global Fts5Global;
|
|
typedef struct Fts5Colset Fts5Colset;
|
|
|
|
-/* If a NEAR() clump or phrase may only match a specific set of columns,
|
|
+/* If a NEAR() clump or phrase may only match a specific set of columns,
|
|
** then an object of the following type is used to record the set of columns.
|
|
** Each entry in the aiCol[] array is a column that may be matched.
|
|
**
|
|
@@ -206586,20 +222705,20 @@ typedef struct Fts5Config Fts5Config;
|
|
**
|
|
** nAutomerge:
|
|
** The minimum number of segments that an auto-merge operation should
|
|
-** attempt to merge together. A value of 1 sets the object to use the
|
|
+** attempt to merge together. A value of 1 sets the object to use the
|
|
** compile time default. Zero disables auto-merge altogether.
|
|
**
|
|
** zContent:
|
|
**
|
|
** zContentRowid:
|
|
-** The value of the content_rowid= option, if one was specified. Or
|
|
+** The value of the content_rowid= option, if one was specified. Or
|
|
** the string "rowid" otherwise. This text is not quoted - if it is
|
|
** used as part of an SQL statement it needs to be quoted appropriately.
|
|
**
|
|
** zContentExprlist:
|
|
**
|
|
** pzErrmsg:
|
|
-** This exists in order to allow the fts5_index.c module to return a
|
|
+** This exists in order to allow the fts5_index.c module to return a
|
|
** decent error message if it encounters a file-format version it does
|
|
** not understand.
|
|
**
|
|
@@ -206623,14 +222742,15 @@ struct Fts5Config {
|
|
int nPrefix; /* Number of prefix indexes */
|
|
int *aPrefix; /* Sizes in bytes of nPrefix prefix indexes */
|
|
int eContent; /* An FTS5_CONTENT value */
|
|
- char *zContent; /* content table */
|
|
- char *zContentRowid; /* "content_rowid=" option value */
|
|
+ char *zContent; /* content table */
|
|
+ char *zContentRowid; /* "content_rowid=" option value */
|
|
int bColumnsize; /* "columnsize=" option value (dflt==1) */
|
|
int eDetail; /* FTS5_DETAIL_XXX value */
|
|
char *zContentExprlist;
|
|
Fts5Tokenizer *pTok;
|
|
fts5_tokenizer *pTokApi;
|
|
int bLock; /* True when table is preparing statement */
|
|
+ int ePattern; /* FTS_PATTERN_XXX constant */
|
|
|
|
/* Values loaded from the %_config table */
|
|
int iCookie; /* Incremented when %_config is modified */
|
|
@@ -206651,17 +222771,19 @@ struct Fts5Config {
|
|
};
|
|
|
|
/* Current expected value of %_config table 'version' field */
|
|
-#define FTS5_CURRENT_VERSION 4
|
|
+#define FTS5_CURRENT_VERSION 4
|
|
|
|
#define FTS5_CONTENT_NORMAL 0
|
|
#define FTS5_CONTENT_NONE 1
|
|
#define FTS5_CONTENT_EXTERNAL 2
|
|
|
|
-#define FTS5_DETAIL_FULL 0
|
|
-#define FTS5_DETAIL_NONE 1
|
|
-#define FTS5_DETAIL_COLUMNS 2
|
|
-
|
|
+#define FTS5_DETAIL_FULL 0
|
|
+#define FTS5_DETAIL_NONE 1
|
|
+#define FTS5_DETAIL_COLUMNS 2
|
|
|
|
+#define FTS5_PATTERN_NONE 0
|
|
+#define FTS5_PATTERN_LIKE 65 /* matches SQLITE_INDEX_CONSTRAINT_LIKE */
|
|
+#define FTS5_PATTERN_GLOB 66 /* matches SQLITE_INDEX_CONSTRAINT_GLOB */
|
|
|
|
static int sqlite3Fts5ConfigParse(
|
|
Fts5Global*, sqlite3*, int, const char **, Fts5Config**, char**
|
|
@@ -206718,7 +222840,7 @@ static void sqlite3Fts5BufferAppendPrintf(int *, Fts5Buffer*, char *zFmt, ...);
|
|
static char *sqlite3Fts5Mprintf(int *pRc, const char *zFmt, ...);
|
|
|
|
#define fts5BufferZero(x) sqlite3Fts5BufferZero(x)
|
|
-#define fts5BufferAppendVarint(a,b,c) sqlite3Fts5BufferAppendVarint(a,b,c)
|
|
+#define fts5BufferAppendVarint(a,b,c) sqlite3Fts5BufferAppendVarint(a,b,(i64)c)
|
|
#define fts5BufferFree(a) sqlite3Fts5BufferFree(a)
|
|
#define fts5BufferAppendBlob(a,b,c,d) sqlite3Fts5BufferAppendBlob(a,b,c,d)
|
|
#define fts5BufferSet(a,b,c,d) sqlite3Fts5BufferSet(a,b,c,d)
|
|
@@ -206826,27 +222948,27 @@ static int sqlite3Fts5IndexClose(Fts5Index *p);
|
|
** Return a simple checksum value based on the arguments.
|
|
*/
|
|
static u64 sqlite3Fts5IndexEntryCksum(
|
|
- i64 iRowid,
|
|
- int iCol,
|
|
- int iPos,
|
|
+ i64 iRowid,
|
|
+ int iCol,
|
|
+ int iPos,
|
|
int iIdx,
|
|
const char *pTerm,
|
|
int nTerm
|
|
);
|
|
|
|
/*
|
|
-** Argument p points to a buffer containing utf-8 text that is n bytes in
|
|
+** Argument p points to a buffer containing utf-8 text that is n bytes in
|
|
** size. Return the number of bytes in the nChar character prefix of the
|
|
** buffer, or 0 if there are less than nChar characters in total.
|
|
*/
|
|
static int sqlite3Fts5IndexCharlenToBytelen(
|
|
- const char *p,
|
|
- int nByte,
|
|
+ const char *p,
|
|
+ int nByte,
|
|
int nChar
|
|
);
|
|
|
|
/*
|
|
-** Open a new iterator to iterate though all rowids that match the
|
|
+** Open a new iterator to iterate though all rowids that match the
|
|
** specified token or token prefix.
|
|
*/
|
|
static int sqlite3Fts5IndexQuery(
|
|
@@ -206879,10 +223001,13 @@ static void sqlite3Fts5IndexCloseReader(Fts5Index*);
|
|
*/
|
|
static const char *sqlite3Fts5IterTerm(Fts5IndexIter*, int*);
|
|
static int sqlite3Fts5IterNextScan(Fts5IndexIter*);
|
|
+static void *sqlite3Fts5StructureRef(Fts5Index*);
|
|
+static void sqlite3Fts5StructureRelease(void*);
|
|
+static int sqlite3Fts5StructureTest(Fts5Index*, void*);
|
|
|
|
|
|
/*
|
|
-** Insert or remove data to or from the index. Each time a document is
|
|
+** Insert or remove data to or from the index. Each time a document is
|
|
** added to or removed from the index, this function is called one or more
|
|
** times.
|
|
**
|
|
@@ -206917,7 +223042,7 @@ static int sqlite3Fts5IndexSync(Fts5Index *p);
|
|
/*
|
|
** Discard any data stored in the in-memory hash tables. Do not write it
|
|
** to the database. Additionally, assume that the contents of the %_data
|
|
-** table may have changed on disk. So any in-memory caches of %_data
|
|
+** table may have changed on disk. So any in-memory caches of %_data
|
|
** records must be invalidated.
|
|
*/
|
|
static int sqlite3Fts5IndexRollback(Fts5Index *p);
|
|
@@ -206931,18 +223056,18 @@ static int sqlite3Fts5IndexSetAverages(Fts5Index *p, const u8*, int);
|
|
/*
|
|
** Functions called by the storage module as part of integrity-check.
|
|
*/
|
|
-static int sqlite3Fts5IndexIntegrityCheck(Fts5Index*, u64 cksum);
|
|
+static int sqlite3Fts5IndexIntegrityCheck(Fts5Index*, u64 cksum, int bUseCksum);
|
|
|
|
-/*
|
|
-** Called during virtual module initialization to register UDF
|
|
-** fts5_decode() with SQLite
|
|
+/*
|
|
+** Called during virtual module initialization to register UDF
|
|
+** fts5_decode() with SQLite
|
|
*/
|
|
static int sqlite3Fts5IndexInit(sqlite3*);
|
|
|
|
static int sqlite3Fts5IndexSetCookie(Fts5Index*, int);
|
|
|
|
/*
|
|
-** Return the total number of entries read from the %_data table by
|
|
+** Return the total number of entries read from the %_data table by
|
|
** this connection since it was created.
|
|
*/
|
|
static int sqlite3Fts5IndexReads(Fts5Index *p);
|
|
@@ -206959,7 +223084,7 @@ static int sqlite3Fts5IndexLoadConfig(Fts5Index *p);
|
|
**************************************************************************/
|
|
|
|
/**************************************************************************
|
|
-** Interface to code in fts5_varint.c.
|
|
+** Interface to code in fts5_varint.c.
|
|
*/
|
|
static int sqlite3Fts5GetVarint32(const unsigned char *p, u32 *v);
|
|
static int sqlite3Fts5GetVarintLen(u32 iVal);
|
|
@@ -206984,7 +223109,7 @@ static int sqlite3Fts5PutVarint(unsigned char *p, u64 v);
|
|
|
|
|
|
/**************************************************************************
|
|
-** Interface to code in fts5_main.c.
|
|
+** Interface to code in fts5_main.c.
|
|
*/
|
|
|
|
/*
|
|
@@ -206998,11 +223123,10 @@ struct Fts5Table {
|
|
};
|
|
|
|
static int sqlite3Fts5GetTokenizer(
|
|
- Fts5Global*,
|
|
+ Fts5Global*,
|
|
const char **azArg,
|
|
int nArg,
|
|
- Fts5Tokenizer**,
|
|
- fts5_tokenizer**,
|
|
+ Fts5Config*,
|
|
char **pzErr
|
|
);
|
|
|
|
@@ -207015,7 +223139,7 @@ static int sqlite3Fts5FlushToDisk(Fts5Table*);
|
|
**************************************************************************/
|
|
|
|
/**************************************************************************
|
|
-** Interface to code in fts5_hash.c.
|
|
+** Interface to code in fts5_hash.c.
|
|
*/
|
|
typedef struct Fts5Hash Fts5Hash;
|
|
|
|
@@ -207065,7 +223189,7 @@ static void sqlite3Fts5HashScanEntry(Fts5Hash *,
|
|
**************************************************************************/
|
|
|
|
/**************************************************************************
|
|
-** Interface to code in fts5_storage.c. fts5_storage.c contains contains
|
|
+** Interface to code in fts5_storage.c. fts5_storage.c contains contains
|
|
** code to access the data stored in the %_content and %_docsize tables.
|
|
*/
|
|
|
|
@@ -207086,7 +223210,7 @@ static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64, sqlite3_value**);
|
|
static int sqlite3Fts5StorageContentInsert(Fts5Storage *p, sqlite3_value**, i64*);
|
|
static int sqlite3Fts5StorageIndexInsert(Fts5Storage *p, sqlite3_value**, i64);
|
|
|
|
-static int sqlite3Fts5StorageIntegrity(Fts5Storage *p);
|
|
+static int sqlite3Fts5StorageIntegrity(Fts5Storage *p, int iArg);
|
|
|
|
static int sqlite3Fts5StorageStmt(Fts5Storage *p, int eStmt, sqlite3_stmt**, char**);
|
|
static void sqlite3Fts5StorageStmtRelease(Fts5Storage *p, int eStmt, sqlite3_stmt*);
|
|
@@ -207114,7 +223238,7 @@ static int sqlite3Fts5StorageReset(Fts5Storage *p);
|
|
|
|
|
|
/**************************************************************************
|
|
-** Interface to code in fts5_expr.c.
|
|
+** Interface to code in fts5_expr.c.
|
|
*/
|
|
typedef struct Fts5Expr Fts5Expr;
|
|
typedef struct Fts5ExprNode Fts5ExprNode;
|
|
@@ -207130,12 +223254,20 @@ struct Fts5Token {
|
|
|
|
/* Parse a MATCH expression. */
|
|
static int sqlite3Fts5ExprNew(
|
|
- Fts5Config *pConfig,
|
|
+ Fts5Config *pConfig,
|
|
+ int bPhraseToAnd,
|
|
int iCol, /* Column on LHS of MATCH operator */
|
|
const char *zExpr,
|
|
- Fts5Expr **ppNew,
|
|
+ Fts5Expr **ppNew,
|
|
char **pzErr
|
|
);
|
|
+static int sqlite3Fts5ExprPattern(
|
|
+ Fts5Config *pConfig,
|
|
+ int bGlob,
|
|
+ int iCol,
|
|
+ const char *zText,
|
|
+ Fts5Expr **pp
|
|
+);
|
|
|
|
/*
|
|
** for(rc = sqlite3Fts5ExprFirst(pExpr, pIdx, bDesc);
|
|
@@ -207194,8 +223326,8 @@ static Fts5ExprNode *sqlite3Fts5ParseImplicitAnd(
|
|
);
|
|
|
|
static Fts5ExprPhrase *sqlite3Fts5ParseTerm(
|
|
- Fts5Parse *pParse,
|
|
- Fts5ExprPhrase *pPhrase,
|
|
+ Fts5Parse *pParse,
|
|
+ Fts5ExprPhrase *pPhrase,
|
|
Fts5Token *pToken,
|
|
int bPrefix
|
|
);
|
|
@@ -207203,14 +223335,14 @@ static Fts5ExprPhrase *sqlite3Fts5ParseTerm(
|
|
static void sqlite3Fts5ParseSetCaret(Fts5ExprPhrase*);
|
|
|
|
static Fts5ExprNearset *sqlite3Fts5ParseNearset(
|
|
- Fts5Parse*,
|
|
+ Fts5Parse*,
|
|
Fts5ExprNearset*,
|
|
- Fts5ExprPhrase*
|
|
+ Fts5ExprPhrase*
|
|
);
|
|
|
|
static Fts5Colset *sqlite3Fts5ParseColset(
|
|
- Fts5Parse*,
|
|
- Fts5Colset*,
|
|
+ Fts5Parse*,
|
|
+ Fts5Colset*,
|
|
Fts5Token *
|
|
);
|
|
|
|
@@ -207231,7 +223363,7 @@ static void sqlite3Fts5ParseNear(Fts5Parse *pParse, Fts5Token*);
|
|
|
|
|
|
/**************************************************************************
|
|
-** Interface to code in fts5_aux.c.
|
|
+** Interface to code in fts5_aux.c.
|
|
*/
|
|
|
|
static int sqlite3Fts5AuxInit(fts5_api*);
|
|
@@ -207240,16 +223372,20 @@ static int sqlite3Fts5AuxInit(fts5_api*);
|
|
**************************************************************************/
|
|
|
|
/**************************************************************************
|
|
-** Interface to code in fts5_tokenizer.c.
|
|
+** Interface to code in fts5_tokenizer.c.
|
|
*/
|
|
|
|
static int sqlite3Fts5TokenizerInit(fts5_api*);
|
|
+static int sqlite3Fts5TokenizerPattern(
|
|
+ int (*xCreate)(void*, const char**, int, Fts5Tokenizer**),
|
|
+ Fts5Tokenizer *pTok
|
|
+);
|
|
/*
|
|
** End of interface to code in fts5_tokenizer.c.
|
|
**************************************************************************/
|
|
|
|
/**************************************************************************
|
|
-** Interface to code in fts5_vocab.c.
|
|
+** Interface to code in fts5_vocab.c.
|
|
*/
|
|
|
|
static int sqlite3Fts5VocabInit(Fts5Global*, sqlite3*);
|
|
@@ -207260,7 +223396,7 @@ static int sqlite3Fts5VocabInit(Fts5Global*, sqlite3*);
|
|
|
|
|
|
/**************************************************************************
|
|
-** Interface to automatically generated code in fts5_unicode2.c.
|
|
+** Interface to automatically generated code in fts5_unicode2.c.
|
|
*/
|
|
static int sqlite3Fts5UnicodeIsdiacritic(int c);
|
|
static int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic);
|
|
@@ -207290,6 +223426,8 @@ static void sqlite3Fts5UnicodeAscii(u8*, u8*);
|
|
#define FTS5_PLUS 14
|
|
#define FTS5_STAR 15
|
|
|
|
+/* This file is automatically generated by Lemon from input grammar
|
|
+** source file "fts5parse.y". */
|
|
/*
|
|
** 2000-05-29
|
|
**
|
|
@@ -207314,8 +223452,6 @@ static void sqlite3Fts5UnicodeAscii(u8*, u8*);
|
|
** The following is the concatenation of all %include directives from the
|
|
** input grammar file:
|
|
*/
|
|
-/* #include <stdio.h> */
|
|
-/* #include <assert.h> */
|
|
/************ Begin %include sections from the grammar ************************/
|
|
|
|
/* #include "fts5Int.h" */
|
|
@@ -207345,11 +223481,26 @@ static void sqlite3Fts5UnicodeAscii(u8*, u8*);
|
|
#define fts5YYMALLOCARGTYPE u64
|
|
|
|
/**************** End of %include directives **********************************/
|
|
-/* These constants specify the various numeric values for terminal symbols
|
|
-** in a format understandable to "makeheaders". This section is blank unless
|
|
-** "lemon" is run with the "-m" command-line option.
|
|
-***************** Begin makeheaders token definitions *************************/
|
|
-/**************** End makeheaders token definitions ***************************/
|
|
+/* These constants specify the various numeric values for terminal symbols.
|
|
+***************** Begin token definitions *************************************/
|
|
+#ifndef FTS5_OR
|
|
+#define FTS5_OR 1
|
|
+#define FTS5_AND 2
|
|
+#define FTS5_NOT 3
|
|
+#define FTS5_TERM 4
|
|
+#define FTS5_COLON 5
|
|
+#define FTS5_MINUS 6
|
|
+#define FTS5_LCP 7
|
|
+#define FTS5_RCP 8
|
|
+#define FTS5_STRING 9
|
|
+#define FTS5_LP 10
|
|
+#define FTS5_RP 11
|
|
+#define FTS5_CARET 12
|
|
+#define FTS5_COMMA 13
|
|
+#define FTS5_PLUS 14
|
|
+#define FTS5_STAR 15
|
|
+#endif
|
|
+/**************** End token definitions ***************************************/
|
|
|
|
/* The next sections is a series of control #defines.
|
|
** various aspects of the generated parser.
|
|
@@ -207374,7 +223525,7 @@ static void sqlite3Fts5UnicodeAscii(u8*, u8*);
|
|
** the minor type might be the name of the identifier.
|
|
** Each non-terminal can have a different minor type.
|
|
** Terminal symbols all have the same minor type, though.
|
|
-** This macros defines the minor type for terminal
|
|
+** This macros defines the minor type for terminal
|
|
** symbols.
|
|
** fts5YYMINORTYPE is the data type used for all minor types.
|
|
** This is typically a union of many types, one of
|
|
@@ -207463,7 +223614,7 @@ typedef union {
|
|
/* Next are the tables used to determine what action to take based on the
|
|
** current state and lookahead token. These tables are used to implement
|
|
** functions that take a state number and lookahead value and return an
|
|
-** action integer.
|
|
+** action integer.
|
|
**
|
|
** Suppose the action integer is N. Then the action is determined as
|
|
** follows
|
|
@@ -207563,9 +223714,9 @@ static const fts5YYACTIONTYPE fts5yy_default[] = {
|
|
};
|
|
/********** End of lemon-generated parsing tables *****************************/
|
|
|
|
-/* The next table maps tokens (terminal symbols) into fallback tokens.
|
|
+/* The next table maps tokens (terminal symbols) into fallback tokens.
|
|
** If a construct like the following:
|
|
-**
|
|
+**
|
|
** %fallback ID X Y Z.
|
|
**
|
|
** appears in the grammar, then ID becomes a fallback token for X, Y,
|
|
@@ -207630,6 +223781,7 @@ struct fts5yyParser {
|
|
};
|
|
typedef struct fts5yyParser fts5yyParser;
|
|
|
|
+/* #include <assert.h> */
|
|
#ifndef NDEBUG
|
|
/* #include <stdio.h> */
|
|
static FILE *fts5yyTraceFILE = 0;
|
|
@@ -207637,10 +223789,10 @@ static char *fts5yyTracePrompt = 0;
|
|
#endif /* NDEBUG */
|
|
|
|
#ifndef NDEBUG
|
|
-/*
|
|
+/*
|
|
** Turn parser tracing on by giving a stream to which to write the trace
|
|
** and a prompt to preface each trace message. Tracing is turned off
|
|
-** by making either argument NULL
|
|
+** by making either argument NULL
|
|
**
|
|
** Inputs:
|
|
** <ul>
|
|
@@ -207665,7 +223817,7 @@ static void sqlite3Fts5ParserTrace(FILE *TraceFILE, char *zTracePrompt){
|
|
#if defined(fts5YYCOVERAGE) || !defined(NDEBUG)
|
|
/* For tracing shifts, the names of all terminals and nonterminals
|
|
** are required. The following table supplies these names */
|
|
-static const char *const fts5yyTokenName[] = {
|
|
+static const char *const fts5yyTokenName[] = {
|
|
/* 0 */ "$",
|
|
/* 1 */ "OR",
|
|
/* 2 */ "AND",
|
|
@@ -207761,7 +223913,7 @@ static int fts5yyGrowStack(fts5yyParser *p){
|
|
#endif
|
|
p->fts5yystksz = newSize;
|
|
}
|
|
- return pNew==0;
|
|
+ return pNew==0;
|
|
}
|
|
#endif
|
|
|
|
@@ -207803,7 +223955,7 @@ static void sqlite3Fts5ParserInit(void *fts5yypRawParser sqlite3Fts5ParserCTX_PD
|
|
}
|
|
|
|
#ifndef sqlite3Fts5Parser_ENGINEALWAYSONSTACK
|
|
-/*
|
|
+/*
|
|
** This function allocates a new parser.
|
|
** The only argument is a pointer to a function which works like
|
|
** malloc.
|
|
@@ -207830,7 +223982,7 @@ static void *sqlite3Fts5ParserAlloc(void *(*mallocProc)(fts5YYMALLOCARGTYPE) sql
|
|
/* The following function deletes the "minor type" or semantic value
|
|
** associated with a symbol. The symbol can be either a terminal
|
|
** or nonterminal. "fts5yymajor" is the symbol code, and "fts5yypminor" is
|
|
-** a pointer to the value to be deleted. The code used to do the
|
|
+** a pointer to the value to be deleted. The code used to do the
|
|
** deletions is derived from the %destructor and/or %token_destructor
|
|
** directives of the input grammar.
|
|
*/
|
|
@@ -207845,7 +223997,7 @@ static void fts5yy_destructor(
|
|
/* Here is inserted the actions which take place when a
|
|
** terminal or non-terminal is destroyed. This can happen
|
|
** when the symbol is popped from the stack during a
|
|
- ** reduce or during error processing or when a parser is
|
|
+ ** reduce or during error processing or when a parser is
|
|
** being destroyed before it is finished parsing.
|
|
**
|
|
** Note: during a reduce, the only symbols destroyed are those
|
|
@@ -207855,31 +224007,31 @@ static void fts5yy_destructor(
|
|
/********* Begin destructor definitions ***************************************/
|
|
case 16: /* input */
|
|
{
|
|
- (void)pParse;
|
|
+ (void)pParse;
|
|
}
|
|
break;
|
|
case 17: /* expr */
|
|
case 18: /* cnearset */
|
|
case 19: /* exprlist */
|
|
{
|
|
- sqlite3Fts5ParseNodeFree((fts5yypminor->fts5yy24));
|
|
+ sqlite3Fts5ParseNodeFree((fts5yypminor->fts5yy24));
|
|
}
|
|
break;
|
|
case 20: /* colset */
|
|
case 21: /* colsetlist */
|
|
{
|
|
- sqlite3_free((fts5yypminor->fts5yy11));
|
|
+ sqlite3_free((fts5yypminor->fts5yy11));
|
|
}
|
|
break;
|
|
case 22: /* nearset */
|
|
case 23: /* nearphrases */
|
|
{
|
|
- sqlite3Fts5ParseNearsetFree((fts5yypminor->fts5yy46));
|
|
+ sqlite3Fts5ParseNearsetFree((fts5yypminor->fts5yy46));
|
|
}
|
|
break;
|
|
case 24: /* phrase */
|
|
{
|
|
- sqlite3Fts5ParsePhraseFree((fts5yypminor->fts5yy53));
|
|
+ sqlite3Fts5ParsePhraseFree((fts5yypminor->fts5yy53));
|
|
}
|
|
break;
|
|
/********* End destructor definitions *****************************************/
|
|
@@ -207920,7 +224072,7 @@ static void sqlite3Fts5ParserFinalize(void *p){
|
|
}
|
|
|
|
#ifndef sqlite3Fts5Parser_ENGINEALWAYSONSTACK
|
|
-/*
|
|
+/*
|
|
** Deallocate and destroy a parser. Destructors are called for
|
|
** all stack elements before shutting the parser down.
|
|
**
|
|
@@ -208046,7 +224198,7 @@ static fts5YYACTIONTYPE fts5yy_find_shift_action(
|
|
#endif /* fts5YYWILDCARD */
|
|
return fts5yy_default[stateno];
|
|
}else{
|
|
- assert( i>=0 && i<sizeof(fts5yy_action)/sizeof(fts5yy_action[0]) );
|
|
+ assert( i>=0 && i<(int)(sizeof(fts5yy_action)/sizeof(fts5yy_action[0])) );
|
|
return fts5yy_action[i];
|
|
}
|
|
}while(1);
|
|
@@ -208142,7 +224294,7 @@ static void fts5yy_shift(
|
|
assert( fts5yypParser->fts5yyhwm == (int)(fts5yypParser->fts5yytos - fts5yypParser->fts5yystack) );
|
|
}
|
|
#endif
|
|
-#if fts5YYSTACKDEPTH>0
|
|
+#if fts5YYSTACKDEPTH>0
|
|
if( fts5yypParser->fts5yytos>fts5yypParser->fts5yystackEnd ){
|
|
fts5yypParser->fts5yytos--;
|
|
fts5yyStackOverflow(fts5yypParser);
|
|
@@ -208260,54 +224412,6 @@ static fts5YYACTIONTYPE fts5yy_reduce(
|
|
(void)fts5yyLookahead;
|
|
(void)fts5yyLookaheadToken;
|
|
fts5yymsp = fts5yypParser->fts5yytos;
|
|
-#ifndef NDEBUG
|
|
- if( fts5yyTraceFILE && fts5yyruleno<(int)(sizeof(fts5yyRuleName)/sizeof(fts5yyRuleName[0])) ){
|
|
- fts5yysize = fts5yyRuleInfoNRhs[fts5yyruleno];
|
|
- if( fts5yysize ){
|
|
- fprintf(fts5yyTraceFILE, "%sReduce %d [%s]%s, pop back to state %d.\n",
|
|
- fts5yyTracePrompt,
|
|
- fts5yyruleno, fts5yyRuleName[fts5yyruleno],
|
|
- fts5yyruleno<fts5YYNRULE_WITH_ACTION ? "" : " without external action",
|
|
- fts5yymsp[fts5yysize].stateno);
|
|
- }else{
|
|
- fprintf(fts5yyTraceFILE, "%sReduce %d [%s]%s.\n",
|
|
- fts5yyTracePrompt, fts5yyruleno, fts5yyRuleName[fts5yyruleno],
|
|
- fts5yyruleno<fts5YYNRULE_WITH_ACTION ? "" : " without external action");
|
|
- }
|
|
- }
|
|
-#endif /* NDEBUG */
|
|
-
|
|
- /* Check that the stack is large enough to grow by a single entry
|
|
- ** if the RHS of the rule is empty. This ensures that there is room
|
|
- ** enough on the stack to push the LHS value */
|
|
- if( fts5yyRuleInfoNRhs[fts5yyruleno]==0 ){
|
|
-#ifdef fts5YYTRACKMAXSTACKDEPTH
|
|
- if( (int)(fts5yypParser->fts5yytos - fts5yypParser->fts5yystack)>fts5yypParser->fts5yyhwm ){
|
|
- fts5yypParser->fts5yyhwm++;
|
|
- assert( fts5yypParser->fts5yyhwm == (int)(fts5yypParser->fts5yytos - fts5yypParser->fts5yystack));
|
|
- }
|
|
-#endif
|
|
-#if fts5YYSTACKDEPTH>0
|
|
- if( fts5yypParser->fts5yytos>=fts5yypParser->fts5yystackEnd ){
|
|
- fts5yyStackOverflow(fts5yypParser);
|
|
- /* The call to fts5yyStackOverflow() above pops the stack until it is
|
|
- ** empty, causing the main parser loop to exit. So the return value
|
|
- ** is never used and does not matter. */
|
|
- return 0;
|
|
- }
|
|
-#else
|
|
- if( fts5yypParser->fts5yytos>=&fts5yypParser->fts5yystack[fts5yypParser->fts5yystksz-1] ){
|
|
- if( fts5yyGrowStack(fts5yypParser) ){
|
|
- fts5yyStackOverflow(fts5yypParser);
|
|
- /* The call to fts5yyStackOverflow() above pops the stack until it is
|
|
- ** empty, causing the main parser loop to exit. So the return value
|
|
- ** is never used and does not matter. */
|
|
- return 0;
|
|
- }
|
|
- fts5yymsp = fts5yypParser->fts5yytos;
|
|
- }
|
|
-#endif
|
|
- }
|
|
|
|
switch( fts5yyruleno ){
|
|
/* Beginning here are the reduction cases. A typical example
|
|
@@ -208324,7 +224428,7 @@ static fts5YYACTIONTYPE fts5yy_reduce(
|
|
{ sqlite3Fts5ParseFinished(pParse, fts5yymsp[0].minor.fts5yy24); }
|
|
break;
|
|
case 1: /* colset ::= MINUS LCP colsetlist RCP */
|
|
-{
|
|
+{
|
|
fts5yymsp[-3].minor.fts5yy11 = sqlite3Fts5ParseColsetInvert(pParse, fts5yymsp[-1].minor.fts5yy11);
|
|
}
|
|
break;
|
|
@@ -208344,13 +224448,13 @@ static fts5YYACTIONTYPE fts5yy_reduce(
|
|
}
|
|
break;
|
|
case 5: /* colsetlist ::= colsetlist STRING */
|
|
-{
|
|
+{
|
|
fts5yylhsminor.fts5yy11 = sqlite3Fts5ParseColset(pParse, fts5yymsp[-1].minor.fts5yy11, &fts5yymsp[0].minor.fts5yy0); }
|
|
fts5yymsp[-1].minor.fts5yy11 = fts5yylhsminor.fts5yy11;
|
|
break;
|
|
case 6: /* colsetlist ::= STRING */
|
|
-{
|
|
- fts5yylhsminor.fts5yy11 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0);
|
|
+{
|
|
+ fts5yylhsminor.fts5yy11 = sqlite3Fts5ParseColset(pParse, 0, &fts5yymsp[0].minor.fts5yy0);
|
|
}
|
|
fts5yymsp[0].minor.fts5yy11 = fts5yylhsminor.fts5yy11;
|
|
break;
|
|
@@ -208394,14 +224498,14 @@ static fts5YYACTIONTYPE fts5yy_reduce(
|
|
fts5yymsp[-1].minor.fts5yy24 = fts5yylhsminor.fts5yy24;
|
|
break;
|
|
case 15: /* cnearset ::= nearset */
|
|
-{
|
|
- fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, fts5yymsp[0].minor.fts5yy46);
|
|
+{
|
|
+ fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, fts5yymsp[0].minor.fts5yy46);
|
|
}
|
|
fts5yymsp[0].minor.fts5yy24 = fts5yylhsminor.fts5yy24;
|
|
break;
|
|
case 16: /* cnearset ::= colset COLON nearset */
|
|
-{
|
|
- fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, fts5yymsp[0].minor.fts5yy46);
|
|
+{
|
|
+ fts5yylhsminor.fts5yy24 = sqlite3Fts5ParseNode(pParse, FTS5_STRING, 0, 0, fts5yymsp[0].minor.fts5yy46);
|
|
sqlite3Fts5ParseSetColset(pParse, fts5yylhsminor.fts5yy24, fts5yymsp[-2].minor.fts5yy11);
|
|
}
|
|
fts5yymsp[-2].minor.fts5yy24 = fts5yylhsminor.fts5yy24;
|
|
@@ -208411,9 +224515,9 @@ static fts5YYACTIONTYPE fts5yy_reduce(
|
|
fts5yymsp[0].minor.fts5yy46 = fts5yylhsminor.fts5yy46;
|
|
break;
|
|
case 18: /* nearset ::= CARET phrase */
|
|
-{
|
|
+{
|
|
sqlite3Fts5ParseSetCaret(fts5yymsp[0].minor.fts5yy53);
|
|
- fts5yymsp[-1].minor.fts5yy46 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy53);
|
|
+ fts5yymsp[-1].minor.fts5yy46 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy53);
|
|
}
|
|
break;
|
|
case 19: /* nearset ::= STRING LP nearphrases neardist_opt RP */
|
|
@@ -208425,8 +224529,8 @@ static fts5YYACTIONTYPE fts5yy_reduce(
|
|
fts5yymsp[-4].minor.fts5yy46 = fts5yylhsminor.fts5yy46;
|
|
break;
|
|
case 20: /* nearphrases ::= phrase */
|
|
-{
|
|
- fts5yylhsminor.fts5yy46 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy53);
|
|
+{
|
|
+ fts5yylhsminor.fts5yy46 = sqlite3Fts5ParseNearset(pParse, 0, fts5yymsp[0].minor.fts5yy53);
|
|
}
|
|
fts5yymsp[0].minor.fts5yy46 = fts5yylhsminor.fts5yy46;
|
|
break;
|
|
@@ -208443,13 +224547,13 @@ static fts5YYACTIONTYPE fts5yy_reduce(
|
|
{ fts5yymsp[-1].minor.fts5yy0 = fts5yymsp[0].minor.fts5yy0; }
|
|
break;
|
|
case 24: /* phrase ::= phrase PLUS STRING star_opt */
|
|
-{
|
|
+{
|
|
fts5yylhsminor.fts5yy53 = sqlite3Fts5ParseTerm(pParse, fts5yymsp[-3].minor.fts5yy53, &fts5yymsp[-1].minor.fts5yy0, fts5yymsp[0].minor.fts5yy4);
|
|
}
|
|
fts5yymsp[-3].minor.fts5yy53 = fts5yylhsminor.fts5yy53;
|
|
break;
|
|
case 25: /* phrase ::= STRING star_opt */
|
|
-{
|
|
+{
|
|
fts5yylhsminor.fts5yy53 = sqlite3Fts5ParseTerm(pParse, 0, &fts5yymsp[-1].minor.fts5yy0, fts5yymsp[0].minor.fts5yy4);
|
|
}
|
|
fts5yymsp[-1].minor.fts5yy53 = fts5yylhsminor.fts5yy53;
|
|
@@ -208610,12 +224714,56 @@ static void sqlite3Fts5Parser(
|
|
}
|
|
#endif
|
|
|
|
- do{
|
|
+ while(1){ /* Exit by "break" */
|
|
+ assert( fts5yypParser->fts5yytos>=fts5yypParser->fts5yystack );
|
|
assert( fts5yyact==fts5yypParser->fts5yytos->stateno );
|
|
fts5yyact = fts5yy_find_shift_action((fts5YYCODETYPE)fts5yymajor,fts5yyact);
|
|
if( fts5yyact >= fts5YY_MIN_REDUCE ){
|
|
- fts5yyact = fts5yy_reduce(fts5yypParser,fts5yyact-fts5YY_MIN_REDUCE,fts5yymajor,
|
|
- fts5yyminor sqlite3Fts5ParserCTX_PARAM);
|
|
+ unsigned int fts5yyruleno = fts5yyact - fts5YY_MIN_REDUCE; /* Reduce by this rule */
|
|
+#ifndef NDEBUG
|
|
+ assert( fts5yyruleno<(int)(sizeof(fts5yyRuleName)/sizeof(fts5yyRuleName[0])) );
|
|
+ if( fts5yyTraceFILE ){
|
|
+ int fts5yysize = fts5yyRuleInfoNRhs[fts5yyruleno];
|
|
+ if( fts5yysize ){
|
|
+ fprintf(fts5yyTraceFILE, "%sReduce %d [%s]%s, pop back to state %d.\n",
|
|
+ fts5yyTracePrompt,
|
|
+ fts5yyruleno, fts5yyRuleName[fts5yyruleno],
|
|
+ fts5yyruleno<fts5YYNRULE_WITH_ACTION ? "" : " without external action",
|
|
+ fts5yypParser->fts5yytos[fts5yysize].stateno);
|
|
+ }else{
|
|
+ fprintf(fts5yyTraceFILE, "%sReduce %d [%s]%s.\n",
|
|
+ fts5yyTracePrompt, fts5yyruleno, fts5yyRuleName[fts5yyruleno],
|
|
+ fts5yyruleno<fts5YYNRULE_WITH_ACTION ? "" : " without external action");
|
|
+ }
|
|
+ }
|
|
+#endif /* NDEBUG */
|
|
+
|
|
+ /* Check that the stack is large enough to grow by a single entry
|
|
+ ** if the RHS of the rule is empty. This ensures that there is room
|
|
+ ** enough on the stack to push the LHS value */
|
|
+ if( fts5yyRuleInfoNRhs[fts5yyruleno]==0 ){
|
|
+#ifdef fts5YYTRACKMAXSTACKDEPTH
|
|
+ if( (int)(fts5yypParser->fts5yytos - fts5yypParser->fts5yystack)>fts5yypParser->fts5yyhwm ){
|
|
+ fts5yypParser->fts5yyhwm++;
|
|
+ assert( fts5yypParser->fts5yyhwm ==
|
|
+ (int)(fts5yypParser->fts5yytos - fts5yypParser->fts5yystack));
|
|
+ }
|
|
+#endif
|
|
+#if fts5YYSTACKDEPTH>0
|
|
+ if( fts5yypParser->fts5yytos>=fts5yypParser->fts5yystackEnd ){
|
|
+ fts5yyStackOverflow(fts5yypParser);
|
|
+ break;
|
|
+ }
|
|
+#else
|
|
+ if( fts5yypParser->fts5yytos>=&fts5yypParser->fts5yystack[fts5yypParser->fts5yystksz-1] ){
|
|
+ if( fts5yyGrowStack(fts5yypParser) ){
|
|
+ fts5yyStackOverflow(fts5yypParser);
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+#endif
|
|
+ }
|
|
+ fts5yyact = fts5yy_reduce(fts5yypParser,fts5yyruleno,fts5yymajor,fts5yyminor sqlite3Fts5ParserCTX_PARAM);
|
|
}else if( fts5yyact <= fts5YY_MAX_SHIFTREDUCE ){
|
|
fts5yy_shift(fts5yypParser,fts5yyact,(fts5YYCODETYPE)fts5yymajor,fts5yyminor);
|
|
#ifndef fts5YYNOERRORRECOVERY
|
|
@@ -208640,7 +224788,7 @@ static void sqlite3Fts5Parser(
|
|
#ifdef fts5YYERRORSYMBOL
|
|
/* A syntax error has occurred.
|
|
** The response to an error depends upon whether or not the
|
|
- ** grammar defines an error token "ERROR".
|
|
+ ** grammar defines an error token "ERROR".
|
|
**
|
|
** This is what we do if the grammar does define ERROR:
|
|
**
|
|
@@ -208671,14 +224819,13 @@ static void sqlite3Fts5Parser(
|
|
fts5yy_destructor(fts5yypParser, (fts5YYCODETYPE)fts5yymajor, &fts5yyminorunion);
|
|
fts5yymajor = fts5YYNOCODE;
|
|
}else{
|
|
- while( fts5yypParser->fts5yytos >= fts5yypParser->fts5yystack
|
|
- && (fts5yyact = fts5yy_find_reduce_action(
|
|
- fts5yypParser->fts5yytos->stateno,
|
|
- fts5YYERRORSYMBOL)) > fts5YY_MAX_SHIFTREDUCE
|
|
- ){
|
|
+ while( fts5yypParser->fts5yytos > fts5yypParser->fts5yystack ){
|
|
+ fts5yyact = fts5yy_find_reduce_action(fts5yypParser->fts5yytos->stateno,
|
|
+ fts5YYERRORSYMBOL);
|
|
+ if( fts5yyact<=fts5YY_MAX_SHIFTREDUCE ) break;
|
|
fts5yy_pop_parser_stack(fts5yypParser);
|
|
}
|
|
- if( fts5yypParser->fts5yytos < fts5yypParser->fts5yystack || fts5yymajor==0 ){
|
|
+ if( fts5yypParser->fts5yytos <= fts5yypParser->fts5yystack || fts5yymajor==0 ){
|
|
fts5yy_destructor(fts5yypParser,(fts5YYCODETYPE)fts5yymajor,&fts5yyminorunion);
|
|
fts5yy_parse_failed(fts5yypParser);
|
|
#ifndef fts5YYNOERRORRECOVERY
|
|
@@ -208728,7 +224875,7 @@ static void sqlite3Fts5Parser(
|
|
break;
|
|
#endif
|
|
}
|
|
- }while( fts5yypParser->fts5yytos>fts5yypParser->fts5yystack );
|
|
+ }
|
|
#ifndef NDEBUG
|
|
if( fts5yyTraceFILE ){
|
|
fts5yyStackEntry *i;
|
|
@@ -208776,7 +224923,7 @@ static int sqlite3Fts5ParserFallback(int iToken){
|
|
#include <math.h> /* amalgamator: keep */
|
|
|
|
/*
|
|
-** Object used to iterate through all "coalesced phrase instances" in
|
|
+** Object used to iterate through all "coalesced phrase instances" in
|
|
** a single column of the current row. If the phrase instances in the
|
|
** column being considered do not overlap, this object simply iterates
|
|
** through them. Or, if they do overlap (share one or more tokens in
|
|
@@ -208839,7 +224986,7 @@ static int fts5CInstIterNext(CInstIter *pIter){
|
|
}
|
|
|
|
/*
|
|
-** Initialize the iterator object indicated by the final parameter to
|
|
+** Initialize the iterator object indicated by the final parameter to
|
|
** iterate through coalesced phrase instances in column iCol.
|
|
*/
|
|
static int fts5CInstIterInit(
|
|
@@ -208884,16 +225031,16 @@ struct HighlightContext {
|
|
|
|
/*
|
|
** Append text to the HighlightContext output string - p->zOut. Argument
|
|
-** z points to a buffer containing n bytes of text to append. If n is
|
|
+** z points to a buffer containing n bytes of text to append. If n is
|
|
** negative, everything up until the first '\0' is appended to the output.
|
|
**
|
|
-** If *pRc is set to any value other than SQLITE_OK when this function is
|
|
-** called, it is a no-op. If an error (i.e. an OOM condition) is encountered,
|
|
-** *pRc is set to an error code before returning.
|
|
+** If *pRc is set to any value other than SQLITE_OK when this function is
|
|
+** called, it is a no-op. If an error (i.e. an OOM condition) is encountered,
|
|
+** *pRc is set to an error code before returning.
|
|
*/
|
|
static void fts5HighlightAppend(
|
|
- int *pRc,
|
|
- HighlightContext *p,
|
|
+ int *pRc,
|
|
+ HighlightContext *p,
|
|
const char *z, int n
|
|
){
|
|
if( *pRc==SQLITE_OK && z ){
|
|
@@ -209120,7 +225267,7 @@ static int fts5SnippetScore(
|
|
}
|
|
|
|
/*
|
|
-** Return the value in pVal interpreted as utf-8 text. Except, if pVal
|
|
+** Return the value in pVal interpreted as utf-8 text. Except, if pVal
|
|
** contains a NULL value, return a pointer to a static string zero
|
|
** bytes in length instead of a NULL pointer.
|
|
*/
|
|
@@ -209189,7 +225336,7 @@ static void fts5SnippetFunction(
|
|
sFinder.nFirst = 0;
|
|
rc = pApi->xColumnText(pFts, i, &sFinder.zDoc, &nDoc);
|
|
if( rc!=SQLITE_OK ) break;
|
|
- rc = pApi->xTokenize(pFts,
|
|
+ rc = pApi->xTokenize(pFts,
|
|
sFinder.zDoc, nDoc, (void*)&sFinder,fts5SentenceFinderCb
|
|
);
|
|
if( rc!=SQLITE_OK ) break;
|
|
@@ -209224,7 +225371,7 @@ static void fts5SnippetFunction(
|
|
|
|
if( sFinder.aFirst[jj]<io ){
|
|
memset(aSeen, 0, nPhrase);
|
|
- rc = fts5SnippetScore(pApi, pFts, nDocsize, aSeen, i,
|
|
+ rc = fts5SnippetScore(pApi, pFts, nDocsize, aSeen, i,
|
|
sFinder.aFirst[jj], nToken, &nScore, 0
|
|
);
|
|
|
|
@@ -209303,7 +225450,7 @@ struct Fts5Bm25Data {
|
|
** table matched by each individual phrase within the query.
|
|
*/
|
|
static int fts5CountCb(
|
|
- const Fts5ExtensionApi *pApi,
|
|
+ const Fts5ExtensionApi *pApi,
|
|
Fts5Context *pFts,
|
|
void *pUserData /* Pointer to sqlite3_int64 variable */
|
|
){
|
|
@@ -209314,19 +225461,19 @@ static int fts5CountCb(
|
|
}
|
|
|
|
/*
|
|
-** Set *ppData to point to the Fts5Bm25Data object for the current query.
|
|
+** Set *ppData to point to the Fts5Bm25Data object for the current query.
|
|
** If the object has not already been allocated, allocate and populate it
|
|
** now.
|
|
*/
|
|
static int fts5Bm25GetData(
|
|
- const Fts5ExtensionApi *pApi,
|
|
+ const Fts5ExtensionApi *pApi,
|
|
Fts5Context *pFts,
|
|
Fts5Bm25Data **ppData /* OUT: bm25-data object for this query */
|
|
){
|
|
int rc = SQLITE_OK; /* Return code */
|
|
Fts5Bm25Data *p; /* Object to return */
|
|
|
|
- p = pApi->xGetAuxdata(pFts, 0);
|
|
+ p = (Fts5Bm25Data*)pApi->xGetAuxdata(pFts, 0);
|
|
if( p==0 ){
|
|
int nPhrase; /* Number of phrases in query */
|
|
sqlite3_int64 nRow = 0; /* Number of rows in table */
|
|
@@ -209367,7 +225514,7 @@ static int fts5Bm25GetData(
|
|
** is the number that contain at least one instance of the phrase
|
|
** under consideration.
|
|
**
|
|
- ** The problem with this is that if (N < 2*nHit), the IDF is
|
|
+ ** The problem with this is that if (N < 2*nHit), the IDF is
|
|
** negative. Which is undesirable. So the mimimum allowable IDF is
|
|
** (1e-6) - roughly the same as a term that appears in just over
|
|
** half of set of 5,000,000 documents. */
|
|
@@ -209400,7 +225547,7 @@ static void fts5Bm25Function(
|
|
){
|
|
const double k1 = 1.2; /* Constant "k1" from BM25 formula */
|
|
const double b = 0.75; /* Constant "b" from BM25 formula */
|
|
- int rc = SQLITE_OK; /* Error code */
|
|
+ int rc; /* Error code */
|
|
double score = 0.0; /* SQL function return value */
|
|
Fts5Bm25Data *pData; /* Values allocated/calculated once only */
|
|
int i; /* Iterator variable */
|
|
@@ -209432,17 +225579,15 @@ static void fts5Bm25Function(
|
|
D = (double)nTok;
|
|
}
|
|
|
|
- /* Determine the BM25 score for the current row. */
|
|
- for(i=0; rc==SQLITE_OK && i<pData->nPhrase; i++){
|
|
- score += pData->aIDF[i] * (
|
|
- ( aFreq[i] * (k1 + 1.0) ) /
|
|
- ( aFreq[i] + k1 * (1 - b + b * D / pData->avgdl) )
|
|
- );
|
|
- }
|
|
-
|
|
- /* If no error has occurred, return the calculated score. Otherwise,
|
|
- ** throw an SQL exception. */
|
|
+ /* Determine and return the BM25 score for the current row. Or, if an
|
|
+ ** error has occurred, throw an exception. */
|
|
if( rc==SQLITE_OK ){
|
|
+ for(i=0; i<pData->nPhrase; i++){
|
|
+ score += pData->aIDF[i] * (
|
|
+ ( aFreq[i] * (k1 + 1.0) ) /
|
|
+ ( aFreq[i] + k1 * (1 - b + b * D / pData->avgdl) )
|
|
+ );
|
|
+ }
|
|
sqlite3_result_double(pCtx, -1.0 * score);
|
|
}else{
|
|
sqlite3_result_error_code(pCtx, rc);
|
|
@@ -209533,17 +225678,16 @@ static int sqlite3Fts5Get32(const u8 *aBuf){
|
|
}
|
|
|
|
/*
|
|
-** Append buffer nData/pData to buffer pBuf. If an OOM error occurs, set
|
|
+** Append buffer nData/pData to buffer pBuf. If an OOM error occurs, set
|
|
** the error code in p. If an error has already occurred when this function
|
|
** is called, it is a no-op.
|
|
*/
|
|
static void sqlite3Fts5BufferAppendBlob(
|
|
int *pRc,
|
|
- Fts5Buffer *pBuf,
|
|
- u32 nData,
|
|
+ Fts5Buffer *pBuf,
|
|
+ u32 nData,
|
|
const u8 *pData
|
|
){
|
|
- assert_nc( *pRc || nData>=0 );
|
|
if( nData ){
|
|
if( fts5BufferGrow(pRc, pBuf, nData) ) return;
|
|
memcpy(&pBuf->p[pBuf->n], pData, nData);
|
|
@@ -209553,12 +225697,12 @@ static void sqlite3Fts5BufferAppendBlob(
|
|
|
|
/*
|
|
** Append the nul-terminated string zStr to the buffer pBuf. This function
|
|
-** ensures that the byte following the buffer data is set to 0x00, even
|
|
+** ensures that the byte following the buffer data is set to 0x00, even
|
|
** though this byte is not included in the pBuf->n count.
|
|
*/
|
|
static void sqlite3Fts5BufferAppendString(
|
|
int *pRc,
|
|
- Fts5Buffer *pBuf,
|
|
+ Fts5Buffer *pBuf,
|
|
const char *zStr
|
|
){
|
|
int nStr = (int)strlen(zStr);
|
|
@@ -209570,13 +225714,13 @@ static void sqlite3Fts5BufferAppendString(
|
|
** Argument zFmt is a printf() style format string. This function performs
|
|
** the printf() style processing, then appends the results to buffer pBuf.
|
|
**
|
|
-** Like sqlite3Fts5BufferAppendString(), this function ensures that the byte
|
|
+** Like sqlite3Fts5BufferAppendString(), this function ensures that the byte
|
|
** following the buffer data is set to 0x00, even though this byte is not
|
|
** included in the pBuf->n count.
|
|
-*/
|
|
+*/
|
|
static void sqlite3Fts5BufferAppendPrintf(
|
|
int *pRc,
|
|
- Fts5Buffer *pBuf,
|
|
+ Fts5Buffer *pBuf,
|
|
char *zFmt, ...
|
|
){
|
|
if( *pRc==SQLITE_OK ){
|
|
@@ -209603,12 +225747,12 @@ static char *sqlite3Fts5Mprintf(int *pRc, const char *zFmt, ...){
|
|
zRet = sqlite3_vmprintf(zFmt, ap);
|
|
va_end(ap);
|
|
if( zRet==0 ){
|
|
- *pRc = SQLITE_NOMEM;
|
|
+ *pRc = SQLITE_NOMEM;
|
|
}
|
|
}
|
|
return zRet;
|
|
}
|
|
-
|
|
+
|
|
|
|
/*
|
|
** Free any buffer allocated by pBuf. Zero the structure before returning.
|
|
@@ -209619,7 +225763,7 @@ static void sqlite3Fts5BufferFree(Fts5Buffer *pBuf){
|
|
}
|
|
|
|
/*
|
|
-** Zero the contents of the buffer object. But do not free the associated
|
|
+** Zero the contents of the buffer object. But do not free the associated
|
|
** memory allocation.
|
|
*/
|
|
static void sqlite3Fts5BufferZero(Fts5Buffer *pBuf){
|
|
@@ -209633,8 +225777,8 @@ static void sqlite3Fts5BufferZero(Fts5Buffer *pBuf){
|
|
*/
|
|
static void sqlite3Fts5BufferSet(
|
|
int *pRc,
|
|
- Fts5Buffer *pBuf,
|
|
- int nData,
|
|
+ Fts5Buffer *pBuf,
|
|
+ int nData,
|
|
const u8 *pData
|
|
){
|
|
pBuf->n = 0;
|
|
@@ -209650,10 +225794,10 @@ static int sqlite3Fts5PoslistNext64(
|
|
if( i>=n ){
|
|
/* EOF */
|
|
*piOff = -1;
|
|
- return 1;
|
|
+ return 1;
|
|
}else{
|
|
i64 iOff = *piOff;
|
|
- int iVal;
|
|
+ u32 iVal;
|
|
fts5FastGetVarint32(a, i, iVal);
|
|
if( iVal<=1 ){
|
|
if( iVal==0 ){
|
|
@@ -209662,15 +225806,19 @@ static int sqlite3Fts5PoslistNext64(
|
|
}
|
|
fts5FastGetVarint32(a, i, iVal);
|
|
iOff = ((i64)iVal) << 32;
|
|
+ assert( iOff>=0 );
|
|
fts5FastGetVarint32(a, i, iVal);
|
|
if( iVal<2 ){
|
|
/* This is a corrupt record. So stop parsing it here. */
|
|
*piOff = -1;
|
|
return 1;
|
|
}
|
|
+ *piOff = iOff + ((iVal-2) & 0x7FFFFFFF);
|
|
+ }else{
|
|
+ *piOff = (iOff & (i64)0x7FFFFFFF<<32)+((iOff + (iVal-2)) & 0x7FFFFFFF);
|
|
}
|
|
- *piOff = iOff + ((iVal-2) & 0x7FFFFFFF);
|
|
*pi = i;
|
|
+ assert_nc( *piOff>=iOff );
|
|
return 0;
|
|
}
|
|
}
|
|
@@ -209705,22 +225853,24 @@ static int sqlite3Fts5PoslistReaderInit(
|
|
** to iPos before returning.
|
|
*/
|
|
static void sqlite3Fts5PoslistSafeAppend(
|
|
- Fts5Buffer *pBuf,
|
|
- i64 *piPrev,
|
|
+ Fts5Buffer *pBuf,
|
|
+ i64 *piPrev,
|
|
i64 iPos
|
|
){
|
|
- static const i64 colmask = ((i64)(0x7FFFFFFF)) << 32;
|
|
- if( (iPos & colmask) != (*piPrev & colmask) ){
|
|
- pBuf->p[pBuf->n++] = 1;
|
|
- pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos>>32));
|
|
- *piPrev = (iPos & colmask);
|
|
+ if( iPos>=*piPrev ){
|
|
+ static const i64 colmask = ((i64)(0x7FFFFFFF)) << 32;
|
|
+ if( (iPos & colmask) != (*piPrev & colmask) ){
|
|
+ pBuf->p[pBuf->n++] = 1;
|
|
+ pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos>>32));
|
|
+ *piPrev = (iPos & colmask);
|
|
+ }
|
|
+ pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos-*piPrev)+2);
|
|
+ *piPrev = iPos;
|
|
}
|
|
- pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], (iPos-*piPrev)+2);
|
|
- *piPrev = iPos;
|
|
}
|
|
|
|
static int sqlite3Fts5PoslistWriterAppend(
|
|
- Fts5Buffer *pBuf,
|
|
+ Fts5Buffer *pBuf,
|
|
Fts5PoslistWriter *pWriter,
|
|
i64 iPos
|
|
){
|
|
@@ -209749,7 +225899,7 @@ static void *sqlite3Fts5MallocZero(int *pRc, sqlite3_int64 nByte){
|
|
** the length of the string is determined using strlen().
|
|
**
|
|
** It is the responsibility of the caller to eventually free the returned
|
|
-** buffer using sqlite3_free(). If an OOM error occurs, NULL is returned.
|
|
+** buffer using sqlite3_free(). If an OOM error occurs, NULL is returned.
|
|
*/
|
|
static char *sqlite3Fts5Strndup(int *pRc, const char *pIn, int nIn){
|
|
char *zRet = 0;
|
|
@@ -209816,9 +225966,9 @@ static int sqlite3Fts5TermsetNew(Fts5Termset **pp){
|
|
}
|
|
|
|
static int sqlite3Fts5TermsetAdd(
|
|
- Fts5Termset *p,
|
|
+ Fts5Termset *p,
|
|
int iIdx,
|
|
- const char *pTerm, int nTerm,
|
|
+ const char *pTerm, int nTerm,
|
|
int *pbPresent
|
|
){
|
|
int rc = SQLITE_OK;
|
|
@@ -209839,9 +225989,9 @@ static int sqlite3Fts5TermsetAdd(
|
|
hash = hash % ArraySize(p->apHash);
|
|
|
|
for(pEntry=p->apHash[hash]; pEntry; pEntry=pEntry->pNext){
|
|
- if( pEntry->iIdx==iIdx
|
|
- && pEntry->nTerm==nTerm
|
|
- && memcmp(pEntry->pTerm, pTerm, nTerm)==0
|
|
+ if( pEntry->iIdx==iIdx
|
|
+ && pEntry->nTerm==nTerm
|
|
+ && memcmp(pEntry->pTerm, pTerm, nTerm)==0
|
|
){
|
|
*pbPresent = 1;
|
|
break;
|
|
@@ -209915,8 +226065,8 @@ static int fts5_isopenquote(char x){
|
|
}
|
|
|
|
/*
|
|
-** Argument pIn points to a character that is part of a nul-terminated
|
|
-** string. Return a pointer to the first character following *pIn in
|
|
+** Argument pIn points to a character that is part of a nul-terminated
|
|
+** string. Return a pointer to the first character following *pIn in
|
|
** the string that is not a white-space character.
|
|
*/
|
|
static const char *fts5ConfigSkipWhitespace(const char *pIn){
|
|
@@ -209928,8 +226078,8 @@ static const char *fts5ConfigSkipWhitespace(const char *pIn){
|
|
}
|
|
|
|
/*
|
|
-** Argument pIn points to a character that is part of a nul-terminated
|
|
-** string. Return a pointer to the first character following *pIn in
|
|
+** Argument pIn points to a character that is part of a nul-terminated
|
|
+** string. Return a pointer to the first character following *pIn in
|
|
** the string that is not a "bareword" character.
|
|
*/
|
|
static const char *fts5ConfigSkipBareword(const char *pIn){
|
|
@@ -209960,9 +226110,9 @@ static const char *fts5ConfigSkipLiteral(const char *pIn){
|
|
p++;
|
|
if( *p=='\'' ){
|
|
p++;
|
|
- while( (*p>='a' && *p<='f')
|
|
- || (*p>='A' && *p<='F')
|
|
- || (*p>='0' && *p<='9')
|
|
+ while( (*p>='a' && *p<='f')
|
|
+ || (*p>='A' && *p<='F')
|
|
+ || (*p>='0' && *p<='9')
|
|
){
|
|
p++;
|
|
}
|
|
@@ -209993,7 +226143,7 @@ static const char *fts5ConfigSkipLiteral(const char *pIn){
|
|
if( *p=='+' || *p=='-' ) p++;
|
|
while( fts5_isdigit(*p) ) p++;
|
|
|
|
- /* At this point, if the literal was an integer, the parse is
|
|
+ /* At this point, if the literal was an integer, the parse is
|
|
** finished. Or, if it is a floating point value, it may continue
|
|
** with either a decimal point or an 'E' character. */
|
|
if( *p=='.' && fts5_isdigit(p[1]) ){
|
|
@@ -210017,8 +226167,8 @@ static const char *fts5ConfigSkipLiteral(const char *pIn){
|
|
** nul-terminator byte.
|
|
**
|
|
** If the close-quote is found, the value returned is the byte offset of
|
|
-** the character immediately following it. Or, if the close-quote is not
|
|
-** found, -1 is returned. If -1 is returned, the buffer is left in an
|
|
+** the character immediately following it. Or, if the close-quote is not
|
|
+** found, -1 is returned. If -1 is returned, the buffer is left in an
|
|
** undefined state.
|
|
*/
|
|
static int fts5Dequote(char *z){
|
|
@@ -210029,7 +226179,7 @@ static int fts5Dequote(char *z){
|
|
|
|
/* Set stack variable q to the close-quote character */
|
|
assert( q=='[' || q=='\'' || q=='"' || q=='`' );
|
|
- if( q=='[' ) q = ']';
|
|
+ if( q=='[' ) q = ']';
|
|
|
|
while( z[iIn] ){
|
|
if( z[iIn]==q ){
|
|
@@ -210039,7 +226189,7 @@ static int fts5Dequote(char *z){
|
|
break;
|
|
}else{
|
|
/* Character iIn and iIn+1 form an escaped quote character. Skip
|
|
- ** the input cursor past both and copy a single quote character
|
|
+ ** the input cursor past both and copy a single quote character
|
|
** to the output buffer. */
|
|
iIn += 2;
|
|
z[iOut++] = q;
|
|
@@ -210084,8 +226234,8 @@ struct Fts5Enum {
|
|
typedef struct Fts5Enum Fts5Enum;
|
|
|
|
static int fts5ConfigSetEnum(
|
|
- const Fts5Enum *aEnum,
|
|
- const char *zEnum,
|
|
+ const Fts5Enum *aEnum,
|
|
+ const char *zEnum,
|
|
int *peVal
|
|
){
|
|
int nEnum = (int)strlen(zEnum);
|
|
@@ -210205,8 +226355,8 @@ static int fts5ConfigParseSpecial(
|
|
*pzErr = sqlite3_mprintf("parse error in tokenize directive");
|
|
rc = SQLITE_ERROR;
|
|
}else{
|
|
- rc = sqlite3Fts5GetTokenizer(pGlobal,
|
|
- (const char**)azArg, (int)nArg, &pConfig->pTok, &pConfig->pTokApi,
|
|
+ rc = sqlite3Fts5GetTokenizer(pGlobal,
|
|
+ (const char**)azArg, (int)nArg, pConfig,
|
|
pzErr
|
|
);
|
|
}
|
|
@@ -210272,15 +226422,13 @@ static int fts5ConfigParseSpecial(
|
|
}
|
|
|
|
/*
|
|
-** Allocate an instance of the default tokenizer ("simple") at
|
|
+** Allocate an instance of the default tokenizer ("simple") at
|
|
** Fts5Config.pTokenizer. Return SQLITE_OK if successful, or an SQLite error
|
|
** code if an error occurs.
|
|
*/
|
|
static int fts5ConfigDefaultTokenizer(Fts5Global *pGlobal, Fts5Config *pConfig){
|
|
assert( pConfig->pTok==0 && pConfig->pTokApi==0 );
|
|
- return sqlite3Fts5GetTokenizer(
|
|
- pGlobal, 0, 0, &pConfig->pTok, &pConfig->pTokApi, 0
|
|
- );
|
|
+ return sqlite3Fts5GetTokenizer(pGlobal, 0, 0, pConfig, 0);
|
|
}
|
|
|
|
/*
|
|
@@ -210339,14 +226487,14 @@ static const char *fts5ConfigGobbleWord(
|
|
}
|
|
|
|
static int fts5ConfigParseColumn(
|
|
- Fts5Config *p,
|
|
- char *zCol,
|
|
- char *zArg,
|
|
+ Fts5Config *p,
|
|
+ char *zCol,
|
|
+ char *zArg,
|
|
char **pzErr
|
|
){
|
|
int rc = SQLITE_OK;
|
|
- if( 0==sqlite3_stricmp(zCol, FTS5_RANK_NAME)
|
|
- || 0==sqlite3_stricmp(zCol, FTS5_ROWID_NAME)
|
|
+ if( 0==sqlite3_stricmp(zCol, FTS5_RANK_NAME)
|
|
+ || 0==sqlite3_stricmp(zCol, FTS5_ROWID_NAME)
|
|
){
|
|
*pzErr = sqlite3_mprintf("reserved fts5 column name: %s", zCol);
|
|
rc = SQLITE_ERROR;
|
|
@@ -210389,14 +226537,14 @@ static int fts5ConfigMakeExprlist(Fts5Config *p){
|
|
|
|
/*
|
|
** Arguments nArg/azArg contain the string arguments passed to the xCreate
|
|
-** or xConnect method of the virtual table. This function attempts to
|
|
+** or xConnect method of the virtual table. This function attempts to
|
|
** allocate an instance of Fts5Config containing the results of parsing
|
|
** those arguments.
|
|
**
|
|
** If successful, SQLITE_OK is returned and *ppOut is set to point to the
|
|
-** new Fts5Config object. If an error occurs, an SQLite error code is
|
|
+** new Fts5Config object. If an error occurs, an SQLite error code is
|
|
** returned, *ppOut is set to NULL and an error message may be left in
|
|
-** *pzErr. It is the responsibility of the caller to eventually free any
|
|
+** *pzErr. It is the responsibility of the caller to eventually free any
|
|
** such error message using sqlite3_free().
|
|
*/
|
|
static int sqlite3Fts5ConfigParse(
|
|
@@ -210420,7 +226568,7 @@ static int sqlite3Fts5ConfigParse(
|
|
|
|
nByte = nArg * (sizeof(char*) + sizeof(u8));
|
|
pRet->azCol = (char**)sqlite3Fts5MallocZero(&rc, nByte);
|
|
- pRet->abUnindexed = (u8*)&pRet->azCol[nArg];
|
|
+ pRet->abUnindexed = pRet->azCol ? (u8*)&pRet->azCol[nArg] : 0;
|
|
pRet->zDb = sqlite3Fts5Strndup(&rc, azArg[1], -1);
|
|
pRet->zName = sqlite3Fts5Strndup(&rc, azArg[2], -1);
|
|
pRet->bColumnsize = 1;
|
|
@@ -210445,6 +226593,7 @@ static int sqlite3Fts5ConfigParse(
|
|
z = fts5ConfigSkipWhitespace(z);
|
|
if( z && *z=='=' ){
|
|
bOption = 1;
|
|
+ assert( zOne!=0 );
|
|
z++;
|
|
if( bMustBeCol ) z = 0;
|
|
}
|
|
@@ -210461,7 +226610,11 @@ static int sqlite3Fts5ConfigParse(
|
|
rc = SQLITE_ERROR;
|
|
}else{
|
|
if( bOption ){
|
|
- rc = fts5ConfigParseSpecial(pGlobal, pRet, zOne, zTwo?zTwo:"", pzErr);
|
|
+ rc = fts5ConfigParseSpecial(pGlobal, pRet,
|
|
+ ALWAYS(zOne)?zOne:"",
|
|
+ zTwo?zTwo:"",
|
|
+ pzErr
|
|
+ );
|
|
}else{
|
|
rc = fts5ConfigParseColumn(pRet, zOne, zTwo, pzErr);
|
|
zOne = 0;
|
|
@@ -210483,8 +226636,8 @@ static int sqlite3Fts5ConfigParse(
|
|
/* If no zContent option was specified, fill in the default values. */
|
|
if( rc==SQLITE_OK && pRet->zContent==0 ){
|
|
const char *zTail = 0;
|
|
- assert( pRet->eContent==FTS5_CONTENT_NORMAL
|
|
- || pRet->eContent==FTS5_CONTENT_NONE
|
|
+ assert( pRet->eContent==FTS5_CONTENT_NORMAL
|
|
+ || pRet->eContent==FTS5_CONTENT_NONE
|
|
);
|
|
if( pRet->eContent==FTS5_CONTENT_NORMAL ){
|
|
zTail = "content";
|
|
@@ -210555,7 +226708,7 @@ static int sqlite3Fts5ConfigDeclareVtab(Fts5Config *pConfig){
|
|
const char *zSep = (i==0?"":", ");
|
|
zSql = sqlite3Fts5Mprintf(&rc, "%z%s%Q", zSql, zSep, pConfig->azCol[i]);
|
|
}
|
|
- zSql = sqlite3Fts5Mprintf(&rc, "%z, %Q HIDDEN, %s HIDDEN)",
|
|
+ zSql = sqlite3Fts5Mprintf(&rc, "%z, %Q HIDDEN, %s HIDDEN)",
|
|
zSql, pConfig->zName, FTS5_RANK_NAME
|
|
);
|
|
|
|
@@ -210564,7 +226717,7 @@ static int sqlite3Fts5ConfigDeclareVtab(Fts5Config *pConfig){
|
|
rc = sqlite3_declare_vtab(pConfig->db, zSql);
|
|
sqlite3_free(zSql);
|
|
}
|
|
-
|
|
+
|
|
return rc;
|
|
}
|
|
|
|
@@ -210582,7 +226735,7 @@ static int sqlite3Fts5ConfigDeclareVtab(Fts5Config *pConfig){
|
|
** int iPos // Position of token in input (first token is 0)
|
|
**
|
|
** If the callback returns a non-zero value the tokenization is abandoned
|
|
-** and no further callbacks are issued.
|
|
+** and no further callbacks are issued.
|
|
**
|
|
** This function returns SQLITE_OK if successful or an SQLite error code
|
|
** if an error occurs. If the tokenization was abandoned early because
|
|
@@ -210612,7 +226765,7 @@ static int sqlite3Fts5Tokenize(
|
|
*/
|
|
static const char *fts5ConfigSkipArgs(const char *pIn){
|
|
const char *p = pIn;
|
|
-
|
|
+
|
|
while( 1 ){
|
|
p = fts5ConfigSkipWhitespace(p);
|
|
p = fts5ConfigSkipLiteral(p);
|
|
@@ -210629,7 +226782,7 @@ static const char *fts5ConfigSkipArgs(const char *pIn){
|
|
}
|
|
|
|
/*
|
|
-** Parameter zIn contains a rank() function specification. The format of
|
|
+** Parameter zIn contains a rank() function specification. The format of
|
|
** this is:
|
|
**
|
|
** + Bareword (function name)
|
|
@@ -210671,7 +226824,7 @@ static int sqlite3Fts5ConfigParseRank(
|
|
p++;
|
|
}
|
|
if( rc==SQLITE_OK ){
|
|
- const char *pArgs;
|
|
+ const char *pArgs;
|
|
p = fts5ConfigSkipWhitespace(p);
|
|
pArgs = p;
|
|
if( *p!=')' ){
|
|
@@ -210697,8 +226850,8 @@ static int sqlite3Fts5ConfigParseRank(
|
|
}
|
|
|
|
static int sqlite3Fts5ConfigSetValue(
|
|
- Fts5Config *pConfig,
|
|
- const char *zKey,
|
|
+ Fts5Config *pConfig,
|
|
+ const char *zKey,
|
|
sqlite3_value *pVal,
|
|
int *pbBadkey
|
|
){
|
|
@@ -210824,7 +226977,7 @@ static int sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){
|
|
}
|
|
rc = sqlite3_finalize(p);
|
|
}
|
|
-
|
|
+
|
|
if( rc==SQLITE_OK && iVersion!=FTS5_CURRENT_VERSION ){
|
|
rc = SQLITE_ERROR;
|
|
if( pConfig->pzErrmsg ){
|
|
@@ -210913,7 +227066,7 @@ struct Fts5ExprNode {
|
|
i64 iRowid; /* Current rowid */
|
|
Fts5ExprNearset *pNear; /* For FTS5_STRING - cluster of phrases */
|
|
|
|
- /* Child nodes. For a NOT node, this array always contains 2 entries. For
|
|
+ /* Child nodes. For a NOT node, this array always contains 2 entries. For
|
|
** AND or OR nodes, it contains 2 or more entries. */
|
|
int nChild; /* Number of child nodes */
|
|
Fts5ExprNode *apChild[1]; /* Array of child nodes */
|
|
@@ -210972,12 +227125,14 @@ struct Fts5Parse {
|
|
int nPhrase; /* Size of apPhrase array */
|
|
Fts5ExprPhrase **apPhrase; /* Array of all phrases */
|
|
Fts5ExprNode *pExpr; /* Result of a successful parse */
|
|
+ int bPhraseToAnd; /* Convert "a+b" to "a AND b" */
|
|
};
|
|
|
|
static void sqlite3Fts5ParseError(Fts5Parse *pParse, const char *zFmt, ...){
|
|
va_list ap;
|
|
va_start(ap, zFmt);
|
|
if( pParse->rc==SQLITE_OK ){
|
|
+ assert( pParse->zErr==0 );
|
|
pParse->zErr = sqlite3_vmprintf(zFmt, ap);
|
|
pParse->rc = SQLITE_ERROR;
|
|
}
|
|
@@ -210992,7 +227147,7 @@ static int fts5ExprIsspace(char t){
|
|
** Read the first token from the nul-terminated string at *pz.
|
|
*/
|
|
static int fts5ExprGetToken(
|
|
- Fts5Parse *pParse,
|
|
+ Fts5Parse *pParse,
|
|
const char **pz, /* IN/OUT: Pointer into buffer */
|
|
Fts5Token *pToken
|
|
){
|
|
@@ -211060,9 +227215,10 @@ static void fts5ParseFree(void *p){ sqlite3_free(p); }
|
|
|
|
static int sqlite3Fts5ExprNew(
|
|
Fts5Config *pConfig, /* FTS5 Configuration */
|
|
+ int bPhraseToAnd,
|
|
int iCol,
|
|
const char *zExpr, /* Expression text */
|
|
- Fts5Expr **ppNew,
|
|
+ Fts5Expr **ppNew,
|
|
char **pzErr
|
|
){
|
|
Fts5Parse sParse;
|
|
@@ -211075,6 +227231,7 @@ static int sqlite3Fts5ExprNew(
|
|
*ppNew = 0;
|
|
*pzErr = 0;
|
|
memset(&sParse, 0, sizeof(sParse));
|
|
+ sParse.bPhraseToAnd = bPhraseToAnd;
|
|
pEngine = sqlite3Fts5ParserAlloc(fts5ParseAlloc);
|
|
if( pEngine==0 ){ return SQLITE_NOMEM; }
|
|
sParse.pConfig = pConfig;
|
|
@@ -211117,6 +227274,7 @@ static int sqlite3Fts5ExprNew(
|
|
pNew->pConfig = pConfig;
|
|
pNew->apExprPhrase = sParse.apPhrase;
|
|
pNew->nPhrase = sParse.nPhrase;
|
|
+ pNew->bDesc = 0;
|
|
sParse.apPhrase = 0;
|
|
}
|
|
}else{
|
|
@@ -211128,6 +227286,95 @@ static int sqlite3Fts5ExprNew(
|
|
return sParse.rc;
|
|
}
|
|
|
|
+/*
|
|
+** Assuming that buffer z is at least nByte bytes in size and contains a
|
|
+** valid utf-8 string, return the number of characters in the string.
|
|
+*/
|
|
+static int fts5ExprCountChar(const char *z, int nByte){
|
|
+ int nRet = 0;
|
|
+ int ii;
|
|
+ for(ii=0; ii<nByte; ii++){
|
|
+ if( (z[ii] & 0xC0)!=0x80 ) nRet++;
|
|
+ }
|
|
+ return nRet;
|
|
+}
|
|
+
|
|
+/*
|
|
+** This function is only called when using the special 'trigram' tokenizer.
|
|
+** Argument zText contains the text of a LIKE or GLOB pattern matched
|
|
+** against column iCol. This function creates and compiles an FTS5 MATCH
|
|
+** expression that will match a superset of the rows matched by the LIKE or
|
|
+** GLOB. If successful, SQLITE_OK is returned. Otherwise, an SQLite error
|
|
+** code.
|
|
+*/
|
|
+static int sqlite3Fts5ExprPattern(
|
|
+ Fts5Config *pConfig, int bGlob, int iCol, const char *zText, Fts5Expr **pp
|
|
+){
|
|
+ i64 nText = strlen(zText);
|
|
+ char *zExpr = (char*)sqlite3_malloc64(nText*4 + 1);
|
|
+ int rc = SQLITE_OK;
|
|
+
|
|
+ if( zExpr==0 ){
|
|
+ rc = SQLITE_NOMEM;
|
|
+ }else{
|
|
+ char aSpec[3];
|
|
+ int iOut = 0;
|
|
+ int i = 0;
|
|
+ int iFirst = 0;
|
|
+
|
|
+ if( bGlob==0 ){
|
|
+ aSpec[0] = '_';
|
|
+ aSpec[1] = '%';
|
|
+ aSpec[2] = 0;
|
|
+ }else{
|
|
+ aSpec[0] = '*';
|
|
+ aSpec[1] = '?';
|
|
+ aSpec[2] = '[';
|
|
+ }
|
|
+
|
|
+ while( i<=nText ){
|
|
+ if( i==nText
|
|
+ || zText[i]==aSpec[0] || zText[i]==aSpec[1] || zText[i]==aSpec[2]
|
|
+ ){
|
|
+
|
|
+ if( fts5ExprCountChar(&zText[iFirst], i-iFirst)>=3 ){
|
|
+ int jj;
|
|
+ zExpr[iOut++] = '"';
|
|
+ for(jj=iFirst; jj<i; jj++){
|
|
+ zExpr[iOut++] = zText[jj];
|
|
+ if( zText[jj]=='"' ) zExpr[iOut++] = '"';
|
|
+ }
|
|
+ zExpr[iOut++] = '"';
|
|
+ zExpr[iOut++] = ' ';
|
|
+ }
|
|
+ if( zText[i]==aSpec[2] ){
|
|
+ i += 2;
|
|
+ if( zText[i-1]=='^' ) i++;
|
|
+ while( i<nText && zText[i]!=']' ) i++;
|
|
+ }
|
|
+ iFirst = i+1;
|
|
+ }
|
|
+ i++;
|
|
+ }
|
|
+ if( iOut>0 ){
|
|
+ int bAnd = 0;
|
|
+ if( pConfig->eDetail!=FTS5_DETAIL_FULL ){
|
|
+ bAnd = 1;
|
|
+ if( pConfig->eDetail==FTS5_DETAIL_NONE ){
|
|
+ iCol = pConfig->nCol;
|
|
+ }
|
|
+ }
|
|
+ zExpr[iOut] = '\0';
|
|
+ rc = sqlite3Fts5ExprNew(pConfig, bAnd, iCol, zExpr, pp,pConfig->pzErrmsg);
|
|
+ }else{
|
|
+ *pp = 0;
|
|
+ }
|
|
+ sqlite3_free(zExpr);
|
|
+ }
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
/*
|
|
** Free the expression node object passed as the only argument.
|
|
*/
|
|
@@ -211198,6 +227445,7 @@ static i64 fts5ExprSynonymRowid(Fts5ExprTerm *pTerm, int bDesc, int *pbEof){
|
|
int bRetValid = 0;
|
|
Fts5ExprTerm *p;
|
|
|
|
+ assert( pTerm );
|
|
assert( pTerm->pSynonym );
|
|
assert( bDesc==0 || bDesc==1 );
|
|
for(p=pTerm; p; p=p->pSynonym){
|
|
@@ -211218,7 +227466,7 @@ static i64 fts5ExprSynonymRowid(Fts5ExprTerm *pTerm, int bDesc, int *pbEof){
|
|
** Argument pTerm must be a synonym iterator.
|
|
*/
|
|
static int fts5ExprSynonymList(
|
|
- Fts5ExprTerm *pTerm,
|
|
+ Fts5ExprTerm *pTerm,
|
|
i64 iRowid,
|
|
Fts5Buffer *pBuf, /* Use this buffer for space if required */
|
|
u8 **pa, int *pn
|
|
@@ -211291,13 +227539,13 @@ static int fts5ExprSynonymList(
|
|
|
|
/*
|
|
** All individual term iterators in pPhrase are guaranteed to be valid and
|
|
-** pointing to the same rowid when this function is called. This function
|
|
+** pointing to the same rowid when this function is called. This function
|
|
** checks if the current rowid really is a match, and if so populates
|
|
** the pPhrase->poslist buffer accordingly. Output parameter *pbMatch
|
|
** is set to true if this is really a match, or false otherwise.
|
|
**
|
|
-** SQLITE_OK is returned if an error occurs, or an SQLite error code
|
|
-** otherwise. It is not considered an error code if the current rowid is
|
|
+** SQLITE_OK is returned if an error occurs, or an SQLite error code
|
|
+** otherwise. It is not considered an error code if the current rowid is
|
|
** not a match.
|
|
*/
|
|
static int fts5ExprPhraseIsMatch(
|
|
@@ -211311,7 +227559,7 @@ static int fts5ExprPhraseIsMatch(
|
|
int i;
|
|
int rc = SQLITE_OK;
|
|
int bFirst = pPhrase->aTerm[0].bFirst;
|
|
-
|
|
+
|
|
fts5BufferZero(&pPhrase->poslist);
|
|
|
|
/* If the aStatic[] array is not large enough, allocate a large array
|
|
@@ -211433,7 +227681,7 @@ struct Fts5NearTrimmer {
|
|
** function is called, it is a no-op. Or, if an error (e.g. SQLITE_NOMEM)
|
|
** occurs within this function (*pRc) is set accordingly before returning.
|
|
** The return value is undefined in both these cases.
|
|
-**
|
|
+**
|
|
** If no error occurs and non-zero (a match) is returned, the position-list
|
|
** of each phrase object is edited to contain only those entries that
|
|
** meet the constraint before returning.
|
|
@@ -211465,7 +227713,7 @@ static int fts5ExprNearIsMatch(int *pRc, Fts5ExprNearset *pNear){
|
|
/* Initialize a lookahead iterator for each phrase. After passing the
|
|
** buffer and buffer size to the lookaside-reader init function, zero
|
|
** the phrase poslist buffer. The new poslist for the phrase (containing
|
|
- ** the same entries as the original with some entries removed on account
|
|
+ ** the same entries as the original with some entries removed on account
|
|
** of the NEAR constraint) is written over the original even as it is
|
|
** being read. This is safe as the entries for the new poslist are a
|
|
** subset of the old, so it is not possible for data yet to be read to
|
|
@@ -211622,7 +227870,7 @@ static int fts5ExprNearTest(
|
|
** phrase is not a match, break out of the loop early. */
|
|
for(i=0; rc==SQLITE_OK && i<pNear->nPhrase; i++){
|
|
Fts5ExprPhrase *pPhrase = pNear->apPhrase[i];
|
|
- if( pPhrase->nTerm>1 || pPhrase->aTerm[0].pSynonym
|
|
+ if( pPhrase->nTerm>1 || pPhrase->aTerm[0].pSynonym
|
|
|| pNear->pColset || pPhrase->aTerm[0].bFirst
|
|
){
|
|
int bMatch = 0;
|
|
@@ -211770,7 +228018,7 @@ static void fts5ExprNodeZeroPoslist(Fts5ExprNode *pNode){
|
|
*/
|
|
static int fts5NodeCompare(
|
|
Fts5Expr *pExpr,
|
|
- Fts5ExprNode *p1,
|
|
+ Fts5ExprNode *p1,
|
|
Fts5ExprNode *p2
|
|
){
|
|
if( p2->bEof ) return -1;
|
|
@@ -211785,7 +228033,7 @@ static int fts5NodeCompare(
|
|
** If an EOF is reached before this happens, *pbEof is set to true before
|
|
** returning.
|
|
**
|
|
-** SQLITE_OK is returned if an error occurs, or an SQLite error code
|
|
+** SQLITE_OK is returned if an error occurs, or an SQLite error code
|
|
** otherwise. It is not considered an error code if an iterator reaches
|
|
** EOF.
|
|
*/
|
|
@@ -211802,8 +228050,8 @@ static int fts5ExprNodeTest_STRING(
|
|
const int bDesc = pExpr->bDesc;
|
|
|
|
/* Check that this node should not be FTS5_TERM */
|
|
- assert( pNear->nPhrase>1
|
|
- || pNear->apPhrase[0]->nTerm>1
|
|
+ assert( pNear->nPhrase>1
|
|
+ || pNear->apPhrase[0]->nTerm>1
|
|
|| pNear->apPhrase[0]->aTerm[0].pSynonym
|
|
|| pNear->apPhrase[0]->aTerm[0].bFirst
|
|
);
|
|
@@ -211863,7 +228111,7 @@ static int fts5ExprNodeNext_STRING(
|
|
Fts5Expr *pExpr, /* Expression pPhrase belongs to */
|
|
Fts5ExprNode *pNode, /* FTS5_STRING or FTS5_TERM node */
|
|
int bFromValid,
|
|
- i64 iFrom
|
|
+ i64 iFrom
|
|
){
|
|
Fts5ExprTerm *pTerm = &pNode->pNear->apPhrase[0]->aTerm[0];
|
|
int rc = SQLITE_OK;
|
|
@@ -211881,8 +228129,8 @@ static int fts5ExprNodeNext_STRING(
|
|
for(p=pTerm; p; p=p->pSynonym){
|
|
if( sqlite3Fts5IterEof(p->pIter)==0 ){
|
|
i64 ii = p->pIter->iRowid;
|
|
- if( ii==iRowid
|
|
- || (bFromValid && ii!=iFrom && (ii>iFrom)==pExpr->bDesc)
|
|
+ if( ii==iRowid
|
|
+ || (bFromValid && ii!=iFrom && (ii>iFrom)==pExpr->bDesc)
|
|
){
|
|
if( bFromValid ){
|
|
rc = sqlite3Fts5IterNextFrom(p->pIter, iFrom);
|
|
@@ -211928,9 +228176,9 @@ static int fts5ExprNodeTest_TERM(
|
|
Fts5Expr *pExpr, /* Expression that pNear is a part of */
|
|
Fts5ExprNode *pNode /* The "NEAR" node (FTS5_TERM) */
|
|
){
|
|
- /* As this "NEAR" object is actually a single phrase that consists
|
|
+ /* As this "NEAR" object is actually a single phrase that consists
|
|
** of a single term only, grab pointers into the poslist managed by the
|
|
- ** fts5_index.c iterator object. This is much faster than synthesizing
|
|
+ ** fts5_index.c iterator object. This is much faster than synthesizing
|
|
** a new poslist the way we have to for more complicated phrase or NEAR
|
|
** expressions. */
|
|
Fts5ExprPhrase *pPhrase = pNode->pNear->apPhrase[0];
|
|
@@ -211953,7 +228201,7 @@ static int fts5ExprNodeTest_TERM(
|
|
** xNext() method for a node of type FTS5_TERM.
|
|
*/
|
|
static int fts5ExprNodeNext_TERM(
|
|
- Fts5Expr *pExpr,
|
|
+ Fts5Expr *pExpr,
|
|
Fts5ExprNode *pNode,
|
|
int bFromValid,
|
|
i64 iFrom
|
|
@@ -211996,7 +228244,7 @@ static void fts5ExprNodeTest_OR(
|
|
}
|
|
|
|
static int fts5ExprNodeNext_OR(
|
|
- Fts5Expr *pExpr,
|
|
+ Fts5Expr *pExpr,
|
|
Fts5ExprNode *pNode,
|
|
int bFromValid,
|
|
i64 iFrom
|
|
@@ -212008,7 +228256,7 @@ static int fts5ExprNodeNext_OR(
|
|
Fts5ExprNode *p1 = pNode->apChild[i];
|
|
assert( p1->bEof || fts5RowidCmp(pExpr, p1->iRowid, iLast)>=0 );
|
|
if( p1->bEof==0 ){
|
|
- if( (p1->iRowid==iLast)
|
|
+ if( (p1->iRowid==iLast)
|
|
|| (bFromValid && fts5RowidCmp(pExpr, p1->iRowid, iFrom)<0)
|
|
){
|
|
int rc = fts5ExprNodeNext(pExpr, p1, bFromValid, iFrom);
|
|
@@ -212080,7 +228328,7 @@ static int fts5ExprNodeTest_AND(
|
|
}
|
|
|
|
static int fts5ExprNodeNext_AND(
|
|
- Fts5Expr *pExpr,
|
|
+ Fts5Expr *pExpr,
|
|
Fts5ExprNode *pNode,
|
|
int bFromValid,
|
|
i64 iFrom
|
|
@@ -212123,7 +228371,7 @@ static int fts5ExprNodeTest_NOT(
|
|
}
|
|
|
|
static int fts5ExprNodeNext_NOT(
|
|
- Fts5Expr *pExpr,
|
|
+ Fts5Expr *pExpr,
|
|
Fts5ExprNode *pNode,
|
|
int bFromValid,
|
|
i64 iFrom
|
|
@@ -212180,7 +228428,7 @@ static int fts5ExprNodeTest(
|
|
return rc;
|
|
}
|
|
|
|
-
|
|
+
|
|
/*
|
|
** Set node pNode, which is part of expression pExpr, to point to the first
|
|
** match. If there are no matches, set the Node.bEof flag to indicate EOF.
|
|
@@ -212234,8 +228482,8 @@ static int fts5ExprNodeFirst(Fts5Expr *pExpr, Fts5ExprNode *pNode){
|
|
|
|
/*
|
|
** Begin iterating through the set of documents in index pIdx matched by
|
|
-** the MATCH expression passed as the first argument. If the "bDesc"
|
|
-** parameter is passed a non-zero value, iteration is in descending rowid
|
|
+** the MATCH expression passed as the first argument. If the "bDesc"
|
|
+** parameter is passed a non-zero value, iteration is in descending rowid
|
|
** order. Or, if it is zero, in ascending order.
|
|
**
|
|
** If iterating in ascending rowid order (bDesc==0), the first document
|
|
@@ -212257,23 +228505,23 @@ static int sqlite3Fts5ExprFirst(Fts5Expr *p, Fts5Index *pIdx, i64 iFirst, int bD
|
|
|
|
/* If not at EOF but the current rowid occurs earlier than iFirst in
|
|
** the iteration order, move to document iFirst or later. */
|
|
- if( rc==SQLITE_OK
|
|
- && 0==pRoot->bEof
|
|
- && fts5RowidCmp(p, pRoot->iRowid, iFirst)<0
|
|
+ if( rc==SQLITE_OK
|
|
+ && 0==pRoot->bEof
|
|
+ && fts5RowidCmp(p, pRoot->iRowid, iFirst)<0
|
|
){
|
|
rc = fts5ExprNodeNext(p, pRoot, 1, iFirst);
|
|
}
|
|
|
|
/* If the iterator is not at a real match, skip forward until it is. */
|
|
- while( pRoot->bNomatch ){
|
|
- assert( pRoot->bEof==0 && rc==SQLITE_OK );
|
|
+ while( pRoot->bNomatch && rc==SQLITE_OK ){
|
|
+ assert( pRoot->bEof==0 );
|
|
rc = fts5ExprNodeNext(p, pRoot, 0, 0);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
-** Move to the next document
|
|
+** Move to the next document
|
|
**
|
|
** Return SQLITE_OK if successful, or an SQLite error code otherwise. It
|
|
** is not considered an error if the query does not match any documents.
|
|
@@ -212390,6 +228638,9 @@ static Fts5ExprNearset *sqlite3Fts5ParseNearset(
|
|
}else{
|
|
if( pRet->nPhrase>0 ){
|
|
Fts5ExprPhrase *pLast = pRet->apPhrase[pRet->nPhrase-1];
|
|
+ assert( pParse!=0 );
|
|
+ assert( pParse->apPhrase!=0 );
|
|
+ assert( pParse->nPhrase>=2 );
|
|
assert( pLast==pParse->apPhrase[pParse->nPhrase-2] );
|
|
if( pPhrase->nTerm==0 ){
|
|
fts5ExprPhraseFree(pPhrase);
|
|
@@ -212455,7 +228706,7 @@ static int fts5ParseTokenize(
|
|
Fts5ExprPhrase *pNew;
|
|
int nNew = SZALLOC + (pPhrase ? pPhrase->nTerm : 0);
|
|
|
|
- pNew = (Fts5ExprPhrase*)sqlite3_realloc64(pPhrase,
|
|
+ pNew = (Fts5ExprPhrase*)sqlite3_realloc64(pPhrase,
|
|
sizeof(Fts5ExprPhrase) + sizeof(Fts5ExprTerm) * nNew
|
|
);
|
|
if( pNew==0 ){
|
|
@@ -212505,6 +228756,20 @@ static void sqlite3Fts5ParseFinished(Fts5Parse *pParse, Fts5ExprNode *p){
|
|
pParse->pExpr = p;
|
|
}
|
|
|
|
+static int parseGrowPhraseArray(Fts5Parse *pParse){
|
|
+ if( (pParse->nPhrase % 8)==0 ){
|
|
+ sqlite3_int64 nByte = sizeof(Fts5ExprPhrase*) * (pParse->nPhrase + 8);
|
|
+ Fts5ExprPhrase **apNew;
|
|
+ apNew = (Fts5ExprPhrase**)sqlite3_realloc64(pParse->apPhrase, nByte);
|
|
+ if( apNew==0 ){
|
|
+ pParse->rc = SQLITE_NOMEM;
|
|
+ return SQLITE_NOMEM;
|
|
+ }
|
|
+ pParse->apPhrase = apNew;
|
|
+ }
|
|
+ return SQLITE_OK;
|
|
+}
|
|
+
|
|
/*
|
|
** This function is called by the parser to process a string token. The
|
|
** string may or may not be quoted. In any case it is tokenized and a
|
|
@@ -212540,16 +228805,9 @@ static Fts5ExprPhrase *sqlite3Fts5ParseTerm(
|
|
}else{
|
|
|
|
if( pAppend==0 ){
|
|
- if( (pParse->nPhrase % 8)==0 ){
|
|
- sqlite3_int64 nByte = sizeof(Fts5ExprPhrase*) * (pParse->nPhrase + 8);
|
|
- Fts5ExprPhrase **apNew;
|
|
- apNew = (Fts5ExprPhrase**)sqlite3_realloc64(pParse->apPhrase, nByte);
|
|
- if( apNew==0 ){
|
|
- pParse->rc = SQLITE_NOMEM;
|
|
- fts5ExprPhraseFree(sCtx.pPhrase);
|
|
- return 0;
|
|
- }
|
|
- pParse->apPhrase = apNew;
|
|
+ if( parseGrowPhraseArray(pParse) ){
|
|
+ fts5ExprPhraseFree(sCtx.pPhrase);
|
|
+ return 0;
|
|
}
|
|
pParse->nPhrase++;
|
|
}
|
|
@@ -212572,8 +228830,8 @@ static Fts5ExprPhrase *sqlite3Fts5ParseTerm(
|
|
** expression passed as the second argument.
|
|
*/
|
|
static int sqlite3Fts5ExprClonePhrase(
|
|
- Fts5Expr *pExpr,
|
|
- int iPhrase,
|
|
+ Fts5Expr *pExpr,
|
|
+ int iPhrase,
|
|
Fts5Expr **ppNew
|
|
){
|
|
int rc = SQLITE_OK; /* Return code */
|
|
@@ -212584,15 +228842,15 @@ static int sqlite3Fts5ExprClonePhrase(
|
|
pOrig = pExpr->apExprPhrase[iPhrase];
|
|
pNew = (Fts5Expr*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Expr));
|
|
if( rc==SQLITE_OK ){
|
|
- pNew->apExprPhrase = (Fts5ExprPhrase**)sqlite3Fts5MallocZero(&rc,
|
|
+ pNew->apExprPhrase = (Fts5ExprPhrase**)sqlite3Fts5MallocZero(&rc,
|
|
sizeof(Fts5ExprPhrase*));
|
|
}
|
|
if( rc==SQLITE_OK ){
|
|
- pNew->pRoot = (Fts5ExprNode*)sqlite3Fts5MallocZero(&rc,
|
|
+ pNew->pRoot = (Fts5ExprNode*)sqlite3Fts5MallocZero(&rc,
|
|
sizeof(Fts5ExprNode));
|
|
}
|
|
if( rc==SQLITE_OK ){
|
|
- pNew->pRoot->pNear = (Fts5ExprNearset*)sqlite3Fts5MallocZero(&rc,
|
|
+ pNew->pRoot->pNear = (Fts5ExprNearset*)sqlite3Fts5MallocZero(&rc,
|
|
sizeof(Fts5ExprNearset) + sizeof(Fts5ExprPhrase*));
|
|
}
|
|
if( rc==SQLITE_OK ){
|
|
@@ -212602,7 +228860,7 @@ static int sqlite3Fts5ExprClonePhrase(
|
|
Fts5Colset *pColset;
|
|
nByte = sizeof(Fts5Colset) + (pColsetOrig->nCol-1) * sizeof(int);
|
|
pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&rc, nByte);
|
|
- if( pColset ){
|
|
+ if( pColset ){
|
|
memcpy(pColset, pColsetOrig, (size_t)nByte);
|
|
}
|
|
pNew->pRoot->pNear->pColset = pColset;
|
|
@@ -212631,7 +228889,7 @@ static int sqlite3Fts5ExprClonePhrase(
|
|
sCtx.pPhrase = sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprPhrase));
|
|
}
|
|
|
|
- if( rc==SQLITE_OK ){
|
|
+ if( rc==SQLITE_OK && ALWAYS(sCtx.pPhrase) ){
|
|
/* All the allocations succeeded. Put the expression object together. */
|
|
pNew->pIndex = pExpr->pIndex;
|
|
pNew->pConfig = pExpr->pConfig;
|
|
@@ -212641,9 +228899,9 @@ static int sqlite3Fts5ExprClonePhrase(
|
|
pNew->pRoot->pNear->nPhrase = 1;
|
|
sCtx.pPhrase->pNode = pNew->pRoot;
|
|
|
|
- if( pOrig->nTerm==1
|
|
- && pOrig->aTerm[0].pSynonym==0
|
|
- && pOrig->aTerm[0].bFirst==0
|
|
+ if( pOrig->nTerm==1
|
|
+ && pOrig->aTerm[0].pSynonym==0
|
|
+ && pOrig->aTerm[0].bFirst==0
|
|
){
|
|
pNew->pRoot->eType = FTS5_TERM;
|
|
pNew->pRoot->xNext = fts5ExprNodeNext_TERM;
|
|
@@ -212676,7 +228934,7 @@ static void sqlite3Fts5ParseNear(Fts5Parse *pParse, Fts5Token *pTok){
|
|
}
|
|
|
|
static void sqlite3Fts5ParseSetDistance(
|
|
- Fts5Parse *pParse,
|
|
+ Fts5Parse *pParse,
|
|
Fts5ExprNearset *pNear,
|
|
Fts5Token *p
|
|
){
|
|
@@ -212705,7 +228963,7 @@ static void sqlite3Fts5ParseSetDistance(
|
|
** The second argument passed to this function may be NULL, or it may be
|
|
** an existing Fts5Colset object. This function returns a pointer to
|
|
** a new colset object containing the contents of (p) with new value column
|
|
-** number iCol appended.
|
|
+** number iCol appended.
|
|
**
|
|
** If an OOM error occurs, store an error code in pParse and return NULL.
|
|
** The old colset object (if any) is not freed in this case.
|
|
@@ -212755,7 +229013,7 @@ static Fts5Colset *sqlite3Fts5ParseColsetInvert(Fts5Parse *pParse, Fts5Colset *p
|
|
Fts5Colset *pRet;
|
|
int nCol = pParse->pConfig->nCol;
|
|
|
|
- pRet = (Fts5Colset*)sqlite3Fts5MallocZero(&pParse->rc,
|
|
+ pRet = (Fts5Colset*)sqlite3Fts5MallocZero(&pParse->rc,
|
|
sizeof(Fts5Colset) + sizeof(int)*nCol
|
|
);
|
|
if( pRet ){
|
|
@@ -212808,7 +229066,7 @@ static Fts5Colset *sqlite3Fts5ParseColset(
|
|
|
|
/*
|
|
** If argument pOrig is NULL, or if (*pRc) is set to anything other than
|
|
-** SQLITE_OK when this function is called, NULL is returned.
|
|
+** SQLITE_OK when this function is called, NULL is returned.
|
|
**
|
|
** Otherwise, a copy of (*pOrig) is made into memory obtained from
|
|
** sqlite3Fts5MallocZero() and a pointer to it returned. If the allocation
|
|
@@ -212819,7 +229077,7 @@ static Fts5Colset *fts5CloneColset(int *pRc, Fts5Colset *pOrig){
|
|
if( pOrig ){
|
|
sqlite3_int64 nByte = sizeof(Fts5Colset) + (pOrig->nCol-1) * sizeof(int);
|
|
pRet = (Fts5Colset*)sqlite3Fts5MallocZero(pRc, nByte);
|
|
- if( pRet ){
|
|
+ if( pRet ){
|
|
memcpy(pRet, pOrig, (size_t)nByte);
|
|
}
|
|
}else{
|
|
@@ -212858,13 +229116,13 @@ static void fts5MergeColset(Fts5Colset *pColset, Fts5Colset *pMerge){
|
|
** zero, or it may create copies of pColset using fts5CloneColset().
|
|
*/
|
|
static void fts5ParseSetColset(
|
|
- Fts5Parse *pParse,
|
|
- Fts5ExprNode *pNode,
|
|
+ Fts5Parse *pParse,
|
|
+ Fts5ExprNode *pNode,
|
|
Fts5Colset *pColset,
|
|
Fts5Colset **ppFree
|
|
){
|
|
if( pParse->rc==SQLITE_OK ){
|
|
- assert( pNode->eType==FTS5_TERM || pNode->eType==FTS5_STRING
|
|
+ assert( pNode->eType==FTS5_TERM || pNode->eType==FTS5_STRING
|
|
|| pNode->eType==FTS5_AND || pNode->eType==FTS5_OR
|
|
|| pNode->eType==FTS5_NOT || pNode->eType==FTS5_EOF
|
|
);
|
|
@@ -212896,15 +229154,14 @@ static void fts5ParseSetColset(
|
|
** Apply colset pColset to expression node pExpr and all of its descendents.
|
|
*/
|
|
static void sqlite3Fts5ParseSetColset(
|
|
- Fts5Parse *pParse,
|
|
- Fts5ExprNode *pExpr,
|
|
- Fts5Colset *pColset
|
|
+ Fts5Parse *pParse,
|
|
+ Fts5ExprNode *pExpr,
|
|
+ Fts5Colset *pColset
|
|
){
|
|
Fts5Colset *pFree = pColset;
|
|
if( pParse->pConfig->eDetail==FTS5_DETAIL_NONE ){
|
|
- pParse->rc = SQLITE_ERROR;
|
|
- pParse->zErr = sqlite3_mprintf(
|
|
- "fts5: column queries are not supported (detail=none)"
|
|
+ sqlite3Fts5ParseError(pParse,
|
|
+ "fts5: column queries are not supported (detail=none)"
|
|
);
|
|
}else{
|
|
fts5ParseSetColset(pParse, pExpr, pColset, &pFree);
|
|
@@ -212916,7 +229173,7 @@ static void fts5ExprAssignXNext(Fts5ExprNode *pNode){
|
|
switch( pNode->eType ){
|
|
case FTS5_STRING: {
|
|
Fts5ExprNearset *pNear = pNode->pNear;
|
|
- if( pNear->nPhrase==1 && pNear->apPhrase[0]->nTerm==1
|
|
+ if( pNear->nPhrase==1 && pNear->apPhrase[0]->nTerm==1
|
|
&& pNear->apPhrase[0]->aTerm[0].pSynonym==0
|
|
&& pNear->apPhrase[0]->aTerm[0].bFirst==0
|
|
){
|
|
@@ -212956,6 +229213,67 @@ static void fts5ExprAddChildren(Fts5ExprNode *p, Fts5ExprNode *pSub){
|
|
}
|
|
}
|
|
|
|
+/*
|
|
+** This function is used when parsing LIKE or GLOB patterns against
|
|
+** trigram indexes that specify either detail=column or detail=none.
|
|
+** It converts a phrase:
|
|
+**
|
|
+** abc + def + ghi
|
|
+**
|
|
+** into an AND tree:
|
|
+**
|
|
+** abc AND def AND ghi
|
|
+*/
|
|
+static Fts5ExprNode *fts5ParsePhraseToAnd(
|
|
+ Fts5Parse *pParse,
|
|
+ Fts5ExprNearset *pNear
|
|
+){
|
|
+ int nTerm = pNear->apPhrase[0]->nTerm;
|
|
+ int ii;
|
|
+ int nByte;
|
|
+ Fts5ExprNode *pRet;
|
|
+
|
|
+ assert( pNear->nPhrase==1 );
|
|
+ assert( pParse->bPhraseToAnd );
|
|
+
|
|
+ nByte = sizeof(Fts5ExprNode) + nTerm*sizeof(Fts5ExprNode*);
|
|
+ pRet = (Fts5ExprNode*)sqlite3Fts5MallocZero(&pParse->rc, nByte);
|
|
+ if( pRet ){
|
|
+ pRet->eType = FTS5_AND;
|
|
+ pRet->nChild = nTerm;
|
|
+ fts5ExprAssignXNext(pRet);
|
|
+ pParse->nPhrase--;
|
|
+ for(ii=0; ii<nTerm; ii++){
|
|
+ Fts5ExprPhrase *pPhrase = (Fts5ExprPhrase*)sqlite3Fts5MallocZero(
|
|
+ &pParse->rc, sizeof(Fts5ExprPhrase)
|
|
+ );
|
|
+ if( pPhrase ){
|
|
+ if( parseGrowPhraseArray(pParse) ){
|
|
+ fts5ExprPhraseFree(pPhrase);
|
|
+ }else{
|
|
+ pParse->apPhrase[pParse->nPhrase++] = pPhrase;
|
|
+ pPhrase->nTerm = 1;
|
|
+ pPhrase->aTerm[0].zTerm = sqlite3Fts5Strndup(
|
|
+ &pParse->rc, pNear->apPhrase[0]->aTerm[ii].zTerm, -1
|
|
+ );
|
|
+ pRet->apChild[ii] = sqlite3Fts5ParseNode(pParse, FTS5_STRING,
|
|
+ 0, 0, sqlite3Fts5ParseNearset(pParse, 0, pPhrase)
|
|
+ );
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if( pParse->rc ){
|
|
+ sqlite3Fts5ParseNodeFree(pRet);
|
|
+ pRet = 0;
|
|
+ }else{
|
|
+ sqlite3Fts5ParseNearsetFree(pNear);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return pRet;
|
|
+}
|
|
+
|
|
/*
|
|
** Allocate and return a new expression object. If anything goes wrong (i.e.
|
|
** OOM error), leave an error code in pParse and return NULL.
|
|
@@ -212972,7 +229290,7 @@ static Fts5ExprNode *sqlite3Fts5ParseNode(
|
|
if( pParse->rc==SQLITE_OK ){
|
|
int nChild = 0; /* Number of children of returned node */
|
|
sqlite3_int64 nByte; /* Bytes of space to allocate for this node */
|
|
-
|
|
+
|
|
assert( (eType!=FTS5_STRING && !pNear)
|
|
|| (eType==FTS5_STRING && !pLeft && !pRight)
|
|
);
|
|
@@ -212980,51 +229298,55 @@ static Fts5ExprNode *sqlite3Fts5ParseNode(
|
|
if( eType!=FTS5_STRING && pLeft==0 ) return pRight;
|
|
if( eType!=FTS5_STRING && pRight==0 ) return pLeft;
|
|
|
|
- if( eType==FTS5_NOT ){
|
|
- nChild = 2;
|
|
- }else if( eType==FTS5_AND || eType==FTS5_OR ){
|
|
- nChild = 2;
|
|
- if( pLeft->eType==eType ) nChild += pLeft->nChild-1;
|
|
- if( pRight->eType==eType ) nChild += pRight->nChild-1;
|
|
- }
|
|
+ if( eType==FTS5_STRING
|
|
+ && pParse->bPhraseToAnd
|
|
+ && pNear->apPhrase[0]->nTerm>1
|
|
+ ){
|
|
+ pRet = fts5ParsePhraseToAnd(pParse, pNear);
|
|
+ }else{
|
|
+ if( eType==FTS5_NOT ){
|
|
+ nChild = 2;
|
|
+ }else if( eType==FTS5_AND || eType==FTS5_OR ){
|
|
+ nChild = 2;
|
|
+ if( pLeft->eType==eType ) nChild += pLeft->nChild-1;
|
|
+ if( pRight->eType==eType ) nChild += pRight->nChild-1;
|
|
+ }
|
|
|
|
- nByte = sizeof(Fts5ExprNode) + sizeof(Fts5ExprNode*)*(nChild-1);
|
|
- pRet = (Fts5ExprNode*)sqlite3Fts5MallocZero(&pParse->rc, nByte);
|
|
+ nByte = sizeof(Fts5ExprNode) + sizeof(Fts5ExprNode*)*(nChild-1);
|
|
+ pRet = (Fts5ExprNode*)sqlite3Fts5MallocZero(&pParse->rc, nByte);
|
|
|
|
- if( pRet ){
|
|
- pRet->eType = eType;
|
|
- pRet->pNear = pNear;
|
|
- fts5ExprAssignXNext(pRet);
|
|
- if( eType==FTS5_STRING ){
|
|
- int iPhrase;
|
|
- for(iPhrase=0; iPhrase<pNear->nPhrase; iPhrase++){
|
|
- pNear->apPhrase[iPhrase]->pNode = pRet;
|
|
- if( pNear->apPhrase[iPhrase]->nTerm==0 ){
|
|
- pRet->xNext = 0;
|
|
- pRet->eType = FTS5_EOF;
|
|
+ if( pRet ){
|
|
+ pRet->eType = eType;
|
|
+ pRet->pNear = pNear;
|
|
+ fts5ExprAssignXNext(pRet);
|
|
+ if( eType==FTS5_STRING ){
|
|
+ int iPhrase;
|
|
+ for(iPhrase=0; iPhrase<pNear->nPhrase; iPhrase++){
|
|
+ pNear->apPhrase[iPhrase]->pNode = pRet;
|
|
+ if( pNear->apPhrase[iPhrase]->nTerm==0 ){
|
|
+ pRet->xNext = 0;
|
|
+ pRet->eType = FTS5_EOF;
|
|
+ }
|
|
}
|
|
- }
|
|
|
|
- if( pParse->pConfig->eDetail!=FTS5_DETAIL_FULL ){
|
|
- Fts5ExprPhrase *pPhrase = pNear->apPhrase[0];
|
|
- if( pNear->nPhrase!=1
|
|
- || pPhrase->nTerm>1
|
|
- || (pPhrase->nTerm>0 && pPhrase->aTerm[0].bFirst)
|
|
- ){
|
|
- assert( pParse->rc==SQLITE_OK );
|
|
- pParse->rc = SQLITE_ERROR;
|
|
- assert( pParse->zErr==0 );
|
|
- pParse->zErr = sqlite3_mprintf(
|
|
- "fts5: %s queries are not supported (detail!=full)",
|
|
- pNear->nPhrase==1 ? "phrase": "NEAR"
|
|
- );
|
|
- sqlite3_free(pRet);
|
|
- pRet = 0;
|
|
+ if( pParse->pConfig->eDetail!=FTS5_DETAIL_FULL ){
|
|
+ Fts5ExprPhrase *pPhrase = pNear->apPhrase[0];
|
|
+ if( pNear->nPhrase!=1
|
|
+ || pPhrase->nTerm>1
|
|
+ || (pPhrase->nTerm>0 && pPhrase->aTerm[0].bFirst)
|
|
+ ){
|
|
+ sqlite3Fts5ParseError(pParse,
|
|
+ "fts5: %s queries are not supported (detail!=full)",
|
|
+ pNear->nPhrase==1 ? "phrase": "NEAR"
|
|
+ );
|
|
+ sqlite3_free(pRet);
|
|
+ pRet = 0;
|
|
+ }
|
|
}
|
|
+ }else{
|
|
+ fts5ExprAddChildren(pRet, pLeft);
|
|
+ fts5ExprAddChildren(pRet, pRight);
|
|
}
|
|
- }else{
|
|
- fts5ExprAddChildren(pRet, pLeft);
|
|
- fts5ExprAddChildren(pRet, pRight);
|
|
}
|
|
}
|
|
}
|
|
@@ -213051,14 +229373,14 @@ static Fts5ExprNode *sqlite3Fts5ParseImplicitAnd(
|
|
sqlite3Fts5ParseNodeFree(pRight);
|
|
}else{
|
|
|
|
- assert( pLeft->eType==FTS5_STRING
|
|
+ assert( pLeft->eType==FTS5_STRING
|
|
|| pLeft->eType==FTS5_TERM
|
|
|| pLeft->eType==FTS5_EOF
|
|
|| pLeft->eType==FTS5_AND
|
|
);
|
|
- assert( pRight->eType==FTS5_STRING
|
|
- || pRight->eType==FTS5_TERM
|
|
- || pRight->eType==FTS5_EOF
|
|
+ assert( pRight->eType==FTS5_STRING
|
|
+ || pRight->eType==FTS5_TERM
|
|
+ || pRight->eType==FTS5_EOF
|
|
);
|
|
|
|
if( pLeft->eType==FTS5_AND ){
|
|
@@ -213066,9 +229388,9 @@ static Fts5ExprNode *sqlite3Fts5ParseImplicitAnd(
|
|
}else{
|
|
pPrev = pLeft;
|
|
}
|
|
- assert( pPrev->eType==FTS5_STRING
|
|
- || pPrev->eType==FTS5_TERM
|
|
- || pPrev->eType==FTS5_EOF
|
|
+ assert( pPrev->eType==FTS5_STRING
|
|
+ || pPrev->eType==FTS5_TERM
|
|
+ || pPrev->eType==FTS5_EOF
|
|
);
|
|
|
|
if( pRight->eType==FTS5_EOF ){
|
|
@@ -213102,6 +229424,7 @@ static Fts5ExprNode *sqlite3Fts5ParseImplicitAnd(
|
|
return pRet;
|
|
}
|
|
|
|
+#ifdef SQLITE_TEST
|
|
static char *fts5ExprTermPrint(Fts5ExprTerm *pTerm){
|
|
sqlite3_int64 nByte = 0;
|
|
Fts5ExprTerm *p;
|
|
@@ -213150,20 +229473,20 @@ static char *fts5PrintfAppend(char *zApp, const char *zFmt, ...){
|
|
}
|
|
|
|
/*
|
|
-** Compose a tcl-readable representation of expression pExpr. Return a
|
|
-** pointer to a buffer containing that representation. It is the
|
|
-** responsibility of the caller to at some point free the buffer using
|
|
+** Compose a tcl-readable representation of expression pExpr. Return a
|
|
+** pointer to a buffer containing that representation. It is the
|
|
+** responsibility of the caller to at some point free the buffer using
|
|
** sqlite3_free().
|
|
*/
|
|
static char *fts5ExprPrintTcl(
|
|
- Fts5Config *pConfig,
|
|
+ Fts5Config *pConfig,
|
|
const char *zNearsetCmd,
|
|
Fts5ExprNode *pExpr
|
|
){
|
|
char *zRet = 0;
|
|
if( pExpr->eType==FTS5_STRING || pExpr->eType==FTS5_TERM ){
|
|
Fts5ExprNearset *pNear = pExpr->pNear;
|
|
- int i;
|
|
+ int i;
|
|
int iTerm;
|
|
|
|
zRet = fts5PrintfAppend(zRet, "%s ", zNearsetCmd);
|
|
@@ -213213,9 +229536,9 @@ static char *fts5ExprPrintTcl(
|
|
switch( pExpr->eType ){
|
|
case FTS5_AND: zOp = "AND"; break;
|
|
case FTS5_NOT: zOp = "NOT"; break;
|
|
- default:
|
|
+ default:
|
|
assert( pExpr->eType==FTS5_OR );
|
|
- zOp = "OR";
|
|
+ zOp = "OR";
|
|
break;
|
|
}
|
|
|
|
@@ -213241,12 +229564,21 @@ static char *fts5ExprPrint(Fts5Config *pConfig, Fts5ExprNode *pExpr){
|
|
}else
|
|
if( pExpr->eType==FTS5_STRING || pExpr->eType==FTS5_TERM ){
|
|
Fts5ExprNearset *pNear = pExpr->pNear;
|
|
- int i;
|
|
+ int i;
|
|
int iTerm;
|
|
|
|
if( pNear->pColset ){
|
|
- int iCol = pNear->pColset->aiCol[0];
|
|
- zRet = fts5PrintfAppend(zRet, "%s : ", pConfig->azCol[iCol]);
|
|
+ int ii;
|
|
+ Fts5Colset *pColset = pNear->pColset;
|
|
+ if( pColset->nCol>1 ) zRet = fts5PrintfAppend(zRet, "{");
|
|
+ for(ii=0; ii<pColset->nCol; ii++){
|
|
+ zRet = fts5PrintfAppend(zRet, "%s%s",
|
|
+ pConfig->azCol[pColset->aiCol[ii]], ii==pColset->nCol-1 ? "" : " "
|
|
+ );
|
|
+ }
|
|
+ if( zRet ){
|
|
+ zRet = fts5PrintfAppend(zRet, "%s : ", pColset->nCol>1 ? "}" : "");
|
|
+ }
|
|
if( zRet==0 ) return 0;
|
|
}
|
|
|
|
@@ -213286,9 +229618,9 @@ static char *fts5ExprPrint(Fts5Config *pConfig, Fts5ExprNode *pExpr){
|
|
switch( pExpr->eType ){
|
|
case FTS5_AND: zOp = " AND "; break;
|
|
case FTS5_NOT: zOp = " NOT "; break;
|
|
- default:
|
|
+ default:
|
|
assert( pExpr->eType==FTS5_OR );
|
|
- zOp = " OR ";
|
|
+ zOp = " OR ";
|
|
break;
|
|
}
|
|
|
|
@@ -213300,7 +229632,7 @@ static char *fts5ExprPrint(Fts5Config *pConfig, Fts5ExprNode *pExpr){
|
|
}else{
|
|
int e = pExpr->apChild[i]->eType;
|
|
int b = (e!=FTS5_STRING && e!=FTS5_TERM && e!=FTS5_EOF);
|
|
- zRet = fts5PrintfAppend(zRet, "%s%s%z%s",
|
|
+ zRet = fts5PrintfAppend(zRet, "%s%s%z%s",
|
|
(i==0 ? "" : zOp),
|
|
(b?"(":""), z, (b?")":"")
|
|
);
|
|
@@ -213369,7 +229701,7 @@ static void fts5ExprFunction(
|
|
|
|
rc = sqlite3Fts5ConfigParse(pGlobal, db, nConfig, azConfig, &pConfig, &zErr);
|
|
if( rc==SQLITE_OK ){
|
|
- rc = sqlite3Fts5ExprNew(pConfig, pConfig->nCol, zExpr, &pExpr, &zErr);
|
|
+ rc = sqlite3Fts5ExprNew(pConfig, 0, pConfig->nCol, zExpr, &pExpr, &zErr);
|
|
}
|
|
if( rc==SQLITE_OK ){
|
|
char *zText;
|
|
@@ -213418,7 +229750,7 @@ static void fts5ExprFunctionTcl(
|
|
|
|
/*
|
|
** The implementation of an SQLite user-defined-function that accepts a
|
|
-** single integer as an argument. If the integer is an alpha-numeric
|
|
+** single integer as an argument. If the integer is an alpha-numeric
|
|
** unicode code point, 1 is returned. Otherwise 0.
|
|
*/
|
|
static void fts5ExprIsAlnum(
|
|
@@ -213429,7 +229761,7 @@ static void fts5ExprIsAlnum(
|
|
int iCode;
|
|
u8 aArr[32];
|
|
if( nArg!=1 ){
|
|
- sqlite3_result_error(pCtx,
|
|
+ sqlite3_result_error(pCtx,
|
|
"wrong number of arguments to function fts5_isalnum", -1
|
|
);
|
|
return;
|
|
@@ -213448,7 +229780,7 @@ static void fts5ExprFold(
|
|
sqlite3_value **apVal /* Function arguments */
|
|
){
|
|
if( nArg!=1 && nArg!=2 ){
|
|
- sqlite3_result_error(pCtx,
|
|
+ sqlite3_result_error(pCtx,
|
|
"wrong number of arguments to function fts5_fold", -1
|
|
);
|
|
}else{
|
|
@@ -213459,12 +229791,14 @@ static void fts5ExprFold(
|
|
sqlite3_result_int(pCtx, sqlite3Fts5UnicodeFold(iCode, bRemoveDiacritics));
|
|
}
|
|
}
|
|
+#endif /* ifdef SQLITE_TEST */
|
|
|
|
/*
|
|
** This is called during initialization to register the fts5_expr() scalar
|
|
** UDF with the SQLite handle passed as the only argument.
|
|
*/
|
|
static int sqlite3Fts5ExprInit(Fts5Global *pGlobal, sqlite3 *db){
|
|
+#ifdef SQLITE_TEST
|
|
struct Fts5ExprFunc {
|
|
const char *z;
|
|
void (*x)(sqlite3_context*,int,sqlite3_value**);
|
|
@@ -213482,6 +229816,10 @@ static int sqlite3Fts5ExprInit(Fts5Global *pGlobal, sqlite3 *db){
|
|
struct Fts5ExprFunc *p = &aFunc[i];
|
|
rc = sqlite3_create_function(db, p->z, -1, SQLITE_UTF8, pCtx, p->x, 0, 0);
|
|
}
|
|
+#else
|
|
+ int rc = SQLITE_OK;
|
|
+ UNUSED_PARAM2(pGlobal,db);
|
|
+#endif
|
|
|
|
/* Avoid warnings indicating that sqlite3Fts5ParserTrace() and
|
|
** sqlite3Fts5ParserFallback() are unused */
|
|
@@ -213532,6 +229870,15 @@ struct Fts5PoslistPopulator {
|
|
int bMiss;
|
|
};
|
|
|
|
+/*
|
|
+** Clear the position lists associated with all phrases in the expression
|
|
+** passed as the first argument. Argument bLive is true if the expression
|
|
+** might be pointing to a real entry, otherwise it has just been reset.
|
|
+**
|
|
+** At present this function is only used for detail=col and detail=none
|
|
+** fts5 tables. This implies that all phrases must be at most 1 token
|
|
+** in size, as phrase matches are not supported without detail=full.
|
|
+*/
|
|
static Fts5PoslistPopulator *sqlite3Fts5ExprClearPoslists(Fts5Expr *pExpr, int bLive){
|
|
Fts5PoslistPopulator *pRet;
|
|
pRet = sqlite3_malloc64(sizeof(Fts5PoslistPopulator)*pExpr->nPhrase);
|
|
@@ -213541,8 +229888,8 @@ static Fts5PoslistPopulator *sqlite3Fts5ExprClearPoslists(Fts5Expr *pExpr, int b
|
|
for(i=0; i<pExpr->nPhrase; i++){
|
|
Fts5Buffer *pBuf = &pExpr->apExprPhrase[i]->poslist;
|
|
Fts5ExprNode *pNode = pExpr->apExprPhrase[i]->pNode;
|
|
- assert( pExpr->apExprPhrase[i]->nTerm==1 );
|
|
- if( bLive &&
|
|
+ assert( pExpr->apExprPhrase[i]->nTerm<=1 );
|
|
+ if( bLive &&
|
|
(pBuf->n==0 || pNode->iRowid!=pExpr->pRoot->iRowid || pNode->bEof)
|
|
){
|
|
pRet[i].bMiss = 1;
|
|
@@ -213609,9 +229956,9 @@ static int fts5ExprPopulatePoslistsCb(
|
|
|
|
static int sqlite3Fts5ExprPopulatePoslists(
|
|
Fts5Config *pConfig,
|
|
- Fts5Expr *pExpr,
|
|
+ Fts5Expr *pExpr,
|
|
Fts5PoslistPopulator *aPopulator,
|
|
- int iCol,
|
|
+ int iCol,
|
|
const char *z, int n
|
|
){
|
|
int i;
|
|
@@ -213623,7 +229970,7 @@ static int sqlite3Fts5ExprPopulatePoslists(
|
|
for(i=0; i<pExpr->nPhrase; i++){
|
|
Fts5ExprNode *pNode = pExpr->apExprPhrase[i]->pNode;
|
|
Fts5Colset *pColset = pNode->pNear->pColset;
|
|
- if( (pColset && 0==fts5ExprColsetTest(pColset, iCol))
|
|
+ if( (pColset && 0==fts5ExprColsetTest(pColset, iCol))
|
|
|| aPopulator[i].bMiss
|
|
){
|
|
aPopulator[i].bOk = 0;
|
|
@@ -213632,7 +229979,7 @@ static int sqlite3Fts5ExprPopulatePoslists(
|
|
}
|
|
}
|
|
|
|
- return sqlite3Fts5Tokenize(pConfig,
|
|
+ return sqlite3Fts5Tokenize(pConfig,
|
|
FTS5_TOKENIZE_DOCUMENT, z, n, (void*)&sCtx, fts5ExprPopulatePoslistsCb
|
|
);
|
|
}
|
|
@@ -213697,12 +230044,12 @@ static void sqlite3Fts5ExprCheckPoslists(Fts5Expr *pExpr, i64 iRowid){
|
|
}
|
|
|
|
/*
|
|
-** This function is only called for detail=columns tables.
|
|
+** This function is only called for detail=columns tables.
|
|
*/
|
|
static int sqlite3Fts5ExprPhraseCollist(
|
|
- Fts5Expr *pExpr,
|
|
- int iPhrase,
|
|
- const u8 **ppCollist,
|
|
+ Fts5Expr *pExpr,
|
|
+ int iPhrase,
|
|
+ const u8 **ppCollist,
|
|
int *pnCollist
|
|
){
|
|
Fts5ExprPhrase *pPhrase = pExpr->apExprPhrase[iPhrase];
|
|
@@ -213712,8 +230059,8 @@ static int sqlite3Fts5ExprPhraseCollist(
|
|
assert( iPhrase>=0 && iPhrase<pExpr->nPhrase );
|
|
assert( pExpr->pConfig->eDetail==FTS5_DETAIL_COLUMNS );
|
|
|
|
- if( pNode->bEof==0
|
|
- && pNode->iRowid==pExpr->pRoot->iRowid
|
|
+ if( pNode->bEof==0
|
|
+ && pNode->iRowid==pExpr->pRoot->iRowid
|
|
&& pPhrase->poslist.n>0
|
|
){
|
|
Fts5ExprTerm *pTerm = &pPhrase->aTerm[0];
|
|
@@ -213771,9 +230118,9 @@ struct Fts5Hash {
|
|
};
|
|
|
|
/*
|
|
-** Each entry in the hash table is represented by an object of the
|
|
-** following type. Each object, its key (a nul-terminated string) and
|
|
-** its current data are stored in a single memory allocation. The
|
|
+** Each entry in the hash table is represented by an object of the
|
|
+** following type. Each object, its key (a nul-terminated string) and
|
|
+** its current data are stored in a single memory allocation. The
|
|
** key immediately follows the object in memory. The position list
|
|
** data immediately follows the key data in memory.
|
|
**
|
|
@@ -213795,7 +230142,7 @@ struct Fts5Hash {
|
|
struct Fts5HashEntry {
|
|
Fts5HashEntry *pHashNext; /* Next hash entry with same hash-key */
|
|
Fts5HashEntry *pScanNext; /* Next entry in sorted order */
|
|
-
|
|
+
|
|
int nAlloc; /* Total size of allocation */
|
|
int iSzPoslist; /* Offset of space for 4-byte poslist size */
|
|
int nData; /* Total bytes of data (incl. structure) */
|
|
@@ -213924,7 +230271,7 @@ static int fts5HashResize(Fts5Hash *pHash){
|
|
}
|
|
|
|
static int fts5HashAddPoslistSize(
|
|
- Fts5Hash *pHash,
|
|
+ Fts5Hash *pHash,
|
|
Fts5HashEntry *p,
|
|
Fts5HashEntry *p2
|
|
){
|
|
@@ -213987,16 +230334,16 @@ static int sqlite3Fts5HashWrite(
|
|
u8 *pPtr;
|
|
int nIncr = 0; /* Amount to increment (*pHash->pnByte) by */
|
|
int bNew; /* If non-delete entry should be written */
|
|
-
|
|
+
|
|
bNew = (pHash->eDetail==FTS5_DETAIL_FULL);
|
|
|
|
/* Attempt to locate an existing hash entry */
|
|
iHash = fts5HashKey2(pHash->nSlot, (u8)bByte, (const u8*)pToken, nToken);
|
|
for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){
|
|
char *zKey = fts5EntryKey(p);
|
|
- if( zKey[0]==bByte
|
|
+ if( zKey[0]==bByte
|
|
&& p->nKey==nToken
|
|
- && memcmp(&zKey[1], pToken, nToken)==0
|
|
+ && memcmp(&zKey[1], pToken, nToken)==0
|
|
){
|
|
break;
|
|
}
|
|
@@ -214042,11 +230389,10 @@ static int sqlite3Fts5HashWrite(
|
|
p->iCol = (pHash->eDetail==FTS5_DETAIL_FULL ? 0 : -1);
|
|
}
|
|
|
|
- nIncr += p->nData;
|
|
}else{
|
|
|
|
- /* Appending to an existing hash-entry. Check that there is enough
|
|
- ** space to append the largest possible new entry. Worst case scenario
|
|
+ /* Appending to an existing hash-entry. Check that there is enough
|
|
+ ** space to append the largest possible new entry. Worst case scenario
|
|
** is:
|
|
**
|
|
** + 9 bytes for a new rowid,
|
|
@@ -214075,8 +230421,9 @@ static int sqlite3Fts5HashWrite(
|
|
/* If this is a new rowid, append the 4-byte size field for the previous
|
|
** entry, and the new rowid for this entry. */
|
|
if( iRowid!=p->iRowid ){
|
|
+ u64 iDiff = (u64)iRowid - (u64)p->iRowid;
|
|
fts5HashAddPoslistSize(pHash, p, 0);
|
|
- p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iRowid - p->iRowid);
|
|
+ p->nData += sqlite3Fts5PutVarint(&pPtr[p->nData], iDiff);
|
|
p->iRowid = iRowid;
|
|
bNew = 1;
|
|
p->iSzPoslist = p->nData;
|
|
@@ -214092,7 +230439,7 @@ static int sqlite3Fts5HashWrite(
|
|
p->bContent = 1;
|
|
}else{
|
|
/* Append a new column value, if necessary */
|
|
- assert( iCol>=p->iCol );
|
|
+ assert_nc( iCol>=p->iCol );
|
|
if( iCol!=p->iCol ){
|
|
if( pHash->eDetail==FTS5_DETAIL_FULL ){
|
|
pPtr[p->nData++] = 0x01;
|
|
@@ -214174,7 +230521,7 @@ static Fts5HashEntry *fts5HashEntryMerge(
|
|
** list.
|
|
*/
|
|
static int fts5HashEntrySort(
|
|
- Fts5Hash *pHash,
|
|
+ Fts5Hash *pHash,
|
|
const char *pTerm, int nTerm, /* Query prefix, if any */
|
|
Fts5HashEntry **ppSorted
|
|
){
|
|
@@ -214192,7 +230539,7 @@ static int fts5HashEntrySort(
|
|
for(iSlot=0; iSlot<pHash->nSlot; iSlot++){
|
|
Fts5HashEntry *pIter;
|
|
for(pIter=pHash->aSlot[iSlot]; pIter; pIter=pIter->pHashNext){
|
|
- if( pTerm==0
|
|
+ if( pTerm==0
|
|
|| (pIter->nKey+1>=nTerm && 0==memcmp(fts5EntryKey(pIter), pTerm, nTerm))
|
|
){
|
|
Fts5HashEntry *pEntry = pIter;
|
|
@@ -214307,7 +230654,7 @@ static void sqlite3Fts5HashScanEntry(
|
|
**
|
|
******************************************************************************
|
|
**
|
|
-** Low level access to the FTS index stored in the database file. The
|
|
+** Low level access to the FTS index stored in the database file. The
|
|
** routines in this file file implement all read and write access to the
|
|
** %_data table. Other parts of the system access this functionality via
|
|
** the interface defined in fts5Int.h.
|
|
@@ -214323,10 +230670,10 @@ static void sqlite3Fts5HashScanEntry(
|
|
** As well as the main term index, there may be up to 31 prefix indexes.
|
|
** The format is similar to FTS3/4, except that:
|
|
**
|
|
-** * all segment b-tree leaf data is stored in fixed size page records
|
|
-** (e.g. 1000 bytes). A single doclist may span multiple pages. Care is
|
|
-** taken to ensure it is possible to iterate in either direction through
|
|
-** the entries in a doclist, or to seek to a specific entry within a
|
|
+** * all segment b-tree leaf data is stored in fixed size page records
|
|
+** (e.g. 1000 bytes). A single doclist may span multiple pages. Care is
|
|
+** taken to ensure it is possible to iterate in either direction through
|
|
+** the entries in a doclist, or to seek to a specific entry within a
|
|
** doclist, without loading it into memory.
|
|
**
|
|
** * large doclists that span many pages have associated "doclist index"
|
|
@@ -214351,6 +230698,8 @@ static void sqlite3Fts5HashScanEntry(
|
|
# error "FTS5_MAX_PREFIX_INDEXES is too large"
|
|
#endif
|
|
|
|
+#define FTS5_MAX_LEVEL 64
|
|
+
|
|
/*
|
|
** Details:
|
|
**
|
|
@@ -214359,14 +230708,14 @@ static void sqlite3Fts5HashScanEntry(
|
|
** CREATE TABLE %_data(id INTEGER PRIMARY KEY, block BLOB);
|
|
**
|
|
** , contains the following 5 types of records. See the comments surrounding
|
|
-** the FTS5_*_ROWID macros below for a description of how %_data rowids are
|
|
+** the FTS5_*_ROWID macros below for a description of how %_data rowids are
|
|
** assigned to each fo them.
|
|
**
|
|
** 1. Structure Records:
|
|
**
|
|
** 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
|
|
+** 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.
|
|
@@ -214398,7 +230747,7 @@ static void sqlite3Fts5HashScanEntry(
|
|
**
|
|
** TERM/DOCLIST FORMAT:
|
|
**
|
|
-** Most of each segment leaf is taken up by term/doclist data. The
|
|
+** Most of each segment leaf is taken up by term/doclist data. The
|
|
** general format of term/doclist, starting with the first term
|
|
** on the leaf page, is:
|
|
**
|
|
@@ -214441,7 +230790,7 @@ static void sqlite3Fts5HashScanEntry(
|
|
**
|
|
** PAGE FORMAT
|
|
**
|
|
-** Each leaf page begins with a 4-byte header containing 2 16-bit
|
|
+** Each leaf page begins with a 4-byte header containing 2 16-bit
|
|
** unsigned integer fields in big-endian format. They are:
|
|
**
|
|
** * The byte offset of the first rowid on the page, if it exists
|
|
@@ -214476,7 +230825,7 @@ static void sqlite3Fts5HashScanEntry(
|
|
** 5. Segment doclist indexes:
|
|
**
|
|
** Doclist indexes are themselves b-trees, however they usually consist of
|
|
-** a single leaf record only. The format of each doclist index leaf page
|
|
+** a single leaf record only. The format of each doclist index leaf page
|
|
** is:
|
|
**
|
|
** * Flags byte. Bits are:
|
|
@@ -214486,8 +230835,8 @@ static void sqlite3Fts5HashScanEntry(
|
|
**
|
|
** * First rowid on page indicated by previous field. As a varint.
|
|
**
|
|
-** * A list of varints, one for each subsequent termless page. A
|
|
-** positive delta if the termless page contains at least one rowid,
|
|
+** * A list of varints, one for each subsequent termless page. A
|
|
+** positive delta if the termless page contains at least one rowid,
|
|
** or an 0x00 byte otherwise.
|
|
**
|
|
** Internal doclist index nodes are:
|
|
@@ -214500,7 +230849,7 @@ static void sqlite3Fts5HashScanEntry(
|
|
** * Copy of first rowid on page indicated by previous field. As a varint.
|
|
**
|
|
** * A list of delta-encoded varints - the first rowid on each subsequent
|
|
-** child page.
|
|
+** child page.
|
|
**
|
|
*/
|
|
|
|
@@ -214517,7 +230866,7 @@ static void sqlite3Fts5HashScanEntry(
|
|
**
|
|
** Each segment has a unique non-zero 16-bit id.
|
|
**
|
|
-** The rowid for each segment leaf is found by passing the segment id and
|
|
+** The rowid for each segment leaf is found by passing the segment id and
|
|
** the leaf page number to the FTS5_SEGMENT_ROWID macro. Leaves are numbered
|
|
** sequentially starting from 1.
|
|
*/
|
|
@@ -214593,7 +230942,7 @@ struct Fts5Index {
|
|
sqlite3_stmt *pWriter; /* "INSERT ... %_data VALUES(?,?)" */
|
|
sqlite3_stmt *pDeleter; /* "DELETE FROM %_data ... id>=? AND id<=?" */
|
|
sqlite3_stmt *pIdxWriter; /* "INSERT ... %_idx VALUES(?,?,?,?)" */
|
|
- sqlite3_stmt *pIdxDeleter; /* "DELETE FROM %_idx WHERE segid=? */
|
|
+ sqlite3_stmt *pIdxDeleter; /* "DELETE FROM %_idx WHERE segid=?" */
|
|
sqlite3_stmt *pIdxSelect;
|
|
int nRead; /* Total number of blocks read */
|
|
|
|
@@ -214614,7 +230963,7 @@ struct Fts5DoclistIter {
|
|
|
|
/*
|
|
** The contents of the "structure" record for each index are represented
|
|
-** using an Fts5Structure record in memory. Which uses instances of the
|
|
+** using an Fts5Structure record in memory. Which uses instances of the
|
|
** other Fts5StructureXXX types as components.
|
|
*/
|
|
struct Fts5StructureSegment {
|
|
@@ -214687,10 +231036,10 @@ struct Fts5CResult {
|
|
** Current leaf page number within segment.
|
|
**
|
|
** iLeafOffset:
|
|
-** Byte offset within the current leaf that is the first byte of the
|
|
+** 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
|
|
+** position list data. The exception is if the rowid for the current entry
|
|
** is the last thing on the leaf page.
|
|
**
|
|
** pLeaf:
|
|
@@ -214704,7 +231053,7 @@ struct Fts5CResult {
|
|
** Mask of FTS5_SEGITER_XXX values. Interpreted as follows:
|
|
**
|
|
** FTS5_SEGITER_ONETERM:
|
|
-** If set, set the iterator to point to EOF after the current doclist
|
|
+** If set, set the iterator to point to EOF after the current doclist
|
|
** has been exhausted. Do not proceed to the next term in the segment.
|
|
**
|
|
** FTS5_SEGITER_REVERSE:
|
|
@@ -214728,12 +231077,12 @@ struct Fts5SegIter {
|
|
int iLeafPgno; /* Current leaf page number */
|
|
Fts5Data *pLeaf; /* Current leaf data */
|
|
Fts5Data *pNextLeaf; /* Leaf page (iLeafPgno+1) */
|
|
- int iLeafOffset; /* Byte offset within current leaf */
|
|
+ i64 iLeafOffset; /* Byte offset within current leaf */
|
|
|
|
/* Next method */
|
|
void (*xNext)(Fts5Index*, Fts5SegIter*, int*);
|
|
|
|
- /* The page and offset from which the current term was read. The offset
|
|
+ /* The page and offset from which the current term was read. The offset
|
|
** is the offset of the first rowid in the current doclist. */
|
|
int iTermLeafPgno;
|
|
int iTermLeafOffset;
|
|
@@ -214756,7 +231105,7 @@ struct Fts5SegIter {
|
|
};
|
|
|
|
/*
|
|
-** Argument is a pointer to an Fts5Data structure that contains a
|
|
+** Argument is a pointer to an Fts5Data structure that contains a
|
|
** leaf page.
|
|
*/
|
|
#define ASSERT_SZLEAF_OK(x) assert( \
|
|
@@ -214766,7 +231115,7 @@ struct Fts5SegIter {
|
|
#define FTS5_SEGITER_ONETERM 0x01
|
|
#define FTS5_SEGITER_REVERSE 0x02
|
|
|
|
-/*
|
|
+/*
|
|
** Argument is a pointer to an Fts5Data structure that contains a leaf
|
|
** page. This macro evaluates to true if the leaf contains no terms, or
|
|
** false if it contains at least one term.
|
|
@@ -214788,13 +231137,13 @@ struct Fts5SegIter {
|
|
** on empty segments.
|
|
**
|
|
** The results of comparing segments aSeg[N] and aSeg[N+1], where N is an
|
|
-** even number, is stored in aFirst[(nSeg+N)/2]. The "result" of the
|
|
+** even number, is stored in aFirst[(nSeg+N)/2]. The "result" of the
|
|
** comparison in this context is the index of the iterator that currently
|
|
** points to the smaller term/rowid combination. Iterators at EOF are
|
|
** considered to be greater than all other iterators.
|
|
**
|
|
** aFirst[1] contains the index in aSeg[] of the iterator that points to
|
|
-** the smallest key overall. aFirst[0] is unused.
|
|
+** the smallest key overall. aFirst[0] is unused.
|
|
**
|
|
** poslist:
|
|
** Used by sqlite3Fts5IterPoslist() when the poslist needs to be buffered.
|
|
@@ -214856,7 +231205,7 @@ static void fts5PutU16(u8 *aOut, u16 iVal){
|
|
|
|
static u16 fts5GetU16(const u8 *aIn){
|
|
return ((u16)aIn[0] << 8) + aIn[1];
|
|
-}
|
|
+}
|
|
|
|
/*
|
|
** Allocate and return a buffer at least nByte bytes in size.
|
|
@@ -214897,8 +231246,11 @@ static int fts5BufferCompareBlob(
|
|
** res = *pLeft - *pRight
|
|
*/
|
|
static int fts5BufferCompare(Fts5Buffer *pLeft, Fts5Buffer *pRight){
|
|
- int nCmp = MIN(pLeft->n, pRight->n);
|
|
- int res = fts5Memcmp(pLeft->p, pRight->p, nCmp);
|
|
+ int nCmp, res;
|
|
+ nCmp = MIN(pLeft->n, pRight->n);
|
|
+ assert( nCmp<=0 || pLeft->p!=0 );
|
|
+ assert( nCmp<=0 || pRight->p!=0 );
|
|
+ res = fts5Memcmp(pLeft->p, pRight->p, nCmp);
|
|
return (res==0 ? (pLeft->n - pRight->n) : res);
|
|
}
|
|
|
|
@@ -214922,7 +231274,7 @@ static void sqlite3Fts5IndexCloseReader(Fts5Index *p){
|
|
/*
|
|
** Retrieve a record from the %_data table.
|
|
**
|
|
-** If an error occurs, NULL is returned and an error left in the
|
|
+** If an error occurs, NULL is returned and an error left in the
|
|
** Fts5Index object.
|
|
*/
|
|
static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){
|
|
@@ -214945,11 +231297,11 @@ static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){
|
|
if( rc==SQLITE_ABORT ) rc = SQLITE_OK;
|
|
}
|
|
|
|
- /* If the blob handle is not open at this point, open it and seek
|
|
+ /* If the blob handle is not open at this point, open it and seek
|
|
** to the requested entry. */
|
|
if( p->pReader==0 && rc==SQLITE_OK ){
|
|
Fts5Config *pConfig = p->pConfig;
|
|
- rc = sqlite3_blob_open(pConfig->db,
|
|
+ rc = sqlite3_blob_open(pConfig->db,
|
|
pConfig->zDb, p->zDataTbl, "block", iRowid, 0, &p->pReader
|
|
);
|
|
}
|
|
@@ -214957,7 +231309,7 @@ static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){
|
|
/* If either of the sqlite3_blob_open() or sqlite3_blob_reopen() calls
|
|
** above returned SQLITE_ERROR, return SQLITE_CORRUPT_VTAB instead.
|
|
** All the reasons those functions might return SQLITE_ERROR - missing
|
|
- ** table, missing row, non-blob/text in block column - indicate
|
|
+ ** table, missing row, non-blob/text in block column - indicate
|
|
** backing store corruption. */
|
|
if( rc==SQLITE_ERROR ) rc = FTS5_CORRUPT;
|
|
|
|
@@ -214994,6 +231346,7 @@ static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){
|
|
return pRet;
|
|
}
|
|
|
|
+
|
|
/*
|
|
** Release a reference to data record returned by an earlier call to
|
|
** fts5DataRead().
|
|
@@ -215042,7 +231395,7 @@ static void fts5DataWrite(Fts5Index *p, i64 iRowid, const u8 *pData, int nData){
|
|
if( p->pWriter==0 ){
|
|
Fts5Config *pConfig = p->pConfig;
|
|
fts5IndexPrepareStmt(p, &p->pWriter, sqlite3_mprintf(
|
|
- "REPLACE INTO '%q'.'%q_data'(id, block) VALUES(?,?)",
|
|
+ "REPLACE INTO '%q'.'%q_data'(id, block) VALUES(?,?)",
|
|
pConfig->zDb, pConfig->zName
|
|
));
|
|
if( p->rc ) return;
|
|
@@ -215066,7 +231419,7 @@ static void fts5DataDelete(Fts5Index *p, i64 iFirst, i64 iLast){
|
|
if( p->pDeleter==0 ){
|
|
Fts5Config *pConfig = p->pConfig;
|
|
char *zSql = sqlite3_mprintf(
|
|
- "DELETE FROM '%q'.'%q_data' WHERE id>=? AND id<=?",
|
|
+ "DELETE FROM '%q'.'%q_data' WHERE id>=? AND id<=?",
|
|
pConfig->zDb, pConfig->zName
|
|
);
|
|
if( fts5IndexPrepareStmt(p, &p->pDeleter, zSql) ) return;
|
|
@@ -215100,7 +231453,7 @@ static void fts5DataRemoveSegment(Fts5Index *p, int iSegid){
|
|
}
|
|
|
|
/*
|
|
-** Release a reference to an Fts5Structure object returned by an earlier
|
|
+** Release a reference to an Fts5Structure object returned by an earlier
|
|
** call to fts5StructureRead() or fts5StructureDecode().
|
|
*/
|
|
static void fts5StructureRelease(Fts5Structure *pStruct){
|
|
@@ -215118,6 +231471,58 @@ static void fts5StructureRef(Fts5Structure *pStruct){
|
|
pStruct->nRef++;
|
|
}
|
|
|
|
+static void *sqlite3Fts5StructureRef(Fts5Index *p){
|
|
+ fts5StructureRef(p->pStruct);
|
|
+ return (void*)p->pStruct;
|
|
+}
|
|
+static void sqlite3Fts5StructureRelease(void *p){
|
|
+ if( p ){
|
|
+ fts5StructureRelease((Fts5Structure*)p);
|
|
+ }
|
|
+}
|
|
+static int sqlite3Fts5StructureTest(Fts5Index *p, void *pStruct){
|
|
+ if( p->pStruct!=(Fts5Structure*)pStruct ){
|
|
+ return SQLITE_ABORT;
|
|
+ }
|
|
+ return SQLITE_OK;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Ensure that structure object (*pp) is writable.
|
|
+**
|
|
+** This function is a no-op if (*pRc) is not SQLITE_OK when it is called. If
|
|
+** an error occurs, (*pRc) is set to an SQLite error code before returning.
|
|
+*/
|
|
+static void fts5StructureMakeWritable(int *pRc, Fts5Structure **pp){
|
|
+ Fts5Structure *p = *pp;
|
|
+ if( *pRc==SQLITE_OK && p->nRef>1 ){
|
|
+ i64 nByte = sizeof(Fts5Structure)+(p->nLevel-1)*sizeof(Fts5StructureLevel);
|
|
+ Fts5Structure *pNew;
|
|
+ pNew = (Fts5Structure*)sqlite3Fts5MallocZero(pRc, nByte);
|
|
+ if( pNew ){
|
|
+ int i;
|
|
+ memcpy(pNew, p, nByte);
|
|
+ for(i=0; i<p->nLevel; i++) pNew->aLevel[i].aSeg = 0;
|
|
+ for(i=0; i<p->nLevel; i++){
|
|
+ Fts5StructureLevel *pLvl = &pNew->aLevel[i];
|
|
+ nByte = sizeof(Fts5StructureSegment) * pNew->aLevel[i].nSeg;
|
|
+ pLvl->aSeg = (Fts5StructureSegment*)sqlite3Fts5MallocZero(pRc, nByte);
|
|
+ if( pLvl->aSeg==0 ){
|
|
+ for(i=0; i<p->nLevel; i++){
|
|
+ sqlite3_free(pNew->aLevel[i].aSeg);
|
|
+ }
|
|
+ sqlite3_free(pNew);
|
|
+ return;
|
|
+ }
|
|
+ memcpy(pLvl->aSeg, p->aLevel[i].aSeg, nByte);
|
|
+ }
|
|
+ p->nRef--;
|
|
+ pNew->nRef = 1;
|
|
+ }
|
|
+ *pp = pNew;
|
|
+ }
|
|
+}
|
|
+
|
|
/*
|
|
** Deserialize and return the structure record currently stored in serialized
|
|
** form within buffer pData/nData.
|
|
@@ -215180,7 +231585,7 @@ static int fts5StructureDecode(
|
|
i += fts5GetVarint32(&pData[i], pLvl->nMerge);
|
|
i += fts5GetVarint32(&pData[i], nTotal);
|
|
if( nTotal<pLvl->nMerge ) rc = FTS5_CORRUPT;
|
|
- pLvl->aSeg = (Fts5StructureSegment*)sqlite3Fts5MallocZero(&rc,
|
|
+ pLvl->aSeg = (Fts5StructureSegment*)sqlite3Fts5MallocZero(&rc,
|
|
nTotal * sizeof(Fts5StructureSegment)
|
|
);
|
|
nSegment -= nTotal;
|
|
@@ -215219,9 +231624,11 @@ static int fts5StructureDecode(
|
|
}
|
|
|
|
/*
|
|
-**
|
|
+** Add a level to the Fts5Structure.aLevel[] array of structure object
|
|
+** (*ppStruct).
|
|
*/
|
|
static void fts5StructureAddLevel(int *pRc, Fts5Structure **ppStruct){
|
|
+ fts5StructureMakeWritable(pRc, ppStruct);
|
|
if( *pRc==SQLITE_OK ){
|
|
Fts5Structure *pStruct = *ppStruct;
|
|
int nLevel = pStruct->nLevel;
|
|
@@ -215246,10 +231653,10 @@ static void fts5StructureAddLevel(int *pRc, Fts5Structure **ppStruct){
|
|
** segments.
|
|
*/
|
|
static void fts5StructureExtendLevel(
|
|
- int *pRc,
|
|
- Fts5Structure *pStruct,
|
|
- int iLvl,
|
|
- int nExtra,
|
|
+ int *pRc,
|
|
+ Fts5Structure *pStruct,
|
|
+ int iLvl,
|
|
+ int nExtra,
|
|
int bInsert
|
|
){
|
|
if( *pRc==SQLITE_OK ){
|
|
@@ -215303,7 +231710,7 @@ static i64 fts5IndexDataVersion(Fts5Index *p){
|
|
|
|
if( p->rc==SQLITE_OK ){
|
|
if( p->pDataVersion==0 ){
|
|
- p->rc = fts5IndexPrepareStmt(p, &p->pDataVersion,
|
|
+ p->rc = fts5IndexPrepareStmt(p, &p->pDataVersion,
|
|
sqlite3_mprintf("PRAGMA %Q.data_version", p->pConfig->zDb)
|
|
);
|
|
if( p->rc ) return 0;
|
|
@@ -215322,7 +231729,7 @@ static i64 fts5IndexDataVersion(Fts5Index *p){
|
|
** Read, deserialize and return the structure record.
|
|
**
|
|
** The Fts5Structure.aLevel[] and each Fts5StructureLevel.aSeg[] array
|
|
-** are over-allocated as described for function fts5StructureDecode()
|
|
+** are over-allocated as described for function fts5StructureDecode()
|
|
** above.
|
|
**
|
|
** If an error occurs, NULL is returned and an error code left in the
|
|
@@ -215471,8 +231878,8 @@ static int fts5SegmentSize(Fts5StructureSegment *pSeg){
|
|
}
|
|
|
|
/*
|
|
-** Return a copy of index structure pStruct. Except, promote as many
|
|
-** segments as possible to level iPromote. If an OOM occurs, NULL is
|
|
+** Return a copy of index structure pStruct. Except, promote as many
|
|
+** segments as possible to level iPromote. If an OOM occurs, NULL is
|
|
** returned.
|
|
*/
|
|
static void fts5StructurePromoteTo(
|
|
@@ -215512,8 +231919,8 @@ static void fts5StructurePromoteTo(
|
|
**
|
|
** b) If the segment just written is larger than the newest segment on
|
|
** the next populated level, then that segment, and any other adjacent
|
|
-** segments that are also smaller than the one just written, are
|
|
-** promoted.
|
|
+** segments that are also smaller than the one just written, are
|
|
+** promoted.
|
|
**
|
|
** If one or more segments are promoted, the structure object is updated
|
|
** to reflect this.
|
|
@@ -215547,7 +231954,7 @@ static void fts5StructurePromote(
|
|
if( sz>szMax ) szMax = sz;
|
|
}
|
|
if( szMax>=szSeg ){
|
|
- /* Condition (a) is true. Promote the newest segment on level
|
|
+ /* Condition (a) is true. Promote the newest segment on level
|
|
** iLvl to level iTst. */
|
|
iPromote = iTst;
|
|
szPromote = szMax;
|
|
@@ -215566,7 +231973,7 @@ static void fts5StructurePromote(
|
|
|
|
|
|
/*
|
|
-** Advance the iterator passed as the only argument. If the end of the
|
|
+** Advance the iterator passed as the only argument. If the end of the
|
|
** doclist-index page is reached, return non-zero.
|
|
*/
|
|
static int fts5DlidxLvlNext(Fts5DlidxLvl *pLvl){
|
|
@@ -215581,7 +231988,7 @@ static int fts5DlidxLvlNext(Fts5DlidxLvl *pLvl){
|
|
}else{
|
|
int iOff;
|
|
for(iOff=pLvl->iOff; iOff<pData->nn; iOff++){
|
|
- if( pData->p[iOff] ) break;
|
|
+ if( pData->p[iOff] ) break;
|
|
}
|
|
|
|
if( iOff<pData->nn ){
|
|
@@ -215611,7 +232018,7 @@ static int fts5DlidxIterNextR(Fts5Index *p, Fts5DlidxIter *pIter, int iLvl){
|
|
if( pLvl[1].bEof==0 ){
|
|
fts5DataRelease(pLvl->pData);
|
|
memset(pLvl, 0, sizeof(Fts5DlidxLvl));
|
|
- pLvl->pData = fts5DataRead(p,
|
|
+ pLvl->pData = fts5DataRead(p,
|
|
FTS5_DLIDX_ROWID(pIter->iSegid, iLvl, pLvl[1].iLeafPgno)
|
|
);
|
|
if( pLvl->pData ) fts5DlidxLvlNext(pLvl);
|
|
@@ -215631,7 +232038,7 @@ static int fts5DlidxIterNext(Fts5Index *p, Fts5DlidxIter *pIter){
|
|
** points to the first rowid in the doclist-index.
|
|
**
|
|
** pData:
|
|
-** pointer to doclist-index record,
|
|
+** pointer to doclist-index record,
|
|
**
|
|
** When this function is called pIter->iLeafPgno is the page number the
|
|
** doclist is associated with (the one featuring the term).
|
|
@@ -215662,7 +232069,7 @@ static void fts5DlidxIterLast(Fts5Index *p, Fts5DlidxIter *pIter){
|
|
Fts5DlidxLvl *pChild = &pLvl[-1];
|
|
fts5DataRelease(pChild->pData);
|
|
memset(pChild, 0, sizeof(Fts5DlidxLvl));
|
|
- pChild->pData = fts5DataRead(p,
|
|
+ pChild->pData = fts5DataRead(p,
|
|
FTS5_DLIDX_ROWID(pIter->iSegid, i-1, pLvl->iLeafPgno)
|
|
);
|
|
}
|
|
@@ -215685,8 +232092,8 @@ static int fts5DlidxLvlPrev(Fts5DlidxLvl *pLvl){
|
|
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
|
|
+ /* 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);
|
|
@@ -215731,7 +232138,7 @@ static int fts5DlidxIterPrevR(Fts5Index *p, Fts5DlidxIter *pIter, int iLvl){
|
|
if( pLvl[1].bEof==0 ){
|
|
fts5DataRelease(pLvl->pData);
|
|
memset(pLvl, 0, sizeof(Fts5DlidxLvl));
|
|
- pLvl->pData = fts5DataRead(p,
|
|
+ pLvl->pData = fts5DataRead(p,
|
|
FTS5_DLIDX_ROWID(pIter->iSegid, iLvl, pLvl[1].iLeafPgno)
|
|
);
|
|
if( pLvl->pData ){
|
|
@@ -215830,7 +232237,7 @@ static void fts5SegIterNextPage(
|
|
pIter->pLeaf = pIter->pNextLeaf;
|
|
pIter->pNextLeaf = 0;
|
|
}else if( pIter->iLeafPgno<=pSeg->pgnoLast ){
|
|
- pIter->pLeaf = fts5LeafRead(p,
|
|
+ pIter->pLeaf = fts5LeafRead(p,
|
|
FTS5_SEGMENT_ROWID(pSeg->iSegid, pIter->iLeafPgno)
|
|
);
|
|
}else{
|
|
@@ -215874,7 +232281,7 @@ static int fts5GetPoslistSize(const u8 *p, int *pnSz, int *pbDel){
|
|
** Fts5SegIter.nPos
|
|
** Fts5SegIter.bDel
|
|
**
|
|
-** Leave Fts5SegIter.iLeafOffset pointing to the first byte of the
|
|
+** Leave Fts5SegIter.iLeafOffset pointing to the first byte of the
|
|
** position list content (if any).
|
|
*/
|
|
static void fts5SegIterLoadNPos(Fts5Index *p, Fts5SegIter *pIter){
|
|
@@ -215908,7 +232315,7 @@ static void fts5SegIterLoadNPos(Fts5Index *p, Fts5SegIter *pIter){
|
|
|
|
static void fts5SegIterLoadRowid(Fts5Index *p, Fts5SegIter *pIter){
|
|
u8 *a = pIter->pLeaf->p; /* Buffer to read data from */
|
|
- int iOff = pIter->iLeafOffset;
|
|
+ i64 iOff = pIter->iLeafOffset;
|
|
|
|
ASSERT_SZLEAF_OK(pIter->pLeaf);
|
|
if( iOff>=pIter->pLeaf->szLeaf ){
|
|
@@ -215925,7 +232332,7 @@ static void fts5SegIterLoadRowid(Fts5Index *p, Fts5SegIter *pIter){
|
|
}
|
|
|
|
/*
|
|
-** Fts5SegIter.iLeafOffset currently points to the first byte of the
|
|
+** Fts5SegIter.iLeafOffset currently points to the first byte of the
|
|
** "nSuffix" field of a term. Function parameter nKeep contains the value
|
|
** of the "nPrefix" field (if there was one - it is passed 0 if this is
|
|
** the first term in the segment).
|
|
@@ -215936,12 +232343,12 @@ static void fts5SegIterLoadRowid(Fts5Index *p, Fts5SegIter *pIter){
|
|
** Fts5SegIter.rowid
|
|
**
|
|
** accordingly and leaves (Fts5SegIter.iLeafOffset) set to the content of
|
|
-** the first position list. The position list belonging to document
|
|
+** the first position list. The position list belonging to document
|
|
** (Fts5SegIter.iRowid).
|
|
*/
|
|
static void fts5SegIterLoadTerm(Fts5Index *p, Fts5SegIter *pIter, int nKeep){
|
|
u8 *a = pIter->pLeaf->p; /* Buffer to read data from */
|
|
- int iOff = pIter->iLeafOffset; /* Offset to read at */
|
|
+ i64 iOff = pIter->iLeafOffset; /* Offset to read at */
|
|
int nNew; /* Bytes of new data */
|
|
|
|
iOff += fts5GetVarint32(&a[iOff], nNew);
|
|
@@ -215984,10 +232391,10 @@ static void fts5SegIterSetNext(Fts5Index *p, Fts5SegIter *pIter){
|
|
|
|
/*
|
|
** Initialize the iterator object pIter to iterate through the entries in
|
|
-** segment pSeg. The iterator is left pointing to the first entry when
|
|
+** segment pSeg. The iterator is left pointing to the first entry when
|
|
** this function returns.
|
|
**
|
|
-** If an error occurs, Fts5Index.rc is set to an appropriate error code. If
|
|
+** If an error occurs, Fts5Index.rc is set to an appropriate error code. If
|
|
** an error has already occurred when this function is called, it is a no-op.
|
|
*/
|
|
static void fts5SegIterInit(
|
|
@@ -216015,6 +232422,7 @@ static void fts5SegIterInit(
|
|
|
|
if( p->rc==SQLITE_OK ){
|
|
pIter->iLeafOffset = 4;
|
|
+ assert( pIter->pLeaf!=0 );
|
|
assert_nc( pIter->pLeaf->nn>4 );
|
|
assert_nc( fts5LeafFirstTermOff(pIter->pLeaf)==4 );
|
|
pIter->iPgidxOff = pIter->pLeaf->szLeaf+1;
|
|
@@ -216032,8 +232440,8 @@ static void fts5SegIterInit(
|
|
** the position-list size field for the first relevant rowid on the page.
|
|
** Fts5SegIter.rowid is set, but nPos and bDel are not.
|
|
**
|
|
-** This function advances the iterator so that it points to the last
|
|
-** relevant rowid on the page and, if necessary, initializes the
|
|
+** This function advances the iterator so that it points to the last
|
|
+** relevant rowid on the page and, if necessary, initializes the
|
|
** aRowidOffset[] and iRowidOffset variables. At this point the iterator
|
|
** is in its regular state - Fts5SegIter.iLeafOffset points to the first
|
|
** byte of the position list content associated with said rowid.
|
|
@@ -216051,7 +232459,7 @@ static void fts5SegIterReverseInitPage(Fts5Index *p, Fts5SegIter *pIter){
|
|
|
|
ASSERT_SZLEAF_OK(pIter->pLeaf);
|
|
while( 1 ){
|
|
- i64 iDelta = 0;
|
|
+ u64 iDelta = 0;
|
|
|
|
if( eDetail==FTS5_DETAIL_NONE ){
|
|
/* todo */
|
|
@@ -216066,7 +232474,7 @@ static void fts5SegIterReverseInitPage(Fts5Index *p, Fts5SegIter *pIter){
|
|
i += nPos;
|
|
}
|
|
if( i>=n ) break;
|
|
- i += fts5GetVarint(&a[i], (u64*)&iDelta);
|
|
+ i += fts5GetVarint(&a[i], &iDelta);
|
|
pIter->iRowid += iDelta;
|
|
|
|
/* If necessary, grow the pIter->aRowidOffset[] array. */
|
|
@@ -216117,8 +232525,12 @@ static void fts5SegIterReverseNewPage(Fts5Index *p, Fts5SegIter *pIter){
|
|
int iRowidOff;
|
|
iRowidOff = fts5LeafFirstRowidOff(pNew);
|
|
if( iRowidOff ){
|
|
- pIter->pLeaf = pNew;
|
|
- pIter->iLeafOffset = iRowidOff;
|
|
+ if( iRowidOff>=pNew->szLeaf ){
|
|
+ p->rc = FTS5_CORRUPT;
|
|
+ }else{
|
|
+ pIter->pLeaf = pNew;
|
|
+ pIter->iLeafOffset = iRowidOff;
|
|
+ }
|
|
}
|
|
}
|
|
|
|
@@ -216165,7 +232577,7 @@ static void fts5SegIterNext_Reverse(
|
|
if( pIter->iRowidOffset>0 ){
|
|
u8 *a = pIter->pLeaf->p;
|
|
int iOff;
|
|
- i64 iDelta;
|
|
+ u64 iDelta;
|
|
|
|
pIter->iRowidOffset--;
|
|
pIter->iLeafOffset = pIter->aRowidOffset[pIter->iRowidOffset];
|
|
@@ -216174,7 +232586,7 @@ static void fts5SegIterNext_Reverse(
|
|
if( p->pConfig->eDetail!=FTS5_DETAIL_NONE ){
|
|
iOff += pIter->nPos;
|
|
}
|
|
- fts5GetVarint(&a[iOff], (u64*)&iDelta);
|
|
+ fts5GetVarint(&a[iOff], &iDelta);
|
|
pIter->iRowid -= iDelta;
|
|
}else{
|
|
fts5SegIterReverseNewPage(p, pIter);
|
|
@@ -216253,10 +232665,10 @@ static void fts5SegIterNext_None(
|
|
|
|
|
|
/*
|
|
-** Advance iterator pIter to the next entry.
|
|
+** Advance iterator pIter to the next entry.
|
|
**
|
|
-** If an error occurs, Fts5Index.rc is set to an appropriate error code. It
|
|
-** is not considered an error if the iterator reaches EOF. If an error has
|
|
+** If an error occurs, Fts5Index.rc is set to an appropriate error code. It
|
|
+** is not considered an error if the iterator reaches EOF. If an error has
|
|
** already occurred when this function is called, it is a no-op.
|
|
*/
|
|
static void fts5SegIterNext(
|
|
@@ -216367,14 +232779,9 @@ static void fts5SegIterNext(
|
|
}else{
|
|
/* The following could be done by calling fts5SegIterLoadNPos(). But
|
|
** this block is particularly performance critical, so equivalent
|
|
- ** code is inlined.
|
|
- **
|
|
- ** Later: Switched back to fts5SegIterLoadNPos() because it supports
|
|
- ** detail=none mode. Not ideal.
|
|
- */
|
|
+ ** code is inlined. */
|
|
int nSz;
|
|
- assert( p->rc==SQLITE_OK );
|
|
- assert( pIter->iLeafOffset<=pIter->pLeaf->nn );
|
|
+ assert_nc( pIter->iLeafOffset<=pIter->pLeaf->nn );
|
|
fts5FastGetVarint32(pIter->pLeaf->p, pIter->iLeafOffset, nSz);
|
|
pIter->bDel = (nSz & 0x0001);
|
|
pIter->nPos = nSz>>1;
|
|
@@ -216403,7 +232810,7 @@ static void fts5SegIterReverse(Fts5Index *p, Fts5SegIter *pIter){
|
|
if( pDlidx ){
|
|
int iSegid = pIter->pSeg->iSegid;
|
|
pgnoLast = fts5DlidxIterPgno(pDlidx);
|
|
- pLast = fts5DataRead(p, FTS5_SEGMENT_ROWID(iSegid, pgnoLast));
|
|
+ pLast = fts5LeafRead(p, FTS5_SEGMENT_ROWID(iSegid, pgnoLast));
|
|
}else{
|
|
Fts5Data *pLeaf = pIter->pLeaf; /* Current leaf data */
|
|
|
|
@@ -216430,7 +232837,7 @@ static void fts5SegIterReverse(Fts5Index *p, Fts5SegIter *pIter){
|
|
** forward to find the page containing the last rowid. */
|
|
for(pgno=pIter->iLeafPgno+1; !p->rc && pgno<=pSeg->pgnoLast; pgno++){
|
|
i64 iAbs = FTS5_SEGMENT_ROWID(pSeg->iSegid, pgno);
|
|
- Fts5Data *pNew = fts5DataRead(p, iAbs);
|
|
+ Fts5Data *pNew = fts5LeafRead(p, iAbs);
|
|
if( pNew ){
|
|
int iRowid, bTermless;
|
|
iRowid = fts5LeafFirstRowidOff(pNew);
|
|
@@ -216447,7 +232854,7 @@ static void fts5SegIterReverse(Fts5Index *p, Fts5SegIter *pIter){
|
|
}
|
|
|
|
/* If pLast is NULL at this point, then the last rowid for this doclist
|
|
- ** lies on the page currently indicated by the iterator. In this case
|
|
+ ** lies on the page currently indicated by the iterator. In this case
|
|
** pIter->iLeafOffset is already set to point to the position-list size
|
|
** field associated with the first relevant rowid on the page.
|
|
**
|
|
@@ -216461,6 +232868,10 @@ static void fts5SegIterReverse(Fts5Index *p, Fts5SegIter *pIter){
|
|
pIter->pLeaf = pLast;
|
|
pIter->iLeafPgno = pgnoLast;
|
|
iOff = fts5LeafFirstRowidOff(pLast);
|
|
+ if( iOff>pLast->szLeaf ){
|
|
+ p->rc = FTS5_CORRUPT;
|
|
+ return;
|
|
+ }
|
|
iOff += fts5GetVarint(&pLast->p[iOff], (u64*)&pIter->iRowid);
|
|
pIter->iLeafOffset = iOff;
|
|
|
|
@@ -216469,7 +232880,6 @@ static void fts5SegIterReverse(Fts5Index *p, Fts5SegIter *pIter){
|
|
}else{
|
|
pIter->iEndofDoclist = fts5LeafFirstTermOff(pLast);
|
|
}
|
|
-
|
|
}
|
|
|
|
fts5SegIterReverseInitPage(p, pIter);
|
|
@@ -216477,8 +232887,8 @@ static void fts5SegIterReverse(Fts5Index *p, Fts5SegIter *pIter){
|
|
|
|
/*
|
|
** Iterator pIter currently points to the first rowid of a doclist.
|
|
-** There is a doclist-index associated with the final term on the current
|
|
-** page. If the current term is the last term on the page, load the
|
|
+** There is a doclist-index associated with the final term on the current
|
|
+** page. If the current term is the last term on the page, load the
|
|
** doclist-index from disk and initialize an iterator at (pIter->pDlidx).
|
|
*/
|
|
static void fts5SegIterLoadDlidx(Fts5Index *p, Fts5SegIter *pIter){
|
|
@@ -216492,8 +232902,8 @@ static void fts5SegIterLoadDlidx(Fts5Index *p, Fts5SegIter *pIter){
|
|
/* Check if the current doclist ends on this page. If it does, return
|
|
** early without loading the doclist-index (as it belongs to a different
|
|
** term. */
|
|
- if( pIter->iTermLeafPgno==pIter->iLeafPgno
|
|
- && pIter->iEndofDoclist<pLeaf->szLeaf
|
|
+ if( pIter->iTermLeafPgno==pIter->iLeafPgno
|
|
+ && pIter->iEndofDoclist<pLeaf->szLeaf
|
|
){
|
|
return;
|
|
}
|
|
@@ -216521,21 +232931,20 @@ static void fts5LeafSeek(
|
|
Fts5SegIter *pIter, /* Iterator to seek */
|
|
const u8 *pTerm, int nTerm /* Term to search for */
|
|
){
|
|
- int iOff;
|
|
+ u32 iOff;
|
|
const u8 *a = pIter->pLeaf->p;
|
|
- int szLeaf = pIter->pLeaf->szLeaf;
|
|
- int n = pIter->pLeaf->nn;
|
|
+ u32 n = (u32)pIter->pLeaf->nn;
|
|
|
|
u32 nMatch = 0;
|
|
u32 nKeep = 0;
|
|
u32 nNew = 0;
|
|
u32 iTermOff;
|
|
- int iPgidx; /* Current offset in pgidx */
|
|
+ u32 iPgidx; /* Current offset in pgidx */
|
|
int bEndOfPage = 0;
|
|
|
|
assert( p->rc==SQLITE_OK );
|
|
|
|
- iPgidx = szLeaf;
|
|
+ iPgidx = (u32)pIter->pLeaf->szLeaf;
|
|
iPgidx += fts5GetVarint32(&a[iPgidx], iTermOff);
|
|
iOff = iTermOff;
|
|
if( iOff>n ){
|
|
@@ -216601,15 +233010,15 @@ static void fts5LeafSeek(
|
|
if( pIter->pLeaf==0 ) return;
|
|
a = pIter->pLeaf->p;
|
|
if( fts5LeafIsTermless(pIter->pLeaf)==0 ){
|
|
- iPgidx = pIter->pLeaf->szLeaf;
|
|
+ iPgidx = (u32)pIter->pLeaf->szLeaf;
|
|
iPgidx += fts5GetVarint32(&pIter->pLeaf->p[iPgidx], iOff);
|
|
- if( iOff<4 || iOff>=pIter->pLeaf->szLeaf ){
|
|
+ if( iOff<4 || (i64)iOff>=pIter->pLeaf->szLeaf ){
|
|
p->rc = FTS5_CORRUPT;
|
|
return;
|
|
}else{
|
|
nKeep = 0;
|
|
iTermOff = iOff;
|
|
- n = pIter->pLeaf->nn;
|
|
+ n = (u32)pIter->pLeaf->nn;
|
|
iOff += fts5GetVarint32(&a[iOff], nNew);
|
|
break;
|
|
}
|
|
@@ -216618,11 +233027,11 @@ static void fts5LeafSeek(
|
|
}
|
|
|
|
search_success:
|
|
- pIter->iLeafOffset = iOff + nNew;
|
|
- if( pIter->iLeafOffset>n || nNew<1 ){
|
|
+ if( (i64)iOff+nNew>n || nNew<1 ){
|
|
p->rc = FTS5_CORRUPT;
|
|
return;
|
|
}
|
|
+ pIter->iLeafOffset = iOff + nNew;
|
|
pIter->iTermLeafOffset = pIter->iLeafOffset;
|
|
pIter->iTermLeafPgno = pIter->iLeafPgno;
|
|
|
|
@@ -216658,7 +233067,7 @@ static sqlite3_stmt *fts5IdxSelectStmt(Fts5Index *p){
|
|
** Initialize the object pIter to point to term pTerm/nTerm within segment
|
|
** pSeg. If there is no such term in the index, the iterator is set to EOF.
|
|
**
|
|
-** If an error occurs, Fts5Index.rc is set to an appropriate error code. If
|
|
+** If an error occurs, Fts5Index.rc is set to an appropriate error code. If
|
|
** an error has already occurred when this function is called, it is a no-op.
|
|
*/
|
|
static void fts5SegIterSeekInit(
|
|
@@ -216738,10 +233147,10 @@ static void fts5SegIterSeekInit(
|
|
|
|
/*
|
|
** Initialize the object pIter to point to term pTerm/nTerm within the
|
|
-** in-memory hash table. If there is no such term in the hash-table, the
|
|
+** in-memory hash table. If there is no such term in the hash-table, the
|
|
** iterator is set to EOF.
|
|
**
|
|
-** If an error occurs, Fts5Index.rc is set to an appropriate error code. If
|
|
+** If an error occurs, Fts5Index.rc is set to an appropriate error code. If
|
|
** an error has already occurred when this function is called, it is a no-op.
|
|
*/
|
|
static void fts5SegIterHashInit(
|
|
@@ -216771,7 +233180,7 @@ static void fts5SegIterHashInit(
|
|
}
|
|
}
|
|
}else{
|
|
- p->rc = sqlite3Fts5HashQuery(p->pHash, sizeof(Fts5Data),
|
|
+ p->rc = sqlite3Fts5HashQuery(p->pHash, sizeof(Fts5Data),
|
|
(const char*)pTerm, nTerm, (void**)&pLeaf, &nList
|
|
);
|
|
if( pLeaf ){
|
|
@@ -216821,7 +233230,7 @@ static void fts5SegIterClear(Fts5SegIter *pIter){
|
|
** two iterators.
|
|
*/
|
|
static void fts5AssertComparisonResult(
|
|
- Fts5Iter *pIter,
|
|
+ Fts5Iter *pIter,
|
|
Fts5SegIter *p1,
|
|
Fts5SegIter *p2,
|
|
Fts5CResult *pRes
|
|
@@ -216858,7 +233267,7 @@ static void fts5AssertComparisonResult(
|
|
|
|
/*
|
|
** This function is a no-op unless SQLITE_DEBUG is defined when this module
|
|
-** is compiled. In that case, this function is essentially an assert()
|
|
+** is compiled. In that case, this function is essentially an assert()
|
|
** statement used to verify that the contents of the pIter->aFirst[] array
|
|
** are correct.
|
|
*/
|
|
@@ -216872,9 +233281,9 @@ static void fts5AssertMultiIterSetup(Fts5Index *p, Fts5Iter *pIter){
|
|
/* Check that pIter->iSwitchRowid is set correctly. */
|
|
for(i=0; i<pIter->nSeg; i++){
|
|
Fts5SegIter *p1 = &pIter->aSeg[i];
|
|
- assert( p1==pFirst
|
|
- || p1->pLeaf==0
|
|
- || fts5BufferCompare(&pFirst->term, &p1->term)
|
|
+ assert( p1==pFirst
|
|
+ || p1->pLeaf==0
|
|
+ || fts5BufferCompare(&pFirst->term, &p1->term)
|
|
|| p1->iRowid==pIter->iSwitchRowid
|
|
|| (p1->iRowid<pIter->iSwitchRowid)==pIter->bRev
|
|
);
|
|
@@ -216904,7 +233313,7 @@ static void fts5AssertMultiIterSetup(Fts5Index *p, Fts5Iter *pIter){
|
|
**
|
|
** If the returned value is non-zero, then it is the index of an entry
|
|
** in the pIter->aSeg[] array that is (a) not at EOF, and (b) pointing
|
|
-** to a key that is a duplicate of another, higher priority,
|
|
+** to a key that is a duplicate of another, higher priority,
|
|
** segment-iterator in the pSeg->aSeg[] array.
|
|
*/
|
|
static int fts5MultiIterDoCompare(Fts5Iter *pIter, int iOut){
|
|
@@ -216977,7 +233386,7 @@ static void fts5SegIterGotoPage(
|
|
fts5SegIterNextPage(p, pIter);
|
|
assert( p->rc!=SQLITE_OK || pIter->iLeafPgno==iLeafPgno );
|
|
|
|
- if( p->rc==SQLITE_OK ){
|
|
+ if( p->rc==SQLITE_OK && ALWAYS(pIter->pLeaf!=0) ){
|
|
int iOff;
|
|
u8 *a = pIter->pLeaf->p;
|
|
int n = pIter->pLeaf->szLeaf;
|
|
@@ -216995,7 +233404,7 @@ static void fts5SegIterGotoPage(
|
|
}
|
|
|
|
/*
|
|
-** Advance the iterator passed as the second argument until it is at or
|
|
+** Advance the iterator passed as the second argument until it is at or
|
|
** past rowid iFrom. Regardless of the value of iFrom, the iterator is
|
|
** always advanced at least once.
|
|
*/
|
|
@@ -217091,7 +233500,7 @@ static void fts5MultiIterAdvanced(
|
|
** If non-zero is returned, the caller should call fts5MultiIterAdvanced()
|
|
** on the iterator instead. That function does the same as this one, except
|
|
** that it deals with more complicated cases as well.
|
|
-*/
|
|
+*/
|
|
static int fts5MultiIterAdvanceRowid(
|
|
Fts5Iter *pIter, /* Iterator to update aFirst[] array for */
|
|
int iChanged, /* Index of sub-iterator just advanced */
|
|
@@ -217142,14 +233551,14 @@ static void fts5MultiIterSetEof(Fts5Iter *pIter){
|
|
}
|
|
|
|
/*
|
|
-** Move the iterator to the next entry.
|
|
+** Move the iterator to the next entry.
|
|
**
|
|
-** If an error occurs, an error code is left in Fts5Index.rc. It is not
|
|
-** considered an error if the iterator reaches EOF, or if it is already at
|
|
+** If an error occurs, an error code is left in Fts5Index.rc. It is not
|
|
+** considered an error if the iterator reaches EOF, or if it is already at
|
|
** EOF when this function is called.
|
|
*/
|
|
static void fts5MultiIterNext(
|
|
- Fts5Index *p,
|
|
+ Fts5Index *p,
|
|
Fts5Iter *pIter,
|
|
int bFrom, /* True if argument iFrom is valid */
|
|
i64 iFrom /* Advance at least as far as this */
|
|
@@ -217167,7 +233576,7 @@ static void fts5MultiIterNext(
|
|
pSeg->xNext(p, pSeg, &bNewTerm);
|
|
}
|
|
|
|
- if( pSeg->pLeaf==0 || bNewTerm
|
|
+ if( pSeg->pLeaf==0 || bNewTerm
|
|
|| fts5MultiIterAdvanceRowid(pIter, iFirst, &pSeg)
|
|
){
|
|
fts5MultiIterAdvanced(p, pIter, iFirst, 1);
|
|
@@ -217187,7 +233596,7 @@ static void fts5MultiIterNext(
|
|
}
|
|
|
|
static void fts5MultiIterNext2(
|
|
- Fts5Index *p,
|
|
+ Fts5Index *p,
|
|
Fts5Iter *pIter,
|
|
int *pbNewTerm /* OUT: True if *might* be new term */
|
|
){
|
|
@@ -217201,7 +233610,7 @@ static void fts5MultiIterNext2(
|
|
|
|
assert( p->rc==SQLITE_OK );
|
|
pSeg->xNext(p, pSeg, &bNewTerm);
|
|
- if( pSeg->pLeaf==0 || bNewTerm
|
|
+ if( pSeg->pLeaf==0 || bNewTerm
|
|
|| fts5MultiIterAdvanceRowid(pIter, iFirst, &pSeg)
|
|
){
|
|
fts5MultiIterAdvanced(p, pIter, iFirst, 1);
|
|
@@ -217226,7 +233635,7 @@ static Fts5Iter *fts5MultiIterAlloc(
|
|
int nSlot; /* Power of two >= nSeg */
|
|
|
|
for(nSlot=2; nSlot<nSeg; nSlot=nSlot*2);
|
|
- pNew = fts5IdxMalloc(p,
|
|
+ pNew = fts5IdxMalloc(p,
|
|
sizeof(Fts5Iter) + /* pNew */
|
|
sizeof(Fts5SegIter) * (nSlot-1) + /* pNew->aSeg[] */
|
|
sizeof(Fts5CResult) * nSlot /* pNew->aFirst[] */
|
|
@@ -217241,8 +233650,8 @@ static Fts5Iter *fts5MultiIterAlloc(
|
|
}
|
|
|
|
static void fts5PoslistCallback(
|
|
- Fts5Index *pUnused,
|
|
- void *pContext,
|
|
+ Fts5Index *pUnused,
|
|
+ void *pContext,
|
|
const u8 *pChunk, int nChunk
|
|
){
|
|
UNUSED_PARAM(pUnused);
|
|
@@ -217279,8 +233688,8 @@ static int fts5IndexColsetTest(Fts5Colset *pColset, int iCol){
|
|
}
|
|
|
|
static void fts5PoslistOffsetsCallback(
|
|
- Fts5Index *pUnused,
|
|
- void *pContext,
|
|
+ Fts5Index *pUnused,
|
|
+ void *pContext,
|
|
const u8 *pChunk, int nChunk
|
|
){
|
|
PoslistOffsetsCtx *pCtx = (PoslistOffsetsCtx*)pContext;
|
|
@@ -217303,7 +233712,7 @@ static void fts5PoslistOffsetsCallback(
|
|
|
|
static void fts5PoslistFilterCallback(
|
|
Fts5Index *pUnused,
|
|
- void *pContext,
|
|
+ void *pContext,
|
|
const u8 *pChunk, int nChunk
|
|
){
|
|
PoslistCallbackCtx *pCtx = (PoslistCallbackCtx*)pContext;
|
|
@@ -217366,7 +233775,7 @@ static void fts5ChunkIterate(
|
|
int pgno = pSeg->iLeafPgno;
|
|
int pgnoSave = 0;
|
|
|
|
- /* This function does notmwork with detail=none databases. */
|
|
+ /* This function does not work with detail=none databases. */
|
|
assert( p->pConfig->eDetail!=FTS5_DETAIL_NONE );
|
|
|
|
if( (pSeg->flags & FTS5_SEGITER_REVERSE)==0 ){
|
|
@@ -217379,6 +233788,9 @@ static void fts5ChunkIterate(
|
|
fts5DataRelease(pData);
|
|
if( nRem<=0 ){
|
|
break;
|
|
+ }else if( pSeg->pSeg==0 ){
|
|
+ p->rc = FTS5_CORRUPT;
|
|
+ return;
|
|
}else{
|
|
pgno++;
|
|
pData = fts5LeafRead(p, FTS5_SEGMENT_ROWID(pSeg->pSeg->iSegid, pgno));
|
|
@@ -217406,7 +233818,11 @@ static void fts5SegiterPoslist(
|
|
Fts5Colset *pColset,
|
|
Fts5Buffer *pBuf
|
|
){
|
|
+ assert( pBuf!=0 );
|
|
+ assert( pSeg!=0 );
|
|
if( 0==fts5BufferGrow(&p->rc, pBuf, pSeg->nPos+FTS5_DATA_ZERO_PADDING) ){
|
|
+ assert( pBuf->p!=0 );
|
|
+ assert( pBuf->nSpace >= pBuf->n+pSeg->nPos+FTS5_DATA_ZERO_PADDING );
|
|
memset(&pBuf->p[pBuf->n+pSeg->nPos], 0, FTS5_DATA_ZERO_PADDING);
|
|
if( pColset==0 ){
|
|
fts5ChunkIterate(p, pSeg, (void*)pBuf, fts5PoslistCallback);
|
|
@@ -217430,66 +233846,72 @@ static void fts5SegiterPoslist(
|
|
}
|
|
|
|
/*
|
|
-** IN/OUT parameter (*pa) points to a position list n bytes in size. If
|
|
-** the position list contains entries for column iCol, then (*pa) is set
|
|
-** to point to the sub-position-list for that column and the number of
|
|
-** bytes in it returned. Or, if the argument position list does not
|
|
-** contain any entries for column iCol, return 0.
|
|
+** Parameter pPos points to a buffer containing a position list, size nPos.
|
|
+** This function filters it according to pColset (which must be non-NULL)
|
|
+** and sets pIter->base.pData/nData to point to the new position list.
|
|
+** If memory is required for the new position list, use buffer pIter->poslist.
|
|
+** Or, if the new position list is a contiguous subset of the input, set
|
|
+** pIter->base.pData/nData to point directly to it.
|
|
+**
|
|
+** This function is a no-op if *pRc is other than SQLITE_OK when it is
|
|
+** called. If an OOM error is encountered, *pRc is set to SQLITE_NOMEM
|
|
+** before returning.
|
|
*/
|
|
-static int fts5IndexExtractCol(
|
|
- const u8 **pa, /* IN/OUT: Pointer to poslist */
|
|
- int n, /* IN: Size of poslist in bytes */
|
|
- int iCol /* Column to extract from poslist */
|
|
-){
|
|
- int iCurrent = 0; /* Anything before the first 0x01 is col 0 */
|
|
- const u8 *p = *pa;
|
|
- const u8 *pEnd = &p[n]; /* One byte past end of position list */
|
|
-
|
|
- while( iCol>iCurrent ){
|
|
- /* Advance pointer p until it points to pEnd or an 0x01 byte that is
|
|
- ** not part of a varint. Note that it is not possible for a negative
|
|
- ** or extremely large varint to occur within an uncorrupted position
|
|
- ** list. So the last byte of each varint may be assumed to have a clear
|
|
- ** 0x80 bit. */
|
|
- while( *p!=0x01 ){
|
|
- while( *p++ & 0x80 );
|
|
- if( p>=pEnd ) return 0;
|
|
- }
|
|
- *pa = p++;
|
|
- iCurrent = *p++;
|
|
- if( iCurrent & 0x80 ){
|
|
- p--;
|
|
- p += fts5GetVarint32(p, iCurrent);
|
|
- }
|
|
- }
|
|
- if( iCol!=iCurrent ) return 0;
|
|
-
|
|
- /* Advance pointer p until it points to pEnd or an 0x01 byte that is
|
|
- ** not part of a varint */
|
|
- while( p<pEnd && *p!=0x01 ){
|
|
- while( *p++ & 0x80 );
|
|
- }
|
|
-
|
|
- return p - (*pa);
|
|
-}
|
|
-
|
|
static void fts5IndexExtractColset(
|
|
int *pRc,
|
|
Fts5Colset *pColset, /* Colset to filter on */
|
|
const u8 *pPos, int nPos, /* Position list */
|
|
- Fts5Buffer *pBuf /* Output buffer */
|
|
+ Fts5Iter *pIter
|
|
){
|
|
if( *pRc==SQLITE_OK ){
|
|
- int i;
|
|
- fts5BufferZero(pBuf);
|
|
- for(i=0; i<pColset->nCol; i++){
|
|
- const u8 *pSub = pPos;
|
|
- int nSub = fts5IndexExtractCol(&pSub, nPos, pColset->aiCol[i]);
|
|
- if( nSub ){
|
|
- fts5BufferAppendBlob(pRc, pBuf, nSub, pSub);
|
|
+ const u8 *p = pPos;
|
|
+ const u8 *aCopy = p;
|
|
+ const u8 *pEnd = &p[nPos]; /* One byte past end of position list */
|
|
+ int i = 0;
|
|
+ int iCurrent = 0;
|
|
+
|
|
+ if( pColset->nCol>1 && sqlite3Fts5BufferSize(pRc, &pIter->poslist, nPos) ){
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ while( 1 ){
|
|
+ while( pColset->aiCol[i]<iCurrent ){
|
|
+ i++;
|
|
+ if( i==pColset->nCol ){
|
|
+ pIter->base.pData = pIter->poslist.p;
|
|
+ pIter->base.nData = pIter->poslist.n;
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Advance pointer p until it points to pEnd or an 0x01 byte that is
|
|
+ ** not part of a varint */
|
|
+ while( p<pEnd && *p!=0x01 ){
|
|
+ while( *p++ & 0x80 );
|
|
+ }
|
|
+
|
|
+ if( pColset->aiCol[i]==iCurrent ){
|
|
+ if( pColset->nCol==1 ){
|
|
+ pIter->base.pData = aCopy;
|
|
+ pIter->base.nData = p-aCopy;
|
|
+ return;
|
|
+ }
|
|
+ fts5BufferSafeAppendBlob(&pIter->poslist, aCopy, p-aCopy);
|
|
+ }
|
|
+ if( p>=pEnd ){
|
|
+ pIter->base.pData = pIter->poslist.p;
|
|
+ pIter->base.nData = pIter->poslist.n;
|
|
+ return;
|
|
+ }
|
|
+ aCopy = p++;
|
|
+ iCurrent = *p++;
|
|
+ if( iCurrent & 0x80 ){
|
|
+ p--;
|
|
+ p += fts5GetVarint32(p, iCurrent);
|
|
}
|
|
}
|
|
}
|
|
+
|
|
}
|
|
|
|
/*
|
|
@@ -217513,7 +233935,7 @@ static void fts5IterSetOutputs_Nocolset(Fts5Iter *pIter, Fts5SegIter *pSeg){
|
|
assert( pIter->pColset==0 );
|
|
|
|
if( pSeg->iLeafOffset+pSeg->nPos<=pSeg->pLeaf->szLeaf ){
|
|
- /* All data is stored on the current page. Populate the output
|
|
+ /* All data is stored on the current page. Populate the output
|
|
** variables to point into the body of the page object. */
|
|
pIter->base.pData = &pSeg->pLeaf->p[pSeg->iLeafOffset];
|
|
}else{
|
|
@@ -217549,13 +233971,13 @@ static void fts5IterSetOutputs_Col(Fts5Iter *pIter, Fts5SegIter *pSeg){
|
|
}
|
|
|
|
/*
|
|
-** xSetOutputs callback used when:
|
|
+** xSetOutputs callback used when:
|
|
**
|
|
** * detail=col,
|
|
** * there is a column filter, and
|
|
-** * the table contains 100 or fewer columns.
|
|
+** * the table contains 100 or fewer columns.
|
|
**
|
|
-** The last point is to ensure all column numbers are stored as
|
|
+** The last point is to ensure all column numbers are stored as
|
|
** single-byte varints.
|
|
*/
|
|
static void fts5IterSetOutputs_Col100(Fts5Iter *pIter, Fts5SegIter *pSeg){
|
|
@@ -217567,7 +233989,7 @@ static void fts5IterSetOutputs_Col100(Fts5Iter *pIter, Fts5SegIter *pSeg){
|
|
fts5IterSetOutputs_Col(pIter, pSeg);
|
|
}else{
|
|
u8 *a = (u8*)&pSeg->pLeaf->p[pSeg->iLeafOffset];
|
|
- u8 *pEnd = (u8*)&a[pSeg->nPos];
|
|
+ u8 *pEnd = (u8*)&a[pSeg->nPos];
|
|
int iPrev = 0;
|
|
int *aiCol = pIter->pColset->aiCol;
|
|
int *aiColEnd = &aiCol[pIter->pColset->nCol];
|
|
@@ -217606,19 +234028,12 @@ static void fts5IterSetOutputs_Full(Fts5Iter *pIter, Fts5SegIter *pSeg){
|
|
assert( pColset );
|
|
|
|
if( pSeg->iLeafOffset+pSeg->nPos<=pSeg->pLeaf->szLeaf ){
|
|
- /* All data is stored on the current page. Populate the output
|
|
+ /* All data is stored on the current page. Populate the output
|
|
** variables to point into the body of the page object. */
|
|
const u8 *a = &pSeg->pLeaf->p[pSeg->iLeafOffset];
|
|
- if( pColset->nCol==1 ){
|
|
- pIter->base.nData = fts5IndexExtractCol(&a, pSeg->nPos,pColset->aiCol[0]);
|
|
- pIter->base.pData = a;
|
|
- }else{
|
|
- int *pRc = &pIter->pIndex->rc;
|
|
- fts5BufferZero(&pIter->poslist);
|
|
- fts5IndexExtractColset(pRc, pColset, a, pSeg->nPos, &pIter->poslist);
|
|
- pIter->base.pData = pIter->poslist.p;
|
|
- pIter->base.nData = pIter->poslist.n;
|
|
- }
|
|
+ int *pRc = &pIter->pIndex->rc;
|
|
+ fts5BufferZero(&pIter->poslist);
|
|
+ fts5IndexExtractColset(pRc, pColset, a, pSeg->nPos, pIter);
|
|
}else{
|
|
/* The data is distributed over two or more pages. Copy it into the
|
|
** Fts5Iter.poslist buffer and then set the output pointer to point
|
|
@@ -217631,6 +234046,7 @@ static void fts5IterSetOutputs_Full(Fts5Iter *pIter, Fts5SegIter *pSeg){
|
|
}
|
|
|
|
static void fts5IterSetOutputCb(int *pRc, Fts5Iter *pIter){
|
|
+ assert( pIter!=0 || (*pRc)!=SQLITE_OK );
|
|
if( *pRc==SQLITE_OK ){
|
|
Fts5Config *pConfig = pIter->pIndex->pConfig;
|
|
if( pConfig->eDetail==FTS5_DETAIL_NONE ){
|
|
@@ -217670,7 +234086,7 @@ static void fts5IterSetOutputCb(int *pRc, Fts5Iter *pIter){
|
|
** is zero or greater, data from the first nSegment segments on level iLevel
|
|
** is merged.
|
|
**
|
|
-** The iterator initially points to the first term/rowid entry in the
|
|
+** The iterator initially points to the first term/rowid entry in the
|
|
** iterated data.
|
|
*/
|
|
static void fts5MultiIterNew(
|
|
@@ -217702,7 +234118,10 @@ static void fts5MultiIterNew(
|
|
}
|
|
}
|
|
*ppOut = pNew = fts5MultiIterAlloc(p, nSeg);
|
|
- if( pNew==0 ) return;
|
|
+ if( pNew==0 ){
|
|
+ assert( p->rc!=SQLITE_OK );
|
|
+ goto fts5MultiIterNew_post_check;
|
|
+ }
|
|
pNew->bRev = (0!=(flags & FTS5INDEX_QUERY_DESC));
|
|
pNew->bSkipEmpty = (0!=(flags & FTS5INDEX_QUERY_SKIPEMPTY));
|
|
pNew->pColset = pColset;
|
|
@@ -217739,8 +234158,8 @@ static void fts5MultiIterNew(
|
|
assert( iIter==nSeg );
|
|
}
|
|
|
|
- /* If the above was successful, each component iterators now points
|
|
- ** to the first entry in its segment. In this case initialize the
|
|
+ /* If the above was successful, each component iterators now points
|
|
+ ** to the first entry in its segment. In this case initialize the
|
|
** aFirst[] array. Or, if an error has occurred, free the iterator
|
|
** object and set the output variable to NULL. */
|
|
if( p->rc==SQLITE_OK ){
|
|
@@ -217766,6 +234185,10 @@ static void fts5MultiIterNew(
|
|
fts5MultiIterFree(pNew);
|
|
*ppOut = 0;
|
|
}
|
|
+
|
|
+fts5MultiIterNew_post_check:
|
|
+ assert( (*ppOut)!=0 || p->rc!=SQLITE_OK );
|
|
+ return;
|
|
}
|
|
|
|
/*
|
|
@@ -217809,12 +234232,13 @@ static void fts5MultiIterNew2(
|
|
}
|
|
|
|
/*
|
|
-** Return true if the iterator is at EOF or if an error has occurred.
|
|
+** Return true if the iterator is at EOF or if an error has occurred.
|
|
** False otherwise.
|
|
*/
|
|
static int fts5MultiIterEof(Fts5Index *p, Fts5Iter *pIter){
|
|
- assert( p->rc
|
|
- || (pIter->aSeg[ pIter->aFirst[1].iFirst ].pLeaf==0)==pIter->base.bEof
|
|
+ assert( pIter!=0 || p->rc!=SQLITE_OK );
|
|
+ assert( p->rc!=SQLITE_OK
|
|
+ || (pIter->aSeg[ pIter->aFirst[1].iFirst ].pLeaf==0)==pIter->base.bEof
|
|
);
|
|
return (p->rc || pIter->base.bEof);
|
|
}
|
|
@@ -217833,8 +234257,8 @@ static i64 fts5MultiIterRowid(Fts5Iter *pIter){
|
|
** Move the iterator to the next entry at or following iMatch.
|
|
*/
|
|
static void fts5MultiIterNextFrom(
|
|
- Fts5Index *p,
|
|
- Fts5Iter *pIter,
|
|
+ Fts5Index *p,
|
|
+ Fts5Iter *pIter,
|
|
i64 iMatch
|
|
){
|
|
while( 1 ){
|
|
@@ -217848,7 +234272,7 @@ static void fts5MultiIterNextFrom(
|
|
}
|
|
|
|
/*
|
|
-** Return a pointer to a buffer containing the term associated with the
|
|
+** Return a pointer to a buffer containing the term associated with the
|
|
** entry that the iterator currently points to.
|
|
*/
|
|
static const u8 *fts5MultiIterTerm(Fts5Iter *pIter, int *pn){
|
|
@@ -217859,11 +234283,11 @@ static const u8 *fts5MultiIterTerm(Fts5Iter *pIter, int *pn){
|
|
|
|
/*
|
|
** Allocate a new segment-id for the structure pStruct. The new segment
|
|
-** id must be between 1 and 65335 inclusive, and must not be used by
|
|
+** id must be between 1 and 65335 inclusive, and must not be used by
|
|
** any currently existing segment. If a free segment id cannot be found,
|
|
** SQLITE_FULL is returned.
|
|
**
|
|
-** If an error has already occurred, this function is a no-op. 0 is
|
|
+** If an error has already occurred, this function is a no-op. 0 is
|
|
** returned in this case.
|
|
*/
|
|
static int fts5AllocateSegid(Fts5Index *p, Fts5Structure *pStruct){
|
|
@@ -217932,10 +234356,10 @@ static void fts5IndexDiscardData(Fts5Index *p){
|
|
}
|
|
|
|
/*
|
|
-** Return the size of the prefix, in bytes, that buffer
|
|
+** Return the size of the prefix, in bytes, that buffer
|
|
** (pNew/<length-unknown>) shares with buffer (pOld/nOld).
|
|
**
|
|
-** Buffer (pNew/<length-unknown>) is guaranteed to be greater
|
|
+** Buffer (pNew/<length-unknown>) is guaranteed to be greater
|
|
** than buffer (pOld/nOld).
|
|
*/
|
|
static int fts5PrefixCompress(int nOld, const u8 *pOld, const u8 *pNew){
|
|
@@ -217947,7 +234371,7 @@ static int fts5PrefixCompress(int nOld, const u8 *pOld, const u8 *pNew){
|
|
}
|
|
|
|
static void fts5WriteDlidxClear(
|
|
- Fts5Index *p,
|
|
+ Fts5Index *p,
|
|
Fts5SegWriter *pWriter,
|
|
int bFlush /* If true, write dlidx to disk */
|
|
){
|
|
@@ -217958,7 +234382,7 @@ static void fts5WriteDlidxClear(
|
|
if( pDlidx->buf.n==0 ) break;
|
|
if( bFlush ){
|
|
assert( pDlidx->pgno!=0 );
|
|
- fts5DataWrite(p,
|
|
+ fts5DataWrite(p,
|
|
FTS5_DLIDX_ROWID(pWriter->iSegid, i, pDlidx->pgno),
|
|
pDlidx->buf.p, pDlidx->buf.n
|
|
);
|
|
@@ -218012,8 +234436,8 @@ static int fts5WriteFlushDlidx(Fts5Index *p, Fts5SegWriter *pWriter){
|
|
}
|
|
|
|
/*
|
|
-** This function is called whenever processing of the doclist for the
|
|
-** last term on leaf page (pWriter->iBtPage) is completed.
|
|
+** This function is called whenever processing of the doclist for the
|
|
+** last term on leaf page (pWriter->iBtPage) is completed.
|
|
**
|
|
** The doclist-index for that term is currently stored in-memory within the
|
|
** Fts5SegWriter.aDlidx[] array. If it is large enough, this function
|
|
@@ -218098,8 +234522,8 @@ static i64 fts5DlidxExtractFirstRowid(Fts5Buffer *pBuf){
|
|
** doclist-index.
|
|
*/
|
|
static void fts5WriteDlidxAppend(
|
|
- Fts5Index *p,
|
|
- Fts5SegWriter *pWriter,
|
|
+ Fts5Index *p,
|
|
+ Fts5SegWriter *pWriter,
|
|
i64 iRowid
|
|
){
|
|
int i;
|
|
@@ -218112,11 +234536,11 @@ static void fts5WriteDlidxAppend(
|
|
if( pDlidx->buf.n>=p->pConfig->pgsz ){
|
|
/* The current doclist-index page is full. Write it to disk and push
|
|
** a copy of iRowid (which will become the first rowid on the next
|
|
- ** doclist-index leaf page) up into the next level of the b-tree
|
|
+ ** doclist-index leaf page) up into the next level of the b-tree
|
|
** hierarchy. If the node being flushed is currently the root node,
|
|
** also push its first rowid upwards. */
|
|
pDlidx->buf.p[0] = 0x01; /* Not the root node */
|
|
- fts5DataWrite(p,
|
|
+ fts5DataWrite(p,
|
|
FTS5_DLIDX_ROWID(pWriter->iSegid, i, pDlidx->pgno),
|
|
pDlidx->buf.p, pDlidx->buf.n
|
|
);
|
|
@@ -218200,13 +234624,13 @@ static void fts5WriteFlushLeaf(Fts5Index *p, Fts5SegWriter *pWriter){
|
|
** Append term pTerm/nTerm to the segment being written by the writer passed
|
|
** as the second argument.
|
|
**
|
|
-** If an error occurs, set the Fts5Index.rc error code. If an error has
|
|
+** If an error occurs, set the Fts5Index.rc error code. If an error has
|
|
** already occurred, this function is a no-op.
|
|
*/
|
|
static void fts5WriteAppendTerm(
|
|
- Fts5Index *p,
|
|
+ Fts5Index *p,
|
|
Fts5SegWriter *pWriter,
|
|
- int nTerm, const u8 *pTerm
|
|
+ int nTerm, const u8 *pTerm
|
|
){
|
|
int nPrefix; /* Bytes of prefix compression for term */
|
|
Fts5PageWriter *pPage = &pWriter->writer;
|
|
@@ -218225,7 +234649,7 @@ static void fts5WriteAppendTerm(
|
|
}
|
|
fts5BufferGrow(&p->rc, &pPage->buf, nTerm+FTS5_DATA_PADDING);
|
|
}
|
|
-
|
|
+
|
|
/* TODO1: Updating pgidx here. */
|
|
pPgidx->n += sqlite3Fts5PutVarint(
|
|
&pPgidx->p[pPgidx->n], pPage->buf.n - pPage->iPrevPgidx
|
|
@@ -218241,11 +234665,11 @@ static void fts5WriteAppendTerm(
|
|
if( pPage->pgno!=1 ){
|
|
/* This is the first term on a leaf that is not the leftmost leaf in
|
|
** the segment b-tree. In this case it is necessary to add a term to
|
|
- ** the b-tree hierarchy that is (a) larger than the largest term
|
|
+ ** the b-tree hierarchy that is (a) larger than the largest term
|
|
** already written to the segment and (b) smaller than or equal to
|
|
** this term. In other words, a prefix of (pTerm/nTerm) that is one
|
|
** byte longer than the longest prefix (pTerm/nTerm) shares with the
|
|
- ** previous term.
|
|
+ ** previous term.
|
|
**
|
|
** Usually, the previous term is available in pPage->term. The exception
|
|
** is if this is the first term written in an incremental-merge step.
|
|
@@ -218282,10 +234706,10 @@ static void fts5WriteAppendTerm(
|
|
}
|
|
|
|
/*
|
|
-** Append a rowid and position-list size field to the writers output.
|
|
+** Append a rowid and position-list size field to the writers output.
|
|
*/
|
|
static void fts5WriteAppendRowid(
|
|
- Fts5Index *p,
|
|
+ Fts5Index *p,
|
|
Fts5SegWriter *pWriter,
|
|
i64 iRowid
|
|
){
|
|
@@ -218296,7 +234720,7 @@ static void fts5WriteAppendRowid(
|
|
fts5WriteFlushLeaf(p, pWriter);
|
|
}
|
|
|
|
- /* If this is to be the first rowid written to the page, set the
|
|
+ /* If this is to be the first rowid written to the page, set the
|
|
** rowid-pointer in the page-header. Also append a value to the dlidx
|
|
** buffer, in case a doclist-index is required. */
|
|
if( pWriter->bFirstRowidInPage ){
|
|
@@ -218309,7 +234733,9 @@ static void fts5WriteAppendRowid(
|
|
fts5BufferAppendVarint(&p->rc, &pPage->buf, iRowid);
|
|
}else{
|
|
assert_nc( p->rc || iRowid>pWriter->iPrevRowid );
|
|
- fts5BufferAppendVarint(&p->rc, &pPage->buf, iRowid - pWriter->iPrevRowid);
|
|
+ fts5BufferAppendVarint(&p->rc, &pPage->buf,
|
|
+ (u64)iRowid - (u64)pWriter->iPrevRowid
|
|
+ );
|
|
}
|
|
pWriter->iPrevRowid = iRowid;
|
|
pWriter->bFirstRowidInDoclist = 0;
|
|
@@ -218318,18 +234744,18 @@ static void fts5WriteAppendRowid(
|
|
}
|
|
|
|
static void fts5WriteAppendPoslistData(
|
|
- Fts5Index *p,
|
|
- Fts5SegWriter *pWriter,
|
|
- const u8 *aData,
|
|
+ Fts5Index *p,
|
|
+ Fts5SegWriter *pWriter,
|
|
+ const u8 *aData,
|
|
int nData
|
|
){
|
|
Fts5PageWriter *pPage = &pWriter->writer;
|
|
const u8 *a = aData;
|
|
int n = nData;
|
|
-
|
|
+
|
|
assert( p->pConfig->pgsz>0 );
|
|
- while( p->rc==SQLITE_OK
|
|
- && (pPage->buf.n + pPage->pgidx.n + n)>=p->pConfig->pgsz
|
|
+ while( p->rc==SQLITE_OK
|
|
+ && (pPage->buf.n + pPage->pgidx.n + n)>=p->pConfig->pgsz
|
|
){
|
|
int nReq = p->pConfig->pgsz - pPage->buf.n - pPage->pgidx.n;
|
|
int nCopy = 0;
|
|
@@ -218352,7 +234778,7 @@ static void fts5WriteAppendPoslistData(
|
|
** allocations associated with the writer.
|
|
*/
|
|
static void fts5WriteFinish(
|
|
- Fts5Index *p,
|
|
+ Fts5Index *p,
|
|
Fts5SegWriter *pWriter, /* Writer object */
|
|
int *pnLeaf /* OUT: Number of leaf pages in b-tree */
|
|
){
|
|
@@ -218380,8 +234806,8 @@ static void fts5WriteFinish(
|
|
}
|
|
|
|
static void fts5WriteInit(
|
|
- Fts5Index *p,
|
|
- Fts5SegWriter *pWriter,
|
|
+ Fts5Index *p,
|
|
+ Fts5SegWriter *pWriter,
|
|
int iSegid
|
|
){
|
|
const int nBuffer = p->pConfig->pgsz + FTS5_DATA_PADDING;
|
|
@@ -218404,7 +234830,7 @@ static void fts5WriteInit(
|
|
if( p->pIdxWriter==0 ){
|
|
Fts5Config *pConfig = p->pConfig;
|
|
fts5IndexPrepareStmt(p, &p->pIdxWriter, sqlite3_mprintf(
|
|
- "INSERT INTO '%q'.'%q_idx'(segid,term,pgno) VALUES(?,?,?)",
|
|
+ "INSERT INTO '%q'.'%q_idx'(segid,term,pgno) VALUES(?,?,?)",
|
|
pConfig->zDb, pConfig->zName
|
|
));
|
|
}
|
|
@@ -218470,13 +234896,13 @@ static void fts5TrimSegments(Fts5Index *p, Fts5Iter *pIter){
|
|
|
|
/* Set up the new page-index array */
|
|
fts5BufferAppendVarint(&p->rc, &buf, 4);
|
|
- if( pSeg->iLeafPgno==pSeg->iTermLeafPgno
|
|
+ if( pSeg->iLeafPgno==pSeg->iTermLeafPgno
|
|
&& pSeg->iEndofDoclist<pData->szLeaf
|
|
&& pSeg->iPgidxOff<=pData->nn
|
|
){
|
|
int nDiff = pData->szLeaf - pSeg->iEndofDoclist;
|
|
fts5BufferAppendVarint(&p->rc, &buf, buf.n - 1 - nDiff - 4);
|
|
- fts5BufferAppendBlob(&p->rc, &buf,
|
|
+ fts5BufferAppendBlob(&p->rc, &buf,
|
|
pData->nn - pSeg->iPgidxOff, &pData->p[pSeg->iPgidxOff]
|
|
);
|
|
}
|
|
@@ -218493,8 +234919,8 @@ static void fts5TrimSegments(Fts5Index *p, Fts5Iter *pIter){
|
|
}
|
|
|
|
static void fts5MergeChunkCallback(
|
|
- Fts5Index *p,
|
|
- void *pCtx,
|
|
+ Fts5Index *p,
|
|
+ void *pCtx,
|
|
const u8 *pChunk, int nChunk
|
|
){
|
|
Fts5SegWriter *pWriter = (Fts5SegWriter*)pCtx;
|
|
@@ -218617,6 +235043,7 @@ static void fts5IndexMergeLevel(
|
|
** and last leaf page number at the same time. */
|
|
fts5WriteFinish(p, &writer, &pSeg->pgnoLast);
|
|
|
|
+ assert( pIter!=0 || p->rc!=SQLITE_OK );
|
|
if( fts5MultiIterEof(p, pIter) ){
|
|
int i;
|
|
|
|
@@ -218709,7 +235136,7 @@ static int fts5IndexMerge(
|
|
** segment. This function updates the write-counter accordingly and, if
|
|
** necessary, performs incremental merge work.
|
|
**
|
|
-** If an error occurs, set the Fts5Index.rc error code. If an error has
|
|
+** If an error occurs, set the Fts5Index.rc error code. If an error has
|
|
** already occurred, this function is a no-op.
|
|
*/
|
|
static void fts5IndexAutomerge(
|
|
@@ -218717,7 +235144,7 @@ static void fts5IndexAutomerge(
|
|
Fts5Structure **ppStruct, /* IN/OUT: Current structure of index */
|
|
int nLeaf /* Number of output leaves just written */
|
|
){
|
|
- if( p->rc==SQLITE_OK && p->pConfig->nAutomerge>0 ){
|
|
+ if( p->rc==SQLITE_OK && p->pConfig->nAutomerge>0 && ALWAYS((*ppStruct)!=0) ){
|
|
Fts5Structure *pStruct = *ppStruct;
|
|
u64 nWrite; /* Initial value of write-counter */
|
|
int nWork; /* Number of work-quanta to perform */
|
|
@@ -218760,12 +235187,12 @@ static int fts5IndexReturn(Fts5Index *p){
|
|
typedef struct Fts5FlushCtx Fts5FlushCtx;
|
|
struct Fts5FlushCtx {
|
|
Fts5Index *pIdx;
|
|
- Fts5SegWriter writer;
|
|
+ Fts5SegWriter writer;
|
|
};
|
|
|
|
/*
|
|
** Buffer aBuf[] contains a list of varints, all small enough to fit
|
|
-** in a 32-bit integer. Return the size of the largest prefix of this
|
|
+** in a 32-bit integer. Return the size of the largest prefix of this
|
|
** list nMax bytes or less in size.
|
|
*/
|
|
static int fts5PoslistPrefix(const u8 *aBuf, int nMax){
|
|
@@ -218783,10 +235210,10 @@ static int fts5PoslistPrefix(const u8 *aBuf, int nMax){
|
|
}
|
|
|
|
/*
|
|
-** Flush the contents of in-memory hash table iHash to a new level-0
|
|
+** Flush the contents of in-memory hash table iHash to a new level-0
|
|
** segment on disk. Also update the corresponding structure record.
|
|
**
|
|
-** If an error occurs, set the Fts5Index.rc error code. If an error has
|
|
+** If an error occurs, set the Fts5Index.rc error code. If an error has
|
|
** already occurred, this function is a no-op.
|
|
*/
|
|
static void fts5FlushOneHash(Fts5Index *p){
|
|
@@ -218840,16 +235267,16 @@ static void fts5FlushOneHash(Fts5Index *p){
|
|
fts5BufferSafeAppendBlob(pBuf, pDoclist, nDoclist);
|
|
}else{
|
|
i64 iRowid = 0;
|
|
- i64 iDelta = 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
|
|
+ /* 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 && iOff<nDoclist ){
|
|
- iOff += fts5GetVarint(&pDoclist[iOff], (u64*)&iDelta);
|
|
+ iOff += fts5GetVarint(&pDoclist[iOff], &iDelta);
|
|
iRowid += iDelta;
|
|
-
|
|
+
|
|
if( writer.bFirstRowidInPage ){
|
|
fts5PutU16(&pBuf->p[0], (u16)pBuf->n); /* first rowid on page */
|
|
pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iRowid);
|
|
@@ -218953,7 +235380,7 @@ static void fts5IndexFlush(Fts5Index *p){
|
|
}
|
|
|
|
static Fts5Structure *fts5IndexOptimizeStruct(
|
|
- Fts5Index *p,
|
|
+ Fts5Index *p,
|
|
Fts5Structure *pStruct
|
|
){
|
|
Fts5Structure *pNew = 0;
|
|
@@ -218964,7 +235391,7 @@ 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
|
|
+ ** + 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.
|
|
**
|
|
@@ -218987,10 +235414,10 @@ static Fts5Structure *fts5IndexOptimizeStruct(
|
|
if( pNew ){
|
|
Fts5StructureLevel *pLvl;
|
|
nByte = nSeg * sizeof(Fts5StructureSegment);
|
|
- pNew->nLevel = pStruct->nLevel+1;
|
|
+ pNew->nLevel = MIN(pStruct->nLevel+1, FTS5_MAX_LEVEL);
|
|
pNew->nRef = 1;
|
|
pNew->nWriteCounter = pStruct->nWriteCounter;
|
|
- pLvl = &pNew->aLevel[pStruct->nLevel];
|
|
+ pLvl = &pNew->aLevel[pNew->nLevel-1];
|
|
pLvl->aSeg = (Fts5StructureSegment*)sqlite3Fts5MallocZero(&p->rc, nByte);
|
|
if( pLvl->aSeg ){
|
|
int iLvl, iSeg;
|
|
@@ -219041,7 +235468,7 @@ static int sqlite3Fts5IndexOptimize(Fts5Index *p){
|
|
fts5StructureRelease(pNew);
|
|
}
|
|
|
|
- return fts5IndexReturn(p);
|
|
+ return fts5IndexReturn(p);
|
|
}
|
|
|
|
/*
|
|
@@ -219072,7 +235499,7 @@ static int sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge){
|
|
|
|
static void fts5AppendRowid(
|
|
Fts5Index *p,
|
|
- i64 iDelta,
|
|
+ u64 iDelta,
|
|
Fts5Iter *pUnused,
|
|
Fts5Buffer *pBuf
|
|
){
|
|
@@ -219082,7 +235509,7 @@ static void fts5AppendRowid(
|
|
|
|
static void fts5AppendPoslist(
|
|
Fts5Index *p,
|
|
- i64 iDelta,
|
|
+ u64 iDelta,
|
|
Fts5Iter *pMulti,
|
|
Fts5Buffer *pBuf
|
|
){
|
|
@@ -219101,7 +235528,7 @@ static void fts5AppendPoslist(
|
|
static void fts5DoclistIterNext(Fts5DoclistIter *pIter){
|
|
u8 *p = pIter->aPoslist + pIter->nSize + pIter->nPoslist;
|
|
|
|
- assert( pIter->aPoslist );
|
|
+ assert( pIter->aPoslist || (p==0 && pIter->aPoslist==0) );
|
|
if( p>=pIter->aEof ){
|
|
pIter->aPoslist = 0;
|
|
}else{
|
|
@@ -219121,17 +235548,22 @@ static void fts5DoclistIterNext(Fts5DoclistIter *pIter){
|
|
}
|
|
|
|
pIter->aPoslist = p;
|
|
+ if( &pIter->aPoslist[pIter->nPoslist]>pIter->aEof ){
|
|
+ pIter->aPoslist = 0;
|
|
+ }
|
|
}
|
|
}
|
|
|
|
static void fts5DoclistIterInit(
|
|
- Fts5Buffer *pBuf,
|
|
+ Fts5Buffer *pBuf,
|
|
Fts5DoclistIter *pIter
|
|
){
|
|
memset(pIter, 0, sizeof(*pIter));
|
|
- pIter->aPoslist = pBuf->p;
|
|
- pIter->aEof = &pBuf->p[pBuf->n];
|
|
- fts5DoclistIterNext(pIter);
|
|
+ if( pBuf->n>0 ){
|
|
+ pIter->aPoslist = pBuf->p;
|
|
+ pIter->aEof = &pBuf->p[pBuf->n];
|
|
+ fts5DoclistIterNext(pIter);
|
|
+ }
|
|
}
|
|
|
|
#if 0
|
|
@@ -219152,10 +235584,10 @@ static void fts5MergeAppendDocid(
|
|
}
|
|
#endif
|
|
|
|
-#define fts5MergeAppendDocid(pBuf, iLastRowid, iRowid) { \
|
|
- assert( (pBuf)->n!=0 || (iLastRowid)==0 ); \
|
|
- fts5BufferSafeAppendVarint((pBuf), (iRowid) - (iLastRowid)); \
|
|
- (iLastRowid) = (iRowid); \
|
|
+#define fts5MergeAppendDocid(pBuf, iLastRowid, iRowid) { \
|
|
+ assert( (pBuf)->n!=0 || (iLastRowid)==0 ); \
|
|
+ fts5BufferSafeAppendVarint((pBuf), (u64)(iRowid) - (u64)(iLastRowid)); \
|
|
+ (iLastRowid) = (iRowid); \
|
|
}
|
|
|
|
/*
|
|
@@ -219185,16 +235617,20 @@ static void fts5NextRowid(Fts5Buffer *pBuf, int *piOff, i64 *piRowid){
|
|
static void fts5MergeRowidLists(
|
|
Fts5Index *p, /* FTS5 backend object */
|
|
Fts5Buffer *p1, /* First list to merge */
|
|
- Fts5Buffer *p2 /* Second list to merge */
|
|
+ int nBuf, /* Number of entries in apBuf[] */
|
|
+ Fts5Buffer *aBuf /* Array of other lists to merge into p1 */
|
|
){
|
|
int i1 = 0;
|
|
int i2 = 0;
|
|
i64 iRowid1 = 0;
|
|
i64 iRowid2 = 0;
|
|
i64 iOut = 0;
|
|
-
|
|
+ Fts5Buffer *p2 = &aBuf[0];
|
|
Fts5Buffer out;
|
|
+
|
|
+ (void)nBuf;
|
|
memset(&out, 0, sizeof(out));
|
|
+ assert( nBuf==1 );
|
|
sqlite3Fts5BufferSize(&p->rc, &out, p1->n + p2->n);
|
|
if( p->rc ) return;
|
|
|
|
@@ -219221,177 +235657,214 @@ static void fts5MergeRowidLists(
|
|
fts5BufferFree(&out);
|
|
}
|
|
|
|
+typedef struct PrefixMerger PrefixMerger;
|
|
+struct PrefixMerger {
|
|
+ Fts5DoclistIter iter; /* Doclist iterator */
|
|
+ i64 iPos; /* For iterating through a position list */
|
|
+ int iOff;
|
|
+ u8 *aPos;
|
|
+ PrefixMerger *pNext; /* Next in docid/poslist order */
|
|
+};
|
|
+
|
|
+static void fts5PrefixMergerInsertByRowid(
|
|
+ PrefixMerger **ppHead,
|
|
+ PrefixMerger *p
|
|
+){
|
|
+ if( p->iter.aPoslist ){
|
|
+ PrefixMerger **pp = ppHead;
|
|
+ while( *pp && p->iter.iRowid>(*pp)->iter.iRowid ){
|
|
+ pp = &(*pp)->pNext;
|
|
+ }
|
|
+ p->pNext = *pp;
|
|
+ *pp = p;
|
|
+ }
|
|
+}
|
|
+
|
|
+static void fts5PrefixMergerInsertByPosition(
|
|
+ PrefixMerger **ppHead,
|
|
+ PrefixMerger *p
|
|
+){
|
|
+ if( p->iPos>=0 ){
|
|
+ PrefixMerger **pp = ppHead;
|
|
+ while( *pp && p->iPos>(*pp)->iPos ){
|
|
+ pp = &(*pp)->pNext;
|
|
+ }
|
|
+ p->pNext = *pp;
|
|
+ *pp = p;
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
/*
|
|
-** Buffers p1 and p2 contain doclists. This function merges the content
|
|
-** of the two doclists together and sets buffer p1 to the result before
|
|
-** returning.
|
|
-**
|
|
-** If an error occurs, an error code is left in p->rc. If an error has
|
|
-** already occurred, this function is a no-op.
|
|
+** Array aBuf[] contains nBuf doclists. These are all merged in with the
|
|
+** doclist in buffer p1.
|
|
*/
|
|
static void fts5MergePrefixLists(
|
|
Fts5Index *p, /* FTS5 backend object */
|
|
Fts5Buffer *p1, /* First list to merge */
|
|
- Fts5Buffer *p2 /* Second list to merge */
|
|
-){
|
|
- if( p2->n ){
|
|
- i64 iLastRowid = 0;
|
|
- Fts5DoclistIter i1;
|
|
- Fts5DoclistIter i2;
|
|
- Fts5Buffer out = {0, 0, 0};
|
|
- Fts5Buffer tmp = {0, 0, 0};
|
|
-
|
|
- /* The maximum size of the output is equal to the sum of the two
|
|
- ** input sizes + 1 varint (9 bytes). The extra varint is because if the
|
|
- ** first rowid in one input is a large negative number, and the first in
|
|
- ** the other a non-negative number, the delta for the non-negative
|
|
- ** number will be larger on disk than the literal integer value
|
|
- ** was.
|
|
- **
|
|
- ** Or, if the input position-lists are corrupt, then the output might
|
|
- ** include up to 2 extra 10-byte positions created by interpreting -1
|
|
- ** (the value PoslistNext64() uses for EOF) as a position and appending
|
|
- ** it to the output. This can happen at most once for each input
|
|
- ** position-list, hence two 10 byte paddings. */
|
|
- if( sqlite3Fts5BufferSize(&p->rc, &out, p1->n + p2->n + 9+10+10) ) return;
|
|
- fts5DoclistIterInit(p1, &i1);
|
|
- fts5DoclistIterInit(p2, &i2);
|
|
+ int nBuf, /* Number of buffers in array aBuf[] */
|
|
+ Fts5Buffer *aBuf /* Other lists to merge in */
|
|
+){
|
|
+#define fts5PrefixMergerNextPosition(p) \
|
|
+ sqlite3Fts5PoslistNext64((p)->aPos,(p)->iter.nPoslist,&(p)->iOff,&(p)->iPos)
|
|
+#define FTS5_MERGE_NLIST 16
|
|
+ PrefixMerger aMerger[FTS5_MERGE_NLIST];
|
|
+ PrefixMerger *pHead = 0;
|
|
+ int i;
|
|
+ int nOut = 0;
|
|
+ Fts5Buffer out = {0, 0, 0};
|
|
+ Fts5Buffer tmp = {0, 0, 0};
|
|
+ i64 iLastRowid = 0;
|
|
+
|
|
+ /* Initialize a doclist-iterator for each input buffer. Arrange them in
|
|
+ ** a linked-list starting at pHead in ascending order of rowid. Avoid
|
|
+ ** linking any iterators already at EOF into the linked list at all. */
|
|
+ assert( nBuf+1<=(int)(sizeof(aMerger)/sizeof(aMerger[0])) );
|
|
+ memset(aMerger, 0, sizeof(PrefixMerger)*(nBuf+1));
|
|
+ pHead = &aMerger[nBuf];
|
|
+ fts5DoclistIterInit(p1, &pHead->iter);
|
|
+ for(i=0; i<nBuf; i++){
|
|
+ fts5DoclistIterInit(&aBuf[i], &aMerger[i].iter);
|
|
+ fts5PrefixMergerInsertByRowid(&pHead, &aMerger[i]);
|
|
+ nOut += aBuf[i].n;
|
|
+ }
|
|
+ if( nOut==0 ) return;
|
|
+ nOut += p1->n + 9 + 10*nBuf;
|
|
+
|
|
+ /* The maximum size of the output is equal to the sum of the
|
|
+ ** input sizes + 1 varint (9 bytes). The extra varint is because if the
|
|
+ ** first rowid in one input is a large negative number, and the first in
|
|
+ ** the other a non-negative number, the delta for the non-negative
|
|
+ ** number will be larger on disk than the literal integer value
|
|
+ ** was.
|
|
+ **
|
|
+ ** Or, if the input position-lists are corrupt, then the output might
|
|
+ ** include up to (nBuf+1) extra 10-byte positions created by interpreting -1
|
|
+ ** (the value PoslistNext64() uses for EOF) as a position and appending
|
|
+ ** it to the output. This can happen at most once for each input
|
|
+ ** position-list, hence (nBuf+1) 10 byte paddings. */
|
|
+ if( sqlite3Fts5BufferSize(&p->rc, &out, nOut) ) return;
|
|
+
|
|
+ while( pHead ){
|
|
+ fts5MergeAppendDocid(&out, iLastRowid, pHead->iter.iRowid);
|
|
+
|
|
+ if( pHead->pNext && iLastRowid==pHead->pNext->iter.iRowid ){
|
|
+ /* Merge data from two or more poslists */
|
|
+ i64 iPrev = 0;
|
|
+ int nTmp = FTS5_DATA_ZERO_PADDING;
|
|
+ int nMerge = 0;
|
|
+ PrefixMerger *pSave = pHead;
|
|
+ PrefixMerger *pThis = 0;
|
|
+ int nTail = 0;
|
|
+
|
|
+ pHead = 0;
|
|
+ while( pSave && pSave->iter.iRowid==iLastRowid ){
|
|
+ PrefixMerger *pNext = pSave->pNext;
|
|
+ pSave->iOff = 0;
|
|
+ pSave->iPos = 0;
|
|
+ pSave->aPos = &pSave->iter.aPoslist[pSave->iter.nSize];
|
|
+ fts5PrefixMergerNextPosition(pSave);
|
|
+ nTmp += pSave->iter.nPoslist + 10;
|
|
+ nMerge++;
|
|
+ fts5PrefixMergerInsertByPosition(&pHead, pSave);
|
|
+ pSave = pNext;
|
|
+ }
|
|
+
|
|
+ if( pHead==0 || pHead->pNext==0 ){
|
|
+ p->rc = FTS5_CORRUPT;
|
|
+ break;
|
|
+ }
|
|
|
|
- while( 1 ){
|
|
- if( i1.iRowid<i2.iRowid ){
|
|
- /* Copy entry from i1 */
|
|
- fts5MergeAppendDocid(&out, iLastRowid, i1.iRowid);
|
|
- fts5BufferSafeAppendBlob(&out, i1.aPoslist, i1.nPoslist+i1.nSize);
|
|
- fts5DoclistIterNext(&i1);
|
|
- if( i1.aPoslist==0 ) break;
|
|
- assert( out.n<=((i1.aPoslist-p1->p) + (i2.aPoslist-p2->p)+9+10+10) );
|
|
- }
|
|
- else if( i2.iRowid!=i1.iRowid ){
|
|
- /* Copy entry from i2 */
|
|
- fts5MergeAppendDocid(&out, iLastRowid, i2.iRowid);
|
|
- fts5BufferSafeAppendBlob(&out, i2.aPoslist, i2.nPoslist+i2.nSize);
|
|
- fts5DoclistIterNext(&i2);
|
|
- if( i2.aPoslist==0 ) break;
|
|
- assert( out.n<=((i1.aPoslist-p1->p) + (i2.aPoslist-p2->p)+9+10+10) );
|
|
+ /* See the earlier comment in this function for an explanation of why
|
|
+ ** corrupt input position lists might cause the output to consume
|
|
+ ** at most nMerge*10 bytes of unexpected space. */
|
|
+ if( sqlite3Fts5BufferSize(&p->rc, &tmp, nTmp+nMerge*10) ){
|
|
+ break;
|
|
}
|
|
- else{
|
|
- /* Merge the two position lists. */
|
|
- i64 iPos1 = 0;
|
|
- i64 iPos2 = 0;
|
|
- int iOff1 = 0;
|
|
- int iOff2 = 0;
|
|
- u8 *a1 = &i1.aPoslist[i1.nSize];
|
|
- u8 *a2 = &i2.aPoslist[i2.nSize];
|
|
- int nCopy;
|
|
- u8 *aCopy;
|
|
-
|
|
- i64 iPrev = 0;
|
|
- Fts5PoslistWriter writer;
|
|
- memset(&writer, 0, sizeof(writer));
|
|
-
|
|
- /* See the earlier comment in this function for an explanation of why
|
|
- ** corrupt input position lists might cause the output to consume
|
|
- ** at most 20 bytes of unexpected space. */
|
|
- fts5MergeAppendDocid(&out, iLastRowid, i2.iRowid);
|
|
- fts5BufferZero(&tmp);
|
|
- sqlite3Fts5BufferSize(&p->rc, &tmp, i1.nPoslist + i2.nPoslist + 10 + 10);
|
|
- if( p->rc ) break;
|
|
-
|
|
- sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1, &iPos1);
|
|
- sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2);
|
|
- assert_nc( iPos1>=0 && iPos2>=0 );
|
|
-
|
|
- if( iPos1<iPos2 ){
|
|
- sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos1);
|
|
- sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1, &iPos1);
|
|
- }else{
|
|
- sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos2);
|
|
- sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2);
|
|
- }
|
|
- if( iPos1>=0 && iPos2>=0 ){
|
|
- while( 1 ){
|
|
- if( iPos1<iPos2 ){
|
|
- if( iPos1!=iPrev ){
|
|
- sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos1);
|
|
- }
|
|
- sqlite3Fts5PoslistNext64(a1, i1.nPoslist, &iOff1, &iPos1);
|
|
- if( iPos1<0 ) break;
|
|
- }else{
|
|
- assert_nc( iPos2!=iPrev );
|
|
- sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos2);
|
|
- sqlite3Fts5PoslistNext64(a2, i2.nPoslist, &iOff2, &iPos2);
|
|
- if( iPos2<0 ) break;
|
|
- }
|
|
- }
|
|
- }
|
|
+ fts5BufferZero(&tmp);
|
|
|
|
- if( iPos1>=0 ){
|
|
- if( iPos1!=iPrev ){
|
|
- sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos1);
|
|
- }
|
|
- aCopy = &a1[iOff1];
|
|
- nCopy = i1.nPoslist - iOff1;
|
|
- }else{
|
|
- assert_nc( iPos2>=0 && iPos2!=iPrev );
|
|
- sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, iPos2);
|
|
- aCopy = &a2[iOff2];
|
|
- nCopy = i2.nPoslist - iOff2;
|
|
- }
|
|
- if( nCopy>0 ){
|
|
- fts5BufferSafeAppendBlob(&tmp, aCopy, nCopy);
|
|
+ pThis = pHead;
|
|
+ pHead = pThis->pNext;
|
|
+ sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, pThis->iPos);
|
|
+ fts5PrefixMergerNextPosition(pThis);
|
|
+ fts5PrefixMergerInsertByPosition(&pHead, pThis);
|
|
+
|
|
+ while( pHead->pNext ){
|
|
+ pThis = pHead;
|
|
+ if( pThis->iPos!=iPrev ){
|
|
+ sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, pThis->iPos);
|
|
}
|
|
+ fts5PrefixMergerNextPosition(pThis);
|
|
+ pHead = pThis->pNext;
|
|
+ fts5PrefixMergerInsertByPosition(&pHead, pThis);
|
|
+ }
|
|
|
|
- /* WRITEPOSLISTSIZE */
|
|
- assert_nc( tmp.n<=i1.nPoslist+i2.nPoslist );
|
|
- assert( tmp.n<=i1.nPoslist+i2.nPoslist+10+10 );
|
|
- if( tmp.n>i1.nPoslist+i2.nPoslist ){
|
|
- if( p->rc==SQLITE_OK ) p->rc = FTS5_CORRUPT;
|
|
- break;
|
|
+ if( pHead->iPos!=iPrev ){
|
|
+ sqlite3Fts5PoslistSafeAppend(&tmp, &iPrev, pHead->iPos);
|
|
+ }
|
|
+ nTail = pHead->iter.nPoslist - pHead->iOff;
|
|
+
|
|
+ /* WRITEPOSLISTSIZE */
|
|
+ assert_nc( tmp.n+nTail<=nTmp );
|
|
+ assert( tmp.n+nTail<=nTmp+nMerge*10 );
|
|
+ if( tmp.n+nTail>nTmp-FTS5_DATA_ZERO_PADDING ){
|
|
+ if( p->rc==SQLITE_OK ) p->rc = FTS5_CORRUPT;
|
|
+ break;
|
|
+ }
|
|
+ fts5BufferSafeAppendVarint(&out, (tmp.n+nTail) * 2);
|
|
+ fts5BufferSafeAppendBlob(&out, tmp.p, tmp.n);
|
|
+ if( nTail>0 ){
|
|
+ fts5BufferSafeAppendBlob(&out, &pHead->aPos[pHead->iOff], nTail);
|
|
+ }
|
|
+
|
|
+ pHead = pSave;
|
|
+ for(i=0; i<nBuf+1; i++){
|
|
+ PrefixMerger *pX = &aMerger[i];
|
|
+ if( pX->iter.aPoslist && pX->iter.iRowid==iLastRowid ){
|
|
+ fts5DoclistIterNext(&pX->iter);
|
|
+ fts5PrefixMergerInsertByRowid(&pHead, pX);
|
|
}
|
|
- fts5BufferSafeAppendVarint(&out, tmp.n * 2);
|
|
- fts5BufferSafeAppendBlob(&out, tmp.p, tmp.n);
|
|
- fts5DoclistIterNext(&i1);
|
|
- fts5DoclistIterNext(&i2);
|
|
- assert_nc( out.n<=(p1->n+p2->n+9) );
|
|
- if( i1.aPoslist==0 || i2.aPoslist==0 ) break;
|
|
- assert( out.n<=((i1.aPoslist-p1->p) + (i2.aPoslist-p2->p)+9+10+10) );
|
|
}
|
|
- }
|
|
|
|
- if( i1.aPoslist ){
|
|
- fts5MergeAppendDocid(&out, iLastRowid, i1.iRowid);
|
|
- fts5BufferSafeAppendBlob(&out, i1.aPoslist, i1.aEof - i1.aPoslist);
|
|
- }
|
|
- else if( i2.aPoslist ){
|
|
- fts5MergeAppendDocid(&out, iLastRowid, i2.iRowid);
|
|
- fts5BufferSafeAppendBlob(&out, i2.aPoslist, i2.aEof - i2.aPoslist);
|
|
+ }else{
|
|
+ /* Copy poslist from pHead to output */
|
|
+ PrefixMerger *pThis = pHead;
|
|
+ Fts5DoclistIter *pI = &pThis->iter;
|
|
+ fts5BufferSafeAppendBlob(&out, pI->aPoslist, pI->nPoslist+pI->nSize);
|
|
+ fts5DoclistIterNext(pI);
|
|
+ pHead = pThis->pNext;
|
|
+ fts5PrefixMergerInsertByRowid(&pHead, pThis);
|
|
}
|
|
- assert_nc( out.n<=(p1->n+p2->n+9) );
|
|
-
|
|
- fts5BufferSet(&p->rc, p1, out.n, out.p);
|
|
- fts5BufferFree(&tmp);
|
|
- fts5BufferFree(&out);
|
|
}
|
|
+
|
|
+ fts5BufferFree(p1);
|
|
+ fts5BufferFree(&tmp);
|
|
+ memset(&out.p[out.n], 0, FTS5_DATA_ZERO_PADDING);
|
|
+ *p1 = out;
|
|
}
|
|
|
|
static void fts5SetupPrefixIter(
|
|
Fts5Index *p, /* Index to read from */
|
|
int bDesc, /* True for "ORDER BY rowid DESC" */
|
|
- const u8 *pToken, /* Buffer containing prefix to match */
|
|
+ int iIdx, /* Index to scan for data */
|
|
+ u8 *pToken, /* Buffer containing prefix to match */
|
|
int nToken, /* Size of buffer pToken in bytes */
|
|
Fts5Colset *pColset, /* Restrict matches to these columns */
|
|
Fts5Iter **ppIter /* OUT: New iterator */
|
|
){
|
|
Fts5Structure *pStruct;
|
|
Fts5Buffer *aBuf;
|
|
- const int nBuf = 32;
|
|
+ int nBuf = 32;
|
|
+ int nMerge = 1;
|
|
|
|
- void (*xMerge)(Fts5Index*, Fts5Buffer*, Fts5Buffer*);
|
|
- void (*xAppend)(Fts5Index*, i64, Fts5Iter*, Fts5Buffer*);
|
|
+ void (*xMerge)(Fts5Index*, Fts5Buffer*, int, Fts5Buffer*);
|
|
+ void (*xAppend)(Fts5Index*, u64, Fts5Iter*, Fts5Buffer*);
|
|
if( p->pConfig->eDetail==FTS5_DETAIL_NONE ){
|
|
xMerge = fts5MergeRowidLists;
|
|
xAppend = fts5AppendRowid;
|
|
}else{
|
|
+ nMerge = FTS5_MERGE_NLIST-1;
|
|
+ nBuf = nMerge*8; /* Sufficient to merge (16^8)==(2^32) lists */
|
|
xMerge = fts5MergePrefixLists;
|
|
xAppend = fts5AppendPoslist;
|
|
}
|
|
@@ -219400,8 +235873,8 @@ static void fts5SetupPrefixIter(
|
|
pStruct = fts5StructureRead(p);
|
|
|
|
if( aBuf && pStruct ){
|
|
- const int flags = FTS5INDEX_QUERY_SCAN
|
|
- | FTS5INDEX_QUERY_SKIPEMPTY
|
|
+ const int flags = FTS5INDEX_QUERY_SCAN
|
|
+ | FTS5INDEX_QUERY_SKIPEMPTY
|
|
| FTS5INDEX_QUERY_NOOUTPUT;
|
|
int i;
|
|
i64 iLastRowid = 0;
|
|
@@ -219411,6 +235884,27 @@ static void fts5SetupPrefixIter(
|
|
int bNewTerm = 1;
|
|
|
|
memset(&doclist, 0, sizeof(doclist));
|
|
+ if( iIdx!=0 ){
|
|
+ int dummy = 0;
|
|
+ const int f2 = FTS5INDEX_QUERY_SKIPEMPTY|FTS5INDEX_QUERY_NOOUTPUT;
|
|
+ pToken[0] = FTS5_MAIN_PREFIX;
|
|
+ fts5MultiIterNew(p, pStruct, f2, pColset, pToken, nToken, -1, 0, &p1);
|
|
+ fts5IterSetOutputCb(&p->rc, p1);
|
|
+ for(;
|
|
+ fts5MultiIterEof(p, p1)==0;
|
|
+ fts5MultiIterNext2(p, p1, &dummy)
|
|
+ ){
|
|
+ Fts5SegIter *pSeg = &p1->aSeg[ p1->aFirst[1].iFirst ];
|
|
+ p1->xSetOutputs(p1, pSeg);
|
|
+ if( p1->base.nData ){
|
|
+ xAppend(p, (u64)p1->base.iRowid-(u64)iLastRowid, p1, &doclist);
|
|
+ iLastRowid = p1->base.iRowid;
|
|
+ }
|
|
+ }
|
|
+ fts5MultiIterFree(p1);
|
|
+ }
|
|
+
|
|
+ pToken[0] = FTS5_MAIN_PREFIX + iIdx;
|
|
fts5MultiIterNew(p, pStruct, flags, pColset, pToken, nToken, -1, 0, &p1);
|
|
fts5IterSetOutputCb(&p->rc, p1);
|
|
for( /* no-op */ ;
|
|
@@ -219431,27 +235925,39 @@ static void fts5SetupPrefixIter(
|
|
|
|
if( p1->base.iRowid<=iLastRowid && doclist.n>0 ){
|
|
for(i=0; p->rc==SQLITE_OK && doclist.n; i++){
|
|
- assert( i<nBuf );
|
|
- if( aBuf[i].n==0 ){
|
|
- fts5BufferSwap(&doclist, &aBuf[i]);
|
|
- fts5BufferZero(&doclist);
|
|
- }else{
|
|
- xMerge(p, &doclist, &aBuf[i]);
|
|
- fts5BufferZero(&aBuf[i]);
|
|
+ int i1 = i*nMerge;
|
|
+ int iStore;
|
|
+ assert( i1+nMerge<=nBuf );
|
|
+ for(iStore=i1; iStore<i1+nMerge; iStore++){
|
|
+ if( aBuf[iStore].n==0 ){
|
|
+ fts5BufferSwap(&doclist, &aBuf[iStore]);
|
|
+ fts5BufferZero(&doclist);
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ if( iStore==i1+nMerge ){
|
|
+ xMerge(p, &doclist, nMerge, &aBuf[i1]);
|
|
+ for(iStore=i1; iStore<i1+nMerge; iStore++){
|
|
+ fts5BufferZero(&aBuf[iStore]);
|
|
+ }
|
|
}
|
|
}
|
|
iLastRowid = 0;
|
|
}
|
|
|
|
- xAppend(p, p1->base.iRowid-iLastRowid, p1, &doclist);
|
|
+ xAppend(p, (u64)p1->base.iRowid-(u64)iLastRowid, p1, &doclist);
|
|
iLastRowid = p1->base.iRowid;
|
|
}
|
|
|
|
- for(i=0; i<nBuf; i++){
|
|
+ assert( (nBuf%nMerge)==0 );
|
|
+ for(i=0; i<nBuf; i+=nMerge){
|
|
+ int iFree;
|
|
if( p->rc==SQLITE_OK ){
|
|
- xMerge(p, &doclist, &aBuf[i]);
|
|
+ xMerge(p, &doclist, nMerge, &aBuf[i]);
|
|
+ }
|
|
+ for(iFree=i; iFree<i+nMerge; iFree++){
|
|
+ fts5BufferFree(&aBuf[iFree]);
|
|
}
|
|
- fts5BufferFree(&aBuf[i]);
|
|
}
|
|
fts5MultiIterFree(p1);
|
|
|
|
@@ -219483,9 +235989,9 @@ static int sqlite3Fts5IndexBeginWrite(Fts5Index *p, int bDelete, i64 iRowid){
|
|
}
|
|
|
|
/* Flush the hash table to disk if required */
|
|
- if( iRowid<p->iWriteRowid
|
|
+ if( iRowid<p->iWriteRowid
|
|
|| (iRowid==p->iWriteRowid && p->bDelete==0)
|
|
- || (p->nPendingData > p->pConfig->nHashSize)
|
|
+ || (p->nPendingData > p->pConfig->nHashSize)
|
|
){
|
|
fts5IndexFlush(p);
|
|
}
|
|
@@ -219508,7 +236014,7 @@ static int sqlite3Fts5IndexSync(Fts5Index *p){
|
|
/*
|
|
** Discard any data stored in the in-memory hash tables. Do not write it
|
|
** to the database. Additionally, assume that the contents of the %_data
|
|
-** table may have changed on disk. So any in-memory caches of %_data
|
|
+** table may have changed on disk. So any in-memory caches of %_data
|
|
** records must be invalidated.
|
|
*/
|
|
static int sqlite3Fts5IndexRollback(Fts5Index *p){
|
|
@@ -219542,8 +236048,8 @@ static int sqlite3Fts5IndexReinit(Fts5Index *p){
|
|
** Otherwise, set *pp to NULL and return an SQLite error code.
|
|
*/
|
|
static int sqlite3Fts5IndexOpen(
|
|
- Fts5Config *pConfig,
|
|
- int bCreate,
|
|
+ Fts5Config *pConfig,
|
|
+ int bCreate,
|
|
Fts5Index **pp,
|
|
char **pzErr
|
|
){
|
|
@@ -219560,8 +236066,8 @@ static int sqlite3Fts5IndexOpen(
|
|
pConfig, "data", "id INTEGER PRIMARY KEY, block BLOB", 0, pzErr
|
|
);
|
|
if( rc==SQLITE_OK ){
|
|
- rc = sqlite3Fts5CreateTable(pConfig, "idx",
|
|
- "segid, term, pgno, PRIMARY KEY(segid, term)",
|
|
+ rc = sqlite3Fts5CreateTable(pConfig, "idx",
|
|
+ "segid, term, pgno, PRIMARY KEY(segid, term)",
|
|
1, pzErr
|
|
);
|
|
}
|
|
@@ -219601,13 +236107,13 @@ static int sqlite3Fts5IndexClose(Fts5Index *p){
|
|
}
|
|
|
|
/*
|
|
-** Argument p points to a buffer containing utf-8 text that is n bytes in
|
|
+** Argument p points to a buffer containing utf-8 text that is n bytes in
|
|
** size. Return the number of bytes in the nChar character prefix of the
|
|
** buffer, or 0 if there are less than nChar characters in total.
|
|
*/
|
|
static int sqlite3Fts5IndexCharlenToBytelen(
|
|
- const char *p,
|
|
- int nByte,
|
|
+ const char *p,
|
|
+ int nByte,
|
|
int nChar
|
|
){
|
|
int n = 0;
|
|
@@ -219633,7 +236139,7 @@ static int sqlite3Fts5IndexCharlenToBytelen(
|
|
** unicode characters in the string.
|
|
*/
|
|
static int fts5IndexCharlen(const char *pIn, int nIn){
|
|
- int nChar = 0;
|
|
+ int nChar = 0;
|
|
int i = 0;
|
|
while( i<nIn ){
|
|
if( (unsigned char)pIn[i++]>=0xc0 ){
|
|
@@ -219645,7 +236151,7 @@ static int fts5IndexCharlen(const char *pIn, int nIn){
|
|
}
|
|
|
|
/*
|
|
-** Insert or remove data to or from the index. Each time a document is
|
|
+** Insert or remove data to or from the index. Each time a document is
|
|
** added to or removed from the index, this function is called one or more
|
|
** times.
|
|
**
|
|
@@ -219676,7 +236182,7 @@ static int sqlite3Fts5IndexWrite(
|
|
const int nChar = pConfig->aPrefix[i];
|
|
int nByte = sqlite3Fts5IndexCharlenToBytelen(pToken, nToken, nChar);
|
|
if( nByte ){
|
|
- rc = sqlite3Fts5HashWrite(p->pHash,
|
|
+ rc = sqlite3Fts5HashWrite(p->pHash,
|
|
p->iWriteRowid, iCol, iPos, (char)(FTS5_MAIN_PREFIX+i+1), pToken,
|
|
nByte
|
|
);
|
|
@@ -219687,7 +236193,7 @@ static int sqlite3Fts5IndexWrite(
|
|
}
|
|
|
|
/*
|
|
-** Open a new iterator to iterate though all rowid that match the
|
|
+** Open a new iterator to iterate though all rowid that match the
|
|
** specified token or token prefix.
|
|
*/
|
|
static int sqlite3Fts5IndexQuery(
|
|
@@ -219706,7 +236212,8 @@ static int sqlite3Fts5IndexQuery(
|
|
|
|
if( sqlite3Fts5BufferSize(&p->rc, &buf, nToken+1)==0 ){
|
|
int iIdx = 0; /* Index to search */
|
|
- if( nToken ) memcpy(&buf.p[1], pToken, nToken);
|
|
+ int iPrefixIdx = 0; /* +1 prefix index */
|
|
+ if( nToken>0 ) memcpy(&buf.p[1], pToken, nToken);
|
|
|
|
/* Figure out which index to search and set iIdx accordingly. If this
|
|
** is a prefix query for which there is no prefix index, set iIdx to
|
|
@@ -219714,9 +236221,9 @@ static int sqlite3Fts5IndexQuery(
|
|
** satisfied by scanning multiple terms in the main index.
|
|
**
|
|
** If the QUERY_TEST_NOIDX flag was specified, then this must be a
|
|
- ** prefix-query. Instead of using a prefix-index (if one exists),
|
|
+ ** prefix-query. Instead of using a prefix-index (if one exists),
|
|
** evaluate the prefix query using the main FTS index. This is used
|
|
- ** for internal sanity checking by the integrity-check in debug
|
|
+ ** for internal sanity checking by the integrity-check in debug
|
|
** mode only. */
|
|
#ifdef SQLITE_DEBUG
|
|
if( pConfig->bPrefixIndex==0 || (flags & FTS5INDEX_QUERY_TEST_NOIDX) ){
|
|
@@ -219727,7 +236234,9 @@ static int sqlite3Fts5IndexQuery(
|
|
if( flags & FTS5INDEX_QUERY_PREFIX ){
|
|
int nChar = fts5IndexCharlen(pToken, nToken);
|
|
for(iIdx=1; iIdx<=pConfig->nPrefix; iIdx++){
|
|
- if( pConfig->aPrefix[iIdx-1]==nChar ) break;
|
|
+ int nIdxChar = pConfig->aPrefix[iIdx-1];
|
|
+ if( nIdxChar==nChar ) break;
|
|
+ if( nIdxChar==nChar+1 ) iPrefixIdx = iIdx;
|
|
}
|
|
}
|
|
|
|
@@ -219736,7 +236245,7 @@ static int sqlite3Fts5IndexQuery(
|
|
Fts5Structure *pStruct = fts5StructureRead(p);
|
|
buf.p[0] = (u8)(FTS5_MAIN_PREFIX + iIdx);
|
|
if( pStruct ){
|
|
- fts5MultiIterNew(p, pStruct, flags | FTS5INDEX_QUERY_SKIPEMPTY,
|
|
+ fts5MultiIterNew(p, pStruct, flags | FTS5INDEX_QUERY_SKIPEMPTY,
|
|
pColset, buf.p, nToken+1, -1, 0, &pRet
|
|
);
|
|
fts5StructureRelease(pStruct);
|
|
@@ -219744,13 +236253,16 @@ static int sqlite3Fts5IndexQuery(
|
|
}else{
|
|
/* Scan multiple terms in the main index */
|
|
int bDesc = (flags & FTS5INDEX_QUERY_DESC)!=0;
|
|
- buf.p[0] = FTS5_MAIN_PREFIX;
|
|
- fts5SetupPrefixIter(p, bDesc, buf.p, nToken+1, pColset, &pRet);
|
|
- assert( p->rc!=SQLITE_OK || pRet->pColset==0 );
|
|
- fts5IterSetOutputCb(&p->rc, pRet);
|
|
- if( p->rc==SQLITE_OK ){
|
|
- Fts5SegIter *pSeg = &pRet->aSeg[pRet->aFirst[1].iFirst];
|
|
- if( pSeg->pLeaf ) pRet->xSetOutputs(pRet, pSeg);
|
|
+ fts5SetupPrefixIter(p, bDesc, iPrefixIdx, buf.p, nToken+1, pColset,&pRet);
|
|
+ if( pRet==0 ){
|
|
+ assert( p->rc!=SQLITE_OK );
|
|
+ }else{
|
|
+ assert( pRet->pColset==0 );
|
|
+ fts5IterSetOutputCb(&p->rc, pRet);
|
|
+ if( p->rc==SQLITE_OK ){
|
|
+ Fts5SegIter *pSeg = &pRet->aSeg[pRet->aFirst[1].iFirst];
|
|
+ if( pSeg->pLeaf ) pRet->xSetOutputs(pRet, pSeg);
|
|
+ }
|
|
}
|
|
}
|
|
|
|
@@ -219770,7 +236282,7 @@ static int sqlite3Fts5IndexQuery(
|
|
** Return true if the iterator passed as the only argument is at EOF.
|
|
*/
|
|
/*
|
|
-** Move to the next matching rowid.
|
|
+** Move to the next matching rowid.
|
|
*/
|
|
static int sqlite3Fts5IterNext(Fts5IndexIter *pIndexIter){
|
|
Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
|
|
@@ -219818,8 +236330,9 @@ static int sqlite3Fts5IterNextFrom(Fts5IndexIter *pIndexIter, i64 iMatch){
|
|
static const char *sqlite3Fts5IterTerm(Fts5IndexIter *pIndexIter, int *pn){
|
|
int n;
|
|
const char *z = (const char*)fts5MultiIterTerm((Fts5Iter*)pIndexIter, &n);
|
|
+ assert_nc( z || n<=1 );
|
|
*pn = n-1;
|
|
- return &z[1];
|
|
+ return (z ? &z[1] : 0);
|
|
}
|
|
|
|
/*
|
|
@@ -219835,7 +236348,7 @@ static void sqlite3Fts5IterClose(Fts5IndexIter *pIndexIter){
|
|
}
|
|
|
|
/*
|
|
-** Read and decode the "averages" record from the database.
|
|
+** Read and decode the "averages" record from the database.
|
|
**
|
|
** Parameter anSize must point to an array of size nCol, where nCol is
|
|
** the number of user defined columns in the FTS table.
|
|
@@ -219861,7 +236374,7 @@ static int sqlite3Fts5IndexGetAverages(Fts5Index *p, i64 *pnRow, i64 *anSize){
|
|
}
|
|
|
|
/*
|
|
-** Replace the current "averages" record with the contents of the buffer
|
|
+** Replace the current "averages" record with the contents of the buffer
|
|
** supplied as the second argument.
|
|
*/
|
|
static int sqlite3Fts5IndexSetAverages(Fts5Index *p, const u8 *pData, int nData){
|
|
@@ -219879,7 +236392,7 @@ static int sqlite3Fts5IndexReads(Fts5Index *p){
|
|
}
|
|
|
|
/*
|
|
-** Set the 32-bit cookie value stored at the start of all structure
|
|
+** Set the 32-bit cookie value stored at the start of all structure
|
|
** records to the value passed as the second argument.
|
|
**
|
|
** Return SQLITE_OK if successful, or an SQLite error code if an error
|
|
@@ -219894,7 +236407,7 @@ static int sqlite3Fts5IndexSetCookie(Fts5Index *p, int iNew){
|
|
assert( p->rc==SQLITE_OK );
|
|
sqlite3Fts5Put32(aCookie, iNew);
|
|
|
|
- rc = sqlite3_blob_open(pConfig->db, pConfig->zDb, p->zDataTbl,
|
|
+ rc = sqlite3_blob_open(pConfig->db, pConfig->zDb, p->zDataTbl,
|
|
"block", FTS5_STRUCTURE_ROWID, 1, &pBlob
|
|
);
|
|
if( rc==SQLITE_OK ){
|
|
@@ -219915,7 +236428,7 @@ static int sqlite3Fts5IndexLoadConfig(Fts5Index *p){
|
|
|
|
/*************************************************************************
|
|
**************************************************************************
|
|
-** Below this point is the implementation of the integrity-check
|
|
+** Below this point is the implementation of the integrity-check
|
|
** functionality.
|
|
*/
|
|
|
|
@@ -219923,9 +236436,9 @@ static int sqlite3Fts5IndexLoadConfig(Fts5Index *p){
|
|
** Return a simple checksum value based on the arguments.
|
|
*/
|
|
static u64 sqlite3Fts5IndexEntryCksum(
|
|
- i64 iRowid,
|
|
- int iCol,
|
|
- int iPos,
|
|
+ i64 iRowid,
|
|
+ int iCol,
|
|
+ int iPos,
|
|
int iIdx,
|
|
const char *pTerm,
|
|
int nTerm
|
|
@@ -219941,15 +236454,15 @@ static u64 sqlite3Fts5IndexEntryCksum(
|
|
|
|
#ifdef SQLITE_DEBUG
|
|
/*
|
|
-** This function is purely an internal test. It does not contribute to
|
|
+** This function is purely an internal test. It does not contribute to
|
|
** FTS functionality, or even the integrity-check, in any way.
|
|
**
|
|
-** Instead, it tests that the same set of pgno/rowid combinations are
|
|
+** Instead, it tests that the same set of pgno/rowid combinations are
|
|
** visited regardless of whether the doclist-index identified by parameters
|
|
** iSegid/iLeaf is iterated in forwards or reverse order.
|
|
*/
|
|
static void fts5TestDlidxReverse(
|
|
- Fts5Index *p,
|
|
+ Fts5Index *p,
|
|
int iSegid, /* Segment id to load from */
|
|
int iLeaf /* Load doclist-index for this leaf */
|
|
){
|
|
@@ -219997,7 +236510,7 @@ static int fts5QueryCksum(
|
|
Fts5IndexIter *pIter = 0;
|
|
int rc = sqlite3Fts5IndexQuery(p, z, n, flags, 0, &pIter);
|
|
|
|
- while( rc==SQLITE_OK && 0==sqlite3Fts5IterEof(pIter) ){
|
|
+ while( rc==SQLITE_OK && ALWAYS(pIter!=0) && 0==sqlite3Fts5IterEof(pIter) ){
|
|
i64 rowid = pIter->iRowid;
|
|
|
|
if( eDetail==FTS5_DETAIL_NONE ){
|
|
@@ -220056,11 +236569,11 @@ static int fts5TestUtf8(const char *z, int n){
|
|
}
|
|
|
|
/*
|
|
-** This function is also purely an internal test. It does not contribute to
|
|
+** This function is also purely an internal test. It does not contribute to
|
|
** FTS functionality, or even the integrity-check, in any way.
|
|
*/
|
|
static void fts5TestTerm(
|
|
- Fts5Index *p,
|
|
+ Fts5Index *p,
|
|
Fts5Buffer *pPrev, /* Previous term */
|
|
const char *z, int n, /* Possibly new term to test */
|
|
u64 expected,
|
|
@@ -220089,12 +236602,12 @@ static void fts5TestTerm(
|
|
if( rc==SQLITE_OK && ck1!=ck2 ) rc = FTS5_CORRUPT;
|
|
|
|
/* If this is a prefix query, check that the results returned if the
|
|
- ** the index is disabled are the same. In both ASC and DESC order.
|
|
+ ** the index is disabled are the same. In both ASC and DESC order.
|
|
**
|
|
** This check may only be performed if the hash table is empty. This
|
|
** is because the hash table only supports a single scan query at
|
|
** a time, and the multi-iter loop from which this function is called
|
|
- ** is already performing such a scan.
|
|
+ ** is already performing such a scan.
|
|
**
|
|
** Also only do this if buffer zTerm contains nTerm bytes of valid
|
|
** utf-8. Otherwise, the last part of the buffer contents might contain
|
|
@@ -220126,7 +236639,7 @@ static void fts5TestTerm(
|
|
}
|
|
p->rc = rc;
|
|
}
|
|
-
|
|
+
|
|
#else
|
|
# define fts5TestDlidxReverse(x,y,z)
|
|
# define fts5TestTerm(u,v,w,x,y,z)
|
|
@@ -220239,7 +236752,7 @@ static void fts5IndexIntegrityCheckSegment(
|
|
int iIdxLeaf = sqlite3_column_int(pStmt, 2);
|
|
int bIdxDlidx = sqlite3_column_int(pStmt, 3);
|
|
|
|
- /* If the leaf in question has already been trimmed from the segment,
|
|
+ /* If the leaf in question has already been trimmed from the segment,
|
|
** ignore this b-tree entry. Otherwise, load it into memory. */
|
|
if( iIdxLeaf<pSeg->pgnoFirst ) continue;
|
|
iRow = FTS5_SEGMENT_ROWID(pSeg->iSegid, iIdxLeaf);
|
|
@@ -220347,7 +236860,7 @@ static void fts5IndexIntegrityCheckSegment(
|
|
|
|
|
|
/*
|
|
-** Run internal checks to ensure that the FTS index (a) is internally
|
|
+** Run internal checks to ensure that the FTS index (a) is internally
|
|
** consistent and (b) contains entries for which the XOR of the checksums
|
|
** as calculated by sqlite3Fts5IndexEntryCksum() is cksum.
|
|
**
|
|
@@ -220356,12 +236869,13 @@ static void fts5IndexIntegrityCheckSegment(
|
|
** error, or some other SQLite error code if another error (e.g. OOM)
|
|
** occurs.
|
|
*/
|
|
-static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum){
|
|
+static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum, int bUseCksum){
|
|
int eDetail = p->pConfig->eDetail;
|
|
u64 cksum2 = 0; /* Checksum based on contents of indexes */
|
|
Fts5Buffer poslist = {0,0,0}; /* Buffer used to hold a poslist */
|
|
Fts5Iter *pIter; /* Used to iterate through entire index */
|
|
Fts5Structure *pStruct; /* Index structure */
|
|
+ int iLvl, iSeg;
|
|
|
|
#ifdef SQLITE_DEBUG
|
|
/* Used by extra internal tests only run if NDEBUG is not defined */
|
|
@@ -220369,18 +236883,19 @@ static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum){
|
|
Fts5Buffer term = {0,0,0}; /* Buffer used to hold most recent term */
|
|
#endif
|
|
const int flags = FTS5INDEX_QUERY_NOOUTPUT;
|
|
-
|
|
+
|
|
/* Load the FTS index structure */
|
|
pStruct = fts5StructureRead(p);
|
|
+ if( pStruct==0 ){
|
|
+ assert( p->rc!=SQLITE_OK );
|
|
+ return fts5IndexReturn(p);
|
|
+ }
|
|
|
|
/* Check that the internal nodes of each segment match the leaves */
|
|
- if( pStruct ){
|
|
- int iLvl, iSeg;
|
|
- for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
|
|
- for(iSeg=0; iSeg<pStruct->aLevel[iLvl].nSeg; iSeg++){
|
|
- Fts5StructureSegment *pSeg = &pStruct->aLevel[iLvl].aSeg[iSeg];
|
|
- fts5IndexIntegrityCheckSegment(p, pSeg);
|
|
- }
|
|
+ for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
|
|
+ for(iSeg=0; iSeg<pStruct->aLevel[iLvl].nSeg; iSeg++){
|
|
+ Fts5StructureSegment *pSeg = &pStruct->aLevel[iLvl].aSeg[iSeg];
|
|
+ fts5IndexIntegrityCheckSegment(p, pSeg);
|
|
}
|
|
}
|
|
|
|
@@ -220391,7 +236906,7 @@ static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum){
|
|
**
|
|
** Two versions of the same checksum are calculated. The first (stack
|
|
** variable cksum2) based on entries extracted from the full-text index
|
|
- ** while doing a linear scan of each individual index in turn.
|
|
+ ** while doing a linear scan of each individual index in turn.
|
|
**
|
|
** As each term visited by the linear scans, a separate query for the
|
|
** same term is performed. cksum3 is calculated based on the entries
|
|
@@ -220409,6 +236924,7 @@ static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum){
|
|
|
|
/* If this is a new term, query for it. Update cksum3 with the results. */
|
|
fts5TestTerm(p, &term, z, n, cksum2, &cksum3);
|
|
+ if( p->rc ) break;
|
|
|
|
if( eDetail==FTS5_DETAIL_NONE ){
|
|
if( 0==fts5MultiIterIsEmpty(p, pIter) ){
|
|
@@ -220417,6 +236933,7 @@ static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum){
|
|
}else{
|
|
poslist.n = 0;
|
|
fts5SegiterPoslist(p, &pIter->aSeg[pIter->aFirst[1].iFirst], 0, &poslist);
|
|
+ fts5BufferAppendBlob(&p->rc, &poslist, 4, (const u8*)"\0\0\0\0");
|
|
while( 0==sqlite3Fts5PoslistNext64(poslist.p, poslist.n, &iOff, &iPos) ){
|
|
int iCol = FTS5_POS2COLUMN(iPos);
|
|
int iTokOff = FTS5_POS2OFFSET(iPos);
|
|
@@ -220427,7 +236944,7 @@ static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum){
|
|
fts5TestTerm(p, &term, 0, 0, cksum2, &cksum3);
|
|
|
|
fts5MultiIterFree(pIter);
|
|
- if( p->rc==SQLITE_OK && cksum!=cksum2 ) p->rc = FTS5_CORRUPT;
|
|
+ if( p->rc==SQLITE_OK && bUseCksum && cksum!=cksum2 ) p->rc = FTS5_CORRUPT;
|
|
|
|
fts5StructureRelease(pStruct);
|
|
#ifdef SQLITE_DEBUG
|
|
@@ -220443,6 +236960,7 @@ static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum){
|
|
** function only.
|
|
*/
|
|
|
|
+#ifdef SQLITE_TEST
|
|
/*
|
|
** Decode a segment-data rowid from the %_data table. This function is
|
|
** the opposite of macro FTS5_SEGMENT_ROWID().
|
|
@@ -220465,7 +236983,9 @@ static void fts5DecodeRowid(
|
|
|
|
*piSegid = (int)(iRowid & (((i64)1 << FTS5_DATA_ID_B) - 1));
|
|
}
|
|
+#endif /* SQLITE_TEST */
|
|
|
|
+#ifdef SQLITE_TEST
|
|
static void fts5DebugRowid(int *pRc, Fts5Buffer *pBuf, i64 iKey){
|
|
int iSegid, iHeight, iPgno, bDlidx; /* Rowid compenents */
|
|
fts5DecodeRowid(iKey, &iSegid, &bDlidx, &iHeight, &iPgno);
|
|
@@ -220483,7 +237003,9 @@ static void fts5DebugRowid(int *pRc, Fts5Buffer *pBuf, i64 iKey){
|
|
);
|
|
}
|
|
}
|
|
+#endif /* SQLITE_TEST */
|
|
|
|
+#ifdef SQLITE_TEST
|
|
static void fts5DebugStructure(
|
|
int *pRc, /* IN/OUT: error code */
|
|
Fts5Buffer *pBuf,
|
|
@@ -220493,25 +237015,27 @@ static void fts5DebugStructure(
|
|
|
|
for(iLvl=0; iLvl<p->nLevel; iLvl++){
|
|
Fts5StructureLevel *pLvl = &p->aLevel[iLvl];
|
|
- sqlite3Fts5BufferAppendPrintf(pRc, pBuf,
|
|
+ sqlite3Fts5BufferAppendPrintf(pRc, pBuf,
|
|
" {lvl=%d nMerge=%d nSeg=%d", iLvl, pLvl->nMerge, pLvl->nSeg
|
|
);
|
|
for(iSeg=0; iSeg<pLvl->nSeg; iSeg++){
|
|
Fts5StructureSegment *pSeg = &pLvl->aSeg[iSeg];
|
|
- sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " {id=%d leaves=%d..%d}",
|
|
+ sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " {id=%d leaves=%d..%d}",
|
|
pSeg->iSegid, pSeg->pgnoFirst, pSeg->pgnoLast
|
|
);
|
|
}
|
|
sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "}");
|
|
}
|
|
}
|
|
+#endif /* SQLITE_TEST */
|
|
|
|
+#ifdef SQLITE_TEST
|
|
/*
|
|
** This is part of the fts5_decode() debugging aid.
|
|
**
|
|
** Arguments pBlob/nBlob contain a serialized Fts5Structure object. This
|
|
** function appends a human-readable representation of the same object
|
|
-** to the buffer passed as the second argument.
|
|
+** to the buffer passed as the second argument.
|
|
*/
|
|
static void fts5DecodeStructure(
|
|
int *pRc, /* IN/OUT: error code */
|
|
@@ -220530,13 +237054,15 @@ static void fts5DecodeStructure(
|
|
fts5DebugStructure(pRc, pBuf, p);
|
|
fts5StructureRelease(p);
|
|
}
|
|
+#endif /* SQLITE_TEST */
|
|
|
|
+#ifdef SQLITE_TEST
|
|
/*
|
|
** This is part of the fts5_decode() debugging aid.
|
|
**
|
|
-** Arguments pBlob/nBlob contain an "averages" record. This function
|
|
-** appends a human-readable representation of record to the buffer passed
|
|
-** as the second argument.
|
|
+** Arguments pBlob/nBlob contain an "averages" record. This function
|
|
+** appends a human-readable representation of record to the buffer passed
|
|
+** as the second argument.
|
|
*/
|
|
static void fts5DecodeAverages(
|
|
int *pRc, /* IN/OUT: error code */
|
|
@@ -220553,7 +237079,9 @@ static void fts5DecodeAverages(
|
|
zSpace = " ";
|
|
}
|
|
}
|
|
+#endif /* SQLITE_TEST */
|
|
|
|
+#ifdef SQLITE_TEST
|
|
/*
|
|
** Buffer (a/n) is assumed to contain a list of serialized varints. Read
|
|
** each varint and append its string representation to buffer pBuf. Return
|
|
@@ -220570,12 +237098,14 @@ static int fts5DecodePoslist(int *pRc, Fts5Buffer *pBuf, const u8 *a, int n){
|
|
}
|
|
return iOff;
|
|
}
|
|
+#endif /* SQLITE_TEST */
|
|
|
|
+#ifdef SQLITE_TEST
|
|
/*
|
|
** The start of buffer (a/n) contains the start of a doclist. The doclist
|
|
** may or may not finish within the buffer. This function appends a text
|
|
** representation of the part of the doclist that is present to buffer
|
|
-** pBuf.
|
|
+** pBuf.
|
|
**
|
|
** The return value is the number of bytes read from the input buffer.
|
|
*/
|
|
@@ -220603,9 +237133,11 @@ static int fts5DecodeDoclist(int *pRc, Fts5Buffer *pBuf, const u8 *a, int n){
|
|
|
|
return iOff;
|
|
}
|
|
+#endif /* SQLITE_TEST */
|
|
|
|
+#ifdef SQLITE_TEST
|
|
/*
|
|
-** This function is part of the fts5_decode() debugging function. It is
|
|
+** This function is part of the fts5_decode() debugging function. It is
|
|
** only ever used with detail=none tables.
|
|
**
|
|
** Buffer (pData/nData) contains a doclist in the format used by detail=none
|
|
@@ -220644,7 +237176,9 @@ static void fts5DecodeRowidList(
|
|
sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " %lld%s", iRowid, zApp);
|
|
}
|
|
}
|
|
+#endif /* SQLITE_TEST */
|
|
|
|
+#ifdef SQLITE_TEST
|
|
/*
|
|
** The implementation of user-defined scalar function fts5_decode().
|
|
*/
|
|
@@ -220692,7 +237226,7 @@ static void fts5DecodeFunction(
|
|
lvl.iLeafPgno = iPgno;
|
|
|
|
for(fts5DlidxLvlNext(&lvl); lvl.bEof==0; fts5DlidxLvlNext(&lvl)){
|
|
- sqlite3Fts5BufferAppendPrintf(&rc, &s,
|
|
+ sqlite3Fts5BufferAppendPrintf(&rc, &s,
|
|
" %d(%lld)", lvl.iLeafPgno, lvl.iRowid
|
|
);
|
|
}
|
|
@@ -220803,7 +237337,7 @@ static void fts5DecodeFunction(
|
|
int bFirst = (iPgidxOff==szLeaf); /* True for first term on page */
|
|
int nByte; /* Bytes of data */
|
|
int iEnd;
|
|
-
|
|
+
|
|
iPgidxOff += fts5GetVarint32(&a[iPgidxOff], nByte);
|
|
iPgidxPrev += nByte;
|
|
iOff = iPgidxPrev;
|
|
@@ -220843,7 +237377,7 @@ static void fts5DecodeFunction(
|
|
|
|
fts5BufferFree(&term);
|
|
}
|
|
-
|
|
+
|
|
decode_out:
|
|
sqlite3_free(a);
|
|
if( rc==SQLITE_OK ){
|
|
@@ -220853,7 +237387,9 @@ static void fts5DecodeFunction(
|
|
}
|
|
fts5BufferFree(&s);
|
|
}
|
|
+#endif /* SQLITE_TEST */
|
|
|
|
+#ifdef SQLITE_TEST
|
|
/*
|
|
** The implementation of user-defined scalar function fts5_rowid().
|
|
*/
|
|
@@ -220871,7 +237407,7 @@ static void fts5RowidFunction(
|
|
i64 iRowid;
|
|
int segid, pgno;
|
|
if( nArg!=3 ){
|
|
- sqlite3_result_error(pCtx,
|
|
+ sqlite3_result_error(pCtx,
|
|
"should be: fts5_rowid('segment', segid, pgno))", -1
|
|
);
|
|
}else{
|
|
@@ -220881,12 +237417,13 @@ static void fts5RowidFunction(
|
|
sqlite3_result_int64(pCtx, iRowid);
|
|
}
|
|
}else{
|
|
- sqlite3_result_error(pCtx,
|
|
+ sqlite3_result_error(pCtx,
|
|
"first arg to fts5_rowid() must be 'segment'" , -1
|
|
);
|
|
}
|
|
}
|
|
}
|
|
+#endif /* SQLITE_TEST */
|
|
|
|
/*
|
|
** This is called as part of registering the FTS5 module with database
|
|
@@ -220897,13 +237434,14 @@ static void fts5RowidFunction(
|
|
** SQLite error code is returned instead.
|
|
*/
|
|
static int sqlite3Fts5IndexInit(sqlite3 *db){
|
|
+#ifdef SQLITE_TEST
|
|
int rc = sqlite3_create_function(
|
|
db, "fts5_decode", 2, SQLITE_UTF8, 0, fts5DecodeFunction, 0, 0
|
|
);
|
|
|
|
if( rc==SQLITE_OK ){
|
|
rc = sqlite3_create_function(
|
|
- db, "fts5_decode_none", 2,
|
|
+ db, "fts5_decode_none", 2,
|
|
SQLITE_UTF8, (void*)db, fts5DecodeFunction, 0, 0
|
|
);
|
|
}
|
|
@@ -220914,6 +237452,10 @@ static int sqlite3Fts5IndexInit(sqlite3 *db){
|
|
);
|
|
}
|
|
return rc;
|
|
+#else
|
|
+ return SQLITE_OK;
|
|
+ UNUSED_PARAM(db);
|
|
+#endif
|
|
}
|
|
|
|
|
|
@@ -220949,7 +237491,9 @@ static int sqlite3Fts5IndexReset(Fts5Index *p){
|
|
** assert() conditions in the fts5 code are activated - conditions that are
|
|
** only true if it is guaranteed that the fts5 database is not corrupt.
|
|
*/
|
|
+#ifdef SQLITE_DEBUG
|
|
SQLITE_API int sqlite3_fts5_may_be_corrupt = 1;
|
|
+#endif
|
|
|
|
|
|
typedef struct Fts5Auxdata Fts5Auxdata;
|
|
@@ -220960,9 +237504,9 @@ typedef struct Fts5Sorter Fts5Sorter;
|
|
typedef struct Fts5TokenizerModule Fts5TokenizerModule;
|
|
|
|
/*
|
|
-** NOTES ON TRANSACTIONS:
|
|
+** NOTES ON TRANSACTIONS:
|
|
**
|
|
-** SQLite invokes the following virtual table methods as transactions are
|
|
+** SQLite invokes the following virtual table methods as transactions are
|
|
** opened and closed by the user:
|
|
**
|
|
** xBegin(): Start of a new transaction.
|
|
@@ -220971,7 +237515,7 @@ typedef struct Fts5TokenizerModule Fts5TokenizerModule;
|
|
** xRollback(): Rollback the transaction.
|
|
**
|
|
** Anything that is required as part of a commit that may fail is performed
|
|
-** in the xSync() callback. Current versions of SQLite ignore any errors
|
|
+** in the xSync() callback. Current versions of SQLite ignore any errors
|
|
** returned by xCommit().
|
|
**
|
|
** And as sub-transactions are opened/closed:
|
|
@@ -220980,9 +237524,9 @@ typedef struct Fts5TokenizerModule Fts5TokenizerModule;
|
|
** xRelease(int S): Commit and close savepoint S.
|
|
** xRollbackTo(int S): Rollback to start of savepoint S.
|
|
**
|
|
-** During a write-transaction the fts5_index.c module may cache some data
|
|
+** During a write-transaction the fts5_index.c module may cache some data
|
|
** in-memory. It is flushed to disk whenever xSync(), xRelease() or
|
|
-** xSavepoint() is called. And discarded whenever xRollback() or xRollbackTo()
|
|
+** xSavepoint() is called. And discarded whenever xRollback() or xRollbackTo()
|
|
** is called.
|
|
**
|
|
** Additionally, if SQLITE_DEBUG is defined, an instance of the following
|
|
@@ -220996,13 +237540,13 @@ struct Fts5TransactionState {
|
|
};
|
|
|
|
/*
|
|
-** A single object of this type is allocated when the FTS5 module is
|
|
+** A single object of this type is allocated when the FTS5 module is
|
|
** registered with a database handle. It is used to store pointers to
|
|
** all registered FTS5 extensions - tokenizers and auxiliary functions.
|
|
*/
|
|
struct Fts5Global {
|
|
fts5_api api; /* User visible part of object (see fts5.h) */
|
|
- sqlite3 *db; /* Associated database connection */
|
|
+ sqlite3 *db; /* Associated database connection */
|
|
i64 iNextId; /* Used to allocate unique cursor ids */
|
|
Fts5Auxiliary *pAux; /* First in list of all aux. functions */
|
|
Fts5TokenizerModule *pTok; /* First in list of all tokenizer modules */
|
|
@@ -221058,7 +237602,7 @@ struct Fts5MatchPhrase {
|
|
**
|
|
** aIdx[]:
|
|
** There is one entry in the aIdx[] array for each phrase in the query,
|
|
-** the value of which is the offset within aPoslist[] following the last
|
|
+** the value of which is the offset within aPoslist[] following the last
|
|
** byte of the position list for the corresponding phrase.
|
|
*/
|
|
struct Fts5Sorter {
|
|
@@ -221074,8 +237618,8 @@ struct Fts5Sorter {
|
|
** Virtual-table cursor object.
|
|
**
|
|
** iSpecial:
|
|
-** If this is a 'special' query (refer to function fts5SpecialMatch()),
|
|
-** then this variable contains the result of the query.
|
|
+** If this is a 'special' query (refer to function fts5SpecialMatch()),
|
|
+** then this variable contains the result of the query.
|
|
**
|
|
** iFirstRowid, iLastRowid:
|
|
** These variables are only used for FTS5_PLAN_MATCH cursors. Assuming the
|
|
@@ -221126,7 +237670,7 @@ struct Fts5Cursor {
|
|
};
|
|
|
|
/*
|
|
-** Bits that make up the "idxNum" parameter passed indirectly by
|
|
+** Bits that make up the "idxNum" parameter passed indirectly by
|
|
** xBestIndex() to xFilter().
|
|
*/
|
|
#define FTS5_BI_MATCH 0x0001 /* <tbl> MATCH ? */
|
|
@@ -221185,7 +237729,7 @@ static void fts5CheckTransactionState(Fts5FullTable *p, int op, int iSavepoint){
|
|
break;
|
|
|
|
case FTS5_SYNC:
|
|
- assert( p->ts.eState==1 );
|
|
+ assert( p->ts.eState==1 || p->ts.eState==2 );
|
|
p->ts.eState = 2;
|
|
break;
|
|
|
|
@@ -221200,21 +237744,21 @@ static void fts5CheckTransactionState(Fts5FullTable *p, int op, int iSavepoint){
|
|
break;
|
|
|
|
case FTS5_SAVEPOINT:
|
|
- assert( p->ts.eState==1 );
|
|
+ assert( p->ts.eState>=1 );
|
|
assert( iSavepoint>=0 );
|
|
assert( iSavepoint>=p->ts.iSavepoint );
|
|
p->ts.iSavepoint = iSavepoint;
|
|
break;
|
|
-
|
|
+
|
|
case FTS5_RELEASE:
|
|
- assert( p->ts.eState==1 );
|
|
+ assert( p->ts.eState>=1 );
|
|
assert( iSavepoint>=0 );
|
|
assert( iSavepoint<=p->ts.iSavepoint );
|
|
p->ts.iSavepoint = iSavepoint-1;
|
|
break;
|
|
|
|
case FTS5_ROLLBACKTO:
|
|
- assert( p->ts.eState==1 );
|
|
+ assert( p->ts.eState>=1 );
|
|
assert( iSavepoint>=-1 );
|
|
/* The following assert() can fail if another vtab strikes an error
|
|
** within an xSavepoint() call then SQLite calls xRollbackTo() - without
|
|
@@ -221236,7 +237780,7 @@ static int fts5IsContentless(Fts5FullTable *pTab){
|
|
}
|
|
|
|
/*
|
|
-** Delete a virtual table handle allocated by fts5InitVtab().
|
|
+** Delete a virtual table handle allocated by fts5InitVtab().
|
|
*/
|
|
static void fts5FreeVtab(Fts5FullTable *pTab){
|
|
if( pTab ){
|
|
@@ -221391,8 +237935,25 @@ static void fts5SetUniqueFlag(sqlite3_index_info *pIdxInfo){
|
|
#endif
|
|
}
|
|
|
|
+static int fts5UsePatternMatch(
|
|
+ Fts5Config *pConfig,
|
|
+ struct sqlite3_index_constraint *p
|
|
+){
|
|
+ assert( FTS5_PATTERN_GLOB==SQLITE_INDEX_CONSTRAINT_GLOB );
|
|
+ assert( FTS5_PATTERN_LIKE==SQLITE_INDEX_CONSTRAINT_LIKE );
|
|
+ if( pConfig->ePattern==FTS5_PATTERN_GLOB && p->op==FTS5_PATTERN_GLOB ){
|
|
+ return 1;
|
|
+ }
|
|
+ if( pConfig->ePattern==FTS5_PATTERN_LIKE
|
|
+ && (p->op==FTS5_PATTERN_LIKE || p->op==FTS5_PATTERN_GLOB)
|
|
+ ){
|
|
+ return 1;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
/*
|
|
-** Implementation of the xBestIndex method for FTS5 tables. Within the
|
|
+** Implementation of the xBestIndex method for FTS5 tables. Within the
|
|
** WHERE constraint, it searches for the following:
|
|
**
|
|
** 1. A MATCH constraint against the table column.
|
|
@@ -221407,7 +237968,7 @@ static void fts5SetUniqueFlag(sqlite3_index_info *pIdxInfo){
|
|
** 5. ORDER BY rank [ASC|DESC]
|
|
** 6. ORDER BY rowid [ASC|DESC]
|
|
**
|
|
-** Information for the xFilter call is passed via both the idxNum and
|
|
+** Information for the xFilter call is passed via both the idxNum and
|
|
** idxStr variables. Specifically, idxNum is a bitmask of the following
|
|
** flags used to encode the ORDER BY clause:
|
|
**
|
|
@@ -221420,7 +237981,9 @@ static void fts5SetUniqueFlag(sqlite3_index_info *pIdxInfo){
|
|
**
|
|
** Match against table column: "m"
|
|
** Match against rank column: "r"
|
|
-** Match against other column: "<column-number>"
|
|
+** Match against other column: "M<column-number>"
|
|
+** LIKE against other column: "L<column-number>"
|
|
+** GLOB against other column: "G<column-number>"
|
|
** Equality constraint against the rowid: "="
|
|
** A < or <= against the rowid: "<"
|
|
** A > or >= against the rowid: ">"
|
|
@@ -221481,7 +238044,7 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
|
|
return SQLITE_ERROR;
|
|
}
|
|
|
|
- idxStr = (char*)sqlite3_malloc(pInfo->nConstraint * 6 + 1);
|
|
+ idxStr = (char*)sqlite3_malloc(pInfo->nConstraint * 8 + 1);
|
|
if( idxStr==0 ) return SQLITE_NOMEM;
|
|
pInfo->idxStr = idxStr;
|
|
pInfo->needToFreeIdxStr = 1;
|
|
@@ -221494,7 +238057,7 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
|
|
){
|
|
/* A MATCH operator or equivalent */
|
|
if( p->usable==0 || iCol<0 ){
|
|
- /* As there exists an unusable MATCH constraint this is an
|
|
+ /* As there exists an unusable MATCH constraint this is an
|
|
** unusable plan. Set a prohibitively high cost. */
|
|
pInfo->estimatedCost = 1e50;
|
|
assert( iIdxStr < pInfo->nConstraint*6 + 1 );
|
|
@@ -221505,25 +238068,29 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
|
|
if( bSeenRank ) continue;
|
|
idxStr[iIdxStr++] = 'r';
|
|
bSeenRank = 1;
|
|
- }else{
|
|
+ }else if( iCol>=0 ){
|
|
bSeenMatch = 1;
|
|
- idxStr[iIdxStr++] = 'm';
|
|
- if( iCol<nCol ){
|
|
- sqlite3_snprintf(6, &idxStr[iIdxStr], "%d", iCol);
|
|
- idxStr += strlen(&idxStr[iIdxStr]);
|
|
- assert( idxStr[iIdxStr]=='\0' );
|
|
- }
|
|
+ idxStr[iIdxStr++] = 'M';
|
|
+ sqlite3_snprintf(6, &idxStr[iIdxStr], "%d", iCol);
|
|
+ idxStr += strlen(&idxStr[iIdxStr]);
|
|
+ assert( idxStr[iIdxStr]=='\0' );
|
|
}
|
|
pInfo->aConstraintUsage[i].argvIndex = ++iCons;
|
|
pInfo->aConstraintUsage[i].omit = 1;
|
|
}
|
|
- }
|
|
- else if( p->usable && bSeenEq==0
|
|
- && p->op==SQLITE_INDEX_CONSTRAINT_EQ && iCol<0
|
|
- ){
|
|
- idxStr[iIdxStr++] = '=';
|
|
- bSeenEq = 1;
|
|
- pInfo->aConstraintUsage[i].argvIndex = ++iCons;
|
|
+ }else if( p->usable ){
|
|
+ if( iCol>=0 && iCol<nCol && fts5UsePatternMatch(pConfig, p) ){
|
|
+ assert( p->op==FTS5_PATTERN_LIKE || p->op==FTS5_PATTERN_GLOB );
|
|
+ idxStr[iIdxStr++] = p->op==FTS5_PATTERN_LIKE ? 'L' : 'G';
|
|
+ sqlite3_snprintf(6, &idxStr[iIdxStr], "%d", iCol);
|
|
+ idxStr += strlen(&idxStr[iIdxStr]);
|
|
+ pInfo->aConstraintUsage[i].argvIndex = ++iCons;
|
|
+ assert( idxStr[iIdxStr]=='\0' );
|
|
+ }else if( bSeenEq==0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ && iCol<0 ){
|
|
+ idxStr[iIdxStr++] = '=';
|
|
+ bSeenEq = 1;
|
|
+ pInfo->aConstraintUsage[i].argvIndex = ++iCons;
|
|
+ }
|
|
}
|
|
}
|
|
|
|
@@ -221627,15 +238194,15 @@ static int fts5StmtType(Fts5Cursor *pCsr){
|
|
|
|
/*
|
|
** This function is called after the cursor passed as the only argument
|
|
-** is moved to point at a different row. It clears all cached data
|
|
+** is moved to point at a different row. It clears all cached data
|
|
** specific to the previous row stored by the cursor object.
|
|
*/
|
|
static void fts5CsrNewrow(Fts5Cursor *pCsr){
|
|
- CsrFlagSet(pCsr,
|
|
- FTS5CSR_REQUIRE_CONTENT
|
|
- | FTS5CSR_REQUIRE_DOCSIZE
|
|
- | FTS5CSR_REQUIRE_INST
|
|
- | FTS5CSR_REQUIRE_POSLIST
|
|
+ CsrFlagSet(pCsr,
|
|
+ FTS5CSR_REQUIRE_CONTENT
|
|
+ | FTS5CSR_REQUIRE_DOCSIZE
|
|
+ | FTS5CSR_REQUIRE_INST
|
|
+ | FTS5CSR_REQUIRE_POSLIST
|
|
);
|
|
}
|
|
|
|
@@ -221706,7 +238273,7 @@ static int fts5SorterNext(Fts5Cursor *pCsr){
|
|
rc = sqlite3_step(pSorter->pStmt);
|
|
if( rc==SQLITE_DONE ){
|
|
rc = SQLITE_OK;
|
|
- CsrFlagSet(pCsr, FTS5CSR_EOF);
|
|
+ CsrFlagSet(pCsr, FTS5CSR_EOF|FTS5CSR_REQUIRE_CONTENT);
|
|
}else if( rc==SQLITE_ROW ){
|
|
const u8 *a;
|
|
const u8 *aBlob;
|
|
@@ -221739,14 +238306,14 @@ static int fts5SorterNext(Fts5Cursor *pCsr){
|
|
|
|
|
|
/*
|
|
-** Set the FTS5CSR_REQUIRE_RESEEK flag on all FTS5_PLAN_MATCH cursors
|
|
+** Set the FTS5CSR_REQUIRE_RESEEK flag on all FTS5_PLAN_MATCH cursors
|
|
** open on table pTab.
|
|
*/
|
|
static void fts5TripCursors(Fts5FullTable *pTab){
|
|
Fts5Cursor *pCsr;
|
|
for(pCsr=pTab->pGlobal->pCsr; pCsr; pCsr=pCsr->pNext){
|
|
if( pCsr->ePlan==FTS5_PLAN_MATCH
|
|
- && pCsr->base.pVtab==(sqlite3_vtab*)pTab
|
|
+ && pCsr->base.pVtab==(sqlite3_vtab*)pTab
|
|
){
|
|
CsrFlagSet(pCsr, FTS5CSR_REQUIRE_RESEEK);
|
|
}
|
|
@@ -221755,14 +238322,14 @@ static void fts5TripCursors(Fts5FullTable *pTab){
|
|
|
|
/*
|
|
** If the REQUIRE_RESEEK flag is set on the cursor passed as the first
|
|
-** argument, close and reopen all Fts5IndexIter iterators that the cursor
|
|
+** argument, close and reopen all Fts5IndexIter iterators that the cursor
|
|
** is using. Then attempt to move the cursor to a rowid equal to or laster
|
|
-** (in the cursors sort order - ASC or DESC) than the current rowid.
|
|
+** (in the cursors sort order - ASC or DESC) than the current rowid.
|
|
**
|
|
** If the new rowid is not equal to the old, set output parameter *pbSkip
|
|
** to 1 before returning. Otherwise, leave it unchanged.
|
|
**
|
|
-** Return SQLITE_OK if successful or if no reseek was required, or an
|
|
+** Return SQLITE_OK if successful or if no reseek was required, or an
|
|
** error code if an error occurred.
|
|
*/
|
|
static int fts5CursorReseek(Fts5Cursor *pCsr, int *pbSkip){
|
|
@@ -221790,7 +238357,7 @@ static int fts5CursorReseek(Fts5Cursor *pCsr, int *pbSkip){
|
|
|
|
|
|
/*
|
|
-** Advance the cursor to the next row in the table that matches the
|
|
+** Advance the cursor to the next row in the table that matches the
|
|
** search criteria.
|
|
**
|
|
** Return SQLITE_OK if nothing goes wrong. SQLITE_OK is returned
|
|
@@ -221802,7 +238369,7 @@ static int fts5NextMethod(sqlite3_vtab_cursor *pCursor){
|
|
int rc;
|
|
|
|
assert( (pCsr->ePlan<3)==
|
|
- (pCsr->ePlan==FTS5_PLAN_MATCH || pCsr->ePlan==FTS5_PLAN_SOURCE)
|
|
+ (pCsr->ePlan==FTS5_PLAN_MATCH || pCsr->ePlan==FTS5_PLAN_SOURCE)
|
|
);
|
|
assert( !CsrFlagTest(pCsr, FTS5CSR_EOF) );
|
|
|
|
@@ -221819,12 +238386,12 @@ static int fts5NextMethod(sqlite3_vtab_cursor *pCursor){
|
|
rc = SQLITE_OK;
|
|
break;
|
|
}
|
|
-
|
|
+
|
|
case FTS5_PLAN_SORTED_MATCH: {
|
|
rc = fts5SorterNext(pCsr);
|
|
break;
|
|
}
|
|
-
|
|
+
|
|
default: {
|
|
Fts5Config *pConfig = ((Fts5Table*)pCursor->pVtab)->pConfig;
|
|
pConfig->bLock++;
|
|
@@ -221845,14 +238412,14 @@ static int fts5NextMethod(sqlite3_vtab_cursor *pCursor){
|
|
}
|
|
}
|
|
}
|
|
-
|
|
+
|
|
return rc;
|
|
}
|
|
|
|
|
|
static int fts5PrepareStatement(
|
|
sqlite3_stmt **ppStmt,
|
|
- Fts5Config *pConfig,
|
|
+ Fts5Config *pConfig,
|
|
const char *zFmt,
|
|
...
|
|
){
|
|
@@ -221864,9 +238431,9 @@ static int fts5PrepareStatement(
|
|
va_start(ap, zFmt);
|
|
zSql = sqlite3_vmprintf(zFmt, ap);
|
|
if( zSql==0 ){
|
|
- rc = SQLITE_NOMEM;
|
|
+ rc = SQLITE_NOMEM;
|
|
}else{
|
|
- rc = sqlite3_prepare_v3(pConfig->db, zSql, -1,
|
|
+ rc = sqlite3_prepare_v3(pConfig->db, zSql, -1,
|
|
SQLITE_PREPARE_PERSISTENT, &pRet, 0);
|
|
if( rc!=SQLITE_OK ){
|
|
*pConfig->pzErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(pConfig->db));
|
|
@@ -221877,11 +238444,11 @@ static int fts5PrepareStatement(
|
|
va_end(ap);
|
|
*ppStmt = pRet;
|
|
return rc;
|
|
-}
|
|
+}
|
|
|
|
static int fts5CursorFirstSorted(
|
|
- Fts5FullTable *pTab,
|
|
- Fts5Cursor *pCsr,
|
|
+ Fts5FullTable *pTab,
|
|
+ Fts5Cursor *pCsr,
|
|
int bDesc
|
|
){
|
|
Fts5Config *pConfig = pTab->p.pConfig;
|
|
@@ -221891,7 +238458,7 @@ static int fts5CursorFirstSorted(
|
|
int rc;
|
|
const char *zRank = pCsr->zRank;
|
|
const char *zRankArgs = pCsr->zRankArgs;
|
|
-
|
|
+
|
|
nPhrase = sqlite3Fts5ExprPhraseCount(pCsr->pExpr);
|
|
nByte = sizeof(Fts5Sorter) + sizeof(int) * (nPhrase-1);
|
|
pSorter = (Fts5Sorter*)sqlite3_malloc64(nByte);
|
|
@@ -221902,7 +238469,7 @@ static int fts5CursorFirstSorted(
|
|
/* TODO: It would be better to have some system for reusing statement
|
|
** handles here, rather than preparing a new one for each query. But that
|
|
** is not possible as SQLite reference counts the virtual table objects.
|
|
- ** And since the statement required here reads from this very virtual
|
|
+ ** And since the statement required here reads from this very virtual
|
|
** table, saving it creates a circular reference.
|
|
**
|
|
** If SQLite a built-in statement cache, this wouldn't be a problem. */
|
|
@@ -221949,8 +238516,8 @@ static int fts5CursorFirst(Fts5FullTable *pTab, Fts5Cursor *pCsr, int bDesc){
|
|
** parameters.
|
|
*/
|
|
static int fts5SpecialMatch(
|
|
- Fts5FullTable *pTab,
|
|
- Fts5Cursor *pCsr,
|
|
+ Fts5FullTable *pTab,
|
|
+ Fts5Cursor *pCsr,
|
|
const char *zQuery
|
|
){
|
|
int rc = SQLITE_OK; /* Return code */
|
|
@@ -222048,7 +238615,7 @@ static int fts5FindRankFunction(Fts5Cursor *pCsr){
|
|
|
|
static int fts5CursorParseRank(
|
|
Fts5Config *pConfig,
|
|
- Fts5Cursor *pCsr,
|
|
+ Fts5Cursor *pCsr,
|
|
sqlite3_value *pRank
|
|
){
|
|
int rc = SQLITE_OK;
|
|
@@ -222097,7 +238664,7 @@ static i64 fts5GetRowidLimit(sqlite3_value *pVal, i64 iDefault){
|
|
** This is the xFilter interface for the virtual table. See
|
|
** the virtual table xFilter method documentation for additional
|
|
** information.
|
|
-**
|
|
+**
|
|
** There are three possible query strategies:
|
|
**
|
|
** 1. Full-text search using a MATCH operator.
|
|
@@ -222156,19 +238723,14 @@ static int fts5FilterMethod(
|
|
case 'r':
|
|
pRank = apVal[i];
|
|
break;
|
|
- case 'm': {
|
|
+ case 'M': {
|
|
const char *zText = (const char*)sqlite3_value_text(apVal[i]);
|
|
if( zText==0 ) zText = "";
|
|
-
|
|
- if( idxStr[iIdxStr]>='0' && idxStr[iIdxStr]<='9' ){
|
|
- iCol = 0;
|
|
- do{
|
|
- iCol = iCol*10 + (idxStr[iIdxStr]-'0');
|
|
- iIdxStr++;
|
|
- }while( idxStr[iIdxStr]>='0' && idxStr[iIdxStr]<='9' );
|
|
- }else{
|
|
- iCol = pConfig->nCol;
|
|
- }
|
|
+ iCol = 0;
|
|
+ do{
|
|
+ iCol = iCol*10 + (idxStr[iIdxStr]-'0');
|
|
+ iIdxStr++;
|
|
+ }while( idxStr[iIdxStr]>='0' && idxStr[iIdxStr]<='9' );
|
|
|
|
if( zText[0]=='*' ){
|
|
/* The user has issued a query of the form "MATCH '*...'". This
|
|
@@ -222178,7 +238740,7 @@ static int fts5FilterMethod(
|
|
goto filter_out;
|
|
}else{
|
|
char **pzErr = &pTab->p.base.zErrMsg;
|
|
- rc = sqlite3Fts5ExprNew(pConfig, iCol, zText, &pExpr, pzErr);
|
|
+ rc = sqlite3Fts5ExprNew(pConfig, 0, iCol, zText, &pExpr, pzErr);
|
|
if( rc==SQLITE_OK ){
|
|
rc = sqlite3Fts5ExprAnd(&pCsr->pExpr, pExpr);
|
|
pExpr = 0;
|
|
@@ -222188,6 +238750,25 @@ static int fts5FilterMethod(
|
|
|
|
break;
|
|
}
|
|
+ case 'L':
|
|
+ case 'G': {
|
|
+ int bGlob = (idxStr[iIdxStr-1]=='G');
|
|
+ const char *zText = (const char*)sqlite3_value_text(apVal[i]);
|
|
+ iCol = 0;
|
|
+ do{
|
|
+ iCol = iCol*10 + (idxStr[iIdxStr]-'0');
|
|
+ iIdxStr++;
|
|
+ }while( idxStr[iIdxStr]>='0' && idxStr[iIdxStr]<='9' );
|
|
+ if( zText ){
|
|
+ rc = sqlite3Fts5ExprPattern(pConfig, bGlob, iCol, zText, &pExpr);
|
|
+ }
|
|
+ if( rc==SQLITE_OK ){
|
|
+ rc = sqlite3Fts5ExprAnd(&pCsr->pExpr, pExpr);
|
|
+ pExpr = 0;
|
|
+ }
|
|
+ if( rc!=SQLITE_OK ) goto filter_out;
|
|
+ break;
|
|
+ }
|
|
case '=':
|
|
pRowidEq = apVal[i];
|
|
break;
|
|
@@ -222202,7 +238783,7 @@ static int fts5FilterMethod(
|
|
bOrderByRank = ((idxNum & FTS5_BI_ORDER_RANK) ? 1 : 0);
|
|
pCsr->bDesc = bDesc = ((idxNum & FTS5_BI_ORDER_DESC) ? 1 : 0);
|
|
|
|
- /* Set the cursor upper and lower rowid limits. Only some strategies
|
|
+ /* Set the cursor upper and lower rowid limits. Only some strategies
|
|
** actually use them. This is ok, as the xBestIndex() method leaves the
|
|
** sqlite3_index_constraint.omit flag clear for range constraints
|
|
** on the rowid field. */
|
|
@@ -222218,11 +238799,11 @@ static int fts5FilterMethod(
|
|
}
|
|
|
|
if( pTab->pSortCsr ){
|
|
- /* If pSortCsr is non-NULL, then this call is being made as part of
|
|
+ /* If pSortCsr is non-NULL, then this call is being made as part of
|
|
** processing for a "... MATCH <expr> ORDER BY rank" query (ePlan is
|
|
** set to FTS5_PLAN_SORTED_MATCH). pSortCsr is the cursor that will
|
|
- ** return results to the user for this query. The current cursor
|
|
- ** (pCursor) is used to execute the query issued by function
|
|
+ ** return results to the user for this query. The current cursor
|
|
+ ** (pCursor) is used to execute the query issued by function
|
|
** fts5CursorFirstSorted() above. */
|
|
assert( pRowidEq==0 && pRowidLe==0 && pRowidGe==0 && pRank==0 );
|
|
assert( nVal==0 && bOrderByRank==0 && bDesc==0 );
|
|
@@ -222262,7 +238843,8 @@ static int fts5FilterMethod(
|
|
pTab->pStorage, fts5StmtType(pCsr), &pCsr->pStmt, &pTab->p.base.zErrMsg
|
|
);
|
|
if( rc==SQLITE_OK ){
|
|
- if( pCsr->ePlan==FTS5_PLAN_ROWID ){
|
|
+ if( pRowidEq!=0 ){
|
|
+ assert( pCsr->ePlan==FTS5_PLAN_ROWID );
|
|
sqlite3_bind_value(pCsr->pStmt, 1, pRowidEq);
|
|
}else{
|
|
sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iFirstRowid);
|
|
@@ -222278,8 +238860,8 @@ static int fts5FilterMethod(
|
|
return rc;
|
|
}
|
|
|
|
-/*
|
|
-** This is the xEof method of the virtual table. SQLite calls this
|
|
+/*
|
|
+** This is the xEof method of the virtual table. SQLite calls this
|
|
** routine to find out if it has reached the end of a result set.
|
|
*/
|
|
static int fts5EofMethod(sqlite3_vtab_cursor *pCursor){
|
|
@@ -222291,9 +238873,9 @@ static int fts5EofMethod(sqlite3_vtab_cursor *pCursor){
|
|
** Return the rowid that the cursor currently points to.
|
|
*/
|
|
static i64 fts5CursorRowid(Fts5Cursor *pCsr){
|
|
- assert( pCsr->ePlan==FTS5_PLAN_MATCH
|
|
- || pCsr->ePlan==FTS5_PLAN_SORTED_MATCH
|
|
- || pCsr->ePlan==FTS5_PLAN_SOURCE
|
|
+ assert( pCsr->ePlan==FTS5_PLAN_MATCH
|
|
+ || pCsr->ePlan==FTS5_PLAN_SORTED_MATCH
|
|
+ || pCsr->ePlan==FTS5_PLAN_SOURCE
|
|
);
|
|
if( pCsr->pSorter ){
|
|
return pCsr->pSorter->iRowid;
|
|
@@ -222302,7 +238884,7 @@ static i64 fts5CursorRowid(Fts5Cursor *pCsr){
|
|
}
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** This is the xRowid method. The SQLite core calls this routine to
|
|
** retrieve the rowid for the current row of the result set. fts5
|
|
** exposes %_content.rowid as the rowid for the virtual table. The
|
|
@@ -222311,7 +238893,7 @@ static i64 fts5CursorRowid(Fts5Cursor *pCsr){
|
|
static int fts5RowidMethod(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
|
|
Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
|
|
int ePlan = pCsr->ePlan;
|
|
-
|
|
+
|
|
assert( CsrFlagTest(pCsr, FTS5CSR_EOF)==0 );
|
|
switch( ePlan ){
|
|
case FTS5_PLAN_SPECIAL:
|
|
@@ -222342,7 +238924,7 @@ static int fts5RowidMethod(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
|
|
static int fts5SeekCursor(Fts5Cursor *pCsr, int bErrormsg){
|
|
int rc = SQLITE_OK;
|
|
|
|
- /* If the cursor does not yet have a statement handle, obtain one now. */
|
|
+ /* If the cursor does not yet have a statement handle, obtain one now. */
|
|
if( pCsr->pStmt==0 ){
|
|
Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab);
|
|
int eStmt = fts5StmtType(pCsr);
|
|
@@ -222393,7 +238975,7 @@ static void fts5SetVtabError(Fts5FullTable *p, const char *zFormat, ...){
|
|
** INSERT INTO fts(fts) VALUES($pCmd)
|
|
** INSERT INTO fts(fts, rank) VALUES($pCmd, $pVal)
|
|
**
|
|
-** Argument pVal is the value assigned to column "fts" by the INSERT
|
|
+** Argument pVal is the value assigned to column "fts" by the INSERT
|
|
** statement. This function returns SQLITE_OK if successful, or an SQLite
|
|
** error code if an error occurs.
|
|
**
|
|
@@ -222412,7 +238994,7 @@ static int fts5SpecialInsert(
|
|
|
|
if( 0==sqlite3_stricmp("delete-all", zCmd) ){
|
|
if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
|
|
- fts5SetVtabError(pTab,
|
|
+ fts5SetVtabError(pTab,
|
|
"'delete-all' may only be used with a "
|
|
"contentless or external content fts5 table"
|
|
);
|
|
@@ -222422,7 +239004,7 @@ static int fts5SpecialInsert(
|
|
}
|
|
}else if( 0==sqlite3_stricmp("rebuild", zCmd) ){
|
|
if( pConfig->eContent==FTS5_CONTENT_NONE ){
|
|
- fts5SetVtabError(pTab,
|
|
+ fts5SetVtabError(pTab,
|
|
"'rebuild' may not be used with a contentless fts5 table"
|
|
);
|
|
rc = SQLITE_ERROR;
|
|
@@ -222435,7 +239017,8 @@ static int fts5SpecialInsert(
|
|
int nMerge = sqlite3_value_int(pVal);
|
|
rc = sqlite3Fts5StorageMerge(pTab->pStorage, nMerge);
|
|
}else if( 0==sqlite3_stricmp("integrity-check", zCmd) ){
|
|
- rc = sqlite3Fts5StorageIntegrity(pTab->pStorage);
|
|
+ int iArg = sqlite3_value_int(pVal);
|
|
+ rc = sqlite3Fts5StorageIntegrity(pTab->pStorage, iArg);
|
|
#ifdef SQLITE_DEBUG
|
|
}else if( 0==sqlite3_stricmp("prefix-index", zCmd) ){
|
|
pConfig->bPrefixIndex = sqlite3_value_int(pVal);
|
|
@@ -222457,7 +239040,7 @@ static int fts5SpecialInsert(
|
|
}
|
|
|
|
static int fts5SpecialDelete(
|
|
- Fts5FullTable *pTab,
|
|
+ Fts5FullTable *pTab,
|
|
sqlite3_value **apVal
|
|
){
|
|
int rc = SQLITE_OK;
|
|
@@ -222470,9 +239053,9 @@ static int fts5SpecialDelete(
|
|
}
|
|
|
|
static void fts5StorageInsert(
|
|
- int *pRc,
|
|
- Fts5FullTable *pTab,
|
|
- sqlite3_value **apVal,
|
|
+ int *pRc,
|
|
+ Fts5FullTable *pTab,
|
|
+ sqlite3_value **apVal,
|
|
i64 *piRowid
|
|
){
|
|
int rc = *pRc;
|
|
@@ -222485,13 +239068,13 @@ static void fts5StorageInsert(
|
|
*pRc = rc;
|
|
}
|
|
|
|
-/*
|
|
-** This function is the implementation of the xUpdate callback used by
|
|
+/*
|
|
+** This function is the implementation of the xUpdate callback used by
|
|
** FTS3 virtual tables. It is invoked by SQLite each time a row is to be
|
|
** inserted, updated or deleted.
|
|
**
|
|
** A delete specifies a single argument - the rowid of the row to remove.
|
|
-**
|
|
+**
|
|
** Update and insert operations pass:
|
|
**
|
|
** 1. The "old" rowid, or NULL.
|
|
@@ -222511,12 +239094,12 @@ static int fts5UpdateMethod(
|
|
int rc = SQLITE_OK; /* Return code */
|
|
|
|
/* A transaction must be open when this is called. */
|
|
- assert( pTab->ts.eState==1 );
|
|
+ assert( pTab->ts.eState==1 || pTab->ts.eState==2 );
|
|
|
|
assert( pVtab->zErrMsg==0 );
|
|
assert( nArg==1 || nArg==(2+pConfig->nCol+2) );
|
|
- assert( sqlite3_value_type(apVal[0])==SQLITE_INTEGER
|
|
- || sqlite3_value_type(apVal[0])==SQLITE_NULL
|
|
+ assert( sqlite3_value_type(apVal[0])==SQLITE_INTEGER
|
|
+ || sqlite3_value_type(apVal[0])==SQLITE_NULL
|
|
);
|
|
assert( pTab->p.pConfig->pzErrmsg==0 );
|
|
pTab->p.pConfig->pzErrmsg = &pTab->p.base.zErrMsg;
|
|
@@ -222525,13 +239108,13 @@ static int fts5UpdateMethod(
|
|
fts5TripCursors(pTab);
|
|
|
|
eType0 = sqlite3_value_type(apVal[0]);
|
|
- if( eType0==SQLITE_NULL
|
|
- && sqlite3_value_type(apVal[2+pConfig->nCol])!=SQLITE_NULL
|
|
+ if( eType0==SQLITE_NULL
|
|
+ && sqlite3_value_type(apVal[2+pConfig->nCol])!=SQLITE_NULL
|
|
){
|
|
/* A "special" INSERT op. These are handled separately. */
|
|
const char *z = (const char*)sqlite3_value_text(apVal[2+pConfig->nCol]);
|
|
- if( pConfig->eContent!=FTS5_CONTENT_NORMAL
|
|
- && 0==sqlite3_stricmp("delete", z)
|
|
+ if( pConfig->eContent!=FTS5_CONTENT_NORMAL
|
|
+ && 0==sqlite3_stricmp("delete", z)
|
|
){
|
|
rc = fts5SpecialDelete(pTab, apVal);
|
|
}else{
|
|
@@ -222539,7 +239122,7 @@ static int fts5UpdateMethod(
|
|
}
|
|
}else{
|
|
/* A regular INSERT, UPDATE or DELETE statement. The trick here is that
|
|
- ** any conflict on the rowid value must be detected before any
|
|
+ ** any conflict on the rowid value must be detected before any
|
|
** modifications are made to the database file. There are 4 cases:
|
|
**
|
|
** 1) DELETE
|
|
@@ -222561,7 +239144,7 @@ static int fts5UpdateMethod(
|
|
** This is not suported. */
|
|
if( eType0==SQLITE_INTEGER && fts5IsContentless(pTab) ){
|
|
pTab->p.base.zErrMsg = sqlite3_mprintf(
|
|
- "cannot %s contentless fts5 table: %s",
|
|
+ "cannot %s contentless fts5 table: %s",
|
|
(nArg>1 ? "UPDATE" : "DELETE from"), pConfig->zName
|
|
);
|
|
rc = SQLITE_ERROR;
|
|
@@ -222581,7 +239164,7 @@ static int fts5UpdateMethod(
|
|
rc = SQLITE_MISMATCH;
|
|
}
|
|
|
|
- else if( eType0!=SQLITE_INTEGER ){
|
|
+ else if( eType0!=SQLITE_INTEGER ){
|
|
/* If this is a REPLACE, first remove the current entry (if any) */
|
|
if( eConflict==SQLITE_REPLACE && eType1==SQLITE_INTEGER ){
|
|
i64 iNew = sqlite3_value_int64(apVal[1]); /* Rowid to delete */
|
|
@@ -222623,7 +239206,7 @@ static int fts5UpdateMethod(
|
|
}
|
|
|
|
/*
|
|
-** Implementation of xSync() method.
|
|
+** Implementation of xSync() method.
|
|
*/
|
|
static int fts5SyncMethod(sqlite3_vtab *pVtab){
|
|
int rc;
|
|
@@ -222637,7 +239220,7 @@ static int fts5SyncMethod(sqlite3_vtab *pVtab){
|
|
}
|
|
|
|
/*
|
|
-** Implementation of xBegin() method.
|
|
+** Implementation of xBegin() method.
|
|
*/
|
|
static int fts5BeginMethod(sqlite3_vtab *pVtab){
|
|
fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_BEGIN, 0);
|
|
@@ -222681,8 +239264,8 @@ static int fts5ApiColumnCount(Fts5Context *pCtx){
|
|
}
|
|
|
|
static int fts5ApiColumnTotalSize(
|
|
- Fts5Context *pCtx,
|
|
- int iCol,
|
|
+ Fts5Context *pCtx,
|
|
+ int iCol,
|
|
sqlite3_int64 *pnToken
|
|
){
|
|
Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
|
|
@@ -222697,8 +239280,8 @@ static int fts5ApiRowCount(Fts5Context *pCtx, i64 *pnRow){
|
|
}
|
|
|
|
static int fts5ApiTokenize(
|
|
- Fts5Context *pCtx,
|
|
- const char *pText, int nText,
|
|
+ Fts5Context *pCtx,
|
|
+ const char *pText, int nText,
|
|
void *pUserData,
|
|
int (*xToken)(void*, int, const char*, int, int, int)
|
|
){
|
|
@@ -222720,15 +239303,15 @@ static int fts5ApiPhraseSize(Fts5Context *pCtx, int iPhrase){
|
|
}
|
|
|
|
static int fts5ApiColumnText(
|
|
- Fts5Context *pCtx,
|
|
- int iCol,
|
|
- const char **pz,
|
|
+ Fts5Context *pCtx,
|
|
+ int iCol,
|
|
+ const char **pz,
|
|
int *pn
|
|
){
|
|
int rc = SQLITE_OK;
|
|
Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
|
|
- if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab))
|
|
- || pCsr->ePlan==FTS5_PLAN_SPECIAL
|
|
+ if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab))
|
|
+ || pCsr->ePlan==FTS5_PLAN_SPECIAL
|
|
){
|
|
*pz = 0;
|
|
*pn = 0;
|
|
@@ -222743,8 +239326,8 @@ static int fts5ApiColumnText(
|
|
}
|
|
|
|
static int fts5CsrPoslist(
|
|
- Fts5Cursor *pCsr,
|
|
- int iPhrase,
|
|
+ Fts5Cursor *pCsr,
|
|
+ int iPhrase,
|
|
const u8 **pa,
|
|
int *pn
|
|
){
|
|
@@ -222799,7 +239382,7 @@ static int fts5CacheInstArray(Fts5Cursor *pCsr){
|
|
Fts5PoslistReader *aIter; /* One iterator for each phrase */
|
|
int nIter; /* Number of iterators/phrases */
|
|
int nCol = ((Fts5Table*)pCsr->base.pVtab)->pConfig->nCol;
|
|
-
|
|
+
|
|
nIter = sqlite3Fts5ExprPhraseCount(pCsr->pExpr);
|
|
if( pCsr->aInstIter==0 ){
|
|
sqlite3_int64 nByte = sizeof(Fts5PoslistReader) * nIter;
|
|
@@ -222814,7 +239397,7 @@ static int fts5CacheInstArray(Fts5Cursor *pCsr){
|
|
/* Initialize all iterators */
|
|
for(i=0; i<nIter && rc==SQLITE_OK; i++){
|
|
const u8 *a;
|
|
- int n;
|
|
+ int n;
|
|
rc = fts5CsrPoslist(pCsr, i, &a, &n);
|
|
if( rc==SQLITE_OK ){
|
|
sqlite3Fts5PoslistReaderInit(a, n, &aIter[i]);
|
|
@@ -222826,8 +239409,8 @@ static int fts5CacheInstArray(Fts5Cursor *pCsr){
|
|
int *aInst;
|
|
int iBest = -1;
|
|
for(i=0; i<nIter; i++){
|
|
- if( (aIter[i].bEof==0)
|
|
- && (iBest<0 || aIter[i].iPos<aIter[iBest].iPos)
|
|
+ if( (aIter[i].bEof==0)
|
|
+ && (iBest<0 || aIter[i].iPos<aIter[iBest].iPos)
|
|
){
|
|
iBest = i;
|
|
}
|
|
@@ -222836,13 +239419,15 @@ static int fts5CacheInstArray(Fts5Cursor *pCsr){
|
|
|
|
nInst++;
|
|
if( nInst>=pCsr->nInstAlloc ){
|
|
- pCsr->nInstAlloc = pCsr->nInstAlloc ? pCsr->nInstAlloc*2 : 32;
|
|
+ int nNewSize = pCsr->nInstAlloc ? pCsr->nInstAlloc*2 : 32;
|
|
aInst = (int*)sqlite3_realloc64(
|
|
- pCsr->aInst, pCsr->nInstAlloc*sizeof(int)*3
|
|
+ pCsr->aInst, nNewSize*sizeof(int)*3
|
|
);
|
|
if( aInst ){
|
|
pCsr->aInst = aInst;
|
|
+ pCsr->nInstAlloc = nNewSize;
|
|
}else{
|
|
+ nInst--;
|
|
rc = SQLITE_NOMEM;
|
|
break;
|
|
}
|
|
@@ -222869,7 +239454,7 @@ static int fts5CacheInstArray(Fts5Cursor *pCsr){
|
|
static int fts5ApiInstCount(Fts5Context *pCtx, int *pnInst){
|
|
Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
|
|
int rc = SQLITE_OK;
|
|
- if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0
|
|
+ if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0
|
|
|| SQLITE_OK==(rc = fts5CacheInstArray(pCsr)) ){
|
|
*pnInst = pCsr->nInstCount;
|
|
}
|
|
@@ -222877,16 +239462,16 @@ static int fts5ApiInstCount(Fts5Context *pCtx, int *pnInst){
|
|
}
|
|
|
|
static int fts5ApiInst(
|
|
- Fts5Context *pCtx,
|
|
- int iIdx,
|
|
- int *piPhrase,
|
|
- int *piCol,
|
|
+ Fts5Context *pCtx,
|
|
+ int iIdx,
|
|
+ int *piPhrase,
|
|
+ int *piCol,
|
|
int *piOff
|
|
){
|
|
Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
|
|
int rc = SQLITE_OK;
|
|
- if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0
|
|
- || SQLITE_OK==(rc = fts5CacheInstArray(pCsr))
|
|
+ if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0
|
|
+ || SQLITE_OK==(rc = fts5CacheInstArray(pCsr))
|
|
){
|
|
if( iIdx<0 || iIdx>=pCsr->nInstCount ){
|
|
rc = SQLITE_RANGE;
|
|
@@ -223035,8 +239620,8 @@ static void *fts5ApiGetAuxdata(Fts5Context *pCtx, int bClear){
|
|
}
|
|
|
|
static void fts5ApiPhraseNext(
|
|
- Fts5Context *pUnused,
|
|
- Fts5PhraseIter *pIter,
|
|
+ Fts5Context *pUnused,
|
|
+ Fts5PhraseIter *pIter,
|
|
int *piCol, int *piOff
|
|
){
|
|
UNUSED_PARAM(pUnused);
|
|
@@ -223057,16 +239642,17 @@ static void fts5ApiPhraseNext(
|
|
}
|
|
|
|
static int fts5ApiPhraseFirst(
|
|
- Fts5Context *pCtx,
|
|
- int iPhrase,
|
|
- Fts5PhraseIter *pIter,
|
|
+ Fts5Context *pCtx,
|
|
+ int iPhrase,
|
|
+ Fts5PhraseIter *pIter,
|
|
int *piCol, int *piOff
|
|
){
|
|
Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
|
|
int n;
|
|
int rc = fts5CsrPoslist(pCsr, iPhrase, &pIter->a, &n);
|
|
if( rc==SQLITE_OK ){
|
|
- pIter->b = &pIter->a[n];
|
|
+ assert( pIter->a || n==0 );
|
|
+ pIter->b = (pIter->a ? &pIter->a[n] : 0);
|
|
*piCol = 0;
|
|
*piOff = 0;
|
|
fts5ApiPhraseNext(pCtx, pIter, piCol, piOff);
|
|
@@ -223075,8 +239661,8 @@ static int fts5ApiPhraseFirst(
|
|
}
|
|
|
|
static void fts5ApiPhraseNextColumn(
|
|
- Fts5Context *pCtx,
|
|
- Fts5PhraseIter *pIter,
|
|
+ Fts5Context *pCtx,
|
|
+ Fts5PhraseIter *pIter,
|
|
int *piCol
|
|
){
|
|
Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
|
|
@@ -223105,9 +239691,9 @@ static void fts5ApiPhraseNextColumn(
|
|
}
|
|
|
|
static int fts5ApiPhraseFirstColumn(
|
|
- Fts5Context *pCtx,
|
|
- int iPhrase,
|
|
- Fts5PhraseIter *pIter,
|
|
+ Fts5Context *pCtx,
|
|
+ int iPhrase,
|
|
+ Fts5PhraseIter *pIter,
|
|
int *piCol
|
|
){
|
|
int rc = SQLITE_OK;
|
|
@@ -223125,7 +239711,8 @@ static int fts5ApiPhraseFirstColumn(
|
|
rc = sqlite3Fts5ExprPhraseCollist(pCsr->pExpr, iPhrase, &pIter->a, &n);
|
|
}
|
|
if( rc==SQLITE_OK ){
|
|
- pIter->b = &pIter->a[n];
|
|
+ assert( pIter->a || n==0 );
|
|
+ pIter->b = (pIter->a ? &pIter->a[n] : 0);
|
|
*piCol = 0;
|
|
fts5ApiPhraseNextColumn(pCtx, pIter, piCol);
|
|
}
|
|
@@ -223133,7 +239720,8 @@ static int fts5ApiPhraseFirstColumn(
|
|
int n;
|
|
rc = fts5CsrPoslist(pCsr, iPhrase, &pIter->a, &n);
|
|
if( rc==SQLITE_OK ){
|
|
- pIter->b = &pIter->a[n];
|
|
+ assert( pIter->a || n==0 );
|
|
+ pIter->b = (pIter->a ? &pIter->a[n] : 0);
|
|
if( n<=0 ){
|
|
*piCol = -1;
|
|
}else if( pIter->a[0]==0x01 ){
|
|
@@ -223148,7 +239736,7 @@ static int fts5ApiPhraseFirstColumn(
|
|
}
|
|
|
|
|
|
-static int fts5ApiQueryPhrase(Fts5Context*, int, void*,
|
|
+static int fts5ApiQueryPhrase(Fts5Context*, int, void*,
|
|
int(*)(const Fts5ExtensionApi*, Fts5Context*, void*)
|
|
);
|
|
|
|
@@ -223179,8 +239767,8 @@ static const Fts5ExtensionApi sFts5Api = {
|
|
** Implementation of API function xQueryPhrase().
|
|
*/
|
|
static int fts5ApiQueryPhrase(
|
|
- Fts5Context *pCtx,
|
|
- int iPhrase,
|
|
+ Fts5Context *pCtx,
|
|
+ int iPhrase,
|
|
void *pUserData,
|
|
int(*xCallback)(const Fts5ExtensionApi*, Fts5Context*, void*)
|
|
){
|
|
@@ -223262,7 +239850,7 @@ static void fts5ApiCallback(
|
|
|
|
|
|
/*
|
|
-** Given cursor id iId, return a pointer to the corresponding Fts5Table
|
|
+** Given cursor id iId, return a pointer to the corresponding Fts5Table
|
|
** object. Or NULL If the cursor id does not exist.
|
|
*/
|
|
static Fts5Table *sqlite3Fts5TableFromCsrid(
|
|
@@ -223345,7 +239933,7 @@ static int fts5PoslistBlob(sqlite3_context *pCtx, Fts5Cursor *pCsr){
|
|
return rc;
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** This is the xColumn method, called by SQLite to request a value from
|
|
** the row that the supplied cursor currently points to.
|
|
*/
|
|
@@ -223358,7 +239946,7 @@ static int fts5ColumnMethod(
|
|
Fts5Config *pConfig = pTab->p.pConfig;
|
|
Fts5Cursor *pCsr = (Fts5Cursor*)pCursor;
|
|
int rc = SQLITE_OK;
|
|
-
|
|
+
|
|
assert( CsrFlagTest(pCsr, FTS5CSR_EOF)==0 );
|
|
|
|
if( pCsr->ePlan==FTS5_PLAN_SPECIAL ){
|
|
@@ -223378,7 +239966,7 @@ static int fts5ColumnMethod(
|
|
/* The value of the "rank" column. */
|
|
if( pCsr->ePlan==FTS5_PLAN_SOURCE ){
|
|
fts5PoslistBlob(pCtx, pCsr);
|
|
- }else if(
|
|
+ }else if(
|
|
pCsr->ePlan==FTS5_PLAN_MATCH
|
|
|| pCsr->ePlan==FTS5_PLAN_SORTED_MATCH
|
|
){
|
|
@@ -223514,7 +240102,7 @@ static int fts5CreateAux(
|
|
}
|
|
|
|
/*
|
|
-** Register a new tokenizer. This is the implementation of the
|
|
+** Register a new tokenizer. This is the implementation of the
|
|
** fts5_api.xCreateTokenizer() method.
|
|
*/
|
|
static int fts5CreateTokenizer(
|
|
@@ -223553,7 +240141,7 @@ static int fts5CreateTokenizer(
|
|
}
|
|
|
|
static Fts5TokenizerModule *fts5LocateTokenizer(
|
|
- Fts5Global *pGlobal,
|
|
+ Fts5Global *pGlobal,
|
|
const char *zName
|
|
){
|
|
Fts5TokenizerModule *pMod = 0;
|
|
@@ -223570,7 +240158,7 @@ static Fts5TokenizerModule *fts5LocateTokenizer(
|
|
}
|
|
|
|
/*
|
|
-** Find a tokenizer. This is the implementation of the
|
|
+** Find a tokenizer. This is the implementation of the
|
|
** fts5_api.xFindTokenizer() method.
|
|
*/
|
|
static int fts5FindTokenizer(
|
|
@@ -223595,11 +240183,10 @@ static int fts5FindTokenizer(
|
|
}
|
|
|
|
static int sqlite3Fts5GetTokenizer(
|
|
- Fts5Global *pGlobal,
|
|
+ Fts5Global *pGlobal,
|
|
const char **azArg,
|
|
int nArg,
|
|
- Fts5Tokenizer **ppTok,
|
|
- fts5_tokenizer **ppTokApi,
|
|
+ Fts5Config *pConfig,
|
|
char **pzErr
|
|
){
|
|
Fts5TokenizerModule *pMod;
|
|
@@ -223611,16 +240198,22 @@ static int sqlite3Fts5GetTokenizer(
|
|
rc = SQLITE_ERROR;
|
|
*pzErr = sqlite3_mprintf("no such tokenizer: %s", azArg[0]);
|
|
}else{
|
|
- rc = pMod->x.xCreate(pMod->pUserData, &azArg[1], (nArg?nArg-1:0), ppTok);
|
|
- *ppTokApi = &pMod->x;
|
|
- if( rc!=SQLITE_OK && pzErr ){
|
|
- *pzErr = sqlite3_mprintf("error in tokenizer constructor");
|
|
+ rc = pMod->x.xCreate(
|
|
+ pMod->pUserData, (azArg?&azArg[1]:0), (nArg?nArg-1:0), &pConfig->pTok
|
|
+ );
|
|
+ pConfig->pTokApi = &pMod->x;
|
|
+ if( rc!=SQLITE_OK ){
|
|
+ if( pzErr ) *pzErr = sqlite3_mprintf("error in tokenizer constructor");
|
|
+ }else{
|
|
+ pConfig->ePattern = sqlite3Fts5TokenizerPattern(
|
|
+ pMod->x.xCreate, pConfig->pTok
|
|
+ );
|
|
}
|
|
}
|
|
|
|
if( rc!=SQLITE_OK ){
|
|
- *ppTokApi = 0;
|
|
- *ppTok = 0;
|
|
+ pConfig->pTokApi = 0;
|
|
+ pConfig->pTok = 0;
|
|
}
|
|
|
|
return rc;
|
|
@@ -223669,7 +240262,7 @@ static void fts5SourceIdFunc(
|
|
){
|
|
assert( nArg==0 );
|
|
UNUSED_PARAM2(nArg, apUnused);
|
|
- sqlite3_result_text(pCtx, "fts5: 2020-01-27 19:55:54 3bfa9cc97da10598521b342961df8f5f68c7388fa117345eeb516eaa837bb4d6", -1, SQLITE_TRANSIENT);
|
|
+ sqlite3_result_text(pCtx, "fts5: 2023-03-22 11:56:21 0d1fc92f94cb6b76bffe3ec34d69cffde2924203304e8ffc4155597af0c191da", -1, SQLITE_TRANSIENT);
|
|
}
|
|
|
|
/*
|
|
@@ -223742,7 +240335,9 @@ static int fts5Init(sqlite3 *db){
|
|
}
|
|
if( rc==SQLITE_OK ){
|
|
rc = sqlite3_create_function(
|
|
- db, "fts5_source_id", 0, SQLITE_UTF8, p, fts5SourceIdFunc, 0, 0
|
|
+ db, "fts5_source_id", 0,
|
|
+ SQLITE_UTF8|SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS,
|
|
+ p, fts5SourceIdFunc, 0, 0
|
|
);
|
|
}
|
|
}
|
|
@@ -223765,7 +240360,7 @@ static int fts5Init(sqlite3 *db){
|
|
** this module is being built as part of the SQLite core (SQLITE_CORE is
|
|
** defined), then sqlite3_open() will call sqlite3Fts5Init() directly.
|
|
**
|
|
-** Or, if this module is being built as a loadable extension,
|
|
+** Or, if this module is being built as a loadable extension,
|
|
** sqlite3Fts5Init() is omitted and the two standard entry points
|
|
** sqlite3_fts_init() and sqlite3_fts5_init() defined instead.
|
|
*/
|
|
@@ -223824,19 +240419,19 @@ struct Fts5Storage {
|
|
Fts5Index *pIndex;
|
|
int bTotalsValid; /* True if nTotalRow/aTotalSize[] are valid */
|
|
i64 nTotalRow; /* Total number of rows in FTS table */
|
|
- i64 *aTotalSize; /* Total sizes of each column */
|
|
+ i64 *aTotalSize; /* Total sizes of each column */
|
|
sqlite3_stmt *aStmt[11];
|
|
};
|
|
|
|
|
|
-#if FTS5_STMT_SCAN_ASC!=0
|
|
-# error "FTS5_STMT_SCAN_ASC mismatch"
|
|
+#if FTS5_STMT_SCAN_ASC!=0
|
|
+# error "FTS5_STMT_SCAN_ASC mismatch"
|
|
#endif
|
|
-#if FTS5_STMT_SCAN_DESC!=1
|
|
-# error "FTS5_STMT_SCAN_DESC mismatch"
|
|
+#if FTS5_STMT_SCAN_DESC!=1
|
|
+# error "FTS5_STMT_SCAN_DESC mismatch"
|
|
#endif
|
|
#if FTS5_STMT_LOOKUP!=2
|
|
-# error "FTS5_STMT_LOOKUP mismatch"
|
|
+# error "FTS5_STMT_LOOKUP mismatch"
|
|
#endif
|
|
|
|
#define FTS5_STMT_INSERT_CONTENT 3
|
|
@@ -223862,12 +240457,12 @@ static int fts5StorageGetStmt(
|
|
){
|
|
int rc = SQLITE_OK;
|
|
|
|
- /* If there is no %_docsize table, there should be no requests for
|
|
+ /* If there is no %_docsize table, there should be no requests for
|
|
** statements to operate on it. */
|
|
assert( p->pConfig->bColumnsize || (
|
|
- eStmt!=FTS5_STMT_REPLACE_DOCSIZE
|
|
- && eStmt!=FTS5_STMT_DELETE_DOCSIZE
|
|
- && eStmt!=FTS5_STMT_LOOKUP_DOCSIZE
|
|
+ eStmt!=FTS5_STMT_REPLACE_DOCSIZE
|
|
+ && eStmt!=FTS5_STMT_DELETE_DOCSIZE
|
|
+ && eStmt!=FTS5_STMT_LOOKUP_DOCSIZE
|
|
));
|
|
|
|
assert( eStmt>=0 && eStmt<ArraySize(p->aStmt) );
|
|
@@ -223893,26 +240488,26 @@ static int fts5StorageGetStmt(
|
|
|
|
switch( eStmt ){
|
|
case FTS5_STMT_SCAN:
|
|
- zSql = sqlite3_mprintf(azStmt[eStmt],
|
|
+ zSql = sqlite3_mprintf(azStmt[eStmt],
|
|
pC->zContentExprlist, pC->zContent
|
|
);
|
|
break;
|
|
|
|
case FTS5_STMT_SCAN_ASC:
|
|
case FTS5_STMT_SCAN_DESC:
|
|
- zSql = sqlite3_mprintf(azStmt[eStmt], pC->zContentExprlist,
|
|
+ zSql = sqlite3_mprintf(azStmt[eStmt], pC->zContentExprlist,
|
|
pC->zContent, pC->zContentRowid, pC->zContentRowid,
|
|
pC->zContentRowid
|
|
);
|
|
break;
|
|
|
|
case FTS5_STMT_LOOKUP:
|
|
- zSql = sqlite3_mprintf(azStmt[eStmt],
|
|
+ zSql = sqlite3_mprintf(azStmt[eStmt],
|
|
pC->zContentExprlist, pC->zContent, pC->zContentRowid
|
|
);
|
|
break;
|
|
|
|
- case FTS5_STMT_INSERT_CONTENT:
|
|
+ case FTS5_STMT_INSERT_CONTENT:
|
|
case FTS5_STMT_REPLACE_CONTENT: {
|
|
int nCol = pC->nCol + 1;
|
|
char *zBind;
|
|
@@ -223986,7 +240581,7 @@ static int fts5ExecPrintf(
|
|
** code otherwise.
|
|
*/
|
|
static int sqlite3Fts5DropAll(Fts5Config *pConfig){
|
|
- int rc = fts5ExecPrintf(pConfig->db, 0,
|
|
+ int rc = fts5ExecPrintf(pConfig->db, 0,
|
|
"DROP TABLE IF EXISTS %Q.'%q_data';"
|
|
"DROP TABLE IF EXISTS %Q.'%q_idx';"
|
|
"DROP TABLE IF EXISTS %Q.'%q_config';",
|
|
@@ -223995,13 +240590,13 @@ static int sqlite3Fts5DropAll(Fts5Config *pConfig){
|
|
pConfig->zDb, pConfig->zName
|
|
);
|
|
if( rc==SQLITE_OK && pConfig->bColumnsize ){
|
|
- rc = fts5ExecPrintf(pConfig->db, 0,
|
|
+ rc = fts5ExecPrintf(pConfig->db, 0,
|
|
"DROP TABLE IF EXISTS %Q.'%q_docsize';",
|
|
pConfig->zDb, pConfig->zName
|
|
);
|
|
}
|
|
if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_NORMAL ){
|
|
- rc = fts5ExecPrintf(pConfig->db, 0,
|
|
+ rc = fts5ExecPrintf(pConfig->db, 0,
|
|
"DROP TABLE IF EXISTS %Q.'%q_content';",
|
|
pConfig->zDb, pConfig->zName
|
|
);
|
|
@@ -224016,7 +240611,7 @@ static void fts5StorageRenameOne(
|
|
const char *zName /* New name of FTS5 table */
|
|
){
|
|
if( *pRc==SQLITE_OK ){
|
|
- *pRc = fts5ExecPrintf(pConfig->db, 0,
|
|
+ *pRc = fts5ExecPrintf(pConfig->db, 0,
|
|
"ALTER TABLE %Q.'%q_%s' RENAME TO '%q_%s';",
|
|
pConfig->zDb, pConfig->zName, zTail, zName, zTail
|
|
);
|
|
@@ -224054,7 +240649,7 @@ static int sqlite3Fts5CreateTable(
|
|
char *zErr = 0;
|
|
|
|
rc = fts5ExecPrintf(pConfig->db, &zErr, "CREATE TABLE %Q.'%q_%q'(%s)%s",
|
|
- pConfig->zDb, pConfig->zName, zPost, zDefn,
|
|
+ pConfig->zDb, pConfig->zName, zPost, zDefn,
|
|
#ifndef SQLITE_FTS5_NO_WITHOUT_ROWID
|
|
bWithout?" WITHOUT ROWID":
|
|
#endif
|
|
@@ -224062,7 +240657,7 @@ static int sqlite3Fts5CreateTable(
|
|
);
|
|
if( zErr ){
|
|
*pzErr = sqlite3_mprintf(
|
|
- "fts5: error creating shadow table %q_%s: %s",
|
|
+ "fts5: error creating shadow table %q_%s: %s",
|
|
pConfig->zName, zPost, zErr
|
|
);
|
|
sqlite3_free(zErr);
|
|
@@ -224073,15 +240668,15 @@ static int sqlite3Fts5CreateTable(
|
|
|
|
/*
|
|
** Open a new Fts5Index handle. If the bCreate argument is true, create
|
|
-** and initialize the underlying tables
|
|
+** and initialize the underlying tables
|
|
**
|
|
** If successful, set *pp to point to the new object and return SQLITE_OK.
|
|
** Otherwise, set *pp to NULL and return an SQLite error code.
|
|
*/
|
|
static int sqlite3Fts5StorageOpen(
|
|
- Fts5Config *pConfig,
|
|
- Fts5Index *pIndex,
|
|
- int bCreate,
|
|
+ Fts5Config *pConfig,
|
|
+ Fts5Index *pIndex,
|
|
+ int bCreate,
|
|
Fts5Storage **pp,
|
|
char **pzErr /* OUT: Error message */
|
|
){
|
|
@@ -224193,8 +240788,8 @@ static int fts5StorageInsertCallback(
|
|
** remove the %_content row at this time though.
|
|
*/
|
|
static int fts5StorageDeleteFromIndex(
|
|
- Fts5Storage *p,
|
|
- i64 iDel,
|
|
+ Fts5Storage *p,
|
|
+ i64 iDel,
|
|
sqlite3_value **apVal
|
|
){
|
|
Fts5Config *pConfig = p->pConfig;
|
|
@@ -224220,21 +240815,32 @@ static int fts5StorageDeleteFromIndex(
|
|
if( pConfig->abUnindexed[iCol-1]==0 ){
|
|
const char *zText;
|
|
int nText;
|
|
+ assert( pSeek==0 || apVal==0 );
|
|
+ assert( pSeek!=0 || apVal!=0 );
|
|
if( pSeek ){
|
|
zText = (const char*)sqlite3_column_text(pSeek, iCol);
|
|
nText = sqlite3_column_bytes(pSeek, iCol);
|
|
- }else{
|
|
+ }else if( ALWAYS(apVal) ){
|
|
zText = (const char*)sqlite3_value_text(apVal[iCol-1]);
|
|
nText = sqlite3_value_bytes(apVal[iCol-1]);
|
|
+ }else{
|
|
+ continue;
|
|
}
|
|
ctx.szCol = 0;
|
|
- rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT,
|
|
+ rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT,
|
|
zText, nText, (void*)&ctx, fts5StorageInsertCallback
|
|
);
|
|
p->aTotalSize[iCol-1] -= (i64)ctx.szCol;
|
|
+ if( p->aTotalSize[iCol-1]<0 ){
|
|
+ rc = FTS5_CORRUPT;
|
|
+ }
|
|
}
|
|
}
|
|
- p->nTotalRow--;
|
|
+ if( rc==SQLITE_OK && p->nTotalRow<1 ){
|
|
+ rc = FTS5_CORRUPT;
|
|
+ }else{
|
|
+ p->nTotalRow--;
|
|
+ }
|
|
|
|
rc2 = sqlite3_reset(pSeek);
|
|
if( rc==SQLITE_OK ) rc = rc2;
|
|
@@ -224271,7 +240877,7 @@ static int fts5StorageInsertDocsize(
|
|
}
|
|
|
|
/*
|
|
-** Load the contents of the "averages" record from disk into the
|
|
+** Load the contents of the "averages" record from disk into the
|
|
** p->nTotalRow and p->aTotalSize[] variables. If successful, and if
|
|
** argument bCache is true, set the p->bTotalsValid flag to indicate
|
|
** that the contents of aTotalSize[] and nTotalRow are valid until
|
|
@@ -224290,7 +240896,7 @@ static int fts5StorageLoadTotals(Fts5Storage *p, int bCache){
|
|
}
|
|
|
|
/*
|
|
-** Store the current contents of the p->nTotalRow and p->aTotalSize[]
|
|
+** Store the current contents of the p->nTotalRow and p->aTotalSize[]
|
|
** variables in the "averages" record on disk.
|
|
**
|
|
** Return SQLITE_OK if successful, or an SQLite error code if an error
|
|
@@ -224367,7 +240973,7 @@ static int sqlite3Fts5StorageDeleteAll(Fts5Storage *p){
|
|
|
|
/* Delete the contents of the %_data and %_docsize tables. */
|
|
rc = fts5ExecPrintf(pConfig->db, 0,
|
|
- "DELETE FROM %Q.'%q_data';"
|
|
+ "DELETE FROM %Q.'%q_data';"
|
|
"DELETE FROM %Q.'%q_idx';",
|
|
pConfig->zDb, pConfig->zName,
|
|
pConfig->zDb, pConfig->zName
|
|
@@ -224418,7 +241024,7 @@ static int sqlite3Fts5StorageRebuild(Fts5Storage *p){
|
|
if( pConfig->abUnindexed[ctx.iCol]==0 ){
|
|
const char *zText = (const char*)sqlite3_column_text(pScan, ctx.iCol+1);
|
|
int nText = sqlite3_column_bytes(pScan, ctx.iCol+1);
|
|
- rc = sqlite3Fts5Tokenize(pConfig,
|
|
+ rc = sqlite3Fts5Tokenize(pConfig,
|
|
FTS5_TOKENIZE_DOCUMENT,
|
|
zText, nText,
|
|
(void*)&ctx,
|
|
@@ -224488,8 +241094,8 @@ static int fts5StorageNewRowid(Fts5Storage *p, i64 *piRowid){
|
|
** Insert a new row into the FTS content table.
|
|
*/
|
|
static int sqlite3Fts5StorageContentInsert(
|
|
- Fts5Storage *p,
|
|
- sqlite3_value **apVal,
|
|
+ Fts5Storage *p,
|
|
+ sqlite3_value **apVal,
|
|
i64 *piRowid
|
|
){
|
|
Fts5Config *pConfig = p->pConfig;
|
|
@@ -224523,8 +241129,8 @@ static int sqlite3Fts5StorageContentInsert(
|
|
** Insert new entries into the FTS index and %_docsize table.
|
|
*/
|
|
static int sqlite3Fts5StorageIndexInsert(
|
|
- Fts5Storage *p,
|
|
- sqlite3_value **apVal,
|
|
+ Fts5Storage *p,
|
|
+ sqlite3_value **apVal,
|
|
i64 iRowid
|
|
){
|
|
Fts5Config *pConfig = p->pConfig;
|
|
@@ -224544,7 +241150,7 @@ static int sqlite3Fts5StorageIndexInsert(
|
|
if( pConfig->abUnindexed[ctx.iCol]==0 ){
|
|
const char *zText = (const char*)sqlite3_value_text(apVal[ctx.iCol+2]);
|
|
int nText = sqlite3_value_bytes(apVal[ctx.iCol+2]);
|
|
- rc = sqlite3Fts5Tokenize(pConfig,
|
|
+ rc = sqlite3Fts5Tokenize(pConfig,
|
|
FTS5_TOKENIZE_DOCUMENT,
|
|
zText, nText,
|
|
(void*)&ctx,
|
|
@@ -224570,7 +241176,7 @@ static int fts5StorageCount(Fts5Storage *p, const char *zSuffix, i64 *pnRow){
|
|
char *zSql;
|
|
int rc;
|
|
|
|
- zSql = sqlite3_mprintf("SELECT count(*) FROM %Q.'%q_%s'",
|
|
+ zSql = sqlite3_mprintf("SELECT count(*) FROM %Q.'%q_%s'",
|
|
pConfig->zDb, pConfig->zName, zSuffix
|
|
);
|
|
if( zSql==0 ){
|
|
@@ -224677,13 +241283,14 @@ static int fts5StorageIntegrityCallback(
|
|
** some other SQLite error code if an error occurs while attempting to
|
|
** determine this.
|
|
*/
|
|
-static int sqlite3Fts5StorageIntegrity(Fts5Storage *p){
|
|
+static int sqlite3Fts5StorageIntegrity(Fts5Storage *p, int iArg){
|
|
Fts5Config *pConfig = p->pConfig;
|
|
- int rc; /* Return code */
|
|
+ int rc = SQLITE_OK; /* Return code */
|
|
int *aColSize; /* Array of size pConfig->nCol */
|
|
i64 *aTotalSize; /* Array of size pConfig->nCol */
|
|
Fts5IntegrityCtx ctx;
|
|
sqlite3_stmt *pScan;
|
|
+ int bUseCksum;
|
|
|
|
memset(&ctx, 0, sizeof(Fts5IntegrityCtx));
|
|
ctx.pConfig = p->pConfig;
|
|
@@ -224692,83 +241299,88 @@ static int sqlite3Fts5StorageIntegrity(Fts5Storage *p){
|
|
aColSize = (int*)&aTotalSize[pConfig->nCol];
|
|
memset(aTotalSize, 0, sizeof(i64) * pConfig->nCol);
|
|
|
|
- /* Generate the expected index checksum based on the contents of the
|
|
- ** %_content table. This block stores the checksum in ctx.cksum. */
|
|
- rc = fts5StorageGetStmt(p, FTS5_STMT_SCAN, &pScan, 0);
|
|
- if( rc==SQLITE_OK ){
|
|
- int rc2;
|
|
- while( SQLITE_ROW==sqlite3_step(pScan) ){
|
|
- int i;
|
|
- ctx.iRowid = sqlite3_column_int64(pScan, 0);
|
|
- ctx.szCol = 0;
|
|
- if( pConfig->bColumnsize ){
|
|
- rc = sqlite3Fts5StorageDocsize(p, ctx.iRowid, aColSize);
|
|
- }
|
|
- if( rc==SQLITE_OK && pConfig->eDetail==FTS5_DETAIL_NONE ){
|
|
- rc = sqlite3Fts5TermsetNew(&ctx.pTermset);
|
|
- }
|
|
- for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){
|
|
- if( pConfig->abUnindexed[i] ) continue;
|
|
- ctx.iCol = i;
|
|
+ bUseCksum = (pConfig->eContent==FTS5_CONTENT_NORMAL
|
|
+ || (pConfig->eContent==FTS5_CONTENT_EXTERNAL && iArg)
|
|
+ );
|
|
+ if( bUseCksum ){
|
|
+ /* Generate the expected index checksum based on the contents of the
|
|
+ ** %_content table. This block stores the checksum in ctx.cksum. */
|
|
+ rc = fts5StorageGetStmt(p, FTS5_STMT_SCAN, &pScan, 0);
|
|
+ if( rc==SQLITE_OK ){
|
|
+ int rc2;
|
|
+ while( SQLITE_ROW==sqlite3_step(pScan) ){
|
|
+ int i;
|
|
+ ctx.iRowid = sqlite3_column_int64(pScan, 0);
|
|
ctx.szCol = 0;
|
|
- if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
|
|
- rc = sqlite3Fts5TermsetNew(&ctx.pTermset);
|
|
- }
|
|
- if( rc==SQLITE_OK ){
|
|
- const char *zText = (const char*)sqlite3_column_text(pScan, i+1);
|
|
- int nText = sqlite3_column_bytes(pScan, i+1);
|
|
- rc = sqlite3Fts5Tokenize(pConfig,
|
|
- FTS5_TOKENIZE_DOCUMENT,
|
|
- zText, nText,
|
|
- (void*)&ctx,
|
|
- fts5StorageIntegrityCallback
|
|
- );
|
|
+ if( pConfig->bColumnsize ){
|
|
+ rc = sqlite3Fts5StorageDocsize(p, ctx.iRowid, aColSize);
|
|
}
|
|
- if( rc==SQLITE_OK && pConfig->bColumnsize && ctx.szCol!=aColSize[i] ){
|
|
- rc = FTS5_CORRUPT;
|
|
+ if( rc==SQLITE_OK && pConfig->eDetail==FTS5_DETAIL_NONE ){
|
|
+ rc = sqlite3Fts5TermsetNew(&ctx.pTermset);
|
|
}
|
|
- aTotalSize[i] += ctx.szCol;
|
|
- if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
|
|
- sqlite3Fts5TermsetFree(ctx.pTermset);
|
|
- ctx.pTermset = 0;
|
|
+ for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){
|
|
+ if( pConfig->abUnindexed[i] ) continue;
|
|
+ ctx.iCol = i;
|
|
+ ctx.szCol = 0;
|
|
+ if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
|
|
+ rc = sqlite3Fts5TermsetNew(&ctx.pTermset);
|
|
+ }
|
|
+ if( rc==SQLITE_OK ){
|
|
+ const char *zText = (const char*)sqlite3_column_text(pScan, i+1);
|
|
+ int nText = sqlite3_column_bytes(pScan, i+1);
|
|
+ rc = sqlite3Fts5Tokenize(pConfig,
|
|
+ FTS5_TOKENIZE_DOCUMENT,
|
|
+ zText, nText,
|
|
+ (void*)&ctx,
|
|
+ fts5StorageIntegrityCallback
|
|
+ );
|
|
+ }
|
|
+ if( rc==SQLITE_OK && pConfig->bColumnsize && ctx.szCol!=aColSize[i] ){
|
|
+ rc = FTS5_CORRUPT;
|
|
+ }
|
|
+ aTotalSize[i] += ctx.szCol;
|
|
+ if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){
|
|
+ sqlite3Fts5TermsetFree(ctx.pTermset);
|
|
+ ctx.pTermset = 0;
|
|
+ }
|
|
}
|
|
- }
|
|
- sqlite3Fts5TermsetFree(ctx.pTermset);
|
|
- ctx.pTermset = 0;
|
|
+ sqlite3Fts5TermsetFree(ctx.pTermset);
|
|
+ ctx.pTermset = 0;
|
|
|
|
- if( rc!=SQLITE_OK ) break;
|
|
+ if( rc!=SQLITE_OK ) break;
|
|
+ }
|
|
+ rc2 = sqlite3_reset(pScan);
|
|
+ if( rc==SQLITE_OK ) rc = rc2;
|
|
}
|
|
- rc2 = sqlite3_reset(pScan);
|
|
- if( rc==SQLITE_OK ) rc = rc2;
|
|
- }
|
|
|
|
- /* Test that the "totals" (sometimes called "averages") record looks Ok */
|
|
- if( rc==SQLITE_OK ){
|
|
- int i;
|
|
- rc = fts5StorageLoadTotals(p, 0);
|
|
- for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){
|
|
- if( p->aTotalSize[i]!=aTotalSize[i] ) rc = FTS5_CORRUPT;
|
|
+ /* Test that the "totals" (sometimes called "averages") record looks Ok */
|
|
+ if( rc==SQLITE_OK ){
|
|
+ int i;
|
|
+ rc = fts5StorageLoadTotals(p, 0);
|
|
+ for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){
|
|
+ if( p->aTotalSize[i]!=aTotalSize[i] ) rc = FTS5_CORRUPT;
|
|
+ }
|
|
}
|
|
- }
|
|
|
|
- /* Check that the %_docsize and %_content tables contain the expected
|
|
- ** number of rows. */
|
|
- if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_NORMAL ){
|
|
- i64 nRow = 0;
|
|
- rc = fts5StorageCount(p, "content", &nRow);
|
|
- if( rc==SQLITE_OK && nRow!=p->nTotalRow ) rc = FTS5_CORRUPT;
|
|
- }
|
|
- if( rc==SQLITE_OK && pConfig->bColumnsize ){
|
|
- i64 nRow = 0;
|
|
- rc = fts5StorageCount(p, "docsize", &nRow);
|
|
- if( rc==SQLITE_OK && nRow!=p->nTotalRow ) rc = FTS5_CORRUPT;
|
|
+ /* Check that the %_docsize and %_content tables contain the expected
|
|
+ ** number of rows. */
|
|
+ if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_NORMAL ){
|
|
+ i64 nRow = 0;
|
|
+ rc = fts5StorageCount(p, "content", &nRow);
|
|
+ if( rc==SQLITE_OK && nRow!=p->nTotalRow ) rc = FTS5_CORRUPT;
|
|
+ }
|
|
+ if( rc==SQLITE_OK && pConfig->bColumnsize ){
|
|
+ i64 nRow = 0;
|
|
+ rc = fts5StorageCount(p, "docsize", &nRow);
|
|
+ if( rc==SQLITE_OK && nRow!=p->nTotalRow ) rc = FTS5_CORRUPT;
|
|
+ }
|
|
}
|
|
|
|
/* Pass the expected checksum down to the FTS index module. It will
|
|
** verify, amongst other things, that it matches the checksum generated by
|
|
** inspecting the index itself. */
|
|
if( rc==SQLITE_OK ){
|
|
- rc = sqlite3Fts5IndexIntegrityCheck(p->pIndex, ctx.cksum);
|
|
+ rc = sqlite3Fts5IndexIntegrityCheck(p->pIndex, ctx.cksum, bUseCksum);
|
|
}
|
|
|
|
sqlite3_free(aTotalSize);
|
|
@@ -224780,13 +241392,13 @@ static int sqlite3Fts5StorageIntegrity(Fts5Storage *p){
|
|
** %_content table.
|
|
*/
|
|
static int sqlite3Fts5StorageStmt(
|
|
- Fts5Storage *p,
|
|
- int eStmt,
|
|
- sqlite3_stmt **pp,
|
|
+ Fts5Storage *p,
|
|
+ int eStmt,
|
|
+ sqlite3_stmt **pp,
|
|
char **pzErrMsg
|
|
){
|
|
int rc;
|
|
- assert( eStmt==FTS5_STMT_SCAN_ASC
|
|
+ assert( eStmt==FTS5_STMT_SCAN_ASC
|
|
|| eStmt==FTS5_STMT_SCAN_DESC
|
|
|| eStmt==FTS5_STMT_LOOKUP
|
|
);
|
|
@@ -224804,8 +241416,8 @@ static int sqlite3Fts5StorageStmt(
|
|
** must match that passed to the sqlite3Fts5StorageStmt() call.
|
|
*/
|
|
static void sqlite3Fts5StorageStmtRelease(
|
|
- Fts5Storage *p,
|
|
- int eStmt,
|
|
+ Fts5Storage *p,
|
|
+ int eStmt,
|
|
sqlite3_stmt *pStmt
|
|
){
|
|
assert( eStmt==FTS5_STMT_SCAN_ASC
|
|
@@ -224848,8 +241460,9 @@ static int sqlite3Fts5StorageDocsize(Fts5Storage *p, i64 iRowid, int *aCol){
|
|
|
|
assert( p->pConfig->bColumnsize );
|
|
rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP_DOCSIZE, &pLookup, 0);
|
|
- if( rc==SQLITE_OK ){
|
|
+ if( pLookup ){
|
|
int bCorrupt = 1;
|
|
+ assert( rc==SQLITE_OK );
|
|
sqlite3_bind_int64(pLookup, 1, iRowid);
|
|
if( SQLITE_ROW==sqlite3_step(pLookup) ){
|
|
const u8 *aBlob = sqlite3_column_blob(pLookup, 0);
|
|
@@ -224862,6 +241475,8 @@ static int sqlite3Fts5StorageDocsize(Fts5Storage *p, i64 iRowid, int *aCol){
|
|
if( bCorrupt && rc==SQLITE_OK ){
|
|
rc = FTS5_CORRUPT;
|
|
}
|
|
+ }else{
|
|
+ assert( rc!=SQLITE_OK );
|
|
}
|
|
|
|
return rc;
|
|
@@ -224888,7 +241503,7 @@ static int sqlite3Fts5StorageSize(Fts5Storage *p, int iCol, i64 *pnToken){
|
|
static int sqlite3Fts5StorageRowCount(Fts5Storage *p, i64 *pnRow){
|
|
int rc = fts5StorageLoadTotals(p, 0);
|
|
if( rc==SQLITE_OK ){
|
|
- /* nTotalRow being zero does not necessarily indicate a corrupt
|
|
+ /* nTotalRow being zero does not necessarily indicate a corrupt
|
|
** database - it might be that the FTS5 table really does contain zero
|
|
** rows. However this function is only called from the xRowCount() API,
|
|
** and there is no way for that API to be invoked if the table contains
|
|
@@ -224922,7 +241537,7 @@ static int sqlite3Fts5StorageRollback(Fts5Storage *p){
|
|
}
|
|
|
|
static int sqlite3Fts5StorageConfigValue(
|
|
- Fts5Storage *p,
|
|
+ Fts5Storage *p,
|
|
const char *z,
|
|
sqlite3_value *pVal,
|
|
int iVal
|
|
@@ -224972,7 +241587,7 @@ static int sqlite3Fts5StorageConfigValue(
|
|
|
|
/*
|
|
** For tokenizers with no "unicode" modifier, the set of token characters
|
|
-** is the same as the set of ASCII range alphanumeric characters.
|
|
+** is the same as the set of ASCII range alphanumeric characters.
|
|
*/
|
|
static unsigned char aAsciiTokenChar[128] = {
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00..0x0F */
|
|
@@ -224991,8 +241606,8 @@ struct AsciiTokenizer {
|
|
};
|
|
|
|
static void fts5AsciiAddExceptions(
|
|
- AsciiTokenizer *p,
|
|
- const char *zArg,
|
|
+ AsciiTokenizer *p,
|
|
+ const char *zArg,
|
|
int bTokenChars
|
|
){
|
|
int i;
|
|
@@ -225014,7 +241629,7 @@ static void fts5AsciiDelete(Fts5Tokenizer *p){
|
|
** Create an "ascii" tokenizer.
|
|
*/
|
|
static int fts5AsciiCreate(
|
|
- void *pUnused,
|
|
+ void *pUnused,
|
|
const char **azArg, int nArg,
|
|
Fts5Tokenizer **ppOut
|
|
){
|
|
@@ -225117,7 +241732,7 @@ static int fts5AsciiTokenize(
|
|
rc = xToken(pCtx, 0, pFold, nByte, is, ie);
|
|
is = ie+1;
|
|
}
|
|
-
|
|
+
|
|
if( pFold!=aFold ) sqlite3_free(pFold);
|
|
if( rc==SQLITE_DONE ) rc = SQLITE_OK;
|
|
return rc;
|
|
@@ -225222,7 +241837,7 @@ static int fts5UnicodeAddExceptions(
|
|
p->aTokenChar[iCode] = (unsigned char)bTokenChars;
|
|
}else{
|
|
bToken = p->aCategory[sqlite3Fts5UnicodeCategory(iCode)];
|
|
- assert( (bToken==0 || bToken==1) );
|
|
+ assert( (bToken==0 || bToken==1) );
|
|
assert( (bTokenChars==0 || bTokenChars==1) );
|
|
if( bToken!=bTokenChars && sqlite3Fts5UnicodeIsdiacritic(iCode)==0 ){
|
|
int i;
|
|
@@ -225301,12 +241916,12 @@ static int unicodeSetCategories(Unicode61Tokenizer *p, const char *zCat){
|
|
** Create a "unicode61" tokenizer.
|
|
*/
|
|
static int fts5UnicodeCreate(
|
|
- void *pUnused,
|
|
+ void *pUnused,
|
|
const char **azArg, int nArg,
|
|
Fts5Tokenizer **ppOut
|
|
){
|
|
int rc = SQLITE_OK; /* Return code */
|
|
- Unicode61Tokenizer *p = 0; /* New tokenizer object */
|
|
+ Unicode61Tokenizer *p = 0; /* New tokenizer object */
|
|
|
|
UNUSED_PARAM(pUnused);
|
|
|
|
@@ -225377,7 +241992,7 @@ static int fts5UnicodeCreate(
|
|
|
|
/*
|
|
** Return true if, for the purposes of tokenizing with the tokenizer
|
|
-** passed as the first argument, codepoint iCode is considered a token
|
|
+** passed as the first argument, codepoint iCode is considered a token
|
|
** character (not a separator).
|
|
*/
|
|
static int fts5UnicodeIsAlnum(Unicode61Tokenizer *p, int iCode){
|
|
@@ -225469,7 +242084,7 @@ static int fts5UnicodeTokenize(
|
|
}
|
|
}else if( a[*zCsr]==0 ){
|
|
/* An ascii-range separator character. End of token. */
|
|
- break;
|
|
+ break;
|
|
}else{
|
|
ascii_tokenchar:
|
|
if( *zCsr>='A' && *zCsr<='Z' ){
|
|
@@ -225483,9 +242098,9 @@ static int fts5UnicodeTokenize(
|
|
}
|
|
|
|
/* Invoke the token callback */
|
|
- rc = xToken(pCtx, 0, aFold, zOut-aFold, is, ie);
|
|
+ rc = xToken(pCtx, 0, aFold, zOut-aFold, is, ie);
|
|
}
|
|
-
|
|
+
|
|
tokenize_done:
|
|
if( rc==SQLITE_DONE ) rc = SQLITE_OK;
|
|
return rc;
|
|
@@ -225523,7 +242138,7 @@ static void fts5PorterDelete(Fts5Tokenizer *pTok){
|
|
** Create a "porter" tokenizer.
|
|
*/
|
|
static int fts5PorterCreate(
|
|
- void *pCtx,
|
|
+ void *pCtx,
|
|
const char **azArg, int nArg,
|
|
Fts5Tokenizer **ppOut
|
|
){
|
|
@@ -225667,7 +242282,7 @@ static int fts5Porter_Ostar(char *zStem, int nStem){
|
|
/* porter rule condition: (m > 1 and (*S or *T)) */
|
|
static int fts5Porter_MGt1_and_S_or_T(char *zStem, int nStem){
|
|
assert( nStem>0 );
|
|
- return (zStem[nStem-1]=='s' || zStem[nStem-1]=='t')
|
|
+ return (zStem[nStem-1]=='s' || zStem[nStem-1]=='t')
|
|
&& fts5Porter_MGt1(zStem, nStem);
|
|
}
|
|
|
|
@@ -225692,16 +242307,16 @@ static int fts5PorterStep4(char *aBuf, int *pnBuf){
|
|
int ret = 0;
|
|
int nBuf = *pnBuf;
|
|
switch( aBuf[nBuf-2] ){
|
|
-
|
|
- case 'a':
|
|
+
|
|
+ case 'a':
|
|
if( nBuf>2 && 0==memcmp("al", &aBuf[nBuf-2], 2) ){
|
|
if( fts5Porter_MGt1(aBuf, nBuf-2) ){
|
|
*pnBuf = nBuf - 2;
|
|
}
|
|
}
|
|
break;
|
|
-
|
|
- case 'c':
|
|
+
|
|
+ case 'c':
|
|
if( nBuf>4 && 0==memcmp("ance", &aBuf[nBuf-4], 4) ){
|
|
if( fts5Porter_MGt1(aBuf, nBuf-4) ){
|
|
*pnBuf = nBuf - 4;
|
|
@@ -225712,24 +242327,24 @@ static int fts5PorterStep4(char *aBuf, int *pnBuf){
|
|
}
|
|
}
|
|
break;
|
|
-
|
|
- case 'e':
|
|
+
|
|
+ case 'e':
|
|
if( nBuf>2 && 0==memcmp("er", &aBuf[nBuf-2], 2) ){
|
|
if( fts5Porter_MGt1(aBuf, nBuf-2) ){
|
|
*pnBuf = nBuf - 2;
|
|
}
|
|
}
|
|
break;
|
|
-
|
|
- case 'i':
|
|
+
|
|
+ case 'i':
|
|
if( nBuf>2 && 0==memcmp("ic", &aBuf[nBuf-2], 2) ){
|
|
if( fts5Porter_MGt1(aBuf, nBuf-2) ){
|
|
*pnBuf = nBuf - 2;
|
|
}
|
|
}
|
|
break;
|
|
-
|
|
- case 'l':
|
|
+
|
|
+ case 'l':
|
|
if( nBuf>4 && 0==memcmp("able", &aBuf[nBuf-4], 4) ){
|
|
if( fts5Porter_MGt1(aBuf, nBuf-4) ){
|
|
*pnBuf = nBuf - 4;
|
|
@@ -225740,8 +242355,8 @@ static int fts5PorterStep4(char *aBuf, int *pnBuf){
|
|
}
|
|
}
|
|
break;
|
|
-
|
|
- case 'n':
|
|
+
|
|
+ case 'n':
|
|
if( nBuf>3 && 0==memcmp("ant", &aBuf[nBuf-3], 3) ){
|
|
if( fts5Porter_MGt1(aBuf, nBuf-3) ){
|
|
*pnBuf = nBuf - 3;
|
|
@@ -225760,8 +242375,8 @@ static int fts5PorterStep4(char *aBuf, int *pnBuf){
|
|
}
|
|
}
|
|
break;
|
|
-
|
|
- case 'o':
|
|
+
|
|
+ case 'o':
|
|
if( nBuf>3 && 0==memcmp("ion", &aBuf[nBuf-3], 3) ){
|
|
if( fts5Porter_MGt1_and_S_or_T(aBuf, nBuf-3) ){
|
|
*pnBuf = nBuf - 3;
|
|
@@ -225772,16 +242387,16 @@ static int fts5PorterStep4(char *aBuf, int *pnBuf){
|
|
}
|
|
}
|
|
break;
|
|
-
|
|
- case 's':
|
|
+
|
|
+ case 's':
|
|
if( nBuf>3 && 0==memcmp("ism", &aBuf[nBuf-3], 3) ){
|
|
if( fts5Porter_MGt1(aBuf, nBuf-3) ){
|
|
*pnBuf = nBuf - 3;
|
|
}
|
|
}
|
|
break;
|
|
-
|
|
- case 't':
|
|
+
|
|
+ case 't':
|
|
if( nBuf>3 && 0==memcmp("ate", &aBuf[nBuf-3], 3) ){
|
|
if( fts5Porter_MGt1(aBuf, nBuf-3) ){
|
|
*pnBuf = nBuf - 3;
|
|
@@ -225792,76 +242407,76 @@ static int fts5PorterStep4(char *aBuf, int *pnBuf){
|
|
}
|
|
}
|
|
break;
|
|
-
|
|
- case 'u':
|
|
+
|
|
+ case 'u':
|
|
if( nBuf>3 && 0==memcmp("ous", &aBuf[nBuf-3], 3) ){
|
|
if( fts5Porter_MGt1(aBuf, nBuf-3) ){
|
|
*pnBuf = nBuf - 3;
|
|
}
|
|
}
|
|
break;
|
|
-
|
|
- case 'v':
|
|
+
|
|
+ case 'v':
|
|
if( nBuf>3 && 0==memcmp("ive", &aBuf[nBuf-3], 3) ){
|
|
if( fts5Porter_MGt1(aBuf, nBuf-3) ){
|
|
*pnBuf = nBuf - 3;
|
|
}
|
|
}
|
|
break;
|
|
-
|
|
- case 'z':
|
|
+
|
|
+ case 'z':
|
|
if( nBuf>3 && 0==memcmp("ize", &aBuf[nBuf-3], 3) ){
|
|
if( fts5Porter_MGt1(aBuf, nBuf-3) ){
|
|
*pnBuf = nBuf - 3;
|
|
}
|
|
}
|
|
break;
|
|
-
|
|
+
|
|
}
|
|
return ret;
|
|
}
|
|
-
|
|
+
|
|
|
|
static int fts5PorterStep1B2(char *aBuf, int *pnBuf){
|
|
int ret = 0;
|
|
int nBuf = *pnBuf;
|
|
switch( aBuf[nBuf-2] ){
|
|
-
|
|
- case 'a':
|
|
+
|
|
+ case 'a':
|
|
if( nBuf>2 && 0==memcmp("at", &aBuf[nBuf-2], 2) ){
|
|
memcpy(&aBuf[nBuf-2], "ate", 3);
|
|
*pnBuf = nBuf - 2 + 3;
|
|
ret = 1;
|
|
}
|
|
break;
|
|
-
|
|
- case 'b':
|
|
+
|
|
+ case 'b':
|
|
if( nBuf>2 && 0==memcmp("bl", &aBuf[nBuf-2], 2) ){
|
|
memcpy(&aBuf[nBuf-2], "ble", 3);
|
|
*pnBuf = nBuf - 2 + 3;
|
|
ret = 1;
|
|
}
|
|
break;
|
|
-
|
|
- case 'i':
|
|
+
|
|
+ case 'i':
|
|
if( nBuf>2 && 0==memcmp("iz", &aBuf[nBuf-2], 2) ){
|
|
memcpy(&aBuf[nBuf-2], "ize", 3);
|
|
*pnBuf = nBuf - 2 + 3;
|
|
ret = 1;
|
|
}
|
|
break;
|
|
-
|
|
+
|
|
}
|
|
return ret;
|
|
}
|
|
-
|
|
+
|
|
|
|
static int fts5PorterStep2(char *aBuf, int *pnBuf){
|
|
int ret = 0;
|
|
int nBuf = *pnBuf;
|
|
switch( aBuf[nBuf-2] ){
|
|
-
|
|
- case 'a':
|
|
+
|
|
+ case 'a':
|
|
if( nBuf>7 && 0==memcmp("ational", &aBuf[nBuf-7], 7) ){
|
|
if( fts5Porter_MGt0(aBuf, nBuf-7) ){
|
|
memcpy(&aBuf[nBuf-7], "ate", 3);
|
|
@@ -225874,8 +242489,8 @@ static int fts5PorterStep2(char *aBuf, int *pnBuf){
|
|
}
|
|
}
|
|
break;
|
|
-
|
|
- case 'c':
|
|
+
|
|
+ case 'c':
|
|
if( nBuf>4 && 0==memcmp("enci", &aBuf[nBuf-4], 4) ){
|
|
if( fts5Porter_MGt0(aBuf, nBuf-4) ){
|
|
memcpy(&aBuf[nBuf-4], "ence", 4);
|
|
@@ -225888,8 +242503,8 @@ static int fts5PorterStep2(char *aBuf, int *pnBuf){
|
|
}
|
|
}
|
|
break;
|
|
-
|
|
- case 'e':
|
|
+
|
|
+ case 'e':
|
|
if( nBuf>4 && 0==memcmp("izer", &aBuf[nBuf-4], 4) ){
|
|
if( fts5Porter_MGt0(aBuf, nBuf-4) ){
|
|
memcpy(&aBuf[nBuf-4], "ize", 3);
|
|
@@ -225897,8 +242512,8 @@ static int fts5PorterStep2(char *aBuf, int *pnBuf){
|
|
}
|
|
}
|
|
break;
|
|
-
|
|
- case 'g':
|
|
+
|
|
+ case 'g':
|
|
if( nBuf>4 && 0==memcmp("logi", &aBuf[nBuf-4], 4) ){
|
|
if( fts5Porter_MGt0(aBuf, nBuf-4) ){
|
|
memcpy(&aBuf[nBuf-4], "log", 3);
|
|
@@ -225906,8 +242521,8 @@ static int fts5PorterStep2(char *aBuf, int *pnBuf){
|
|
}
|
|
}
|
|
break;
|
|
-
|
|
- case 'l':
|
|
+
|
|
+ case 'l':
|
|
if( nBuf>3 && 0==memcmp("bli", &aBuf[nBuf-3], 3) ){
|
|
if( fts5Porter_MGt0(aBuf, nBuf-3) ){
|
|
memcpy(&aBuf[nBuf-3], "ble", 3);
|
|
@@ -225935,8 +242550,8 @@ static int fts5PorterStep2(char *aBuf, int *pnBuf){
|
|
}
|
|
}
|
|
break;
|
|
-
|
|
- case 'o':
|
|
+
|
|
+ case 'o':
|
|
if( nBuf>7 && 0==memcmp("ization", &aBuf[nBuf-7], 7) ){
|
|
if( fts5Porter_MGt0(aBuf, nBuf-7) ){
|
|
memcpy(&aBuf[nBuf-7], "ize", 3);
|
|
@@ -225954,8 +242569,8 @@ static int fts5PorterStep2(char *aBuf, int *pnBuf){
|
|
}
|
|
}
|
|
break;
|
|
-
|
|
- case 's':
|
|
+
|
|
+ case 's':
|
|
if( nBuf>5 && 0==memcmp("alism", &aBuf[nBuf-5], 5) ){
|
|
if( fts5Porter_MGt0(aBuf, nBuf-5) ){
|
|
memcpy(&aBuf[nBuf-5], "al", 2);
|
|
@@ -225978,8 +242593,8 @@ static int fts5PorterStep2(char *aBuf, int *pnBuf){
|
|
}
|
|
}
|
|
break;
|
|
-
|
|
- case 't':
|
|
+
|
|
+ case 't':
|
|
if( nBuf>5 && 0==memcmp("aliti", &aBuf[nBuf-5], 5) ){
|
|
if( fts5Porter_MGt0(aBuf, nBuf-5) ){
|
|
memcpy(&aBuf[nBuf-5], "al", 2);
|
|
@@ -225997,18 +242612,18 @@ static int fts5PorterStep2(char *aBuf, int *pnBuf){
|
|
}
|
|
}
|
|
break;
|
|
-
|
|
+
|
|
}
|
|
return ret;
|
|
}
|
|
-
|
|
+
|
|
|
|
static int fts5PorterStep3(char *aBuf, int *pnBuf){
|
|
int ret = 0;
|
|
int nBuf = *pnBuf;
|
|
switch( aBuf[nBuf-2] ){
|
|
-
|
|
- case 'a':
|
|
+
|
|
+ case 'a':
|
|
if( nBuf>4 && 0==memcmp("ical", &aBuf[nBuf-4], 4) ){
|
|
if( fts5Porter_MGt0(aBuf, nBuf-4) ){
|
|
memcpy(&aBuf[nBuf-4], "ic", 2);
|
|
@@ -226016,16 +242631,16 @@ static int fts5PorterStep3(char *aBuf, int *pnBuf){
|
|
}
|
|
}
|
|
break;
|
|
-
|
|
- case 's':
|
|
+
|
|
+ case 's':
|
|
if( nBuf>4 && 0==memcmp("ness", &aBuf[nBuf-4], 4) ){
|
|
if( fts5Porter_MGt0(aBuf, nBuf-4) ){
|
|
*pnBuf = nBuf - 4;
|
|
}
|
|
}
|
|
break;
|
|
-
|
|
- case 't':
|
|
+
|
|
+ case 't':
|
|
if( nBuf>5 && 0==memcmp("icate", &aBuf[nBuf-5], 5) ){
|
|
if( fts5Porter_MGt0(aBuf, nBuf-5) ){
|
|
memcpy(&aBuf[nBuf-5], "ic", 2);
|
|
@@ -226038,24 +242653,24 @@ static int fts5PorterStep3(char *aBuf, int *pnBuf){
|
|
}
|
|
}
|
|
break;
|
|
-
|
|
- case 'u':
|
|
+
|
|
+ case 'u':
|
|
if( nBuf>3 && 0==memcmp("ful", &aBuf[nBuf-3], 3) ){
|
|
if( fts5Porter_MGt0(aBuf, nBuf-3) ){
|
|
*pnBuf = nBuf - 3;
|
|
}
|
|
}
|
|
break;
|
|
-
|
|
- case 'v':
|
|
+
|
|
+ case 'v':
|
|
if( nBuf>5 && 0==memcmp("ative", &aBuf[nBuf-5], 5) ){
|
|
if( fts5Porter_MGt0(aBuf, nBuf-5) ){
|
|
*pnBuf = nBuf - 5;
|
|
}
|
|
}
|
|
break;
|
|
-
|
|
- case 'z':
|
|
+
|
|
+ case 'z':
|
|
if( nBuf>5 && 0==memcmp("alize", &aBuf[nBuf-5], 5) ){
|
|
if( fts5Porter_MGt0(aBuf, nBuf-5) ){
|
|
memcpy(&aBuf[nBuf-5], "al", 2);
|
|
@@ -226063,18 +242678,18 @@ static int fts5PorterStep3(char *aBuf, int *pnBuf){
|
|
}
|
|
}
|
|
break;
|
|
-
|
|
+
|
|
}
|
|
return ret;
|
|
}
|
|
-
|
|
+
|
|
|
|
static int fts5PorterStep1B(char *aBuf, int *pnBuf){
|
|
int ret = 0;
|
|
int nBuf = *pnBuf;
|
|
switch( aBuf[nBuf-2] ){
|
|
-
|
|
- case 'e':
|
|
+
|
|
+ case 'e':
|
|
if( nBuf>3 && 0==memcmp("eed", &aBuf[nBuf-3], 3) ){
|
|
if( fts5Porter_MGt0(aBuf, nBuf-3) ){
|
|
memcpy(&aBuf[nBuf-3], "ee", 2);
|
|
@@ -226087,8 +242702,8 @@ static int fts5PorterStep1B(char *aBuf, int *pnBuf){
|
|
}
|
|
}
|
|
break;
|
|
-
|
|
- case 'n':
|
|
+
|
|
+ case 'n':
|
|
if( nBuf>3 && 0==memcmp("ing", &aBuf[nBuf-3], 3) ){
|
|
if( fts5Porter_Vowel(aBuf, nBuf-3) ){
|
|
*pnBuf = nBuf - 3;
|
|
@@ -226096,12 +242711,12 @@ static int fts5PorterStep1B(char *aBuf, int *pnBuf){
|
|
}
|
|
}
|
|
break;
|
|
-
|
|
+
|
|
}
|
|
return ret;
|
|
}
|
|
-
|
|
-/*
|
|
+
|
|
+/*
|
|
** GENERATED CODE ENDS HERE (mkportersteps.tcl)
|
|
***************************************************************************
|
|
**************************************************************************/
|
|
@@ -226110,7 +242725,7 @@ static void fts5PorterStep1A(char *aBuf, int *pnBuf){
|
|
int nBuf = *pnBuf;
|
|
if( aBuf[nBuf-1]=='s' ){
|
|
if( aBuf[nBuf-2]=='e' ){
|
|
- if( (nBuf>4 && aBuf[nBuf-4]=='s' && aBuf[nBuf-3]=='s')
|
|
+ if( (nBuf>4 && aBuf[nBuf-4]=='s' && aBuf[nBuf-3]=='s')
|
|
|| (nBuf>3 && aBuf[nBuf-3]=='i' )
|
|
){
|
|
*pnBuf = nBuf-2;
|
|
@@ -226125,11 +242740,11 @@ static void fts5PorterStep1A(char *aBuf, int *pnBuf){
|
|
}
|
|
|
|
static int fts5PorterCb(
|
|
- void *pCtx,
|
|
+ void *pCtx,
|
|
int tflags,
|
|
- const char *pToken,
|
|
- int nToken,
|
|
- int iStart,
|
|
+ const char *pToken,
|
|
+ int nToken,
|
|
+ int iStart,
|
|
int iEnd
|
|
){
|
|
PorterContext *p = (PorterContext*)pCtx;
|
|
@@ -226147,8 +242762,8 @@ static int fts5PorterCb(
|
|
if( fts5PorterStep1B(aBuf, &nBuf) ){
|
|
if( fts5PorterStep1B2(aBuf, &nBuf)==0 ){
|
|
char c = aBuf[nBuf-1];
|
|
- if( fts5PorterIsVowel(c, 0)==0
|
|
- && c!='l' && c!='s' && c!='z' && c==aBuf[nBuf-2]
|
|
+ if( fts5PorterIsVowel(c, 0)==0
|
|
+ && c!='l' && c!='s' && c!='z' && c==aBuf[nBuf-2]
|
|
){
|
|
nBuf--;
|
|
}else if( fts5Porter_MEq1(aBuf, nBuf) && fts5Porter_Ostar(aBuf, nBuf) ){
|
|
@@ -226170,7 +242785,7 @@ static int fts5PorterCb(
|
|
/* Step 5a. */
|
|
assert( nBuf>0 );
|
|
if( aBuf[nBuf-1]=='e' ){
|
|
- if( fts5Porter_MGt1(aBuf, nBuf-1)
|
|
+ if( fts5Porter_MGt1(aBuf, nBuf-1)
|
|
|| (fts5Porter_MEq1(aBuf, nBuf-1) && !fts5Porter_Ostar(aBuf, nBuf-1))
|
|
){
|
|
nBuf--;
|
|
@@ -226178,8 +242793,8 @@ static int fts5PorterCb(
|
|
}
|
|
|
|
/* Step 5b. */
|
|
- if( nBuf>1 && aBuf[nBuf-1]=='l'
|
|
- && aBuf[nBuf-2]=='l' && fts5Porter_MGt1(aBuf, nBuf-1)
|
|
+ if( nBuf>1 && aBuf[nBuf-1]=='l'
|
|
+ && aBuf[nBuf-2]=='l' && fts5Porter_MGt1(aBuf, nBuf-1)
|
|
){
|
|
nBuf--;
|
|
}
|
|
@@ -226210,6 +242825,133 @@ static int fts5PorterTokenize(
|
|
);
|
|
}
|
|
|
|
+/**************************************************************************
|
|
+** Start of trigram implementation.
|
|
+*/
|
|
+typedef struct TrigramTokenizer TrigramTokenizer;
|
|
+struct TrigramTokenizer {
|
|
+ int bFold; /* True to fold to lower-case */
|
|
+};
|
|
+
|
|
+/*
|
|
+** Free a trigram tokenizer.
|
|
+*/
|
|
+static void fts5TriDelete(Fts5Tokenizer *p){
|
|
+ sqlite3_free(p);
|
|
+}
|
|
+
|
|
+/*
|
|
+** Allocate a trigram tokenizer.
|
|
+*/
|
|
+static int fts5TriCreate(
|
|
+ void *pUnused,
|
|
+ const char **azArg,
|
|
+ int nArg,
|
|
+ Fts5Tokenizer **ppOut
|
|
+){
|
|
+ int rc = SQLITE_OK;
|
|
+ TrigramTokenizer *pNew = (TrigramTokenizer*)sqlite3_malloc(sizeof(*pNew));
|
|
+ UNUSED_PARAM(pUnused);
|
|
+ if( pNew==0 ){
|
|
+ rc = SQLITE_NOMEM;
|
|
+ }else{
|
|
+ int i;
|
|
+ pNew->bFold = 1;
|
|
+ for(i=0; rc==SQLITE_OK && i<nArg; i+=2){
|
|
+ const char *zArg = azArg[i+1];
|
|
+ if( 0==sqlite3_stricmp(azArg[i], "case_sensitive") ){
|
|
+ if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1] ){
|
|
+ rc = SQLITE_ERROR;
|
|
+ }else{
|
|
+ pNew->bFold = (zArg[0]=='0');
|
|
+ }
|
|
+ }else{
|
|
+ rc = SQLITE_ERROR;
|
|
+ }
|
|
+ }
|
|
+ if( rc!=SQLITE_OK ){
|
|
+ fts5TriDelete((Fts5Tokenizer*)pNew);
|
|
+ pNew = 0;
|
|
+ }
|
|
+ }
|
|
+ *ppOut = (Fts5Tokenizer*)pNew;
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Trigram tokenizer tokenize routine.
|
|
+*/
|
|
+static int fts5TriTokenize(
|
|
+ Fts5Tokenizer *pTok,
|
|
+ void *pCtx,
|
|
+ int unusedFlags,
|
|
+ const char *pText, int nText,
|
|
+ int (*xToken)(void*, int, const char*, int, int, int)
|
|
+){
|
|
+ TrigramTokenizer *p = (TrigramTokenizer*)pTok;
|
|
+ int rc = SQLITE_OK;
|
|
+ char aBuf[32];
|
|
+ const unsigned char *zIn = (const unsigned char*)pText;
|
|
+ const unsigned char *zEof = &zIn[nText];
|
|
+ u32 iCode;
|
|
+
|
|
+ UNUSED_PARAM(unusedFlags);
|
|
+ while( 1 ){
|
|
+ char *zOut = aBuf;
|
|
+ int iStart = zIn - (const unsigned char*)pText;
|
|
+ const unsigned char *zNext;
|
|
+
|
|
+ READ_UTF8(zIn, zEof, iCode);
|
|
+ if( iCode==0 ) break;
|
|
+ zNext = zIn;
|
|
+ if( zIn<zEof ){
|
|
+ if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, 0);
|
|
+ WRITE_UTF8(zOut, iCode);
|
|
+ READ_UTF8(zIn, zEof, iCode);
|
|
+ if( iCode==0 ) break;
|
|
+ }else{
|
|
+ break;
|
|
+ }
|
|
+ if( zIn<zEof ){
|
|
+ if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, 0);
|
|
+ WRITE_UTF8(zOut, iCode);
|
|
+ READ_UTF8(zIn, zEof, iCode);
|
|
+ if( iCode==0 ) break;
|
|
+ if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, 0);
|
|
+ WRITE_UTF8(zOut, iCode);
|
|
+ }else{
|
|
+ break;
|
|
+ }
|
|
+ rc = xToken(pCtx, 0, aBuf, zOut-aBuf, iStart, iStart + zOut-aBuf);
|
|
+ if( rc!=SQLITE_OK ) break;
|
|
+ zIn = zNext;
|
|
+ }
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/*
|
|
+** Argument xCreate is a pointer to a constructor function for a tokenizer.
|
|
+** pTok is a tokenizer previously created using the same method. This function
|
|
+** returns one of FTS5_PATTERN_NONE, FTS5_PATTERN_LIKE or FTS5_PATTERN_GLOB
|
|
+** indicating the style of pattern matching that the tokenizer can support.
|
|
+** In practice, this is:
|
|
+**
|
|
+** "trigram" tokenizer, case_sensitive=1 - FTS5_PATTERN_GLOB
|
|
+** "trigram" tokenizer, case_sensitive=0 (the default) - FTS5_PATTERN_LIKE
|
|
+** all other tokenizers - FTS5_PATTERN_NONE
|
|
+*/
|
|
+static int sqlite3Fts5TokenizerPattern(
|
|
+ int (*xCreate)(void*, const char**, int, Fts5Tokenizer**),
|
|
+ Fts5Tokenizer *pTok
|
|
+){
|
|
+ if( xCreate==fts5TriCreate ){
|
|
+ TrigramTokenizer *p = (TrigramTokenizer*)pTok;
|
|
+ return p->bFold ? FTS5_PATTERN_LIKE : FTS5_PATTERN_GLOB;
|
|
+ }
|
|
+ return FTS5_PATTERN_NONE;
|
|
+}
|
|
+
|
|
/*
|
|
** Register all built-in tokenizers with FTS5.
|
|
*/
|
|
@@ -226221,8 +242963,9 @@ static int sqlite3Fts5TokenizerInit(fts5_api *pApi){
|
|
{ "unicode61", {fts5UnicodeCreate, fts5UnicodeDelete, fts5UnicodeTokenize}},
|
|
{ "ascii", {fts5AsciiCreate, fts5AsciiDelete, fts5AsciiTokenize }},
|
|
{ "porter", {fts5PorterCreate, fts5PorterDelete, fts5PorterTokenize }},
|
|
+ { "trigram", {fts5TriCreate, fts5TriDelete, fts5TriTokenize}},
|
|
};
|
|
-
|
|
+
|
|
int rc = SQLITE_OK; /* Return code */
|
|
int i; /* To iterate through builtin functions */
|
|
|
|
@@ -226270,46 +243013,46 @@ static int sqlite3Fts5TokenizerInit(fts5_api *pApi){
|
|
*/
|
|
static int fts5_remove_diacritic(int c, int bComplex){
|
|
unsigned short aDia[] = {
|
|
- 0, 1797, 1848, 1859, 1891, 1928, 1940, 1995,
|
|
- 2024, 2040, 2060, 2110, 2168, 2206, 2264, 2286,
|
|
- 2344, 2383, 2472, 2488, 2516, 2596, 2668, 2732,
|
|
- 2782, 2842, 2894, 2954, 2984, 3000, 3028, 3336,
|
|
- 3456, 3696, 3712, 3728, 3744, 3766, 3832, 3896,
|
|
- 3912, 3928, 3944, 3968, 4008, 4040, 4056, 4106,
|
|
- 4138, 4170, 4202, 4234, 4266, 4296, 4312, 4344,
|
|
- 4408, 4424, 4442, 4472, 4488, 4504, 6148, 6198,
|
|
- 6264, 6280, 6360, 6429, 6505, 6529, 61448, 61468,
|
|
- 61512, 61534, 61592, 61610, 61642, 61672, 61688, 61704,
|
|
- 61726, 61784, 61800, 61816, 61836, 61880, 61896, 61914,
|
|
- 61948, 61998, 62062, 62122, 62154, 62184, 62200, 62218,
|
|
- 62252, 62302, 62364, 62410, 62442, 62478, 62536, 62554,
|
|
- 62584, 62604, 62640, 62648, 62656, 62664, 62730, 62766,
|
|
- 62830, 62890, 62924, 62974, 63032, 63050, 63082, 63118,
|
|
- 63182, 63242, 63274, 63310, 63368, 63390,
|
|
+ 0, 1797, 1848, 1859, 1891, 1928, 1940, 1995,
|
|
+ 2024, 2040, 2060, 2110, 2168, 2206, 2264, 2286,
|
|
+ 2344, 2383, 2472, 2488, 2516, 2596, 2668, 2732,
|
|
+ 2782, 2842, 2894, 2954, 2984, 3000, 3028, 3336,
|
|
+ 3456, 3696, 3712, 3728, 3744, 3766, 3832, 3896,
|
|
+ 3912, 3928, 3944, 3968, 4008, 4040, 4056, 4106,
|
|
+ 4138, 4170, 4202, 4234, 4266, 4296, 4312, 4344,
|
|
+ 4408, 4424, 4442, 4472, 4488, 4504, 6148, 6198,
|
|
+ 6264, 6280, 6360, 6429, 6505, 6529, 61448, 61468,
|
|
+ 61512, 61534, 61592, 61610, 61642, 61672, 61688, 61704,
|
|
+ 61726, 61784, 61800, 61816, 61836, 61880, 61896, 61914,
|
|
+ 61948, 61998, 62062, 62122, 62154, 62184, 62200, 62218,
|
|
+ 62252, 62302, 62364, 62410, 62442, 62478, 62536, 62554,
|
|
+ 62584, 62604, 62640, 62648, 62656, 62664, 62730, 62766,
|
|
+ 62830, 62890, 62924, 62974, 63032, 63050, 63082, 63118,
|
|
+ 63182, 63242, 63274, 63310, 63368, 63390,
|
|
};
|
|
#define HIBIT ((unsigned char)0x80)
|
|
unsigned char aChar[] = {
|
|
- '\0', 'a', 'c', 'e', 'i', 'n',
|
|
- 'o', 'u', 'y', 'y', 'a', 'c',
|
|
- 'd', 'e', 'e', 'g', 'h', 'i',
|
|
- 'j', 'k', 'l', 'n', 'o', 'r',
|
|
- 's', 't', 'u', 'u', 'w', 'y',
|
|
- 'z', 'o', 'u', 'a', 'i', 'o',
|
|
- 'u', 'u'|HIBIT, 'a'|HIBIT, 'g', 'k', 'o',
|
|
- 'o'|HIBIT, 'j', 'g', 'n', 'a'|HIBIT, 'a',
|
|
- 'e', 'i', 'o', 'r', 'u', 's',
|
|
- 't', 'h', 'a', 'e', 'o'|HIBIT, 'o',
|
|
- 'o'|HIBIT, 'y', '\0', '\0', '\0', '\0',
|
|
- '\0', '\0', '\0', '\0', 'a', 'b',
|
|
- 'c'|HIBIT, 'd', 'd', 'e'|HIBIT, 'e', 'e'|HIBIT,
|
|
- 'f', 'g', 'h', 'h', 'i', 'i'|HIBIT,
|
|
- 'k', 'l', 'l'|HIBIT, 'l', 'm', 'n',
|
|
- 'o'|HIBIT, 'p', 'r', 'r'|HIBIT, 'r', 's',
|
|
- 's'|HIBIT, 't', 'u', 'u'|HIBIT, 'v', 'w',
|
|
- 'w', 'x', 'y', 'z', 'h', 't',
|
|
- 'w', 'y', 'a', 'a'|HIBIT, 'a'|HIBIT, 'a'|HIBIT,
|
|
- 'e', 'e'|HIBIT, 'e'|HIBIT, 'i', 'o', 'o'|HIBIT,
|
|
- 'o'|HIBIT, 'o'|HIBIT, 'u', 'u'|HIBIT, 'u'|HIBIT, 'y',
|
|
+ '\0', 'a', 'c', 'e', 'i', 'n',
|
|
+ 'o', 'u', 'y', 'y', 'a', 'c',
|
|
+ 'd', 'e', 'e', 'g', 'h', 'i',
|
|
+ 'j', 'k', 'l', 'n', 'o', 'r',
|
|
+ 's', 't', 'u', 'u', 'w', 'y',
|
|
+ 'z', 'o', 'u', 'a', 'i', 'o',
|
|
+ 'u', 'u'|HIBIT, 'a'|HIBIT, 'g', 'k', 'o',
|
|
+ 'o'|HIBIT, 'j', 'g', 'n', 'a'|HIBIT, 'a',
|
|
+ 'e', 'i', 'o', 'r', 'u', 's',
|
|
+ 't', 'h', 'a', 'e', 'o'|HIBIT, 'o',
|
|
+ 'o'|HIBIT, 'y', '\0', '\0', '\0', '\0',
|
|
+ '\0', '\0', '\0', '\0', 'a', 'b',
|
|
+ 'c'|HIBIT, 'd', 'd', 'e'|HIBIT, 'e', 'e'|HIBIT,
|
|
+ 'f', 'g', 'h', 'h', 'i', 'i'|HIBIT,
|
|
+ 'k', 'l', 'l'|HIBIT, 'l', 'm', 'n',
|
|
+ 'o'|HIBIT, 'p', 'r', 'r'|HIBIT, 'r', 's',
|
|
+ 's'|HIBIT, 't', 'u', 'u'|HIBIT, 'v', 'w',
|
|
+ 'w', 'x', 'y', 'z', 'h', 't',
|
|
+ 'w', 'y', 'a', 'a'|HIBIT, 'a'|HIBIT, 'a'|HIBIT,
|
|
+ 'e', 'e'|HIBIT, 'e'|HIBIT, 'i', 'o', 'o'|HIBIT,
|
|
+ 'o'|HIBIT, 'o'|HIBIT, 'u', 'u'|HIBIT, 'u'|HIBIT, 'y',
|
|
};
|
|
|
|
unsigned int key = (((unsigned int)c)<<3) | 0x00000007;
|
|
@@ -226431,19 +243174,19 @@ static int sqlite3Fts5UnicodeFold(int c, int eRemoveDiacritic){
|
|
{42802, 1, 62}, {42873, 1, 4}, {42877, 76, 1},
|
|
{42878, 1, 10}, {42891, 0, 1}, {42893, 74, 1},
|
|
{42896, 1, 4}, {42912, 1, 10}, {42922, 72, 1},
|
|
- {65313, 14, 26},
|
|
+ {65313, 14, 26},
|
|
};
|
|
static const unsigned short aiOff[] = {
|
|
- 1, 2, 8, 15, 16, 26, 28, 32,
|
|
- 37, 38, 40, 48, 63, 64, 69, 71,
|
|
- 79, 80, 116, 202, 203, 205, 206, 207,
|
|
- 209, 210, 211, 213, 214, 217, 218, 219,
|
|
- 775, 7264, 10792, 10795, 23228, 23256, 30204, 54721,
|
|
- 54753, 54754, 54756, 54787, 54793, 54809, 57153, 57274,
|
|
- 57921, 58019, 58363, 61722, 65268, 65341, 65373, 65406,
|
|
- 65408, 65410, 65415, 65424, 65436, 65439, 65450, 65462,
|
|
- 65472, 65476, 65478, 65480, 65482, 65488, 65506, 65511,
|
|
- 65514, 65521, 65527, 65528, 65529,
|
|
+ 1, 2, 8, 15, 16, 26, 28, 32,
|
|
+ 37, 38, 40, 48, 63, 64, 69, 71,
|
|
+ 79, 80, 116, 202, 203, 205, 206, 207,
|
|
+ 209, 210, 211, 213, 214, 217, 218, 219,
|
|
+ 775, 7264, 10792, 10795, 23228, 23256, 30204, 54721,
|
|
+ 54753, 54754, 54756, 54787, 54793, 54809, 57153, 57274,
|
|
+ 57921, 58019, 58363, 61722, 65268, 65341, 65373, 65406,
|
|
+ 65408, 65410, 65415, 65424, 65436, 65439, 65450, 65462,
|
|
+ 65472, 65476, 65478, 65480, 65482, 65488, 65506, 65511,
|
|
+ 65514, 65521, 65527, 65528, 65529,
|
|
};
|
|
|
|
int ret = c;
|
|
@@ -226481,7 +243224,7 @@ static int sqlite3Fts5UnicodeFold(int c, int eRemoveDiacritic){
|
|
ret = fts5_remove_diacritic(ret, eRemoveDiacritic==2);
|
|
}
|
|
}
|
|
-
|
|
+
|
|
else if( c>=66560 && c<66600 ){
|
|
ret = c + 40;
|
|
}
|
|
@@ -226490,7 +243233,7 @@ static int sqlite3Fts5UnicodeFold(int c, int eRemoveDiacritic){
|
|
}
|
|
|
|
|
|
-static int sqlite3Fts5UnicodeCatParse(const char *zCat, u8 *aArray){
|
|
+static int sqlite3Fts5UnicodeCatParse(const char *zCat, u8 *aArray){
|
|
aArray[0] = 1;
|
|
switch( zCat[0] ){
|
|
case 'C':
|
|
@@ -226500,7 +243243,7 @@ static int sqlite3Fts5UnicodeCatParse(const char *zCat, u8 *aArray){
|
|
case 'n': aArray[3] = 1; break;
|
|
case 's': aArray[4] = 1; break;
|
|
case 'o': aArray[31] = 1; break;
|
|
- case '*':
|
|
+ case '*':
|
|
aArray[1] = 1;
|
|
aArray[2] = 1;
|
|
aArray[3] = 1;
|
|
@@ -226518,7 +243261,7 @@ static int sqlite3Fts5UnicodeCatParse(const char *zCat, u8 *aArray){
|
|
case 't': aArray[8] = 1; break;
|
|
case 'u': aArray[9] = 1; break;
|
|
case 'C': aArray[30] = 1; break;
|
|
- case '*':
|
|
+ case '*':
|
|
aArray[5] = 1;
|
|
aArray[6] = 1;
|
|
aArray[7] = 1;
|
|
@@ -226534,7 +243277,7 @@ static int sqlite3Fts5UnicodeCatParse(const char *zCat, u8 *aArray){
|
|
case 'c': aArray[10] = 1; break;
|
|
case 'e': aArray[11] = 1; break;
|
|
case 'n': aArray[12] = 1; break;
|
|
- case '*':
|
|
+ case '*':
|
|
aArray[10] = 1;
|
|
aArray[11] = 1;
|
|
aArray[12] = 1;
|
|
@@ -226547,7 +243290,7 @@ static int sqlite3Fts5UnicodeCatParse(const char *zCat, u8 *aArray){
|
|
case 'd': aArray[13] = 1; break;
|
|
case 'l': aArray[14] = 1; break;
|
|
case 'o': aArray[15] = 1; break;
|
|
- case '*':
|
|
+ case '*':
|
|
aArray[13] = 1;
|
|
aArray[14] = 1;
|
|
aArray[15] = 1;
|
|
@@ -226564,7 +243307,7 @@ static int sqlite3Fts5UnicodeCatParse(const char *zCat, u8 *aArray){
|
|
case 'i': aArray[20] = 1; break;
|
|
case 'o': aArray[21] = 1; break;
|
|
case 's': aArray[22] = 1; break;
|
|
- case '*':
|
|
+ case '*':
|
|
aArray[16] = 1;
|
|
aArray[17] = 1;
|
|
aArray[18] = 1;
|
|
@@ -226582,7 +243325,7 @@ static int sqlite3Fts5UnicodeCatParse(const char *zCat, u8 *aArray){
|
|
case 'k': aArray[24] = 1; break;
|
|
case 'm': aArray[25] = 1; break;
|
|
case 'o': aArray[26] = 1; break;
|
|
- case '*':
|
|
+ case '*':
|
|
aArray[23] = 1;
|
|
aArray[24] = 1;
|
|
aArray[25] = 1;
|
|
@@ -226596,7 +243339,7 @@ static int sqlite3Fts5UnicodeCatParse(const char *zCat, u8 *aArray){
|
|
case 'l': aArray[27] = 1; break;
|
|
case 'p': aArray[28] = 1; break;
|
|
case 's': aArray[29] = 1; break;
|
|
- case '*':
|
|
+ case '*':
|
|
aArray[27] = 1;
|
|
aArray[28] = 1;
|
|
aArray[29] = 1;
|
|
@@ -226609,369 +243352,369 @@ static int sqlite3Fts5UnicodeCatParse(const char *zCat, u8 *aArray){
|
|
}
|
|
|
|
static u16 aFts5UnicodeBlock[] = {
|
|
- 0, 1471, 1753, 1760, 1760, 1760, 1760, 1760, 1760, 1760,
|
|
- 1760, 1760, 1760, 1760, 1760, 1763, 1765,
|
|
+ 0, 1471, 1753, 1760, 1760, 1760, 1760, 1760, 1760, 1760,
|
|
+ 1760, 1760, 1760, 1760, 1760, 1763, 1765,
|
|
};
|
|
static u16 aFts5UnicodeMap[] = {
|
|
- 0, 32, 33, 36, 37, 40, 41, 42, 43, 44,
|
|
- 45, 46, 48, 58, 60, 63, 65, 91, 92, 93,
|
|
- 94, 95, 96, 97, 123, 124, 125, 126, 127, 160,
|
|
- 161, 162, 166, 167, 168, 169, 170, 171, 172, 173,
|
|
- 174, 175, 176, 177, 178, 180, 181, 182, 184, 185,
|
|
- 186, 187, 188, 191, 192, 215, 216, 223, 247, 248,
|
|
- 256, 312, 313, 329, 330, 377, 383, 385, 387, 388,
|
|
- 391, 394, 396, 398, 402, 403, 405, 406, 409, 412,
|
|
- 414, 415, 417, 418, 423, 427, 428, 431, 434, 436,
|
|
- 437, 440, 442, 443, 444, 446, 448, 452, 453, 454,
|
|
- 455, 456, 457, 458, 459, 460, 461, 477, 478, 496,
|
|
- 497, 498, 499, 500, 503, 505, 506, 564, 570, 572,
|
|
- 573, 575, 577, 580, 583, 584, 592, 660, 661, 688,
|
|
- 706, 710, 722, 736, 741, 748, 749, 750, 751, 768,
|
|
- 880, 884, 885, 886, 890, 891, 894, 900, 902, 903,
|
|
- 904, 908, 910, 912, 913, 931, 940, 975, 977, 978,
|
|
- 981, 984, 1008, 1012, 1014, 1015, 1018, 1020, 1021, 1072,
|
|
- 1120, 1154, 1155, 1160, 1162, 1217, 1231, 1232, 1329, 1369,
|
|
- 1370, 1377, 1417, 1418, 1423, 1425, 1470, 1471, 1472, 1473,
|
|
- 1475, 1476, 1478, 1479, 1488, 1520, 1523, 1536, 1542, 1545,
|
|
- 1547, 1548, 1550, 1552, 1563, 1566, 1568, 1600, 1601, 1611,
|
|
- 1632, 1642, 1646, 1648, 1649, 1748, 1749, 1750, 1757, 1758,
|
|
- 1759, 1765, 1767, 1769, 1770, 1774, 1776, 1786, 1789, 1791,
|
|
- 1792, 1807, 1808, 1809, 1810, 1840, 1869, 1958, 1969, 1984,
|
|
- 1994, 2027, 2036, 2038, 2039, 2042, 2048, 2070, 2074, 2075,
|
|
- 2084, 2085, 2088, 2089, 2096, 2112, 2137, 2142, 2208, 2210,
|
|
- 2276, 2304, 2307, 2308, 2362, 2363, 2364, 2365, 2366, 2369,
|
|
- 2377, 2381, 2382, 2384, 2385, 2392, 2402, 2404, 2406, 2416,
|
|
- 2417, 2418, 2425, 2433, 2434, 2437, 2447, 2451, 2474, 2482,
|
|
- 2486, 2492, 2493, 2494, 2497, 2503, 2507, 2509, 2510, 2519,
|
|
- 2524, 2527, 2530, 2534, 2544, 2546, 2548, 2554, 2555, 2561,
|
|
- 2563, 2565, 2575, 2579, 2602, 2610, 2613, 2616, 2620, 2622,
|
|
- 2625, 2631, 2635, 2641, 2649, 2654, 2662, 2672, 2674, 2677,
|
|
- 2689, 2691, 2693, 2703, 2707, 2730, 2738, 2741, 2748, 2749,
|
|
- 2750, 2753, 2759, 2761, 2763, 2765, 2768, 2784, 2786, 2790,
|
|
- 2800, 2801, 2817, 2818, 2821, 2831, 2835, 2858, 2866, 2869,
|
|
- 2876, 2877, 2878, 2879, 2880, 2881, 2887, 2891, 2893, 2902,
|
|
- 2903, 2908, 2911, 2914, 2918, 2928, 2929, 2930, 2946, 2947,
|
|
- 2949, 2958, 2962, 2969, 2972, 2974, 2979, 2984, 2990, 3006,
|
|
- 3008, 3009, 3014, 3018, 3021, 3024, 3031, 3046, 3056, 3059,
|
|
- 3065, 3066, 3073, 3077, 3086, 3090, 3114, 3125, 3133, 3134,
|
|
- 3137, 3142, 3146, 3157, 3160, 3168, 3170, 3174, 3192, 3199,
|
|
- 3202, 3205, 3214, 3218, 3242, 3253, 3260, 3261, 3262, 3263,
|
|
- 3264, 3270, 3271, 3274, 3276, 3285, 3294, 3296, 3298, 3302,
|
|
- 3313, 3330, 3333, 3342, 3346, 3389, 3390, 3393, 3398, 3402,
|
|
- 3405, 3406, 3415, 3424, 3426, 3430, 3440, 3449, 3450, 3458,
|
|
- 3461, 3482, 3507, 3517, 3520, 3530, 3535, 3538, 3542, 3544,
|
|
- 3570, 3572, 3585, 3633, 3634, 3636, 3647, 3648, 3654, 3655,
|
|
- 3663, 3664, 3674, 3713, 3716, 3719, 3722, 3725, 3732, 3737,
|
|
- 3745, 3749, 3751, 3754, 3757, 3761, 3762, 3764, 3771, 3773,
|
|
- 3776, 3782, 3784, 3792, 3804, 3840, 3841, 3844, 3859, 3860,
|
|
- 3861, 3864, 3866, 3872, 3882, 3892, 3893, 3894, 3895, 3896,
|
|
- 3897, 3898, 3899, 3900, 3901, 3902, 3904, 3913, 3953, 3967,
|
|
- 3968, 3973, 3974, 3976, 3981, 3993, 4030, 4038, 4039, 4046,
|
|
- 4048, 4053, 4057, 4096, 4139, 4141, 4145, 4146, 4152, 4153,
|
|
- 4155, 4157, 4159, 4160, 4170, 4176, 4182, 4184, 4186, 4190,
|
|
- 4193, 4194, 4197, 4199, 4206, 4209, 4213, 4226, 4227, 4229,
|
|
- 4231, 4237, 4238, 4239, 4240, 4250, 4253, 4254, 4256, 4295,
|
|
- 4301, 4304, 4347, 4348, 4349, 4682, 4688, 4696, 4698, 4704,
|
|
- 4746, 4752, 4786, 4792, 4800, 4802, 4808, 4824, 4882, 4888,
|
|
- 4957, 4960, 4969, 4992, 5008, 5024, 5120, 5121, 5741, 5743,
|
|
- 5760, 5761, 5787, 5788, 5792, 5867, 5870, 5888, 5902, 5906,
|
|
- 5920, 5938, 5941, 5952, 5970, 5984, 5998, 6002, 6016, 6068,
|
|
- 6070, 6071, 6078, 6086, 6087, 6089, 6100, 6103, 6104, 6107,
|
|
- 6108, 6109, 6112, 6128, 6144, 6150, 6151, 6155, 6158, 6160,
|
|
- 6176, 6211, 6212, 6272, 6313, 6314, 6320, 6400, 6432, 6435,
|
|
- 6439, 6441, 6448, 6450, 6451, 6457, 6464, 6468, 6470, 6480,
|
|
- 6512, 6528, 6576, 6593, 6600, 6608, 6618, 6622, 6656, 6679,
|
|
- 6681, 6686, 6688, 6741, 6742, 6743, 6744, 6752, 6753, 6754,
|
|
- 6755, 6757, 6765, 6771, 6783, 6784, 6800, 6816, 6823, 6824,
|
|
- 6912, 6916, 6917, 6964, 6965, 6966, 6971, 6972, 6973, 6978,
|
|
- 6979, 6981, 6992, 7002, 7009, 7019, 7028, 7040, 7042, 7043,
|
|
- 7073, 7074, 7078, 7080, 7082, 7083, 7084, 7086, 7088, 7098,
|
|
- 7142, 7143, 7144, 7146, 7149, 7150, 7151, 7154, 7164, 7168,
|
|
- 7204, 7212, 7220, 7222, 7227, 7232, 7245, 7248, 7258, 7288,
|
|
- 7294, 7360, 7376, 7379, 7380, 7393, 7394, 7401, 7405, 7406,
|
|
- 7410, 7412, 7413, 7424, 7468, 7531, 7544, 7545, 7579, 7616,
|
|
- 7676, 7680, 7830, 7838, 7936, 7944, 7952, 7960, 7968, 7976,
|
|
- 7984, 7992, 8000, 8008, 8016, 8025, 8027, 8029, 8031, 8033,
|
|
- 8040, 8048, 8064, 8072, 8080, 8088, 8096, 8104, 8112, 8118,
|
|
- 8120, 8124, 8125, 8126, 8127, 8130, 8134, 8136, 8140, 8141,
|
|
- 8144, 8150, 8152, 8157, 8160, 8168, 8173, 8178, 8182, 8184,
|
|
- 8188, 8189, 8192, 8203, 8208, 8214, 8216, 8217, 8218, 8219,
|
|
- 8221, 8222, 8223, 8224, 8232, 8233, 8234, 8239, 8240, 8249,
|
|
- 8250, 8251, 8255, 8257, 8260, 8261, 8262, 8263, 8274, 8275,
|
|
- 8276, 8277, 8287, 8288, 8298, 8304, 8305, 8308, 8314, 8317,
|
|
- 8318, 8319, 8320, 8330, 8333, 8334, 8336, 8352, 8400, 8413,
|
|
- 8417, 8418, 8421, 8448, 8450, 8451, 8455, 8456, 8458, 8459,
|
|
- 8462, 8464, 8467, 8468, 8469, 8470, 8472, 8473, 8478, 8484,
|
|
- 8485, 8486, 8487, 8488, 8489, 8490, 8494, 8495, 8496, 8500,
|
|
- 8501, 8505, 8506, 8508, 8510, 8512, 8517, 8519, 8522, 8523,
|
|
- 8524, 8526, 8527, 8528, 8544, 8579, 8581, 8585, 8592, 8597,
|
|
- 8602, 8604, 8608, 8609, 8611, 8612, 8614, 8615, 8622, 8623,
|
|
- 8654, 8656, 8658, 8659, 8660, 8661, 8692, 8960, 8968, 8972,
|
|
- 8992, 8994, 9001, 9002, 9003, 9084, 9085, 9115, 9140, 9180,
|
|
- 9186, 9216, 9280, 9312, 9372, 9450, 9472, 9655, 9656, 9665,
|
|
- 9666, 9720, 9728, 9839, 9840, 9985, 10088, 10089, 10090, 10091,
|
|
- 10092, 10093, 10094, 10095, 10096, 10097, 10098, 10099, 10100, 10101,
|
|
- 10102, 10132, 10176, 10181, 10182, 10183, 10214, 10215, 10216, 10217,
|
|
- 10218, 10219, 10220, 10221, 10222, 10223, 10224, 10240, 10496, 10627,
|
|
- 10628, 10629, 10630, 10631, 10632, 10633, 10634, 10635, 10636, 10637,
|
|
- 10638, 10639, 10640, 10641, 10642, 10643, 10644, 10645, 10646, 10647,
|
|
- 10648, 10649, 10712, 10713, 10714, 10715, 10716, 10748, 10749, 10750,
|
|
- 11008, 11056, 11077, 11079, 11088, 11264, 11312, 11360, 11363, 11365,
|
|
- 11367, 11374, 11377, 11378, 11380, 11381, 11383, 11388, 11390, 11393,
|
|
- 11394, 11492, 11493, 11499, 11503, 11506, 11513, 11517, 11518, 11520,
|
|
- 11559, 11565, 11568, 11631, 11632, 11647, 11648, 11680, 11688, 11696,
|
|
- 11704, 11712, 11720, 11728, 11736, 11744, 11776, 11778, 11779, 11780,
|
|
- 11781, 11782, 11785, 11786, 11787, 11788, 11789, 11790, 11799, 11800,
|
|
- 11802, 11803, 11804, 11805, 11806, 11808, 11809, 11810, 11811, 11812,
|
|
- 11813, 11814, 11815, 11816, 11817, 11818, 11823, 11824, 11834, 11904,
|
|
- 11931, 12032, 12272, 12288, 12289, 12292, 12293, 12294, 12295, 12296,
|
|
- 12297, 12298, 12299, 12300, 12301, 12302, 12303, 12304, 12305, 12306,
|
|
- 12308, 12309, 12310, 12311, 12312, 12313, 12314, 12315, 12316, 12317,
|
|
- 12318, 12320, 12321, 12330, 12334, 12336, 12337, 12342, 12344, 12347,
|
|
- 12348, 12349, 12350, 12353, 12441, 12443, 12445, 12447, 12448, 12449,
|
|
- 12539, 12540, 12543, 12549, 12593, 12688, 12690, 12694, 12704, 12736,
|
|
- 12784, 12800, 12832, 12842, 12872, 12880, 12881, 12896, 12928, 12938,
|
|
- 12977, 12992, 13056, 13312, 19893, 19904, 19968, 40908, 40960, 40981,
|
|
- 40982, 42128, 42192, 42232, 42238, 42240, 42508, 42509, 42512, 42528,
|
|
- 42538, 42560, 42606, 42607, 42608, 42611, 42612, 42622, 42623, 42624,
|
|
- 42655, 42656, 42726, 42736, 42738, 42752, 42775, 42784, 42786, 42800,
|
|
- 42802, 42864, 42865, 42873, 42878, 42888, 42889, 42891, 42896, 42912,
|
|
- 43000, 43002, 43003, 43010, 43011, 43014, 43015, 43019, 43020, 43043,
|
|
- 43045, 43047, 43048, 43056, 43062, 43064, 43065, 43072, 43124, 43136,
|
|
- 43138, 43188, 43204, 43214, 43216, 43232, 43250, 43256, 43259, 43264,
|
|
- 43274, 43302, 43310, 43312, 43335, 43346, 43359, 43360, 43392, 43395,
|
|
- 43396, 43443, 43444, 43446, 43450, 43452, 43453, 43457, 43471, 43472,
|
|
- 43486, 43520, 43561, 43567, 43569, 43571, 43573, 43584, 43587, 43588,
|
|
- 43596, 43597, 43600, 43612, 43616, 43632, 43633, 43639, 43642, 43643,
|
|
- 43648, 43696, 43697, 43698, 43701, 43703, 43705, 43710, 43712, 43713,
|
|
- 43714, 43739, 43741, 43742, 43744, 43755, 43756, 43758, 43760, 43762,
|
|
- 43763, 43765, 43766, 43777, 43785, 43793, 43808, 43816, 43968, 44003,
|
|
- 44005, 44006, 44008, 44009, 44011, 44012, 44013, 44016, 44032, 55203,
|
|
- 55216, 55243, 55296, 56191, 56319, 57343, 57344, 63743, 63744, 64112,
|
|
- 64256, 64275, 64285, 64286, 64287, 64297, 64298, 64312, 64318, 64320,
|
|
- 64323, 64326, 64434, 64467, 64830, 64831, 64848, 64914, 65008, 65020,
|
|
- 65021, 65024, 65040, 65047, 65048, 65049, 65056, 65072, 65073, 65075,
|
|
- 65077, 65078, 65079, 65080, 65081, 65082, 65083, 65084, 65085, 65086,
|
|
- 65087, 65088, 65089, 65090, 65091, 65092, 65093, 65095, 65096, 65097,
|
|
- 65101, 65104, 65108, 65112, 65113, 65114, 65115, 65116, 65117, 65118,
|
|
- 65119, 65122, 65123, 65124, 65128, 65129, 65130, 65136, 65142, 65279,
|
|
- 65281, 65284, 65285, 65288, 65289, 65290, 65291, 65292, 65293, 65294,
|
|
- 65296, 65306, 65308, 65311, 65313, 65339, 65340, 65341, 65342, 65343,
|
|
- 65344, 65345, 65371, 65372, 65373, 65374, 65375, 65376, 65377, 65378,
|
|
- 65379, 65380, 65382, 65392, 65393, 65438, 65440, 65474, 65482, 65490,
|
|
- 65498, 65504, 65506, 65507, 65508, 65509, 65512, 65513, 65517, 65529,
|
|
- 65532, 0, 13, 40, 60, 63, 80, 128, 256, 263,
|
|
- 311, 320, 373, 377, 394, 400, 464, 509, 640, 672,
|
|
- 768, 800, 816, 833, 834, 842, 896, 927, 928, 968,
|
|
- 976, 977, 1024, 1064, 1104, 1184, 2048, 2056, 2058, 2103,
|
|
- 2108, 2111, 2135, 2136, 2304, 2326, 2335, 2336, 2367, 2432,
|
|
- 2494, 2560, 2561, 2565, 2572, 2576, 2581, 2585, 2616, 2623,
|
|
- 2624, 2640, 2656, 2685, 2687, 2816, 2873, 2880, 2904, 2912,
|
|
- 2936, 3072, 3680, 4096, 4097, 4098, 4099, 4152, 4167, 4178,
|
|
- 4198, 4224, 4226, 4227, 4272, 4275, 4279, 4281, 4283, 4285,
|
|
- 4286, 4304, 4336, 4352, 4355, 4391, 4396, 4397, 4406, 4416,
|
|
- 4480, 4482, 4483, 4531, 4534, 4543, 4545, 4549, 4560, 5760,
|
|
- 5803, 5804, 5805, 5806, 5808, 5814, 5815, 5824, 8192, 9216,
|
|
- 9328, 12288, 26624, 28416, 28496, 28497, 28559, 28563, 45056, 53248,
|
|
- 53504, 53545, 53605, 53607, 53610, 53613, 53619, 53627, 53635, 53637,
|
|
- 53644, 53674, 53678, 53760, 53826, 53829, 54016, 54112, 54272, 54298,
|
|
- 54324, 54350, 54358, 54376, 54402, 54428, 54430, 54434, 54437, 54441,
|
|
- 54446, 54454, 54459, 54461, 54469, 54480, 54506, 54532, 54535, 54541,
|
|
- 54550, 54558, 54584, 54587, 54592, 54598, 54602, 54610, 54636, 54662,
|
|
- 54688, 54714, 54740, 54766, 54792, 54818, 54844, 54870, 54896, 54922,
|
|
- 54952, 54977, 54978, 55003, 55004, 55010, 55035, 55036, 55061, 55062,
|
|
- 55068, 55093, 55094, 55119, 55120, 55126, 55151, 55152, 55177, 55178,
|
|
- 55184, 55209, 55210, 55235, 55236, 55242, 55246, 60928, 60933, 60961,
|
|
- 60964, 60967, 60969, 60980, 60985, 60987, 60994, 60999, 61001, 61003,
|
|
- 61005, 61009, 61012, 61015, 61017, 61019, 61021, 61023, 61025, 61028,
|
|
- 61031, 61036, 61044, 61049, 61054, 61056, 61067, 61089, 61093, 61099,
|
|
- 61168, 61440, 61488, 61600, 61617, 61633, 61649, 61696, 61712, 61744,
|
|
- 61808, 61926, 61968, 62016, 62032, 62208, 62256, 62263, 62336, 62368,
|
|
- 62406, 62432, 62464, 62528, 62530, 62713, 62720, 62784, 62800, 62971,
|
|
- 63045, 63104, 63232, 0, 42710, 42752, 46900, 46912, 47133, 63488,
|
|
- 1, 32, 256, 0, 65533,
|
|
+ 0, 32, 33, 36, 37, 40, 41, 42, 43, 44,
|
|
+ 45, 46, 48, 58, 60, 63, 65, 91, 92, 93,
|
|
+ 94, 95, 96, 97, 123, 124, 125, 126, 127, 160,
|
|
+ 161, 162, 166, 167, 168, 169, 170, 171, 172, 173,
|
|
+ 174, 175, 176, 177, 178, 180, 181, 182, 184, 185,
|
|
+ 186, 187, 188, 191, 192, 215, 216, 223, 247, 248,
|
|
+ 256, 312, 313, 329, 330, 377, 383, 385, 387, 388,
|
|
+ 391, 394, 396, 398, 402, 403, 405, 406, 409, 412,
|
|
+ 414, 415, 417, 418, 423, 427, 428, 431, 434, 436,
|
|
+ 437, 440, 442, 443, 444, 446, 448, 452, 453, 454,
|
|
+ 455, 456, 457, 458, 459, 460, 461, 477, 478, 496,
|
|
+ 497, 498, 499, 500, 503, 505, 506, 564, 570, 572,
|
|
+ 573, 575, 577, 580, 583, 584, 592, 660, 661, 688,
|
|
+ 706, 710, 722, 736, 741, 748, 749, 750, 751, 768,
|
|
+ 880, 884, 885, 886, 890, 891, 894, 900, 902, 903,
|
|
+ 904, 908, 910, 912, 913, 931, 940, 975, 977, 978,
|
|
+ 981, 984, 1008, 1012, 1014, 1015, 1018, 1020, 1021, 1072,
|
|
+ 1120, 1154, 1155, 1160, 1162, 1217, 1231, 1232, 1329, 1369,
|
|
+ 1370, 1377, 1417, 1418, 1423, 1425, 1470, 1471, 1472, 1473,
|
|
+ 1475, 1476, 1478, 1479, 1488, 1520, 1523, 1536, 1542, 1545,
|
|
+ 1547, 1548, 1550, 1552, 1563, 1566, 1568, 1600, 1601, 1611,
|
|
+ 1632, 1642, 1646, 1648, 1649, 1748, 1749, 1750, 1757, 1758,
|
|
+ 1759, 1765, 1767, 1769, 1770, 1774, 1776, 1786, 1789, 1791,
|
|
+ 1792, 1807, 1808, 1809, 1810, 1840, 1869, 1958, 1969, 1984,
|
|
+ 1994, 2027, 2036, 2038, 2039, 2042, 2048, 2070, 2074, 2075,
|
|
+ 2084, 2085, 2088, 2089, 2096, 2112, 2137, 2142, 2208, 2210,
|
|
+ 2276, 2304, 2307, 2308, 2362, 2363, 2364, 2365, 2366, 2369,
|
|
+ 2377, 2381, 2382, 2384, 2385, 2392, 2402, 2404, 2406, 2416,
|
|
+ 2417, 2418, 2425, 2433, 2434, 2437, 2447, 2451, 2474, 2482,
|
|
+ 2486, 2492, 2493, 2494, 2497, 2503, 2507, 2509, 2510, 2519,
|
|
+ 2524, 2527, 2530, 2534, 2544, 2546, 2548, 2554, 2555, 2561,
|
|
+ 2563, 2565, 2575, 2579, 2602, 2610, 2613, 2616, 2620, 2622,
|
|
+ 2625, 2631, 2635, 2641, 2649, 2654, 2662, 2672, 2674, 2677,
|
|
+ 2689, 2691, 2693, 2703, 2707, 2730, 2738, 2741, 2748, 2749,
|
|
+ 2750, 2753, 2759, 2761, 2763, 2765, 2768, 2784, 2786, 2790,
|
|
+ 2800, 2801, 2817, 2818, 2821, 2831, 2835, 2858, 2866, 2869,
|
|
+ 2876, 2877, 2878, 2879, 2880, 2881, 2887, 2891, 2893, 2902,
|
|
+ 2903, 2908, 2911, 2914, 2918, 2928, 2929, 2930, 2946, 2947,
|
|
+ 2949, 2958, 2962, 2969, 2972, 2974, 2979, 2984, 2990, 3006,
|
|
+ 3008, 3009, 3014, 3018, 3021, 3024, 3031, 3046, 3056, 3059,
|
|
+ 3065, 3066, 3073, 3077, 3086, 3090, 3114, 3125, 3133, 3134,
|
|
+ 3137, 3142, 3146, 3157, 3160, 3168, 3170, 3174, 3192, 3199,
|
|
+ 3202, 3205, 3214, 3218, 3242, 3253, 3260, 3261, 3262, 3263,
|
|
+ 3264, 3270, 3271, 3274, 3276, 3285, 3294, 3296, 3298, 3302,
|
|
+ 3313, 3330, 3333, 3342, 3346, 3389, 3390, 3393, 3398, 3402,
|
|
+ 3405, 3406, 3415, 3424, 3426, 3430, 3440, 3449, 3450, 3458,
|
|
+ 3461, 3482, 3507, 3517, 3520, 3530, 3535, 3538, 3542, 3544,
|
|
+ 3570, 3572, 3585, 3633, 3634, 3636, 3647, 3648, 3654, 3655,
|
|
+ 3663, 3664, 3674, 3713, 3716, 3719, 3722, 3725, 3732, 3737,
|
|
+ 3745, 3749, 3751, 3754, 3757, 3761, 3762, 3764, 3771, 3773,
|
|
+ 3776, 3782, 3784, 3792, 3804, 3840, 3841, 3844, 3859, 3860,
|
|
+ 3861, 3864, 3866, 3872, 3882, 3892, 3893, 3894, 3895, 3896,
|
|
+ 3897, 3898, 3899, 3900, 3901, 3902, 3904, 3913, 3953, 3967,
|
|
+ 3968, 3973, 3974, 3976, 3981, 3993, 4030, 4038, 4039, 4046,
|
|
+ 4048, 4053, 4057, 4096, 4139, 4141, 4145, 4146, 4152, 4153,
|
|
+ 4155, 4157, 4159, 4160, 4170, 4176, 4182, 4184, 4186, 4190,
|
|
+ 4193, 4194, 4197, 4199, 4206, 4209, 4213, 4226, 4227, 4229,
|
|
+ 4231, 4237, 4238, 4239, 4240, 4250, 4253, 4254, 4256, 4295,
|
|
+ 4301, 4304, 4347, 4348, 4349, 4682, 4688, 4696, 4698, 4704,
|
|
+ 4746, 4752, 4786, 4792, 4800, 4802, 4808, 4824, 4882, 4888,
|
|
+ 4957, 4960, 4969, 4992, 5008, 5024, 5120, 5121, 5741, 5743,
|
|
+ 5760, 5761, 5787, 5788, 5792, 5867, 5870, 5888, 5902, 5906,
|
|
+ 5920, 5938, 5941, 5952, 5970, 5984, 5998, 6002, 6016, 6068,
|
|
+ 6070, 6071, 6078, 6086, 6087, 6089, 6100, 6103, 6104, 6107,
|
|
+ 6108, 6109, 6112, 6128, 6144, 6150, 6151, 6155, 6158, 6160,
|
|
+ 6176, 6211, 6212, 6272, 6313, 6314, 6320, 6400, 6432, 6435,
|
|
+ 6439, 6441, 6448, 6450, 6451, 6457, 6464, 6468, 6470, 6480,
|
|
+ 6512, 6528, 6576, 6593, 6600, 6608, 6618, 6622, 6656, 6679,
|
|
+ 6681, 6686, 6688, 6741, 6742, 6743, 6744, 6752, 6753, 6754,
|
|
+ 6755, 6757, 6765, 6771, 6783, 6784, 6800, 6816, 6823, 6824,
|
|
+ 6912, 6916, 6917, 6964, 6965, 6966, 6971, 6972, 6973, 6978,
|
|
+ 6979, 6981, 6992, 7002, 7009, 7019, 7028, 7040, 7042, 7043,
|
|
+ 7073, 7074, 7078, 7080, 7082, 7083, 7084, 7086, 7088, 7098,
|
|
+ 7142, 7143, 7144, 7146, 7149, 7150, 7151, 7154, 7164, 7168,
|
|
+ 7204, 7212, 7220, 7222, 7227, 7232, 7245, 7248, 7258, 7288,
|
|
+ 7294, 7360, 7376, 7379, 7380, 7393, 7394, 7401, 7405, 7406,
|
|
+ 7410, 7412, 7413, 7424, 7468, 7531, 7544, 7545, 7579, 7616,
|
|
+ 7676, 7680, 7830, 7838, 7936, 7944, 7952, 7960, 7968, 7976,
|
|
+ 7984, 7992, 8000, 8008, 8016, 8025, 8027, 8029, 8031, 8033,
|
|
+ 8040, 8048, 8064, 8072, 8080, 8088, 8096, 8104, 8112, 8118,
|
|
+ 8120, 8124, 8125, 8126, 8127, 8130, 8134, 8136, 8140, 8141,
|
|
+ 8144, 8150, 8152, 8157, 8160, 8168, 8173, 8178, 8182, 8184,
|
|
+ 8188, 8189, 8192, 8203, 8208, 8214, 8216, 8217, 8218, 8219,
|
|
+ 8221, 8222, 8223, 8224, 8232, 8233, 8234, 8239, 8240, 8249,
|
|
+ 8250, 8251, 8255, 8257, 8260, 8261, 8262, 8263, 8274, 8275,
|
|
+ 8276, 8277, 8287, 8288, 8298, 8304, 8305, 8308, 8314, 8317,
|
|
+ 8318, 8319, 8320, 8330, 8333, 8334, 8336, 8352, 8400, 8413,
|
|
+ 8417, 8418, 8421, 8448, 8450, 8451, 8455, 8456, 8458, 8459,
|
|
+ 8462, 8464, 8467, 8468, 8469, 8470, 8472, 8473, 8478, 8484,
|
|
+ 8485, 8486, 8487, 8488, 8489, 8490, 8494, 8495, 8496, 8500,
|
|
+ 8501, 8505, 8506, 8508, 8510, 8512, 8517, 8519, 8522, 8523,
|
|
+ 8524, 8526, 8527, 8528, 8544, 8579, 8581, 8585, 8592, 8597,
|
|
+ 8602, 8604, 8608, 8609, 8611, 8612, 8614, 8615, 8622, 8623,
|
|
+ 8654, 8656, 8658, 8659, 8660, 8661, 8692, 8960, 8968, 8972,
|
|
+ 8992, 8994, 9001, 9002, 9003, 9084, 9085, 9115, 9140, 9180,
|
|
+ 9186, 9216, 9280, 9312, 9372, 9450, 9472, 9655, 9656, 9665,
|
|
+ 9666, 9720, 9728, 9839, 9840, 9985, 10088, 10089, 10090, 10091,
|
|
+ 10092, 10093, 10094, 10095, 10096, 10097, 10098, 10099, 10100, 10101,
|
|
+ 10102, 10132, 10176, 10181, 10182, 10183, 10214, 10215, 10216, 10217,
|
|
+ 10218, 10219, 10220, 10221, 10222, 10223, 10224, 10240, 10496, 10627,
|
|
+ 10628, 10629, 10630, 10631, 10632, 10633, 10634, 10635, 10636, 10637,
|
|
+ 10638, 10639, 10640, 10641, 10642, 10643, 10644, 10645, 10646, 10647,
|
|
+ 10648, 10649, 10712, 10713, 10714, 10715, 10716, 10748, 10749, 10750,
|
|
+ 11008, 11056, 11077, 11079, 11088, 11264, 11312, 11360, 11363, 11365,
|
|
+ 11367, 11374, 11377, 11378, 11380, 11381, 11383, 11388, 11390, 11393,
|
|
+ 11394, 11492, 11493, 11499, 11503, 11506, 11513, 11517, 11518, 11520,
|
|
+ 11559, 11565, 11568, 11631, 11632, 11647, 11648, 11680, 11688, 11696,
|
|
+ 11704, 11712, 11720, 11728, 11736, 11744, 11776, 11778, 11779, 11780,
|
|
+ 11781, 11782, 11785, 11786, 11787, 11788, 11789, 11790, 11799, 11800,
|
|
+ 11802, 11803, 11804, 11805, 11806, 11808, 11809, 11810, 11811, 11812,
|
|
+ 11813, 11814, 11815, 11816, 11817, 11818, 11823, 11824, 11834, 11904,
|
|
+ 11931, 12032, 12272, 12288, 12289, 12292, 12293, 12294, 12295, 12296,
|
|
+ 12297, 12298, 12299, 12300, 12301, 12302, 12303, 12304, 12305, 12306,
|
|
+ 12308, 12309, 12310, 12311, 12312, 12313, 12314, 12315, 12316, 12317,
|
|
+ 12318, 12320, 12321, 12330, 12334, 12336, 12337, 12342, 12344, 12347,
|
|
+ 12348, 12349, 12350, 12353, 12441, 12443, 12445, 12447, 12448, 12449,
|
|
+ 12539, 12540, 12543, 12549, 12593, 12688, 12690, 12694, 12704, 12736,
|
|
+ 12784, 12800, 12832, 12842, 12872, 12880, 12881, 12896, 12928, 12938,
|
|
+ 12977, 12992, 13056, 13312, 19893, 19904, 19968, 40908, 40960, 40981,
|
|
+ 40982, 42128, 42192, 42232, 42238, 42240, 42508, 42509, 42512, 42528,
|
|
+ 42538, 42560, 42606, 42607, 42608, 42611, 42612, 42622, 42623, 42624,
|
|
+ 42655, 42656, 42726, 42736, 42738, 42752, 42775, 42784, 42786, 42800,
|
|
+ 42802, 42864, 42865, 42873, 42878, 42888, 42889, 42891, 42896, 42912,
|
|
+ 43000, 43002, 43003, 43010, 43011, 43014, 43015, 43019, 43020, 43043,
|
|
+ 43045, 43047, 43048, 43056, 43062, 43064, 43065, 43072, 43124, 43136,
|
|
+ 43138, 43188, 43204, 43214, 43216, 43232, 43250, 43256, 43259, 43264,
|
|
+ 43274, 43302, 43310, 43312, 43335, 43346, 43359, 43360, 43392, 43395,
|
|
+ 43396, 43443, 43444, 43446, 43450, 43452, 43453, 43457, 43471, 43472,
|
|
+ 43486, 43520, 43561, 43567, 43569, 43571, 43573, 43584, 43587, 43588,
|
|
+ 43596, 43597, 43600, 43612, 43616, 43632, 43633, 43639, 43642, 43643,
|
|
+ 43648, 43696, 43697, 43698, 43701, 43703, 43705, 43710, 43712, 43713,
|
|
+ 43714, 43739, 43741, 43742, 43744, 43755, 43756, 43758, 43760, 43762,
|
|
+ 43763, 43765, 43766, 43777, 43785, 43793, 43808, 43816, 43968, 44003,
|
|
+ 44005, 44006, 44008, 44009, 44011, 44012, 44013, 44016, 44032, 55203,
|
|
+ 55216, 55243, 55296, 56191, 56319, 57343, 57344, 63743, 63744, 64112,
|
|
+ 64256, 64275, 64285, 64286, 64287, 64297, 64298, 64312, 64318, 64320,
|
|
+ 64323, 64326, 64434, 64467, 64830, 64831, 64848, 64914, 65008, 65020,
|
|
+ 65021, 65024, 65040, 65047, 65048, 65049, 65056, 65072, 65073, 65075,
|
|
+ 65077, 65078, 65079, 65080, 65081, 65082, 65083, 65084, 65085, 65086,
|
|
+ 65087, 65088, 65089, 65090, 65091, 65092, 65093, 65095, 65096, 65097,
|
|
+ 65101, 65104, 65108, 65112, 65113, 65114, 65115, 65116, 65117, 65118,
|
|
+ 65119, 65122, 65123, 65124, 65128, 65129, 65130, 65136, 65142, 65279,
|
|
+ 65281, 65284, 65285, 65288, 65289, 65290, 65291, 65292, 65293, 65294,
|
|
+ 65296, 65306, 65308, 65311, 65313, 65339, 65340, 65341, 65342, 65343,
|
|
+ 65344, 65345, 65371, 65372, 65373, 65374, 65375, 65376, 65377, 65378,
|
|
+ 65379, 65380, 65382, 65392, 65393, 65438, 65440, 65474, 65482, 65490,
|
|
+ 65498, 65504, 65506, 65507, 65508, 65509, 65512, 65513, 65517, 65529,
|
|
+ 65532, 0, 13, 40, 60, 63, 80, 128, 256, 263,
|
|
+ 311, 320, 373, 377, 394, 400, 464, 509, 640, 672,
|
|
+ 768, 800, 816, 833, 834, 842, 896, 927, 928, 968,
|
|
+ 976, 977, 1024, 1064, 1104, 1184, 2048, 2056, 2058, 2103,
|
|
+ 2108, 2111, 2135, 2136, 2304, 2326, 2335, 2336, 2367, 2432,
|
|
+ 2494, 2560, 2561, 2565, 2572, 2576, 2581, 2585, 2616, 2623,
|
|
+ 2624, 2640, 2656, 2685, 2687, 2816, 2873, 2880, 2904, 2912,
|
|
+ 2936, 3072, 3680, 4096, 4097, 4098, 4099, 4152, 4167, 4178,
|
|
+ 4198, 4224, 4226, 4227, 4272, 4275, 4279, 4281, 4283, 4285,
|
|
+ 4286, 4304, 4336, 4352, 4355, 4391, 4396, 4397, 4406, 4416,
|
|
+ 4480, 4482, 4483, 4531, 4534, 4543, 4545, 4549, 4560, 5760,
|
|
+ 5803, 5804, 5805, 5806, 5808, 5814, 5815, 5824, 8192, 9216,
|
|
+ 9328, 12288, 26624, 28416, 28496, 28497, 28559, 28563, 45056, 53248,
|
|
+ 53504, 53545, 53605, 53607, 53610, 53613, 53619, 53627, 53635, 53637,
|
|
+ 53644, 53674, 53678, 53760, 53826, 53829, 54016, 54112, 54272, 54298,
|
|
+ 54324, 54350, 54358, 54376, 54402, 54428, 54430, 54434, 54437, 54441,
|
|
+ 54446, 54454, 54459, 54461, 54469, 54480, 54506, 54532, 54535, 54541,
|
|
+ 54550, 54558, 54584, 54587, 54592, 54598, 54602, 54610, 54636, 54662,
|
|
+ 54688, 54714, 54740, 54766, 54792, 54818, 54844, 54870, 54896, 54922,
|
|
+ 54952, 54977, 54978, 55003, 55004, 55010, 55035, 55036, 55061, 55062,
|
|
+ 55068, 55093, 55094, 55119, 55120, 55126, 55151, 55152, 55177, 55178,
|
|
+ 55184, 55209, 55210, 55235, 55236, 55242, 55246, 60928, 60933, 60961,
|
|
+ 60964, 60967, 60969, 60980, 60985, 60987, 60994, 60999, 61001, 61003,
|
|
+ 61005, 61009, 61012, 61015, 61017, 61019, 61021, 61023, 61025, 61028,
|
|
+ 61031, 61036, 61044, 61049, 61054, 61056, 61067, 61089, 61093, 61099,
|
|
+ 61168, 61440, 61488, 61600, 61617, 61633, 61649, 61696, 61712, 61744,
|
|
+ 61808, 61926, 61968, 62016, 62032, 62208, 62256, 62263, 62336, 62368,
|
|
+ 62406, 62432, 62464, 62528, 62530, 62713, 62720, 62784, 62800, 62971,
|
|
+ 63045, 63104, 63232, 0, 42710, 42752, 46900, 46912, 47133, 63488,
|
|
+ 1, 32, 256, 0, 65533,
|
|
};
|
|
static u16 aFts5UnicodeData[] = {
|
|
- 1025, 61, 117, 55, 117, 54, 50, 53, 57, 53,
|
|
- 49, 85, 333, 85, 121, 85, 841, 54, 53, 50,
|
|
- 56, 48, 56, 837, 54, 57, 50, 57, 1057, 61,
|
|
- 53, 151, 58, 53, 56, 58, 39, 52, 57, 34,
|
|
- 58, 56, 58, 57, 79, 56, 37, 85, 56, 47,
|
|
- 39, 51, 111, 53, 745, 57, 233, 773, 57, 261,
|
|
- 1822, 37, 542, 37, 1534, 222, 69, 73, 37, 126,
|
|
- 126, 73, 69, 137, 37, 73, 37, 105, 101, 73,
|
|
- 37, 73, 37, 190, 158, 37, 126, 126, 73, 37,
|
|
- 126, 94, 37, 39, 94, 69, 135, 41, 40, 37,
|
|
- 41, 40, 37, 41, 40, 37, 542, 37, 606, 37,
|
|
- 41, 40, 37, 126, 73, 37, 1886, 197, 73, 37,
|
|
- 73, 69, 126, 105, 37, 286, 2181, 39, 869, 582,
|
|
- 152, 390, 472, 166, 248, 38, 56, 38, 568, 3596,
|
|
- 158, 38, 56, 94, 38, 101, 53, 88, 41, 53,
|
|
- 105, 41, 73, 37, 553, 297, 1125, 94, 37, 105,
|
|
- 101, 798, 133, 94, 57, 126, 94, 37, 1641, 1541,
|
|
- 1118, 58, 172, 75, 1790, 478, 37, 2846, 1225, 38,
|
|
- 213, 1253, 53, 49, 55, 1452, 49, 44, 53, 76,
|
|
- 53, 76, 53, 44, 871, 103, 85, 162, 121, 85,
|
|
- 55, 85, 90, 364, 53, 85, 1031, 38, 327, 684,
|
|
- 333, 149, 71, 44, 3175, 53, 39, 236, 34, 58,
|
|
- 204, 70, 76, 58, 140, 71, 333, 103, 90, 39,
|
|
- 469, 34, 39, 44, 967, 876, 2855, 364, 39, 333,
|
|
- 1063, 300, 70, 58, 117, 38, 711, 140, 38, 300,
|
|
- 38, 108, 38, 172, 501, 807, 108, 53, 39, 359,
|
|
- 876, 108, 42, 1735, 44, 42, 44, 39, 106, 268,
|
|
- 138, 44, 74, 39, 236, 327, 76, 85, 333, 53,
|
|
- 38, 199, 231, 44, 74, 263, 71, 711, 231, 39,
|
|
- 135, 44, 39, 106, 140, 74, 74, 44, 39, 42,
|
|
- 71, 103, 76, 333, 71, 87, 207, 58, 55, 76,
|
|
- 42, 199, 71, 711, 231, 71, 71, 71, 44, 106,
|
|
- 76, 76, 108, 44, 135, 39, 333, 76, 103, 44,
|
|
- 76, 42, 295, 103, 711, 231, 71, 167, 44, 39,
|
|
- 106, 172, 76, 42, 74, 44, 39, 71, 76, 333,
|
|
- 53, 55, 44, 74, 263, 71, 711, 231, 71, 167,
|
|
- 44, 39, 42, 44, 42, 140, 74, 74, 44, 44,
|
|
- 42, 71, 103, 76, 333, 58, 39, 207, 44, 39,
|
|
- 199, 103, 135, 71, 39, 71, 71, 103, 391, 74,
|
|
- 44, 74, 106, 106, 44, 39, 42, 333, 111, 218,
|
|
- 55, 58, 106, 263, 103, 743, 327, 167, 39, 108,
|
|
- 138, 108, 140, 76, 71, 71, 76, 333, 239, 58,
|
|
- 74, 263, 103, 743, 327, 167, 44, 39, 42, 44,
|
|
- 170, 44, 74, 74, 76, 74, 39, 71, 76, 333,
|
|
- 71, 74, 263, 103, 1319, 39, 106, 140, 106, 106,
|
|
- 44, 39, 42, 71, 76, 333, 207, 58, 199, 74,
|
|
- 583, 775, 295, 39, 231, 44, 106, 108, 44, 266,
|
|
- 74, 53, 1543, 44, 71, 236, 55, 199, 38, 268,
|
|
- 53, 333, 85, 71, 39, 71, 39, 39, 135, 231,
|
|
- 103, 39, 39, 71, 135, 44, 71, 204, 76, 39,
|
|
- 167, 38, 204, 333, 135, 39, 122, 501, 58, 53,
|
|
- 122, 76, 218, 333, 335, 58, 44, 58, 44, 58,
|
|
- 44, 54, 50, 54, 50, 74, 263, 1159, 460, 42,
|
|
- 172, 53, 76, 167, 364, 1164, 282, 44, 218, 90,
|
|
- 181, 154, 85, 1383, 74, 140, 42, 204, 42, 76,
|
|
- 74, 76, 39, 333, 213, 199, 74, 76, 135, 108,
|
|
- 39, 106, 71, 234, 103, 140, 423, 44, 74, 76,
|
|
- 202, 44, 39, 42, 333, 106, 44, 90, 1225, 41,
|
|
- 41, 1383, 53, 38, 10631, 135, 231, 39, 135, 1319,
|
|
- 135, 1063, 135, 231, 39, 135, 487, 1831, 135, 2151,
|
|
- 108, 309, 655, 519, 346, 2727, 49, 19847, 85, 551,
|
|
- 61, 839, 54, 50, 2407, 117, 110, 423, 135, 108,
|
|
- 583, 108, 85, 583, 76, 423, 103, 76, 1671, 76,
|
|
- 42, 236, 266, 44, 74, 364, 117, 38, 117, 55,
|
|
- 39, 44, 333, 335, 213, 49, 149, 108, 61, 333,
|
|
- 1127, 38, 1671, 1319, 44, 39, 2247, 935, 108, 138,
|
|
- 76, 106, 74, 44, 202, 108, 58, 85, 333, 967,
|
|
- 167, 1415, 554, 231, 74, 333, 47, 1114, 743, 76,
|
|
- 106, 85, 1703, 42, 44, 42, 236, 44, 42, 44,
|
|
- 74, 268, 202, 332, 44, 333, 333, 245, 38, 213,
|
|
- 140, 42, 1511, 44, 42, 172, 42, 44, 170, 44,
|
|
- 74, 231, 333, 245, 346, 300, 314, 76, 42, 967,
|
|
- 42, 140, 74, 76, 42, 44, 74, 71, 333, 1415,
|
|
- 44, 42, 76, 106, 44, 42, 108, 74, 149, 1159,
|
|
- 266, 268, 74, 76, 181, 333, 103, 333, 967, 198,
|
|
- 85, 277, 108, 53, 428, 42, 236, 135, 44, 135,
|
|
- 74, 44, 71, 1413, 2022, 421, 38, 1093, 1190, 1260,
|
|
- 140, 4830, 261, 3166, 261, 265, 197, 201, 261, 265,
|
|
- 261, 265, 197, 201, 261, 41, 41, 41, 94, 229,
|
|
- 265, 453, 261, 264, 261, 264, 261, 264, 165, 69,
|
|
- 137, 40, 56, 37, 120, 101, 69, 137, 40, 120,
|
|
- 133, 69, 137, 120, 261, 169, 120, 101, 69, 137,
|
|
- 40, 88, 381, 162, 209, 85, 52, 51, 54, 84,
|
|
- 51, 54, 52, 277, 59, 60, 162, 61, 309, 52,
|
|
- 51, 149, 80, 117, 57, 54, 50, 373, 57, 53,
|
|
- 48, 341, 61, 162, 194, 47, 38, 207, 121, 54,
|
|
- 50, 38, 335, 121, 54, 50, 422, 855, 428, 139,
|
|
- 44, 107, 396, 90, 41, 154, 41, 90, 37, 105,
|
|
- 69, 105, 37, 58, 41, 90, 57, 169, 218, 41,
|
|
- 58, 41, 58, 41, 58, 137, 58, 37, 137, 37,
|
|
- 135, 37, 90, 69, 73, 185, 94, 101, 58, 57,
|
|
- 90, 37, 58, 527, 1134, 94, 142, 47, 185, 186,
|
|
- 89, 154, 57, 90, 57, 90, 57, 250, 57, 1018,
|
|
- 89, 90, 57, 58, 57, 1018, 8601, 282, 153, 666,
|
|
- 89, 250, 54, 50, 2618, 57, 986, 825, 1306, 217,
|
|
- 602, 1274, 378, 1935, 2522, 719, 5882, 57, 314, 57,
|
|
- 1754, 281, 3578, 57, 4634, 3322, 54, 50, 54, 50,
|
|
- 54, 50, 54, 50, 54, 50, 54, 50, 54, 50,
|
|
- 975, 1434, 185, 54, 50, 1017, 54, 50, 54, 50,
|
|
- 54, 50, 54, 50, 54, 50, 537, 8218, 4217, 54,
|
|
- 50, 54, 50, 54, 50, 54, 50, 54, 50, 54,
|
|
- 50, 54, 50, 54, 50, 54, 50, 54, 50, 54,
|
|
- 50, 2041, 54, 50, 54, 50, 1049, 54, 50, 8281,
|
|
- 1562, 697, 90, 217, 346, 1513, 1509, 126, 73, 69,
|
|
- 254, 105, 37, 94, 37, 94, 165, 70, 105, 37,
|
|
- 3166, 37, 218, 158, 108, 94, 149, 47, 85, 1221,
|
|
- 37, 37, 1799, 38, 53, 44, 743, 231, 231, 231,
|
|
- 231, 231, 231, 231, 231, 1036, 85, 52, 51, 52,
|
|
- 51, 117, 52, 51, 53, 52, 51, 309, 49, 85,
|
|
- 49, 53, 52, 51, 85, 52, 51, 54, 50, 54,
|
|
- 50, 54, 50, 54, 50, 181, 38, 341, 81, 858,
|
|
- 2874, 6874, 410, 61, 117, 58, 38, 39, 46, 54,
|
|
- 50, 54, 50, 54, 50, 54, 50, 54, 50, 90,
|
|
- 54, 50, 54, 50, 54, 50, 54, 50, 49, 54,
|
|
- 82, 58, 302, 140, 74, 49, 166, 90, 110, 38,
|
|
- 39, 53, 90, 2759, 76, 88, 70, 39, 49, 2887,
|
|
- 53, 102, 39, 1319, 3015, 90, 143, 346, 871, 1178,
|
|
- 519, 1018, 335, 986, 271, 58, 495, 1050, 335, 1274,
|
|
- 495, 2042, 8218, 39, 39, 2074, 39, 39, 679, 38,
|
|
- 36583, 1786, 1287, 198, 85, 8583, 38, 117, 519, 333,
|
|
- 71, 1502, 39, 44, 107, 53, 332, 53, 38, 798,
|
|
- 44, 2247, 334, 76, 213, 760, 294, 88, 478, 69,
|
|
- 2014, 38, 261, 190, 350, 38, 88, 158, 158, 382,
|
|
- 70, 37, 231, 44, 103, 44, 135, 44, 743, 74,
|
|
- 76, 42, 154, 207, 90, 55, 58, 1671, 149, 74,
|
|
- 1607, 522, 44, 85, 333, 588, 199, 117, 39, 333,
|
|
- 903, 268, 85, 743, 364, 74, 53, 935, 108, 42,
|
|
- 1511, 44, 74, 140, 74, 44, 138, 437, 38, 333,
|
|
- 85, 1319, 204, 74, 76, 74, 76, 103, 44, 263,
|
|
- 44, 42, 333, 149, 519, 38, 199, 122, 39, 42,
|
|
- 1543, 44, 39, 108, 71, 76, 167, 76, 39, 44,
|
|
- 39, 71, 38, 85, 359, 42, 76, 74, 85, 39,
|
|
- 70, 42, 44, 199, 199, 199, 231, 231, 1127, 74,
|
|
- 44, 74, 44, 74, 53, 42, 44, 333, 39, 39,
|
|
- 743, 1575, 36, 68, 68, 36, 63, 63, 11719, 3399,
|
|
- 229, 165, 39, 44, 327, 57, 423, 167, 39, 71,
|
|
- 71, 3463, 536, 11623, 54, 50, 2055, 1735, 391, 55,
|
|
- 58, 524, 245, 54, 50, 53, 236, 53, 81, 80,
|
|
- 54, 50, 54, 50, 54, 50, 54, 50, 54, 50,
|
|
- 54, 50, 54, 50, 54, 50, 85, 54, 50, 149,
|
|
- 112, 117, 149, 49, 54, 50, 54, 50, 54, 50,
|
|
- 117, 57, 49, 121, 53, 55, 85, 167, 4327, 34,
|
|
- 117, 55, 117, 54, 50, 53, 57, 53, 49, 85,
|
|
- 333, 85, 121, 85, 841, 54, 53, 50, 56, 48,
|
|
- 56, 837, 54, 57, 50, 57, 54, 50, 53, 54,
|
|
- 50, 85, 327, 38, 1447, 70, 999, 199, 199, 199,
|
|
- 103, 87, 57, 56, 58, 87, 58, 153, 90, 98,
|
|
- 90, 391, 839, 615, 71, 487, 455, 3943, 117, 1455,
|
|
- 314, 1710, 143, 570, 47, 410, 1466, 44, 935, 1575,
|
|
- 999, 143, 551, 46, 263, 46, 967, 53, 1159, 263,
|
|
- 53, 174, 1289, 1285, 2503, 333, 199, 39, 1415, 71,
|
|
- 39, 743, 53, 271, 711, 207, 53, 839, 53, 1799,
|
|
- 71, 39, 108, 76, 140, 135, 103, 871, 108, 44,
|
|
- 271, 309, 935, 79, 53, 1735, 245, 711, 271, 615,
|
|
- 271, 2343, 1007, 42, 44, 42, 1703, 492, 245, 655,
|
|
- 333, 76, 42, 1447, 106, 140, 74, 76, 85, 34,
|
|
- 149, 807, 333, 108, 1159, 172, 42, 268, 333, 149,
|
|
- 76, 42, 1543, 106, 300, 74, 135, 149, 333, 1383,
|
|
- 44, 42, 44, 74, 204, 42, 44, 333, 28135, 3182,
|
|
- 149, 34279, 18215, 2215, 39, 1482, 140, 422, 71, 7898,
|
|
- 1274, 1946, 74, 108, 122, 202, 258, 268, 90, 236,
|
|
- 986, 140, 1562, 2138, 108, 58, 2810, 591, 841, 837,
|
|
- 841, 229, 581, 841, 837, 41, 73, 41, 73, 137,
|
|
- 265, 133, 37, 229, 357, 841, 837, 73, 137, 265,
|
|
- 233, 837, 73, 137, 169, 41, 233, 837, 841, 837,
|
|
- 841, 837, 841, 837, 841, 837, 841, 837, 841, 901,
|
|
- 809, 57, 805, 57, 197, 809, 57, 805, 57, 197,
|
|
- 809, 57, 805, 57, 197, 809, 57, 805, 57, 197,
|
|
- 809, 57, 805, 57, 197, 94, 1613, 135, 871, 71,
|
|
- 39, 39, 327, 135, 39, 39, 39, 39, 39, 39,
|
|
- 103, 71, 39, 39, 39, 39, 39, 39, 71, 39,
|
|
- 135, 231, 135, 135, 39, 327, 551, 103, 167, 551,
|
|
- 89, 1434, 3226, 506, 474, 506, 506, 367, 1018, 1946,
|
|
- 1402, 954, 1402, 314, 90, 1082, 218, 2266, 666, 1210,
|
|
- 186, 570, 2042, 58, 5850, 154, 2010, 154, 794, 2266,
|
|
- 378, 2266, 3738, 39, 39, 39, 39, 39, 39, 17351,
|
|
- 34, 3074, 7692, 63, 63,
|
|
+ 1025, 61, 117, 55, 117, 54, 50, 53, 57, 53,
|
|
+ 49, 85, 333, 85, 121, 85, 841, 54, 53, 50,
|
|
+ 56, 48, 56, 837, 54, 57, 50, 57, 1057, 61,
|
|
+ 53, 151, 58, 53, 56, 58, 39, 52, 57, 34,
|
|
+ 58, 56, 58, 57, 79, 56, 37, 85, 56, 47,
|
|
+ 39, 51, 111, 53, 745, 57, 233, 773, 57, 261,
|
|
+ 1822, 37, 542, 37, 1534, 222, 69, 73, 37, 126,
|
|
+ 126, 73, 69, 137, 37, 73, 37, 105, 101, 73,
|
|
+ 37, 73, 37, 190, 158, 37, 126, 126, 73, 37,
|
|
+ 126, 94, 37, 39, 94, 69, 135, 41, 40, 37,
|
|
+ 41, 40, 37, 41, 40, 37, 542, 37, 606, 37,
|
|
+ 41, 40, 37, 126, 73, 37, 1886, 197, 73, 37,
|
|
+ 73, 69, 126, 105, 37, 286, 2181, 39, 869, 582,
|
|
+ 152, 390, 472, 166, 248, 38, 56, 38, 568, 3596,
|
|
+ 158, 38, 56, 94, 38, 101, 53, 88, 41, 53,
|
|
+ 105, 41, 73, 37, 553, 297, 1125, 94, 37, 105,
|
|
+ 101, 798, 133, 94, 57, 126, 94, 37, 1641, 1541,
|
|
+ 1118, 58, 172, 75, 1790, 478, 37, 2846, 1225, 38,
|
|
+ 213, 1253, 53, 49, 55, 1452, 49, 44, 53, 76,
|
|
+ 53, 76, 53, 44, 871, 103, 85, 162, 121, 85,
|
|
+ 55, 85, 90, 364, 53, 85, 1031, 38, 327, 684,
|
|
+ 333, 149, 71, 44, 3175, 53, 39, 236, 34, 58,
|
|
+ 204, 70, 76, 58, 140, 71, 333, 103, 90, 39,
|
|
+ 469, 34, 39, 44, 967, 876, 2855, 364, 39, 333,
|
|
+ 1063, 300, 70, 58, 117, 38, 711, 140, 38, 300,
|
|
+ 38, 108, 38, 172, 501, 807, 108, 53, 39, 359,
|
|
+ 876, 108, 42, 1735, 44, 42, 44, 39, 106, 268,
|
|
+ 138, 44, 74, 39, 236, 327, 76, 85, 333, 53,
|
|
+ 38, 199, 231, 44, 74, 263, 71, 711, 231, 39,
|
|
+ 135, 44, 39, 106, 140, 74, 74, 44, 39, 42,
|
|
+ 71, 103, 76, 333, 71, 87, 207, 58, 55, 76,
|
|
+ 42, 199, 71, 711, 231, 71, 71, 71, 44, 106,
|
|
+ 76, 76, 108, 44, 135, 39, 333, 76, 103, 44,
|
|
+ 76, 42, 295, 103, 711, 231, 71, 167, 44, 39,
|
|
+ 106, 172, 76, 42, 74, 44, 39, 71, 76, 333,
|
|
+ 53, 55, 44, 74, 263, 71, 711, 231, 71, 167,
|
|
+ 44, 39, 42, 44, 42, 140, 74, 74, 44, 44,
|
|
+ 42, 71, 103, 76, 333, 58, 39, 207, 44, 39,
|
|
+ 199, 103, 135, 71, 39, 71, 71, 103, 391, 74,
|
|
+ 44, 74, 106, 106, 44, 39, 42, 333, 111, 218,
|
|
+ 55, 58, 106, 263, 103, 743, 327, 167, 39, 108,
|
|
+ 138, 108, 140, 76, 71, 71, 76, 333, 239, 58,
|
|
+ 74, 263, 103, 743, 327, 167, 44, 39, 42, 44,
|
|
+ 170, 44, 74, 74, 76, 74, 39, 71, 76, 333,
|
|
+ 71, 74, 263, 103, 1319, 39, 106, 140, 106, 106,
|
|
+ 44, 39, 42, 71, 76, 333, 207, 58, 199, 74,
|
|
+ 583, 775, 295, 39, 231, 44, 106, 108, 44, 266,
|
|
+ 74, 53, 1543, 44, 71, 236, 55, 199, 38, 268,
|
|
+ 53, 333, 85, 71, 39, 71, 39, 39, 135, 231,
|
|
+ 103, 39, 39, 71, 135, 44, 71, 204, 76, 39,
|
|
+ 167, 38, 204, 333, 135, 39, 122, 501, 58, 53,
|
|
+ 122, 76, 218, 333, 335, 58, 44, 58, 44, 58,
|
|
+ 44, 54, 50, 54, 50, 74, 263, 1159, 460, 42,
|
|
+ 172, 53, 76, 167, 364, 1164, 282, 44, 218, 90,
|
|
+ 181, 154, 85, 1383, 74, 140, 42, 204, 42, 76,
|
|
+ 74, 76, 39, 333, 213, 199, 74, 76, 135, 108,
|
|
+ 39, 106, 71, 234, 103, 140, 423, 44, 74, 76,
|
|
+ 202, 44, 39, 42, 333, 106, 44, 90, 1225, 41,
|
|
+ 41, 1383, 53, 38, 10631, 135, 231, 39, 135, 1319,
|
|
+ 135, 1063, 135, 231, 39, 135, 487, 1831, 135, 2151,
|
|
+ 108, 309, 655, 519, 346, 2727, 49, 19847, 85, 551,
|
|
+ 61, 839, 54, 50, 2407, 117, 110, 423, 135, 108,
|
|
+ 583, 108, 85, 583, 76, 423, 103, 76, 1671, 76,
|
|
+ 42, 236, 266, 44, 74, 364, 117, 38, 117, 55,
|
|
+ 39, 44, 333, 335, 213, 49, 149, 108, 61, 333,
|
|
+ 1127, 38, 1671, 1319, 44, 39, 2247, 935, 108, 138,
|
|
+ 76, 106, 74, 44, 202, 108, 58, 85, 333, 967,
|
|
+ 167, 1415, 554, 231, 74, 333, 47, 1114, 743, 76,
|
|
+ 106, 85, 1703, 42, 44, 42, 236, 44, 42, 44,
|
|
+ 74, 268, 202, 332, 44, 333, 333, 245, 38, 213,
|
|
+ 140, 42, 1511, 44, 42, 172, 42, 44, 170, 44,
|
|
+ 74, 231, 333, 245, 346, 300, 314, 76, 42, 967,
|
|
+ 42, 140, 74, 76, 42, 44, 74, 71, 333, 1415,
|
|
+ 44, 42, 76, 106, 44, 42, 108, 74, 149, 1159,
|
|
+ 266, 268, 74, 76, 181, 333, 103, 333, 967, 198,
|
|
+ 85, 277, 108, 53, 428, 42, 236, 135, 44, 135,
|
|
+ 74, 44, 71, 1413, 2022, 421, 38, 1093, 1190, 1260,
|
|
+ 140, 4830, 261, 3166, 261, 265, 197, 201, 261, 265,
|
|
+ 261, 265, 197, 201, 261, 41, 41, 41, 94, 229,
|
|
+ 265, 453, 261, 264, 261, 264, 261, 264, 165, 69,
|
|
+ 137, 40, 56, 37, 120, 101, 69, 137, 40, 120,
|
|
+ 133, 69, 137, 120, 261, 169, 120, 101, 69, 137,
|
|
+ 40, 88, 381, 162, 209, 85, 52, 51, 54, 84,
|
|
+ 51, 54, 52, 277, 59, 60, 162, 61, 309, 52,
|
|
+ 51, 149, 80, 117, 57, 54, 50, 373, 57, 53,
|
|
+ 48, 341, 61, 162, 194, 47, 38, 207, 121, 54,
|
|
+ 50, 38, 335, 121, 54, 50, 422, 855, 428, 139,
|
|
+ 44, 107, 396, 90, 41, 154, 41, 90, 37, 105,
|
|
+ 69, 105, 37, 58, 41, 90, 57, 169, 218, 41,
|
|
+ 58, 41, 58, 41, 58, 137, 58, 37, 137, 37,
|
|
+ 135, 37, 90, 69, 73, 185, 94, 101, 58, 57,
|
|
+ 90, 37, 58, 527, 1134, 94, 142, 47, 185, 186,
|
|
+ 89, 154, 57, 90, 57, 90, 57, 250, 57, 1018,
|
|
+ 89, 90, 57, 58, 57, 1018, 8601, 282, 153, 666,
|
|
+ 89, 250, 54, 50, 2618, 57, 986, 825, 1306, 217,
|
|
+ 602, 1274, 378, 1935, 2522, 719, 5882, 57, 314, 57,
|
|
+ 1754, 281, 3578, 57, 4634, 3322, 54, 50, 54, 50,
|
|
+ 54, 50, 54, 50, 54, 50, 54, 50, 54, 50,
|
|
+ 975, 1434, 185, 54, 50, 1017, 54, 50, 54, 50,
|
|
+ 54, 50, 54, 50, 54, 50, 537, 8218, 4217, 54,
|
|
+ 50, 54, 50, 54, 50, 54, 50, 54, 50, 54,
|
|
+ 50, 54, 50, 54, 50, 54, 50, 54, 50, 54,
|
|
+ 50, 2041, 54, 50, 54, 50, 1049, 54, 50, 8281,
|
|
+ 1562, 697, 90, 217, 346, 1513, 1509, 126, 73, 69,
|
|
+ 254, 105, 37, 94, 37, 94, 165, 70, 105, 37,
|
|
+ 3166, 37, 218, 158, 108, 94, 149, 47, 85, 1221,
|
|
+ 37, 37, 1799, 38, 53, 44, 743, 231, 231, 231,
|
|
+ 231, 231, 231, 231, 231, 1036, 85, 52, 51, 52,
|
|
+ 51, 117, 52, 51, 53, 52, 51, 309, 49, 85,
|
|
+ 49, 53, 52, 51, 85, 52, 51, 54, 50, 54,
|
|
+ 50, 54, 50, 54, 50, 181, 38, 341, 81, 858,
|
|
+ 2874, 6874, 410, 61, 117, 58, 38, 39, 46, 54,
|
|
+ 50, 54, 50, 54, 50, 54, 50, 54, 50, 90,
|
|
+ 54, 50, 54, 50, 54, 50, 54, 50, 49, 54,
|
|
+ 82, 58, 302, 140, 74, 49, 166, 90, 110, 38,
|
|
+ 39, 53, 90, 2759, 76, 88, 70, 39, 49, 2887,
|
|
+ 53, 102, 39, 1319, 3015, 90, 143, 346, 871, 1178,
|
|
+ 519, 1018, 335, 986, 271, 58, 495, 1050, 335, 1274,
|
|
+ 495, 2042, 8218, 39, 39, 2074, 39, 39, 679, 38,
|
|
+ 36583, 1786, 1287, 198, 85, 8583, 38, 117, 519, 333,
|
|
+ 71, 1502, 39, 44, 107, 53, 332, 53, 38, 798,
|
|
+ 44, 2247, 334, 76, 213, 760, 294, 88, 478, 69,
|
|
+ 2014, 38, 261, 190, 350, 38, 88, 158, 158, 382,
|
|
+ 70, 37, 231, 44, 103, 44, 135, 44, 743, 74,
|
|
+ 76, 42, 154, 207, 90, 55, 58, 1671, 149, 74,
|
|
+ 1607, 522, 44, 85, 333, 588, 199, 117, 39, 333,
|
|
+ 903, 268, 85, 743, 364, 74, 53, 935, 108, 42,
|
|
+ 1511, 44, 74, 140, 74, 44, 138, 437, 38, 333,
|
|
+ 85, 1319, 204, 74, 76, 74, 76, 103, 44, 263,
|
|
+ 44, 42, 333, 149, 519, 38, 199, 122, 39, 42,
|
|
+ 1543, 44, 39, 108, 71, 76, 167, 76, 39, 44,
|
|
+ 39, 71, 38, 85, 359, 42, 76, 74, 85, 39,
|
|
+ 70, 42, 44, 199, 199, 199, 231, 231, 1127, 74,
|
|
+ 44, 74, 44, 74, 53, 42, 44, 333, 39, 39,
|
|
+ 743, 1575, 36, 68, 68, 36, 63, 63, 11719, 3399,
|
|
+ 229, 165, 39, 44, 327, 57, 423, 167, 39, 71,
|
|
+ 71, 3463, 536, 11623, 54, 50, 2055, 1735, 391, 55,
|
|
+ 58, 524, 245, 54, 50, 53, 236, 53, 81, 80,
|
|
+ 54, 50, 54, 50, 54, 50, 54, 50, 54, 50,
|
|
+ 54, 50, 54, 50, 54, 50, 85, 54, 50, 149,
|
|
+ 112, 117, 149, 49, 54, 50, 54, 50, 54, 50,
|
|
+ 117, 57, 49, 121, 53, 55, 85, 167, 4327, 34,
|
|
+ 117, 55, 117, 54, 50, 53, 57, 53, 49, 85,
|
|
+ 333, 85, 121, 85, 841, 54, 53, 50, 56, 48,
|
|
+ 56, 837, 54, 57, 50, 57, 54, 50, 53, 54,
|
|
+ 50, 85, 327, 38, 1447, 70, 999, 199, 199, 199,
|
|
+ 103, 87, 57, 56, 58, 87, 58, 153, 90, 98,
|
|
+ 90, 391, 839, 615, 71, 487, 455, 3943, 117, 1455,
|
|
+ 314, 1710, 143, 570, 47, 410, 1466, 44, 935, 1575,
|
|
+ 999, 143, 551, 46, 263, 46, 967, 53, 1159, 263,
|
|
+ 53, 174, 1289, 1285, 2503, 333, 199, 39, 1415, 71,
|
|
+ 39, 743, 53, 271, 711, 207, 53, 839, 53, 1799,
|
|
+ 71, 39, 108, 76, 140, 135, 103, 871, 108, 44,
|
|
+ 271, 309, 935, 79, 53, 1735, 245, 711, 271, 615,
|
|
+ 271, 2343, 1007, 42, 44, 42, 1703, 492, 245, 655,
|
|
+ 333, 76, 42, 1447, 106, 140, 74, 76, 85, 34,
|
|
+ 149, 807, 333, 108, 1159, 172, 42, 268, 333, 149,
|
|
+ 76, 42, 1543, 106, 300, 74, 135, 149, 333, 1383,
|
|
+ 44, 42, 44, 74, 204, 42, 44, 333, 28135, 3182,
|
|
+ 149, 34279, 18215, 2215, 39, 1482, 140, 422, 71, 7898,
|
|
+ 1274, 1946, 74, 108, 122, 202, 258, 268, 90, 236,
|
|
+ 986, 140, 1562, 2138, 108, 58, 2810, 591, 841, 837,
|
|
+ 841, 229, 581, 841, 837, 41, 73, 41, 73, 137,
|
|
+ 265, 133, 37, 229, 357, 841, 837, 73, 137, 265,
|
|
+ 233, 837, 73, 137, 169, 41, 233, 837, 841, 837,
|
|
+ 841, 837, 841, 837, 841, 837, 841, 837, 841, 901,
|
|
+ 809, 57, 805, 57, 197, 809, 57, 805, 57, 197,
|
|
+ 809, 57, 805, 57, 197, 809, 57, 805, 57, 197,
|
|
+ 809, 57, 805, 57, 197, 94, 1613, 135, 871, 71,
|
|
+ 39, 39, 327, 135, 39, 39, 39, 39, 39, 39,
|
|
+ 103, 71, 39, 39, 39, 39, 39, 39, 71, 39,
|
|
+ 135, 231, 135, 135, 39, 327, 551, 103, 167, 551,
|
|
+ 89, 1434, 3226, 506, 474, 506, 506, 367, 1018, 1946,
|
|
+ 1402, 954, 1402, 314, 90, 1082, 218, 2266, 666, 1210,
|
|
+ 186, 570, 2042, 58, 5850, 154, 2010, 154, 794, 2266,
|
|
+ 378, 2266, 3738, 39, 39, 39, 39, 39, 39, 17351,
|
|
+ 34, 3074, 7692, 63, 63,
|
|
};
|
|
|
|
-static int sqlite3Fts5UnicodeCategory(u32 iCode) {
|
|
+static int sqlite3Fts5UnicodeCategory(u32 iCode) {
|
|
int iRes = -1;
|
|
int iHi;
|
|
int iLo;
|
|
@@ -227013,8 +243756,10 @@ static void sqlite3Fts5UnicodeAscii(u8 *aArray, u8 *aAscii){
|
|
}
|
|
iTbl++;
|
|
}
|
|
+ aAscii[0] = 0; /* 0x00 is never a token character */
|
|
}
|
|
|
|
+
|
|
/*
|
|
** 2015 May 30
|
|
**
|
|
@@ -227321,7 +244066,7 @@ static int FTS5_NOINLINE fts5PutVarint64(unsigned char *p, u64 v){
|
|
v >>= 7;
|
|
}
|
|
return 9;
|
|
- }
|
|
+ }
|
|
n = 0;
|
|
do{
|
|
buf[n++] = (u8)((v & 0x7f) | 0x80);
|
|
@@ -227373,7 +244118,7 @@ static int sqlite3Fts5GetVarintLen(u32 iVal){
|
|
******************************************************************************
|
|
**
|
|
** This is an SQLite virtual table module implementing direct access to an
|
|
-** existing FTS5 index. The module may create several different types of
|
|
+** existing FTS5 index. The module may create several different types of
|
|
** tables:
|
|
**
|
|
** col:
|
|
@@ -227381,21 +244126,21 @@ static int sqlite3Fts5GetVarintLen(u32 iVal){
|
|
**
|
|
** One row for each term/column combination. The value of $doc is set to
|
|
** the number of fts5 rows that contain at least one instance of term
|
|
-** $term within column $col. Field $cnt is set to the total number of
|
|
-** instances of term $term in column $col (in any row of the fts5 table).
|
|
+** $term within column $col. Field $cnt is set to the total number of
|
|
+** instances of term $term in column $col (in any row of the fts5 table).
|
|
**
|
|
** row:
|
|
** CREATE TABLE vocab(term, doc, cnt, PRIMARY KEY(term));
|
|
**
|
|
** One row for each term in the database. The value of $doc is set to
|
|
** the number of fts5 rows that contain at least one instance of term
|
|
-** $term. Field $cnt is set to the total number of instances of term
|
|
+** $term. Field $cnt is set to the total number of instances of term
|
|
** $term in the database.
|
|
**
|
|
** instance:
|
|
** CREATE TABLE vocab(term, doc, col, offset, PRIMARY KEY(<all-fields>));
|
|
**
|
|
-** One row for each term instance in the database.
|
|
+** One row for each term instance in the database.
|
|
*/
|
|
|
|
|
|
@@ -227412,6 +244157,7 @@ struct Fts5VocabTable {
|
|
sqlite3 *db; /* Database handle */
|
|
Fts5Global *pGlobal; /* FTS5 global object for this database */
|
|
int eType; /* FTS5_VOCAB_COL, ROW or INSTANCE */
|
|
+ unsigned bBusy; /* True if busy */
|
|
};
|
|
|
|
struct Fts5VocabCursor {
|
|
@@ -227421,6 +244167,7 @@ struct Fts5VocabCursor {
|
|
|
|
int bEof; /* True if this cursor is at EOF */
|
|
Fts5IndexIter *pIter; /* Term/rowid iterator object */
|
|
+ void *pStruct; /* From sqlite3Fts5StructureRef() */
|
|
|
|
int nLeTerm; /* Size of zLeTerm in bytes */
|
|
char *zLeTerm; /* (term <= $zLeTerm) paramater, or NULL */
|
|
@@ -227456,7 +244203,7 @@ struct Fts5VocabCursor {
|
|
|
|
|
|
/*
|
|
-** Translate a string containing an fts5vocab table type to an
|
|
+** Translate a string containing an fts5vocab table type to an
|
|
** FTS5_VOCAB_XXX constant. If successful, set *peType to the output
|
|
** value and return SQLITE_OK. Otherwise, set *pzErr to an error message
|
|
** and return SQLITE_ERROR.
|
|
@@ -227534,8 +244281,8 @@ static int fts5VocabInitVtab(
|
|
sqlite3_vtab **ppVTab, /* Write the resulting vtab structure here */
|
|
char **pzErr /* Write any error message here */
|
|
){
|
|
- const char *azSchema[] = {
|
|
- "CREATE TABlE vocab(" FTS5_VOCAB_COL_SCHEMA ")",
|
|
+ const char *azSchema[] = {
|
|
+ "CREATE TABlE vocab(" FTS5_VOCAB_COL_SCHEMA ")",
|
|
"CREATE TABlE vocab(" FTS5_VOCAB_ROW_SCHEMA ")",
|
|
"CREATE TABlE vocab(" FTS5_VOCAB_INST_SCHEMA ")"
|
|
};
|
|
@@ -227554,10 +244301,10 @@ static int fts5VocabInitVtab(
|
|
const char *zDb = bDb ? argv[3] : argv[1];
|
|
const char *zTab = bDb ? argv[4] : argv[3];
|
|
const char *zType = bDb ? argv[5] : argv[4];
|
|
- int nDb = (int)strlen(zDb)+1;
|
|
+ int nDb = (int)strlen(zDb)+1;
|
|
int nTab = (int)strlen(zTab)+1;
|
|
int eType = 0;
|
|
-
|
|
+
|
|
rc = fts5VocabTableType(zType, pzErr, &eType);
|
|
if( rc==SQLITE_OK ){
|
|
assert( eType>=0 && eType<ArraySize(azSchema) );
|
|
@@ -227609,7 +244356,7 @@ static int fts5VocabCreateMethod(
|
|
return fts5VocabInitVtab(db, pAux, argc, argv, ppVtab, pzErr);
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** Implementation of the xBestIndex method.
|
|
**
|
|
** Only constraints of the form:
|
|
@@ -227618,7 +244365,7 @@ static int fts5VocabCreateMethod(
|
|
** term == ?
|
|
** term >= ?
|
|
**
|
|
-** are interpreted. Less-than and less-than-or-equal are treated
|
|
+** are interpreted. Less-than and less-than-or-equal are treated
|
|
** identically, as are greater-than and greater-than-or-equal.
|
|
*/
|
|
static int fts5VocabBestIndexMethod(
|
|
@@ -227669,8 +244416,8 @@ static int fts5VocabBestIndexMethod(
|
|
** specifically - "ORDER BY term" or "ORDER BY term ASC" - set the
|
|
** sqlite3_index_info.orderByConsumed flag to tell the core the results
|
|
** are already in sorted order. */
|
|
- if( pInfo->nOrderBy==1
|
|
- && pInfo->aOrderBy[0].iColumn==0
|
|
+ if( pInfo->nOrderBy==1
|
|
+ && pInfo->aOrderBy[0].iColumn==0
|
|
&& pInfo->aOrderBy[0].desc==0
|
|
){
|
|
pInfo->orderByConsumed = 1;
|
|
@@ -227684,7 +244431,7 @@ static int fts5VocabBestIndexMethod(
|
|
** Implementation of xOpen method.
|
|
*/
|
|
static int fts5VocabOpenMethod(
|
|
- sqlite3_vtab *pVTab,
|
|
+ sqlite3_vtab *pVTab,
|
|
sqlite3_vtab_cursor **ppCsr
|
|
){
|
|
Fts5VocabTable *pTab = (Fts5VocabTable*)pVTab;
|
|
@@ -227694,6 +244441,12 @@ static int fts5VocabOpenMethod(
|
|
sqlite3_stmt *pStmt = 0;
|
|
char *zSql = 0;
|
|
|
|
+ if( pTab->bBusy ){
|
|
+ pVTab->zErrMsg = sqlite3_mprintf(
|
|
+ "recursive definition for %s.%s", pTab->zFts5Db, pTab->zFts5Tbl
|
|
+ );
|
|
+ return SQLITE_ERROR;
|
|
+ }
|
|
zSql = sqlite3Fts5Mprintf(&rc,
|
|
"SELECT t.%Q FROM %Q.%Q AS t WHERE t.%Q MATCH '*id'",
|
|
pTab->zFts5Tbl, pTab->zFts5Db, pTab->zFts5Tbl, pTab->zFts5Tbl
|
|
@@ -227705,10 +244458,12 @@ static int fts5VocabOpenMethod(
|
|
assert( rc==SQLITE_OK || pStmt==0 );
|
|
if( rc==SQLITE_ERROR ) rc = SQLITE_OK;
|
|
|
|
+ pTab->bBusy = 1;
|
|
if( pStmt && sqlite3_step(pStmt)==SQLITE_ROW ){
|
|
i64 iId = sqlite3_column_int64(pStmt, 0);
|
|
pFts5 = sqlite3Fts5TableFromCsrid(pTab->pGlobal, iId);
|
|
}
|
|
+ pTab->bBusy = 0;
|
|
|
|
if( rc==SQLITE_OK ){
|
|
if( pFts5==0 ){
|
|
@@ -227726,7 +244481,7 @@ static int fts5VocabOpenMethod(
|
|
}
|
|
|
|
if( rc==SQLITE_OK ){
|
|
- int nByte = pFts5->pConfig->nCol * sizeof(i64)*2 + sizeof(Fts5VocabCursor);
|
|
+ i64 nByte = pFts5->pConfig->nCol * sizeof(i64)*2 + sizeof(Fts5VocabCursor);
|
|
pCsr = (Fts5VocabCursor*)sqlite3Fts5MallocZero(&rc, nByte);
|
|
}
|
|
|
|
@@ -227746,6 +244501,8 @@ static int fts5VocabOpenMethod(
|
|
static void fts5VocabResetCursor(Fts5VocabCursor *pCsr){
|
|
pCsr->rowid = 0;
|
|
sqlite3Fts5IterClose(pCsr->pIter);
|
|
+ sqlite3Fts5StructureRelease(pCsr->pStruct);
|
|
+ pCsr->pStruct = 0;
|
|
pCsr->pIter = 0;
|
|
sqlite3_free(pCsr->zLeTerm);
|
|
pCsr->nLeTerm = -1;
|
|
@@ -227768,7 +244525,7 @@ static int fts5VocabCloseMethod(sqlite3_vtab_cursor *pCursor){
|
|
|
|
static int fts5VocabInstanceNewTerm(Fts5VocabCursor *pCsr){
|
|
int rc = SQLITE_OK;
|
|
-
|
|
+
|
|
if( sqlite3Fts5IterEof(pCsr->pIter) ){
|
|
pCsr->bEof = 1;
|
|
}else{
|
|
@@ -227794,11 +244551,11 @@ static int fts5VocabInstanceNext(Fts5VocabCursor *pCsr){
|
|
Fts5IndexIter *pIter = pCsr->pIter;
|
|
i64 *pp = &pCsr->iInstPos;
|
|
int *po = &pCsr->iInstOff;
|
|
-
|
|
+
|
|
assert( sqlite3Fts5IterEof(pIter)==0 );
|
|
assert( pCsr->bEof==0 );
|
|
while( eDetail==FTS5_DETAIL_NONE
|
|
- || sqlite3Fts5PoslistNext64(pIter->pData, pIter->nData, po, pp)
|
|
+ || sqlite3Fts5PoslistNext64(pIter->pData, pIter->nData, po, pp)
|
|
){
|
|
pCsr->iInstPos = 0;
|
|
pCsr->iInstOff = 0;
|
|
@@ -227823,9 +244580,11 @@ static int fts5VocabInstanceNext(Fts5VocabCursor *pCsr){
|
|
static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){
|
|
Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
|
|
Fts5VocabTable *pTab = (Fts5VocabTable*)pCursor->pVtab;
|
|
- int rc = SQLITE_OK;
|
|
int nCol = pCsr->pFts5->pConfig->nCol;
|
|
+ int rc;
|
|
|
|
+ rc = sqlite3Fts5StructureTest(pCsr->pFts5->pIndex, pCsr->pStruct);
|
|
+ if( rc!=SQLITE_OK ) return rc;
|
|
pCsr->rowid++;
|
|
|
|
if( pTab->eType==FTS5_VOCAB_INSTANCE ){
|
|
@@ -227923,8 +244682,8 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){
|
|
|
|
if( rc==SQLITE_OK ){
|
|
zTerm = sqlite3Fts5IterTerm(pCsr->pIter, &nTerm);
|
|
- if( nTerm!=pCsr->term.n
|
|
- || (nTerm>0 && memcmp(zTerm, pCsr->term.p, nTerm))
|
|
+ if( nTerm!=pCsr->term.n
|
|
+ || (nTerm>0 && memcmp(zTerm, pCsr->term.p, nTerm))
|
|
){
|
|
break;
|
|
}
|
|
@@ -227999,12 +244758,15 @@ static int fts5VocabFilterMethod(
|
|
if( rc==SQLITE_OK ){
|
|
Fts5Index *pIndex = pCsr->pFts5->pIndex;
|
|
rc = sqlite3Fts5IndexQuery(pIndex, zTerm, nTerm, f, 0, &pCsr->pIter);
|
|
+ if( rc==SQLITE_OK ){
|
|
+ pCsr->pStruct = sqlite3Fts5StructureRef(pIndex);
|
|
+ }
|
|
}
|
|
if( rc==SQLITE_OK && eType==FTS5_VOCAB_INSTANCE ){
|
|
rc = fts5VocabInstanceNewTerm(pCsr);
|
|
}
|
|
- if( rc==SQLITE_OK && !pCsr->bEof
|
|
- && (eType!=FTS5_VOCAB_INSTANCE
|
|
+ if( rc==SQLITE_OK && !pCsr->bEof
|
|
+ && (eType!=FTS5_VOCAB_INSTANCE
|
|
|| pCsr->pFts5->pConfig->eDetail!=FTS5_DETAIL_NONE)
|
|
){
|
|
rc = fts5VocabNextMethod(pCursor);
|
|
@@ -228013,8 +244775,8 @@ static int fts5VocabFilterMethod(
|
|
return rc;
|
|
}
|
|
|
|
-/*
|
|
-** This is the xEof method of the virtual table. SQLite calls this
|
|
+/*
|
|
+** This is the xEof method of the virtual table. SQLite calls this
|
|
** routine to find out if it has reached the end of a result set.
|
|
*/
|
|
static int fts5VocabEofMethod(sqlite3_vtab_cursor *pCursor){
|
|
@@ -228089,13 +244851,13 @@ static int fts5VocabColumnMethod(
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
-/*
|
|
+/*
|
|
** This is the xRowid method. The SQLite core calls this routine to
|
|
** retrieve the rowid for the current row of the result set. The
|
|
** rowid should be written to *pRowid.
|
|
*/
|
|
static int fts5VocabRowidMethod(
|
|
- sqlite3_vtab_cursor *pCursor,
|
|
+ sqlite3_vtab_cursor *pCursor,
|
|
sqlite_int64 *pRowid
|
|
){
|
|
Fts5VocabCursor *pCsr = (Fts5VocabCursor*)pCursor;
|
|
@@ -228136,7 +244898,7 @@ static int sqlite3Fts5VocabInit(Fts5Global *pGlobal, sqlite3 *db){
|
|
}
|
|
|
|
|
|
-
|
|
+
|
|
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS5) */
|
|
|
|
/************** End of fts5.c ************************************************/
|
|
@@ -228173,6 +244935,16 @@ SQLITE_EXTENSION_INIT1
|
|
|
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
|
|
|
+
|
|
+#define STMT_NUM_INTEGER_COLUMN 10
|
|
+typedef struct StmtRow StmtRow;
|
|
+struct StmtRow {
|
|
+ sqlite3_int64 iRowid; /* Rowid value */
|
|
+ char *zSql; /* column "sql" */
|
|
+ int aCol[STMT_NUM_INTEGER_COLUMN+1]; /* all other column values */
|
|
+ StmtRow *pNext; /* Next row to return */
|
|
+};
|
|
+
|
|
/* stmt_vtab is a subclass of sqlite3_vtab which will
|
|
** serve as the underlying representation of a stmt virtual table
|
|
*/
|
|
@@ -228190,8 +244962,7 @@ typedef struct stmt_cursor stmt_cursor;
|
|
struct stmt_cursor {
|
|
sqlite3_vtab_cursor base; /* Base class - must be first */
|
|
sqlite3 *db; /* Database connection for this cursor */
|
|
- sqlite3_stmt *pStmt; /* Statement cursor is currently pointing at */
|
|
- sqlite3_int64 iRowid; /* The rowid */
|
|
+ StmtRow *pRow; /* Current row */
|
|
};
|
|
|
|
/*
|
|
@@ -228231,11 +245002,15 @@ static int stmtConnect(
|
|
#define STMT_COLUMN_MEM 10 /* SQLITE_STMTSTATUS_MEMUSED */
|
|
|
|
|
|
+ (void)pAux;
|
|
+ (void)argc;
|
|
+ (void)argv;
|
|
+ (void)pzErr;
|
|
rc = sqlite3_declare_vtab(db,
|
|
"CREATE TABLE x(sql,ncol,ro,busy,nscan,nsort,naidx,nstep,"
|
|
"reprep,run,mem)");
|
|
if( rc==SQLITE_OK ){
|
|
- pNew = sqlite3_malloc( sizeof(*pNew) );
|
|
+ pNew = sqlite3_malloc64( sizeof(*pNew) );
|
|
*ppVtab = (sqlite3_vtab*)pNew;
|
|
if( pNew==0 ) return SQLITE_NOMEM;
|
|
memset(pNew, 0, sizeof(*pNew));
|
|
@@ -228257,7 +245032,7 @@ static int stmtDisconnect(sqlite3_vtab *pVtab){
|
|
*/
|
|
static int stmtOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
|
|
stmt_cursor *pCur;
|
|
- pCur = sqlite3_malloc( sizeof(*pCur) );
|
|
+ pCur = sqlite3_malloc64( sizeof(*pCur) );
|
|
if( pCur==0 ) return SQLITE_NOMEM;
|
|
memset(pCur, 0, sizeof(*pCur));
|
|
pCur->db = ((stmt_vtab*)p)->db;
|
|
@@ -228265,10 +245040,21 @@ static int stmtOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
+static void stmtCsrReset(stmt_cursor *pCur){
|
|
+ StmtRow *pRow = 0;
|
|
+ StmtRow *pNext = 0;
|
|
+ for(pRow=pCur->pRow; pRow; pRow=pNext){
|
|
+ pNext = pRow->pNext;
|
|
+ sqlite3_free(pRow);
|
|
+ }
|
|
+ pCur->pRow = 0;
|
|
+}
|
|
+
|
|
/*
|
|
** Destructor for a stmt_cursor.
|
|
*/
|
|
static int stmtClose(sqlite3_vtab_cursor *cur){
|
|
+ stmtCsrReset((stmt_cursor*)cur);
|
|
sqlite3_free(cur);
|
|
return SQLITE_OK;
|
|
}
|
|
@@ -228279,8 +245065,9 @@ static int stmtClose(sqlite3_vtab_cursor *cur){
|
|
*/
|
|
static int stmtNext(sqlite3_vtab_cursor *cur){
|
|
stmt_cursor *pCur = (stmt_cursor*)cur;
|
|
- pCur->iRowid++;
|
|
- pCur->pStmt = sqlite3_next_stmt(pCur->db, pCur->pStmt);
|
|
+ StmtRow *pNext = pCur->pRow->pNext;
|
|
+ sqlite3_free(pCur->pRow);
|
|
+ pCur->pRow = pNext;
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
@@ -228294,38 +245081,11 @@ static int stmtColumn(
|
|
int i /* Which column to return */
|
|
){
|
|
stmt_cursor *pCur = (stmt_cursor*)cur;
|
|
- switch( i ){
|
|
- case STMT_COLUMN_SQL: {
|
|
- sqlite3_result_text(ctx, sqlite3_sql(pCur->pStmt), -1, SQLITE_TRANSIENT);
|
|
- break;
|
|
- }
|
|
- case STMT_COLUMN_NCOL: {
|
|
- sqlite3_result_int(ctx, sqlite3_column_count(pCur->pStmt));
|
|
- break;
|
|
- }
|
|
- case STMT_COLUMN_RO: {
|
|
- sqlite3_result_int(ctx, sqlite3_stmt_readonly(pCur->pStmt));
|
|
- break;
|
|
- }
|
|
- case STMT_COLUMN_BUSY: {
|
|
- sqlite3_result_int(ctx, sqlite3_stmt_busy(pCur->pStmt));
|
|
- break;
|
|
- }
|
|
- case STMT_COLUMN_MEM: {
|
|
- i = SQLITE_STMTSTATUS_MEMUSED +
|
|
- STMT_COLUMN_NSCAN - SQLITE_STMTSTATUS_FULLSCAN_STEP;
|
|
- /* Fall thru */
|
|
- }
|
|
- case STMT_COLUMN_NSCAN:
|
|
- case STMT_COLUMN_NSORT:
|
|
- case STMT_COLUMN_NAIDX:
|
|
- case STMT_COLUMN_NSTEP:
|
|
- case STMT_COLUMN_REPREP:
|
|
- case STMT_COLUMN_RUN: {
|
|
- sqlite3_result_int(ctx, sqlite3_stmt_status(pCur->pStmt,
|
|
- i-STMT_COLUMN_NSCAN+SQLITE_STMTSTATUS_FULLSCAN_STEP, 0));
|
|
- break;
|
|
- }
|
|
+ StmtRow *pRow = pCur->pRow;
|
|
+ if( i==STMT_COLUMN_SQL ){
|
|
+ sqlite3_result_text(ctx, pRow->zSql, -1, SQLITE_TRANSIENT);
|
|
+ }else{
|
|
+ sqlite3_result_int(ctx, pRow->aCol[i]);
|
|
}
|
|
return SQLITE_OK;
|
|
}
|
|
@@ -228336,7 +245096,7 @@ static int stmtColumn(
|
|
*/
|
|
static int stmtRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
|
|
stmt_cursor *pCur = (stmt_cursor*)cur;
|
|
- *pRowid = pCur->iRowid;
|
|
+ *pRowid = pCur->pRow->iRowid;
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
@@ -228346,24 +245106,72 @@ static int stmtRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
|
|
*/
|
|
static int stmtEof(sqlite3_vtab_cursor *cur){
|
|
stmt_cursor *pCur = (stmt_cursor*)cur;
|
|
- return pCur->pStmt==0;
|
|
+ return pCur->pRow==0;
|
|
}
|
|
|
|
/*
|
|
** This method is called to "rewind" the stmt_cursor object back
|
|
** to the first row of output. This method is always called at least
|
|
-** once prior to any call to stmtColumn() or stmtRowid() or
|
|
+** once prior to any call to stmtColumn() or stmtRowid() or
|
|
** stmtEof().
|
|
*/
|
|
static int stmtFilter(
|
|
- sqlite3_vtab_cursor *pVtabCursor,
|
|
+ sqlite3_vtab_cursor *pVtabCursor,
|
|
int idxNum, const char *idxStr,
|
|
int argc, sqlite3_value **argv
|
|
){
|
|
stmt_cursor *pCur = (stmt_cursor *)pVtabCursor;
|
|
- pCur->pStmt = 0;
|
|
- pCur->iRowid = 0;
|
|
- return stmtNext(pVtabCursor);
|
|
+ sqlite3_stmt *p = 0;
|
|
+ sqlite3_int64 iRowid = 1;
|
|
+ StmtRow **ppRow = 0;
|
|
+
|
|
+ (void)idxNum;
|
|
+ (void)idxStr;
|
|
+ (void)argc;
|
|
+ (void)argv;
|
|
+ stmtCsrReset(pCur);
|
|
+ ppRow = &pCur->pRow;
|
|
+ for(p=sqlite3_next_stmt(pCur->db, 0); p; p=sqlite3_next_stmt(pCur->db, p)){
|
|
+ const char *zSql = sqlite3_sql(p);
|
|
+ sqlite3_int64 nSql = zSql ? strlen(zSql)+1 : 0;
|
|
+ StmtRow *pNew = (StmtRow*)sqlite3_malloc64(sizeof(StmtRow) + nSql);
|
|
+
|
|
+ if( pNew==0 ) return SQLITE_NOMEM;
|
|
+ memset(pNew, 0, sizeof(StmtRow));
|
|
+ if( zSql ){
|
|
+ pNew->zSql = (char*)&pNew[1];
|
|
+ memcpy(pNew->zSql, zSql, nSql);
|
|
+ }
|
|
+ pNew->aCol[STMT_COLUMN_NCOL] = sqlite3_column_count(p);
|
|
+ pNew->aCol[STMT_COLUMN_RO] = sqlite3_stmt_readonly(p);
|
|
+ pNew->aCol[STMT_COLUMN_BUSY] = sqlite3_stmt_busy(p);
|
|
+ pNew->aCol[STMT_COLUMN_NSCAN] = sqlite3_stmt_status(
|
|
+ p, SQLITE_STMTSTATUS_FULLSCAN_STEP, 0
|
|
+ );
|
|
+ pNew->aCol[STMT_COLUMN_NSORT] = sqlite3_stmt_status(
|
|
+ p, SQLITE_STMTSTATUS_SORT, 0
|
|
+ );
|
|
+ pNew->aCol[STMT_COLUMN_NAIDX] = sqlite3_stmt_status(
|
|
+ p, SQLITE_STMTSTATUS_AUTOINDEX, 0
|
|
+ );
|
|
+ pNew->aCol[STMT_COLUMN_NSTEP] = sqlite3_stmt_status(
|
|
+ p, SQLITE_STMTSTATUS_VM_STEP, 0
|
|
+ );
|
|
+ pNew->aCol[STMT_COLUMN_REPREP] = sqlite3_stmt_status(
|
|
+ p, SQLITE_STMTSTATUS_REPREPARE, 0
|
|
+ );
|
|
+ pNew->aCol[STMT_COLUMN_RUN] = sqlite3_stmt_status(
|
|
+ p, SQLITE_STMTSTATUS_RUN, 0
|
|
+ );
|
|
+ pNew->aCol[STMT_COLUMN_MEM] = sqlite3_stmt_status(
|
|
+ p, SQLITE_STMTSTATUS_MEMUSED, 0
|
|
+ );
|
|
+ pNew->iRowid = iRowid++;
|
|
+ *ppRow = pNew;
|
|
+ ppRow = &pNew->pNext;
|
|
+ }
|
|
+
|
|
+ return SQLITE_OK;
|
|
}
|
|
|
|
/*
|
|
@@ -228376,13 +245184,14 @@ static int stmtBestIndex(
|
|
sqlite3_vtab *tab,
|
|
sqlite3_index_info *pIdxInfo
|
|
){
|
|
+ (void)tab;
|
|
pIdxInfo->estimatedCost = (double)500;
|
|
pIdxInfo->estimatedRows = 500;
|
|
return SQLITE_OK;
|
|
}
|
|
|
|
/*
|
|
-** This following structure defines all the methods for the
|
|
+** This following structure defines all the methods for the
|
|
** stmt virtual table.
|
|
*/
|
|
static sqlite3_module stmtModule = {
|
|
@@ -228427,8 +245236,8 @@ SQLITE_PRIVATE int sqlite3StmtVtabInit(sqlite3 *db){
|
|
__declspec(dllexport)
|
|
#endif
|
|
SQLITE_API int sqlite3_stmt_init(
|
|
- sqlite3 *db,
|
|
- char **pzErrMsg,
|
|
+ sqlite3 *db,
|
|
+ char **pzErrMsg,
|
|
const sqlite3_api_routines *pApi
|
|
){
|
|
int rc = SQLITE_OK;
|
|
@@ -228442,10 +245251,6 @@ SQLITE_API int sqlite3_stmt_init(
|
|
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */
|
|
|
|
/************** End of stmt.c ************************************************/
|
|
-#if __LINE__!=228443
|
|
-#undef SQLITE_SOURCE_ID
|
|
-#define SQLITE_SOURCE_ID "2020-01-27 19:55:54 3bfa9cc97da10598521b342961df8f5f68c7388fa117345eeb516eaa837balt2"
|
|
-#endif
|
|
/* Return the source-id for this library */
|
|
SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; }
|
|
/************************** End of sqlite3.c ******************************/
|
|
|
|
From c9dacc1278d5741949cfba2cd8f2885ee2245733 Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?H=C3=A5kon=20Harnes?= <hakon@harnes.dev>
|
|
Date: Sun, 16 Apr 2023 16:30:08 +0200
|
|
Subject: [PATCH 3/3] update sqlite header files
|
|
|
|
---
|
|
pdf_viewer/sqlite3.h | 2700 ++++++++++++++++++++++++++-------------
|
|
pdf_viewer/sqlite3ext.h | 59 +
|
|
2 files changed, 1852 insertions(+), 907 deletions(-)
|
|
|
|
diff --git a/pdf_viewer/sqlite3.h b/pdf_viewer/sqlite3.h
|
|
index cef6eea18..7e43e1f1b 100644
|
|
--- a/pdf_viewer/sqlite3.h
|
|
+++ b/pdf_viewer/sqlite3.h
|
|
@@ -43,7 +43,30 @@ extern "C" {
|
|
|
|
|
|
/*
|
|
-** Provide the ability to override linkage features of the interface.
|
|
+** Facilitate override of interface linkage and calling conventions.
|
|
+** Be aware that these macros may not be used within this particular
|
|
+** translation of the amalgamation and its associated header file.
|
|
+**
|
|
+** The SQLITE_EXTERN and SQLITE_API macros are used to instruct the
|
|
+** compiler that the target identifier should have external linkage.
|
|
+**
|
|
+** The SQLITE_CDECL macro is used to set the calling convention for
|
|
+** public functions that accept a variable number of arguments.
|
|
+**
|
|
+** The SQLITE_APICALL macro is used to set the calling convention for
|
|
+** public functions that accept a fixed number of arguments.
|
|
+**
|
|
+** The SQLITE_STDCALL macro is no longer used and is now deprecated.
|
|
+**
|
|
+** The SQLITE_CALLBACK macro is used to set the calling convention for
|
|
+** function pointers.
|
|
+**
|
|
+** The SQLITE_SYSAPI macro is used to set the calling convention for
|
|
+** functions provided by the operating system.
|
|
+**
|
|
+** Currently, the SQLITE_CDECL, SQLITE_APICALL, SQLITE_CALLBACK, and
|
|
+** SQLITE_SYSAPI macros are used only when building for environments
|
|
+** that require non-default calling conventions.
|
|
*/
|
|
#ifndef SQLITE_EXTERN
|
|
# define SQLITE_EXTERN extern
|
|
@@ -108,7 +131,7 @@ extern "C" {
|
|
** be held constant and Z will be incremented or else Y will be incremented
|
|
** and Z will be reset to zero.
|
|
**
|
|
-** Since [version 3.6.18] ([dateof:3.6.18]),
|
|
+** Since [version 3.6.18] ([dateof:3.6.18]),
|
|
** SQLite source code has been stored in the
|
|
** <a href="http://www.fossil-scm.org/">Fossil configuration management
|
|
** system</a>. ^The SQLITE_SOURCE_ID macro evaluates to
|
|
@@ -123,9 +146,9 @@ extern "C" {
|
|
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
|
|
** [sqlite_version()] and [sqlite_source_id()].
|
|
*/
|
|
-#define SQLITE_VERSION "3.31.1"
|
|
-#define SQLITE_VERSION_NUMBER 3031001
|
|
-#define SQLITE_SOURCE_ID "2020-01-27 19:55:54 3bfa9cc97da10598521b342961df8f5f68c7388fa117345eeb516eaa837bb4d6"
|
|
+#define SQLITE_VERSION "3.41.2"
|
|
+#define SQLITE_VERSION_NUMBER 3041002
|
|
+#define SQLITE_SOURCE_ID "2023-03-22 11:56:21 0d1fc92f94cb6b76bffe3ec34d69cffde2924203304e8ffc4155597af0c191da"
|
|
|
|
/*
|
|
** CAPI3REF: Run-Time Library Version Numbers
|
|
@@ -151,8 +174,8 @@ extern "C" {
|
|
** function is provided for use in DLLs since DLL users usually do not have
|
|
** direct access to string constants within the DLL. ^The
|
|
** sqlite3_libversion_number() function returns an integer equal to
|
|
-** [SQLITE_VERSION_NUMBER]. ^(The sqlite3_sourceid() function returns
|
|
-** a pointer to a string constant whose value is the same as the
|
|
+** [SQLITE_VERSION_NUMBER]. ^(The sqlite3_sourceid() function returns
|
|
+** a pointer to a string constant whose value is the same as the
|
|
** [SQLITE_SOURCE_ID] C preprocessor macro. Except if SQLite is built
|
|
** using an edited copy of [the amalgamation], then the last four characters
|
|
** of the hash might be different from [SQLITE_SOURCE_ID].)^
|
|
@@ -167,20 +190,20 @@ SQLITE_API int sqlite3_libversion_number(void);
|
|
/*
|
|
** CAPI3REF: Run-Time Library Compilation Options Diagnostics
|
|
**
|
|
-** ^The sqlite3_compileoption_used() function returns 0 or 1
|
|
-** indicating whether the specified option was defined at
|
|
-** compile time. ^The SQLITE_ prefix may be omitted from the
|
|
-** option name passed to sqlite3_compileoption_used().
|
|
+** ^The sqlite3_compileoption_used() function returns 0 or 1
|
|
+** indicating whether the specified option was defined at
|
|
+** compile time. ^The SQLITE_ prefix may be omitted from the
|
|
+** option name passed to sqlite3_compileoption_used().
|
|
**
|
|
** ^The sqlite3_compileoption_get() function allows iterating
|
|
** over the list of options that were defined at compile time by
|
|
** returning the N-th compile time option string. ^If N is out of range,
|
|
-** sqlite3_compileoption_get() returns a NULL pointer. ^The SQLITE_
|
|
-** prefix is omitted from any strings returned by
|
|
+** sqlite3_compileoption_get() returns a NULL pointer. ^The SQLITE_
|
|
+** prefix is omitted from any strings returned by
|
|
** sqlite3_compileoption_get().
|
|
**
|
|
** ^Support for the diagnostic functions sqlite3_compileoption_used()
|
|
-** and sqlite3_compileoption_get() may be omitted by specifying the
|
|
+** and sqlite3_compileoption_get() may be omitted by specifying the
|
|
** [SQLITE_OMIT_COMPILEOPTION_DIAGS] option at compile time.
|
|
**
|
|
** See also: SQL functions [sqlite_compileoption_used()] and
|
|
@@ -204,7 +227,7 @@ SQLITE_API const char *sqlite3_compileoption_get(int N);
|
|
** SQLite can be compiled with or without mutexes. When
|
|
** the [SQLITE_THREADSAFE] C preprocessor macro is 1 or 2, mutexes
|
|
** are enabled and SQLite is threadsafe. When the
|
|
-** [SQLITE_THREADSAFE] macro is 0,
|
|
+** [SQLITE_THREADSAFE] macro is 0,
|
|
** the mutexes are omitted. Without the mutexes, it is not safe
|
|
** to use SQLite concurrently from more than one thread.
|
|
**
|
|
@@ -261,14 +284,14 @@ typedef struct sqlite3 sqlite3;
|
|
**
|
|
** ^The sqlite3_int64 and sqlite_int64 types can store integer values
|
|
** between -9223372036854775808 and +9223372036854775807 inclusive. ^The
|
|
-** sqlite3_uint64 and sqlite_uint64 types can store integer values
|
|
+** sqlite3_uint64 and sqlite_uint64 types can store integer values
|
|
** between 0 and +18446744073709551615 inclusive.
|
|
*/
|
|
#ifdef SQLITE_INT64_TYPE
|
|
typedef SQLITE_INT64_TYPE sqlite_int64;
|
|
# ifdef SQLITE_UINT64_TYPE
|
|
typedef SQLITE_UINT64_TYPE sqlite_uint64;
|
|
-# else
|
|
+# else
|
|
typedef unsigned SQLITE_INT64_TYPE sqlite_uint64;
|
|
# endif
|
|
#elif defined(_MSC_VER) || defined(__BORLANDC__)
|
|
@@ -299,26 +322,22 @@ typedef sqlite_uint64 sqlite3_uint64;
|
|
** the [sqlite3] object is successfully destroyed and all associated
|
|
** resources are deallocated.
|
|
**
|
|
-** ^If the database connection is associated with unfinalized prepared
|
|
-** statements or unfinished sqlite3_backup objects then sqlite3_close()
|
|
-** will leave the database connection open and return [SQLITE_BUSY].
|
|
-** ^If sqlite3_close_v2() is called with unfinalized prepared statements
|
|
-** and/or unfinished sqlite3_backups, then the database connection becomes
|
|
-** an unusable "zombie" which will automatically be deallocated when the
|
|
-** last prepared statement is finalized or the last sqlite3_backup is
|
|
-** finished. The sqlite3_close_v2() interface is intended for use with
|
|
-** host languages that are garbage collected, and where the order in which
|
|
-** destructors are called is arbitrary.
|
|
-**
|
|
-** Applications should [sqlite3_finalize | finalize] all [prepared statements],
|
|
-** [sqlite3_blob_close | close] all [BLOB handles], and
|
|
+** Ideally, applications should [sqlite3_finalize | finalize] all
|
|
+** [prepared statements], [sqlite3_blob_close | close] all [BLOB handles], and
|
|
** [sqlite3_backup_finish | finish] all [sqlite3_backup] objects associated
|
|
-** with the [sqlite3] object prior to attempting to close the object. ^If
|
|
-** sqlite3_close_v2() is called on a [database connection] that still has
|
|
-** outstanding [prepared statements], [BLOB handles], and/or
|
|
-** [sqlite3_backup] objects then it returns [SQLITE_OK] and the deallocation
|
|
-** of resources is deferred until all [prepared statements], [BLOB handles],
|
|
-** and [sqlite3_backup] objects are also destroyed.
|
|
+** with the [sqlite3] object prior to attempting to close the object.
|
|
+** ^If the database connection is associated with unfinalized prepared
|
|
+** statements, BLOB handlers, and/or unfinished sqlite3_backup objects then
|
|
+** sqlite3_close() will leave the database connection open and return
|
|
+** [SQLITE_BUSY]. ^If sqlite3_close_v2() is called with unfinalized prepared
|
|
+** statements, unclosed BLOB handlers, and/or unfinished sqlite3_backups,
|
|
+** it returns [SQLITE_OK] regardless, but instead of deallocating the database
|
|
+** connection immediately, it marks the database connection as an unusable
|
|
+** "zombie" and makes arrangements to automatically deallocate the database
|
|
+** connection after all prepared statements are finalized, all BLOB handles
|
|
+** are closed, and all backups have finished. The sqlite3_close_v2() interface
|
|
+** is intended for use with host languages that are garbage collected, and
|
|
+** where the order in which destructors are called is arbitrary.
|
|
**
|
|
** ^If an [sqlite3] object is destroyed while a transaction is open,
|
|
** the transaction is automatically rolled back.
|
|
@@ -348,7 +367,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
|
|
** The sqlite3_exec() interface is a convenience wrapper around
|
|
** [sqlite3_prepare_v2()], [sqlite3_step()], and [sqlite3_finalize()],
|
|
** that allows an application to run multiple statements of SQL
|
|
-** without having to use a lot of C code.
|
|
+** without having to use a lot of C code.
|
|
**
|
|
** ^The sqlite3_exec() interface runs zero or more UTF-8 encoded,
|
|
** semicolon-separate SQL statements passed into its 2nd argument,
|
|
@@ -388,7 +407,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
|
|
** from [sqlite3_column_name()].
|
|
**
|
|
** ^If the 2nd parameter to sqlite3_exec() is a NULL pointer, a pointer
|
|
-** to an empty string, or a pointer that contains only whitespace and/or
|
|
+** to an empty string, or a pointer that contains only whitespace and/or
|
|
** SQL comments, then no SQL statements are evaluated and the database
|
|
** is not changed.
|
|
**
|
|
@@ -507,10 +526,13 @@ SQLITE_API int sqlite3_exec(
|
|
#define SQLITE_IOERR_BEGIN_ATOMIC (SQLITE_IOERR | (29<<8))
|
|
#define SQLITE_IOERR_COMMIT_ATOMIC (SQLITE_IOERR | (30<<8))
|
|
#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_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
|
|
#define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8))
|
|
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
|
|
#define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8))
|
|
+#define SQLITE_BUSY_TIMEOUT (SQLITE_BUSY | (3<<8))
|
|
#define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8))
|
|
#define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8))
|
|
#define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8))
|
|
@@ -519,6 +541,7 @@ SQLITE_API int sqlite3_exec(
|
|
#define SQLITE_CANTOPEN_SYMLINK (SQLITE_CANTOPEN | (6<<8))
|
|
#define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8))
|
|
#define SQLITE_CORRUPT_SEQUENCE (SQLITE_CORRUPT | (2<<8))
|
|
+#define SQLITE_CORRUPT_INDEX (SQLITE_CORRUPT | (3<<8))
|
|
#define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8))
|
|
#define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8))
|
|
#define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8))
|
|
@@ -537,12 +560,14 @@ SQLITE_API int sqlite3_exec(
|
|
#define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9<<8))
|
|
#define SQLITE_CONSTRAINT_ROWID (SQLITE_CONSTRAINT |(10<<8))
|
|
#define SQLITE_CONSTRAINT_PINNED (SQLITE_CONSTRAINT |(11<<8))
|
|
+#define SQLITE_CONSTRAINT_DATATYPE (SQLITE_CONSTRAINT |(12<<8))
|
|
#define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8))
|
|
#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8))
|
|
+#define SQLITE_NOTICE_RBU (SQLITE_NOTICE | (3<<8))
|
|
#define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8))
|
|
#define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8))
|
|
#define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1<<8))
|
|
-#define SQLITE_OK_SYMLINK (SQLITE_OK | (2<<8))
|
|
+#define SQLITE_OK_SYMLINK (SQLITE_OK | (2<<8)) /* internal use only */
|
|
|
|
/*
|
|
** CAPI3REF: Flags For File Open Operations
|
|
@@ -550,6 +575,19 @@ SQLITE_API int sqlite3_exec(
|
|
** These bit values are intended for use in the
|
|
** 3rd parameter to the [sqlite3_open_v2()] interface and
|
|
** in the 4th parameter to the [sqlite3_vfs.xOpen] method.
|
|
+**
|
|
+** Only those flags marked as "Ok for sqlite3_open_v2()" may be
|
|
+** used as the third argument to the [sqlite3_open_v2()] interface.
|
|
+** The other flags have historically been ignored by sqlite3_open_v2(),
|
|
+** though future versions of SQLite might change so that an error is
|
|
+** raised if any of the disallowed bits are passed into sqlite3_open_v2().
|
|
+** Applications should not depend on the historical behavior.
|
|
+**
|
|
+** Note in particular that passing the SQLITE_OPEN_EXCLUSIVE flag into
|
|
+** [sqlite3_open_v2()] does *not* cause the underlying database file
|
|
+** to be opened using O_EXCL. Passing SQLITE_OPEN_EXCLUSIVE into
|
|
+** [sqlite3_open_v2()] has historically be a no-op and might become an
|
|
+** error in future versions of SQLite.
|
|
*/
|
|
#define SQLITE_OPEN_READONLY 0x00000001 /* Ok for sqlite3_open_v2() */
|
|
#define SQLITE_OPEN_READWRITE 0x00000002 /* Ok for sqlite3_open_v2() */
|
|
@@ -565,15 +603,19 @@ SQLITE_API int sqlite3_exec(
|
|
#define SQLITE_OPEN_MAIN_JOURNAL 0x00000800 /* VFS only */
|
|
#define SQLITE_OPEN_TEMP_JOURNAL 0x00001000 /* VFS only */
|
|
#define SQLITE_OPEN_SUBJOURNAL 0x00002000 /* VFS only */
|
|
-#define SQLITE_OPEN_MASTER_JOURNAL 0x00004000 /* VFS only */
|
|
+#define SQLITE_OPEN_SUPER_JOURNAL 0x00004000 /* VFS only */
|
|
#define SQLITE_OPEN_NOMUTEX 0x00008000 /* Ok for sqlite3_open_v2() */
|
|
#define SQLITE_OPEN_FULLMUTEX 0x00010000 /* Ok for sqlite3_open_v2() */
|
|
#define SQLITE_OPEN_SHAREDCACHE 0x00020000 /* Ok for sqlite3_open_v2() */
|
|
#define SQLITE_OPEN_PRIVATECACHE 0x00040000 /* Ok for sqlite3_open_v2() */
|
|
#define SQLITE_OPEN_WAL 0x00080000 /* VFS only */
|
|
#define SQLITE_OPEN_NOFOLLOW 0x01000000 /* Ok for sqlite3_open_v2() */
|
|
+#define SQLITE_OPEN_EXRESCODE 0x02000000 /* Extended result codes */
|
|
|
|
/* Reserved: 0x00F00000 */
|
|
+/* Legacy compatibility: */
|
|
+#define SQLITE_OPEN_MASTER_JOURNAL 0x00004000 /* VFS only */
|
|
+
|
|
|
|
/*
|
|
** CAPI3REF: Device Characteristics
|
|
@@ -629,13 +671,17 @@ SQLITE_API int sqlite3_exec(
|
|
**
|
|
** SQLite uses one of these integer values as the second
|
|
** argument to calls it makes to the xLock() and xUnlock() methods
|
|
-** of an [sqlite3_io_methods] object.
|
|
+** of an [sqlite3_io_methods] object. These values are ordered from
|
|
+** lest restrictive to most restrictive.
|
|
+**
|
|
+** The argument to xLock() is always SHARED or higher. The argument to
|
|
+** xUnlock is either SHARED or NONE.
|
|
*/
|
|
-#define SQLITE_LOCK_NONE 0
|
|
-#define SQLITE_LOCK_SHARED 1
|
|
-#define SQLITE_LOCK_RESERVED 2
|
|
-#define SQLITE_LOCK_PENDING 3
|
|
-#define SQLITE_LOCK_EXCLUSIVE 4
|
|
+#define SQLITE_LOCK_NONE 0 /* xUnlock() only */
|
|
+#define SQLITE_LOCK_SHARED 1 /* xLock() or xUnlock() */
|
|
+#define SQLITE_LOCK_RESERVED 2 /* xLock() only */
|
|
+#define SQLITE_LOCK_PENDING 3 /* xLock() only */
|
|
+#define SQLITE_LOCK_EXCLUSIVE 4 /* xLock() only */
|
|
|
|
/*
|
|
** CAPI3REF: Synchronization Type Flags
|
|
@@ -670,7 +716,7 @@ SQLITE_API int sqlite3_exec(
|
|
/*
|
|
** CAPI3REF: OS Interface Open File Handle
|
|
**
|
|
-** An [sqlite3_file] object represents an open file in the
|
|
+** An [sqlite3_file] object represents an open file in the
|
|
** [sqlite3_vfs | OS interface layer]. Individual OS interface
|
|
** implementations will
|
|
** want to subclass this object by appending additional fields
|
|
@@ -692,7 +738,7 @@ struct sqlite3_file {
|
|
** This object defines the methods used to perform various operations
|
|
** against the open file represented by the [sqlite3_file] object.
|
|
**
|
|
-** If the [sqlite3_vfs.xOpen] method sets the sqlite3_file.pMethods element
|
|
+** If the [sqlite3_vfs.xOpen] method sets the sqlite3_file.pMethods element
|
|
** to a non-NULL pointer, then the sqlite3_io_methods.xClose method
|
|
** may be invoked even if the [sqlite3_vfs.xOpen] reported that it failed. The
|
|
** only way to prevent a call to xClose following a failed [sqlite3_vfs.xOpen]
|
|
@@ -713,7 +759,14 @@ struct sqlite3_file {
|
|
** <li> [SQLITE_LOCK_PENDING], or
|
|
** <li> [SQLITE_LOCK_EXCLUSIVE].
|
|
** </ul>
|
|
-** xLock() increases the lock. xUnlock() decreases the lock.
|
|
+** xLock() upgrades the database file lock. In other words, xLock() moves the
|
|
+** database file lock in the direction NONE toward EXCLUSIVE. The argument to
|
|
+** xLock() is always on of SHARED, RESERVED, PENDING, or EXCLUSIVE, never
|
|
+** SQLITE_LOCK_NONE. If the database file lock is already at or above the
|
|
+** requested lock, then the call to xLock() is a no-op.
|
|
+** xUnlock() downgrades the database file lock to either SHARED or NONE.
|
|
+* If the lock is already at or below the requested lock state, then the call
|
|
+** to xUnlock() is a no-op.
|
|
** The xCheckReservedLock() method checks whether any database connection,
|
|
** either in this process or in some other process, is holding a RESERVED,
|
|
** PENDING, or EXCLUSIVE lock on the file. It returns true
|
|
@@ -818,9 +871,8 @@ struct sqlite3_io_methods {
|
|
** opcode causes the xFileControl method to write the current state of
|
|
** the lock (one of [SQLITE_LOCK_NONE], [SQLITE_LOCK_SHARED],
|
|
** [SQLITE_LOCK_RESERVED], [SQLITE_LOCK_PENDING], or [SQLITE_LOCK_EXCLUSIVE])
|
|
-** into an integer that the pArg argument points to. This capability
|
|
-** is used during testing and is only available when the SQLITE_TEST
|
|
-** compile-time option is used.
|
|
+** into an integer that the pArg argument points to.
|
|
+** This capability is only available if SQLite is compiled with [SQLITE_DEBUG].
|
|
**
|
|
** <li>[[SQLITE_FCNTL_SIZE_HINT]]
|
|
** The [SQLITE_FCNTL_SIZE_HINT] opcode is used by SQLite to give the VFS
|
|
@@ -842,7 +894,7 @@ struct sqlite3_io_methods {
|
|
** <li>[[SQLITE_FCNTL_CHUNK_SIZE]]
|
|
** The [SQLITE_FCNTL_CHUNK_SIZE] opcode is used to request that the VFS
|
|
** extends and truncates the database file in chunks of a size specified
|
|
-** by the user. The fourth argument to [sqlite3_file_control()] should
|
|
+** by the user. The fourth argument to [sqlite3_file_control()] should
|
|
** point to an integer (type int) containing the new chunk-size to use
|
|
** for the nominated database. Allocating database file space in large
|
|
** chunks (say 1MB at a time), may reduce file-system fragmentation and
|
|
@@ -865,24 +917,24 @@ struct sqlite3_io_methods {
|
|
** <li>[[SQLITE_FCNTL_SYNC]]
|
|
** The [SQLITE_FCNTL_SYNC] opcode is generated internally by SQLite and
|
|
** sent to the VFS immediately before the xSync method is invoked on a
|
|
-** database file descriptor. Or, if the xSync method is not invoked
|
|
-** because the user has configured SQLite with
|
|
-** [PRAGMA synchronous | PRAGMA synchronous=OFF] it is invoked in place
|
|
+** database file descriptor. Or, if the xSync method is not invoked
|
|
+** because the user has configured SQLite with
|
|
+** [PRAGMA synchronous | PRAGMA synchronous=OFF] it is invoked in place
|
|
** of the xSync method. In most cases, the pointer argument passed with
|
|
** this file-control is NULL. However, if the database file is being synced
|
|
** as part of a multi-database commit, the argument points to a nul-terminated
|
|
-** string containing the transactions master-journal file name. VFSes that
|
|
-** do not need this signal should silently ignore this opcode. Applications
|
|
-** should not call [sqlite3_file_control()] with this opcode as doing so may
|
|
-** disrupt the operation of the specialized VFSes that do require it.
|
|
+** string containing the transactions super-journal file name. VFSes that
|
|
+** do not need this signal should silently ignore this opcode. Applications
|
|
+** should not call [sqlite3_file_control()] with this opcode as doing so may
|
|
+** disrupt the operation of the specialized VFSes that do require it.
|
|
**
|
|
** <li>[[SQLITE_FCNTL_COMMIT_PHASETWO]]
|
|
** The [SQLITE_FCNTL_COMMIT_PHASETWO] opcode is generated internally by SQLite
|
|
** and sent to the VFS after a transaction has been committed immediately
|
|
** but before the database is unlocked. VFSes that do not need this signal
|
|
** should silently ignore this opcode. Applications should not call
|
|
-** [sqlite3_file_control()] with this opcode as doing so may disrupt the
|
|
-** operation of the specialized VFSes that do require it.
|
|
+** [sqlite3_file_control()] with this opcode as doing so may disrupt the
|
|
+** operation of the specialized VFSes that do require it.
|
|
**
|
|
** <li>[[SQLITE_FCNTL_WIN32_AV_RETRY]]
|
|
** ^The [SQLITE_FCNTL_WIN32_AV_RETRY] opcode is used to configure automatic
|
|
@@ -930,13 +982,13 @@ struct sqlite3_io_methods {
|
|
** <li>[[SQLITE_FCNTL_OVERWRITE]]
|
|
** ^The [SQLITE_FCNTL_OVERWRITE] opcode is invoked by SQLite after opening
|
|
** a write transaction to indicate that, unless it is rolled back for some
|
|
-** reason, the entire database file will be overwritten by the current
|
|
+** reason, the entire database file will be overwritten by the current
|
|
** transaction. This is used by VACUUM operations.
|
|
**
|
|
** <li>[[SQLITE_FCNTL_VFSNAME]]
|
|
** ^The [SQLITE_FCNTL_VFSNAME] opcode can be used to obtain the names of
|
|
** all [VFSes] in the VFS stack. The names are of all VFS shims and the
|
|
-** final bottom-level VFS are written into memory obtained from
|
|
+** final bottom-level VFS are written into memory obtained from
|
|
** [sqlite3_malloc()] and the result is stored in the char* variable
|
|
** that the fourth parameter of [sqlite3_file_control()] points to.
|
|
** The caller is responsible for freeing the memory when done. As with
|
|
@@ -955,7 +1007,7 @@ struct sqlite3_io_methods {
|
|
** upper-most shim only.
|
|
**
|
|
** <li>[[SQLITE_FCNTL_PRAGMA]]
|
|
-** ^Whenever a [PRAGMA] statement is parsed, an [SQLITE_FCNTL_PRAGMA]
|
|
+** ^Whenever a [PRAGMA] statement is parsed, an [SQLITE_FCNTL_PRAGMA]
|
|
** file control is sent to the open [sqlite3_file] object corresponding
|
|
** to the database file to which the pragma statement refers. ^The argument
|
|
** to the [SQLITE_FCNTL_PRAGMA] file control is an array of
|
|
@@ -966,7 +1018,7 @@ struct sqlite3_io_methods {
|
|
** of the char** argument point to a string obtained from [sqlite3_mprintf()]
|
|
** or the equivalent and that string will become the result of the pragma or
|
|
** the error message if the pragma fails. ^If the
|
|
-** [SQLITE_FCNTL_PRAGMA] file control returns [SQLITE_NOTFOUND], then normal
|
|
+** [SQLITE_FCNTL_PRAGMA] file control returns [SQLITE_NOTFOUND], then normal
|
|
** [PRAGMA] processing continues. ^If the [SQLITE_FCNTL_PRAGMA]
|
|
** file control returns [SQLITE_OK], then the parser assumes that the
|
|
** VFS has handled the PRAGMA itself and the parser generates a no-op
|
|
@@ -1006,7 +1058,7 @@ struct sqlite3_io_methods {
|
|
** The argument is a pointer to a value of type sqlite3_int64 that
|
|
** is an advisory maximum number of bytes in the file to memory map. The
|
|
** pointer is overwritten with the old value. The limit is not changed if
|
|
-** the value originally pointed to is negative, and so the current limit
|
|
+** the value originally pointed to is negative, and so the current limit
|
|
** can be queried by passing in a pointer to a negative number. This
|
|
** file-control is used internally to implement [PRAGMA mmap_size].
|
|
**
|
|
@@ -1050,7 +1102,7 @@ struct sqlite3_io_methods {
|
|
** <li>[[SQLITE_FCNTL_RBU]]
|
|
** The [SQLITE_FCNTL_RBU] opcode is implemented by the special VFS used by
|
|
** the RBU extension only. All other VFS should return SQLITE_NOTFOUND for
|
|
-** this opcode.
|
|
+** this opcode.
|
|
**
|
|
** <li>[[SQLITE_FCNTL_BEGIN_ATOMIC_WRITE]]
|
|
** If the [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] opcode returns SQLITE_OK, then
|
|
@@ -1067,7 +1119,7 @@ struct sqlite3_io_methods {
|
|
**
|
|
** <li>[[SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]]
|
|
** The [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE] opcode causes all write
|
|
-** operations since the previous successful call to
|
|
+** operations since the previous successful call to
|
|
** [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] to be performed atomically.
|
|
** This file control returns [SQLITE_OK] if and only if the writes were
|
|
** all performed successfully and have been committed to persistent storage.
|
|
@@ -1079,7 +1131,7 @@ struct sqlite3_io_methods {
|
|
**
|
|
** <li>[[SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE]]
|
|
** The [SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE] opcode causes all write
|
|
-** operations since the previous successful call to
|
|
+** operations since the previous successful call to
|
|
** [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] to be rolled back.
|
|
** ^This file control takes the file descriptor out of batch write mode
|
|
** so that all subsequent write operations are independent.
|
|
@@ -1087,10 +1139,12 @@ struct sqlite3_io_methods {
|
|
** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE].
|
|
**
|
|
** <li>[[SQLITE_FCNTL_LOCK_TIMEOUT]]
|
|
-** The [SQLITE_FCNTL_LOCK_TIMEOUT] opcode causes attempts to obtain
|
|
-** a file lock using the xLock or xShmLock methods of the VFS to wait
|
|
-** for up to M milliseconds before failing, where M is the single
|
|
-** unsigned integer parameter.
|
|
+** The [SQLITE_FCNTL_LOCK_TIMEOUT] opcode is used to configure a VFS
|
|
+** to block for up to M milliseconds before failing when attempting to
|
|
+** obtain a file lock using the xLock or xShmLock methods of the VFS.
|
|
+** The parameter is a pointer to a 32-bit signed integer that contains
|
|
+** the value that M is to be set to. Before returning, the 32-bit signed
|
|
+** integer is overwritten with the previous value of M.
|
|
**
|
|
** <li>[[SQLITE_FCNTL_DATA_VERSION]]
|
|
** The [SQLITE_FCNTL_DATA_VERSION] opcode is used to detect changes to
|
|
@@ -1112,11 +1166,38 @@ struct sqlite3_io_methods {
|
|
** happen either internally or externally and that are associated with
|
|
** a particular attached database.
|
|
**
|
|
+** <li>[[SQLITE_FCNTL_CKPT_START]]
|
|
+** The [SQLITE_FCNTL_CKPT_START] opcode is invoked from within a checkpoint
|
|
+** in wal mode before the client starts to copy pages from the wal
|
|
+** file to the database file.
|
|
+**
|
|
** <li>[[SQLITE_FCNTL_CKPT_DONE]]
|
|
** The [SQLITE_FCNTL_CKPT_DONE] opcode is invoked from within a checkpoint
|
|
** in wal mode after the client has finished copying pages from the wal
|
|
** file to the database file, but before the *-shm file is updated to
|
|
** record the fact that the pages have been checkpointed.
|
|
+**
|
|
+** <li>[[SQLITE_FCNTL_EXTERNAL_READER]]
|
|
+** The EXPERIMENTAL [SQLITE_FCNTL_EXTERNAL_READER] opcode is used to detect
|
|
+** whether or not there is a database client in another process with a wal-mode
|
|
+** transaction open on the database or not. It is only available on unix.The
|
|
+** (void*) argument passed with this file-control should be a pointer to a
|
|
+** value of type (int). The integer value is set to 1 if the database is a wal
|
|
+** mode database and there exists at least one client in another process that
|
|
+** currently has an SQL transaction open on the database. It is set to 0 if
|
|
+** the database is not a wal-mode db, or if there is no such connection in any
|
|
+** other process. This opcode cannot be used to detect transactions opened
|
|
+** by clients within the current process, only within other processes.
|
|
+**
|
|
+** <li>[[SQLITE_FCNTL_CKSM_FILE]]
|
|
+** The [SQLITE_FCNTL_CKSM_FILE] opcode is for use interally by the
|
|
+** [checksum VFS shim] only.
|
|
+**
|
|
+** <li>[[SQLITE_FCNTL_RESET_CACHE]]
|
|
+** If there is currently no transaction open on the database, and the
|
|
+** database is not a temp db, then the [SQLITE_FCNTL_RESET_CACHE] file-control
|
|
+** purges the contents of the in-memory page cache. If there is an open
|
|
+** transaction, or if the db is a temp-db, this opcode is a no-op, not an error.
|
|
** </ul>
|
|
*/
|
|
#define SQLITE_FCNTL_LOCKSTATE 1
|
|
@@ -1155,6 +1236,11 @@ struct sqlite3_io_methods {
|
|
#define SQLITE_FCNTL_DATA_VERSION 35
|
|
#define SQLITE_FCNTL_SIZE_LIMIT 36
|
|
#define SQLITE_FCNTL_CKPT_DONE 37
|
|
+#define SQLITE_FCNTL_RESERVE_BYTES 38
|
|
+#define SQLITE_FCNTL_CKPT_START 39
|
|
+#define SQLITE_FCNTL_EXTERNAL_READER 40
|
|
+#define SQLITE_FCNTL_CKSM_FILE 41
|
|
+#define SQLITE_FCNTL_RESET_CACHE 42
|
|
|
|
/* deprecated names */
|
|
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
|
|
@@ -1184,6 +1270,26 @@ typedef struct sqlite3_mutex sqlite3_mutex;
|
|
*/
|
|
typedef struct sqlite3_api_routines sqlite3_api_routines;
|
|
|
|
+/*
|
|
+** CAPI3REF: File Name
|
|
+**
|
|
+** Type [sqlite3_filename] is used by SQLite to pass filenames to the
|
|
+** xOpen method of a [VFS]. It may be cast to (const char*) and treated
|
|
+** as a normal, nul-terminated, UTF-8 buffer containing the filename, but
|
|
+** may also be passed to special APIs such as:
|
|
+**
|
|
+** <ul>
|
|
+** <li> sqlite3_filename_database()
|
|
+** <li> sqlite3_filename_journal()
|
|
+** <li> sqlite3_filename_wal()
|
|
+** <li> sqlite3_uri_parameter()
|
|
+** <li> sqlite3_uri_boolean()
|
|
+** <li> sqlite3_uri_int64()
|
|
+** <li> sqlite3_uri_key()
|
|
+** </ul>
|
|
+*/
|
|
+typedef const char *sqlite3_filename;
|
|
+
|
|
/*
|
|
** CAPI3REF: OS Interface Object
|
|
**
|
|
@@ -1238,14 +1344,14 @@ typedef struct sqlite3_api_routines sqlite3_api_routines;
|
|
** the [sqlite3_file] can safely store a pointer to the
|
|
** filename if it needs to remember the filename for some reason.
|
|
** If the zFilename parameter to xOpen is a NULL pointer then xOpen
|
|
-** must invent its own temporary name for the file. ^Whenever the
|
|
+** must invent its own temporary name for the file. ^Whenever the
|
|
** xFilename parameter is NULL it will also be the case that the
|
|
** flags parameter will include [SQLITE_OPEN_DELETEONCLOSE].
|
|
**
|
|
** The flags argument to xOpen() includes all bits set in
|
|
** the flags argument to [sqlite3_open_v2()]. Or if [sqlite3_open()]
|
|
** or [sqlite3_open16()] is used, then flags includes at least
|
|
-** [SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE].
|
|
+** [SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE].
|
|
** If xOpen() opens a file read-only then it sets *pOutFlags to
|
|
** include [SQLITE_OPEN_READONLY]. Other bits in *pOutFlags may be set.
|
|
**
|
|
@@ -1259,7 +1365,7 @@ typedef struct sqlite3_api_routines sqlite3_api_routines;
|
|
** <li> [SQLITE_OPEN_TEMP_JOURNAL]
|
|
** <li> [SQLITE_OPEN_TRANSIENT_DB]
|
|
** <li> [SQLITE_OPEN_SUBJOURNAL]
|
|
-** <li> [SQLITE_OPEN_MASTER_JOURNAL]
|
|
+** <li> [SQLITE_OPEN_SUPER_JOURNAL]
|
|
** <li> [SQLITE_OPEN_WAL]
|
|
** </ul>)^
|
|
**
|
|
@@ -1287,10 +1393,10 @@ typedef struct sqlite3_api_routines sqlite3_api_routines;
|
|
** ^The [SQLITE_OPEN_EXCLUSIVE] flag is always used in conjunction
|
|
** with the [SQLITE_OPEN_CREATE] flag, which are both directly
|
|
** analogous to the O_EXCL and O_CREAT flags of the POSIX open()
|
|
-** API. The SQLITE_OPEN_EXCLUSIVE flag, when paired with the
|
|
+** API. The SQLITE_OPEN_EXCLUSIVE flag, when paired with the
|
|
** SQLITE_OPEN_CREATE, is used to indicate that file should always
|
|
** be created, and that it is an error if it already exists.
|
|
-** It is <i>not</i> used to indicate the file should be opened
|
|
+** It is <i>not</i> used to indicate the file should be opened
|
|
** for exclusive access.
|
|
**
|
|
** ^At least szOsFile bytes of memory are allocated by SQLite
|
|
@@ -1314,7 +1420,7 @@ typedef struct sqlite3_api_routines sqlite3_api_routines;
|
|
** non-zero error code if there is an I/O error or if the name of
|
|
** the file given in the second argument is illegal. If SQLITE_OK
|
|
** is returned, then non-zero or zero is written into *pResOut to indicate
|
|
-** whether or not the file is accessible.
|
|
+** whether or not the file is accessible.
|
|
**
|
|
** ^SQLite will always allocate at least mxPathname+1 bytes for the
|
|
** output buffer xFullPathname. The exact size of the output buffer
|
|
@@ -1334,16 +1440,16 @@ typedef struct sqlite3_api_routines sqlite3_api_routines;
|
|
** method returns a Julian Day Number for the current date and time as
|
|
** a floating point value.
|
|
** ^The xCurrentTimeInt64() method returns, as an integer, the Julian
|
|
-** Day Number multiplied by 86400000 (the number of milliseconds in
|
|
-** a 24-hour day).
|
|
+** Day Number multiplied by 86400000 (the number of milliseconds in
|
|
+** a 24-hour day).
|
|
** ^SQLite will use the xCurrentTimeInt64() method to get the current
|
|
-** date and time if that method is available (if iVersion is 2 or
|
|
+** date and time if that method is available (if iVersion is 2 or
|
|
** greater and the function pointer is not NULL) and will fall back
|
|
** to xCurrentTime() if xCurrentTimeInt64() is unavailable.
|
|
**
|
|
** ^The xSetSystemCall(), xGetSystemCall(), and xNestSystemCall() interfaces
|
|
** are not used by the SQLite core. These optional interfaces are provided
|
|
-** by some VFSes to facilitate testing of the VFS code. By overriding
|
|
+** by some VFSes to facilitate testing of the VFS code. By overriding
|
|
** system calls with functions under its control, a test program can
|
|
** simulate faults and error conditions that would otherwise be difficult
|
|
** or impossible to induce. The set of system calls that can be overridden
|
|
@@ -1362,7 +1468,7 @@ struct sqlite3_vfs {
|
|
sqlite3_vfs *pNext; /* Next registered VFS */
|
|
const char *zName; /* Name of this virtual file system */
|
|
void *pAppData; /* Pointer to application-specific data */
|
|
- int (*xOpen)(sqlite3_vfs*, const char *zName, sqlite3_file*,
|
|
+ int (*xOpen)(sqlite3_vfs*, sqlite3_filename zName, sqlite3_file*,
|
|
int flags, int *pOutFlags);
|
|
int (*xDelete)(sqlite3_vfs*, const char *zName, int syncDir);
|
|
int (*xAccess)(sqlite3_vfs*, const char *zName, int flags, int *pResOut);
|
|
@@ -1390,7 +1496,7 @@ struct sqlite3_vfs {
|
|
/*
|
|
** The methods above are in versions 1 through 3 of the sqlite_vfs object.
|
|
** New fields may be appended in future versions. The iVersion
|
|
- ** value will increment whenever this happens.
|
|
+ ** value will increment whenever this happens.
|
|
*/
|
|
};
|
|
|
|
@@ -1434,7 +1540,7 @@ struct sqlite3_vfs {
|
|
** </ul>
|
|
**
|
|
** When unlocking, the same SHARED or EXCLUSIVE flag must be supplied as
|
|
-** was given on the corresponding lock.
|
|
+** was given on the corresponding lock.
|
|
**
|
|
** The xShmLock method can transition between unlocked and SHARED or
|
|
** between unlocked and EXCLUSIVE. It cannot transition between SHARED
|
|
@@ -1579,7 +1685,7 @@ SQLITE_API int sqlite3_config(int, ...);
|
|
** [database connection] (specified in the first argument).
|
|
**
|
|
** The second argument to sqlite3_db_config(D,V,...) is the
|
|
-** [SQLITE_DBCONFIG_LOOKASIDE | configuration verb] - an integer code
|
|
+** [SQLITE_DBCONFIG_LOOKASIDE | configuration verb] - an integer code
|
|
** that indicates what aspect of the [database connection] is being configured.
|
|
** Subsequent arguments vary depending on the configuration verb.
|
|
**
|
|
@@ -1597,7 +1703,7 @@ SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...);
|
|
** This object is used in only one place in the SQLite interface.
|
|
** A pointer to an instance of this object is the argument to
|
|
** [sqlite3_config()] when the configuration option is
|
|
-** [SQLITE_CONFIG_MALLOC] or [SQLITE_CONFIG_GETMALLOC].
|
|
+** [SQLITE_CONFIG_MALLOC] or [SQLITE_CONFIG_GETMALLOC].
|
|
** By creating an instance of this object
|
|
** and passing it to [sqlite3_config]([SQLITE_CONFIG_MALLOC])
|
|
** during configuration, an application can specify an alternative
|
|
@@ -1627,7 +1733,7 @@ SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...);
|
|
** allocators round up memory allocations at least to the next multiple
|
|
** of 8. Some allocators round up to a larger multiple or to a power of 2.
|
|
** Every memory allocation request coming in through [sqlite3_malloc()]
|
|
-** or [sqlite3_realloc()] first calls xRoundup. If xRoundup returns 0,
|
|
+** or [sqlite3_realloc()] first calls xRoundup. If xRoundup returns 0,
|
|
** that causes the corresponding memory allocation to fail.
|
|
**
|
|
** The xInit method initializes the memory allocator. For example,
|
|
@@ -1637,7 +1743,7 @@ SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...);
|
|
** by xInit. The pAppData pointer is used as the only parameter to
|
|
** xInit and xShutdown.
|
|
**
|
|
-** SQLite holds the [SQLITE_MUTEX_STATIC_MASTER] mutex when it invokes
|
|
+** SQLite holds the [SQLITE_MUTEX_STATIC_MAIN] mutex when it invokes
|
|
** the xInit method, so the xInit method need not be threadsafe. The
|
|
** xShutdown method is only called from [sqlite3_shutdown()] so it does
|
|
** not need to be threadsafe either. For all other methods, SQLite
|
|
@@ -1685,7 +1791,7 @@ struct sqlite3_mem_methods {
|
|
** by a single thread. ^If SQLite is compiled with
|
|
** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then
|
|
** it is not possible to change the [threading mode] from its default
|
|
-** value of Single-thread and so [sqlite3_config()] will return
|
|
+** value of Single-thread and so [sqlite3_config()] will return
|
|
** [SQLITE_ERROR] if called with the SQLITE_CONFIG_SINGLETHREAD
|
|
** configuration option.</dd>
|
|
**
|
|
@@ -1720,7 +1826,7 @@ struct sqlite3_mem_methods {
|
|
** SQLITE_CONFIG_SERIALIZED configuration option.</dd>
|
|
**
|
|
** [[SQLITE_CONFIG_MALLOC]] <dt>SQLITE_CONFIG_MALLOC</dt>
|
|
-** <dd> ^(The SQLITE_CONFIG_MALLOC option takes a single argument which is
|
|
+** <dd> ^(The SQLITE_CONFIG_MALLOC option takes a single argument which is
|
|
** a pointer to an instance of the [sqlite3_mem_methods] structure.
|
|
** The argument specifies
|
|
** alternative low-level memory allocation routines to be used in place of
|
|
@@ -1771,7 +1877,7 @@ struct sqlite3_mem_methods {
|
|
** [[SQLITE_CONFIG_PAGECACHE]] <dt>SQLITE_CONFIG_PAGECACHE</dt>
|
|
** <dd> ^The SQLITE_CONFIG_PAGECACHE option specifies a memory pool
|
|
** that SQLite can use for the database page cache with the default page
|
|
-** cache implementation.
|
|
+** cache implementation.
|
|
** This configuration option is a no-op if an application-defined page
|
|
** cache implementation is loaded using the [SQLITE_CONFIG_PCACHE2].
|
|
** ^There are three arguments to SQLITE_CONFIG_PAGECACHE: A pointer to
|
|
@@ -1799,7 +1905,7 @@ struct sqlite3_mem_methods {
|
|
** additional cache line. </dd>
|
|
**
|
|
** [[SQLITE_CONFIG_HEAP]] <dt>SQLITE_CONFIG_HEAP</dt>
|
|
-** <dd> ^The SQLITE_CONFIG_HEAP option specifies a static memory buffer
|
|
+** <dd> ^The SQLITE_CONFIG_HEAP option specifies a static memory buffer
|
|
** that SQLite will use for all of its dynamic memory allocation needs
|
|
** beyond those provided for by [SQLITE_CONFIG_PAGECACHE].
|
|
** ^The SQLITE_CONFIG_HEAP option is only available if SQLite is compiled
|
|
@@ -1854,7 +1960,7 @@ struct sqlite3_mem_methods {
|
|
** configuration on individual connections.)^ </dd>
|
|
**
|
|
** [[SQLITE_CONFIG_PCACHE2]] <dt>SQLITE_CONFIG_PCACHE2</dt>
|
|
-** <dd> ^(The SQLITE_CONFIG_PCACHE2 option takes a single argument which is
|
|
+** <dd> ^(The SQLITE_CONFIG_PCACHE2 option takes a single argument which is
|
|
** a pointer to an [sqlite3_pcache_methods2] object. This object specifies
|
|
** the interface to a custom page cache implementation.)^
|
|
** ^SQLite makes a copy of the [sqlite3_pcache_methods2] object.</dd>
|
|
@@ -1868,7 +1974,7 @@ struct sqlite3_mem_methods {
|
|
** <dd> The SQLITE_CONFIG_LOG option is used to configure the SQLite
|
|
** global [error log].
|
|
** (^The SQLITE_CONFIG_LOG option takes two arguments: a pointer to a
|
|
-** function with a call signature of void(*)(void*,int,const char*),
|
|
+** function with a call signature of void(*)(void*,int,const char*),
|
|
** and a pointer to void. ^If the function pointer is not NULL, it is
|
|
** invoked by [sqlite3_log()] to process each logging event. ^If the
|
|
** function pointer is NULL, the [sqlite3_log()] interface becomes a no-op.
|
|
@@ -1977,7 +2083,7 @@ struct sqlite3_mem_methods {
|
|
** [[SQLITE_CONFIG_STMTJRNL_SPILL]]
|
|
** <dt>SQLITE_CONFIG_STMTJRNL_SPILL
|
|
** <dd>^The SQLITE_CONFIG_STMTJRNL_SPILL option takes a single parameter which
|
|
-** becomes the [statement journal] spill-to-disk threshold.
|
|
+** becomes the [statement journal] spill-to-disk threshold.
|
|
** [Statement journals] are held in memory until their size (in bytes)
|
|
** exceeds this threshold, at which point they are written to disk.
|
|
** Or if the threshold is -1, statement journals are always held
|
|
@@ -1999,7 +2105,7 @@ struct sqlite3_mem_methods {
|
|
** than the configured sorter-reference size threshold - then a reference
|
|
** 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
|
|
+** value for this option is to never use this optimization. Specifying a
|
|
** negative value for this option restores the default behaviour.
|
|
** This option is only available if SQLite is compiled with the
|
|
** [SQLITE_ENABLE_SORTER_REFERENCES] compile-time option.
|
|
@@ -2027,7 +2133,7 @@ struct sqlite3_mem_methods {
|
|
#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. */
|
|
+/* 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 */
|
|
@@ -2062,7 +2168,7 @@ struct sqlite3_mem_methods {
|
|
** <dl>
|
|
** [[SQLITE_DBCONFIG_LOOKASIDE]]
|
|
** <dt>SQLITE_DBCONFIG_LOOKASIDE</dt>
|
|
-** <dd> ^This option takes three additional arguments that determine the
|
|
+** <dd> ^This option takes three additional arguments that determine the
|
|
** [lookaside memory allocator] configuration for the [database connection].
|
|
** ^The first argument (the third parameter to [sqlite3_db_config()] is a
|
|
** pointer to a memory buffer to use for lookaside memory.
|
|
@@ -2078,9 +2184,9 @@ struct sqlite3_mem_methods {
|
|
** configuration for a database connection can only be changed when that
|
|
** connection is not currently using lookaside memory, or in other words
|
|
** when the "current value" returned by
|
|
-** [sqlite3_db_status](D,[SQLITE_CONFIG_LOOKASIDE],...) is zero.
|
|
+** [sqlite3_db_status](D,[SQLITE_DBSTATUS_LOOKASIDE_USED],...) is zero.
|
|
** Any attempt to change the lookaside memory configuration when lookaside
|
|
-** memory is in use leaves the configuration unchanged and returns
|
|
+** memory is in use leaves the configuration unchanged and returns
|
|
** [SQLITE_BUSY].)^</dd>
|
|
**
|
|
** [[SQLITE_DBCONFIG_ENABLE_FKEY]]
|
|
@@ -2103,7 +2209,13 @@ struct sqlite3_mem_methods {
|
|
** The second parameter is a pointer to an integer into which
|
|
** is written 0 or 1 to indicate whether triggers are disabled or enabled
|
|
** following this call. The second parameter may be a NULL pointer, in
|
|
-** which case the trigger setting is not reported back. </dd>
|
|
+** which case the trigger setting is not reported back.
|
|
+**
|
|
+** <p>Originally this option disabled all triggers. ^(However, since
|
|
+** SQLite version 3.35.0, TEMP triggers are still allowed even if
|
|
+** this option is off. So, in other words, this option now only disables
|
|
+** triggers in the main database schema or in the schemas of ATTACH-ed
|
|
+** databases.)^ </dd>
|
|
**
|
|
** [[SQLITE_DBCONFIG_ENABLE_VIEW]]
|
|
** <dt>SQLITE_DBCONFIG_ENABLE_VIEW</dt>
|
|
@@ -2114,7 +2226,13 @@ struct sqlite3_mem_methods {
|
|
** The second parameter is a pointer to an integer into which
|
|
** is written 0 or 1 to indicate whether views are disabled or enabled
|
|
** following this call. The second parameter may be a NULL pointer, in
|
|
-** which case the view setting is not reported back. </dd>
|
|
+** which case the view setting is not reported back.
|
|
+**
|
|
+** <p>Originally this option disabled all views. ^(However, since
|
|
+** SQLite version 3.35.0, TEMP views are still allowed even if
|
|
+** this option is off. So, in other words, this option now only disables
|
|
+** views in the main database schema or in the schemas of ATTACH-ed
|
|
+** databases.)^ </dd>
|
|
**
|
|
** [[SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER]]
|
|
** <dt>SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER</dt>
|
|
@@ -2157,11 +2275,11 @@ struct sqlite3_mem_methods {
|
|
** until after the database connection closes.
|
|
** </dd>
|
|
**
|
|
-** [[SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE]]
|
|
+** [[SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE]]
|
|
** <dt>SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE</dt>
|
|
-** <dd> Usually, when a database in wal mode is closed or detached from a
|
|
-** 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
|
|
+** <dd> Usually, when a database in wal mode is closed or detached from a
|
|
+** 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
|
|
** is an integer - positive to disable checkpoints-on-close, or zero (the
|
|
@@ -2180,7 +2298,7 @@ struct sqlite3_mem_methods {
|
|
** slower. But the QPSG has the advantage of more predictable behavior. With
|
|
** the QPSG active, SQLite will always use the same query plan in the field as
|
|
** was used during testing in the lab.
|
|
-** The first argument to this setting is an integer which is 0 to disable
|
|
+** The first argument to this setting is an integer which is 0 to disable
|
|
** the QPSG, positive to enable QPSG, or negative to leave the setting
|
|
** unchanged. The second parameter is a pointer to an integer into which
|
|
** is written 0 or 1 to indicate whether the QPSG is disabled or enabled
|
|
@@ -2188,15 +2306,15 @@ struct sqlite3_mem_methods {
|
|
** </dd>
|
|
**
|
|
** [[SQLITE_DBCONFIG_TRIGGER_EQP]] <dt>SQLITE_DBCONFIG_TRIGGER_EQP</dt>
|
|
-** <dd> By default, the output of EXPLAIN QUERY PLAN commands does not
|
|
+** <dd> By default, the output of EXPLAIN QUERY PLAN commands does not
|
|
** include output for any operations performed by trigger programs. This
|
|
** option is used to set or clear (the default) a flag that governs this
|
|
** behavior. The first parameter passed to this operation is an integer -
|
|
** positive to enable output for trigger programs, or zero to disable it,
|
|
** or negative to leave the setting unchanged.
|
|
-** The second parameter is a pointer to an integer into which is written
|
|
-** 0 or 1 to indicate whether output-for-triggers has been disabled - 0 if
|
|
-** it is not disabled, 1 if it is.
|
|
+** The second parameter is a pointer to an integer into which is written
|
|
+** 0 or 1 to indicate whether output-for-triggers has been disabled - 0 if
|
|
+** it is not disabled, 1 if it is.
|
|
** </dd>
|
|
**
|
|
** [[SQLITE_DBCONFIG_RESET_DATABASE]] <dt>SQLITE_DBCONFIG_RESET_DATABASE</dt>
|
|
@@ -2210,24 +2328,29 @@ struct sqlite3_mem_methods {
|
|
** database, or calling sqlite3_table_column_metadata(), ignoring any
|
|
** errors. This step is only necessary if the application desires to keep
|
|
** the database in WAL mode after the reset if it was in WAL mode before
|
|
-** the reset.
|
|
+** the reset.
|
|
** <li> sqlite3_db_config(db, SQLITE_DBCONFIG_RESET_DATABASE, 1, 0);
|
|
** <li> [sqlite3_exec](db, "[VACUUM]", 0, 0, 0);
|
|
** <li> sqlite3_db_config(db, SQLITE_DBCONFIG_RESET_DATABASE, 0, 0);
|
|
** </ol>
|
|
** Because resetting a database is destructive and irreversible, the
|
|
-** process requires the use of this obscure API and multiple steps to help
|
|
-** ensure that it does not happen by accident.
|
|
+** process requires the use of this obscure API and multiple steps to
|
|
+** help ensure that it does not happen by accident. Because this
|
|
+** feature must be capable of resetting corrupt databases, and
|
|
+** shutting down virtual tables may require access to that corrupt
|
|
+** storage, the library must abandon any installed virtual tables
|
|
+** without calling their xDestroy() methods.
|
|
**
|
|
** [[SQLITE_DBCONFIG_DEFENSIVE]] <dt>SQLITE_DBCONFIG_DEFENSIVE</dt>
|
|
** <dd>The SQLITE_DBCONFIG_DEFENSIVE option activates or deactivates the
|
|
** "defensive" flag for a database connection. When the defensive
|
|
-** flag is enabled, language features that allow ordinary SQL to
|
|
+** flag is enabled, language features that allow ordinary SQL to
|
|
** deliberately corrupt the database file are disabled. The disabled
|
|
** features include but are not limited to the following:
|
|
** <ul>
|
|
** <li> The [PRAGMA writable_schema=ON] statement.
|
|
** <li> The [PRAGMA journal_mode=OFF] statement.
|
|
+** <li> The [PRAGMA schema_version=N] statement.
|
|
** <li> Writes to the [sqlite_dbpage] virtual table.
|
|
** <li> Direct writes to [shadow tables].
|
|
** </ul>
|
|
@@ -2237,7 +2360,7 @@ struct sqlite3_mem_methods {
|
|
** <dd>The SQLITE_DBCONFIG_WRITABLE_SCHEMA option activates or deactivates the
|
|
** "writable_schema" flag. This has the same effect and is logically equivalent
|
|
** to setting [PRAGMA writable_schema=ON] or [PRAGMA writable_schema=OFF].
|
|
-** The first argument to this setting is an integer which is 0 to disable
|
|
+** The first argument to this setting is an integer which is 0 to disable
|
|
** the writable_schema, positive to enable writable_schema, or negative to
|
|
** leave the setting unchanged. The second parameter is a pointer to an
|
|
** integer into which is written 0 or 1 to indicate whether the writable_schema
|
|
@@ -2275,14 +2398,13 @@ struct sqlite3_mem_methods {
|
|
** [[SQLITE_DBCONFIG_TRUSTED_SCHEMA]]
|
|
** <dt>SQLITE_DBCONFIG_TRUSTED_SCHEMA</td>
|
|
** <dd>The SQLITE_DBCONFIG_TRUSTED_SCHEMA option tells SQLite to
|
|
-** assume that database schemas (the contents of the [sqlite_master] tables)
|
|
-** are untainted by malicious content.
|
|
+** assume that database schemas are untainted by malicious content.
|
|
** When the SQLITE_DBCONFIG_TRUSTED_SCHEMA option is disabled, SQLite
|
|
** takes additional defensive steps to protect the application from harm
|
|
** including:
|
|
** <ul>
|
|
** <li> Prohibit the use of SQL functions inside triggers, views,
|
|
-** CHECK constraints, DEFAULT clauses, expression indexes,
|
|
+** CHECK constraints, DEFAULT clauses, expression indexes,
|
|
** partial indexes, or generated columns
|
|
** unless those functions are tagged with [SQLITE_INNOCUOUS].
|
|
** <li> Prohibit the use of virtual tables inside of triggers or views
|
|
@@ -2303,7 +2425,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 generated database files that are compatible
|
|
** all the way back to version 3.0.0, and so this setting is of little
|
|
** practical use, but is provided so that SQLite can continue to claim the
|
|
** ability to generate new database files that are compatible with version
|
|
@@ -2361,8 +2483,8 @@ SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff);
|
|
** ^The sqlite3_last_insert_rowid(D) interface usually returns the [rowid] of
|
|
** the most recent successful [INSERT] into a rowid table or [virtual table]
|
|
** on database connection D. ^Inserts into [WITHOUT ROWID] tables are not
|
|
-** recorded. ^If no successful [INSERT]s into rowid tables have ever occurred
|
|
-** on the database connection D, then sqlite3_last_insert_rowid(D) returns
|
|
+** recorded. ^If no successful [INSERT]s into rowid tables have ever occurred
|
|
+** on the database connection D, then sqlite3_last_insert_rowid(D) returns
|
|
** zero.
|
|
**
|
|
** As well as being set automatically as rows are inserted into database
|
|
@@ -2372,15 +2494,15 @@ SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff);
|
|
** Some virtual table implementations may INSERT rows into rowid tables as
|
|
** part of committing a transaction (e.g. to flush data accumulated in memory
|
|
** to disk). In this case subsequent calls to this function return the rowid
|
|
-** associated with these internal INSERT operations, which leads to
|
|
+** associated with these internal INSERT operations, which leads to
|
|
** unintuitive results. Virtual table implementations that do write to rowid
|
|
-** tables in this way can avoid this problem by restoring the original
|
|
-** rowid value using [sqlite3_set_last_insert_rowid()] before returning
|
|
+** tables in this way can avoid this problem by restoring the original
|
|
+** rowid value using [sqlite3_set_last_insert_rowid()] before returning
|
|
** control to the user.
|
|
**
|
|
-** ^(If an [INSERT] occurs within a trigger then this routine will
|
|
-** return the [rowid] of the inserted row as long as the trigger is
|
|
-** running. Once the trigger program ends, the value returned
|
|
+** ^(If an [INSERT] occurs within a trigger then this routine will
|
|
+** return the [rowid] of the inserted row as long as the trigger is
|
|
+** running. Once the trigger program ends, the value returned
|
|
** by this routine reverts to what it was before the trigger was fired.)^
|
|
**
|
|
** ^An [INSERT] that fails due to a constraint violation is not a
|
|
@@ -2413,7 +2535,7 @@ SQLITE_API sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*);
|
|
** METHOD: sqlite3
|
|
**
|
|
** The sqlite3_set_last_insert_rowid(D, R) method allows the application to
|
|
-** set the value returned by calling sqlite3_last_insert_rowid(D) to R
|
|
+** set the value returned by calling sqlite3_last_insert_rowid(D) to R
|
|
** without inserting a row into the database.
|
|
*/
|
|
SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3*,sqlite3_int64);
|
|
@@ -2422,44 +2544,47 @@ SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3*,sqlite3_int64);
|
|
** CAPI3REF: Count The Number Of Rows Modified
|
|
** METHOD: sqlite3
|
|
**
|
|
-** ^This function returns the number of rows modified, inserted or
|
|
+** ^These functions return the number of rows modified, inserted or
|
|
** deleted by the most recently completed INSERT, UPDATE or DELETE
|
|
** statement on the database connection specified by the only parameter.
|
|
-** ^Executing any other type of SQL statement does not modify the value
|
|
-** returned by this function.
|
|
+** The two functions are identical except for the type of the return value
|
|
+** and that if the number of rows modified by the most recent INSERT, UPDATE
|
|
+** or DELETE is greater than the maximum value supported by type "int", then
|
|
+** the return value of sqlite3_changes() is undefined. ^Executing any other
|
|
+** type of SQL statement does not modify the value returned by these functions.
|
|
**
|
|
** ^Only changes made directly by the INSERT, UPDATE or DELETE statement are
|
|
-** considered - auxiliary changes caused by [CREATE TRIGGER | triggers],
|
|
+** considered - auxiliary changes caused by [CREATE TRIGGER | triggers],
|
|
** [foreign key actions] or [REPLACE] constraint resolution are not counted.
|
|
-**
|
|
-** Changes to a view that are intercepted by
|
|
-** [INSTEAD OF trigger | INSTEAD OF triggers] are not counted. ^The value
|
|
-** returned by sqlite3_changes() immediately after an INSERT, UPDATE or
|
|
-** DELETE statement run on a view is always zero. Only changes made to real
|
|
+**
|
|
+** Changes to a view that are intercepted by
|
|
+** [INSTEAD OF trigger | INSTEAD OF triggers] are not counted. ^The value
|
|
+** returned by sqlite3_changes() immediately after an INSERT, UPDATE or
|
|
+** DELETE statement run on a view is always zero. Only changes made to real
|
|
** tables are counted.
|
|
**
|
|
** Things are more complicated if the sqlite3_changes() function is
|
|
** executed while a trigger program is running. This may happen if the
|
|
** program uses the [changes() SQL function], or if some other callback
|
|
** function invokes sqlite3_changes() directly. Essentially:
|
|
-**
|
|
+**
|
|
** <ul>
|
|
** <li> ^(Before entering a trigger program the value returned by
|
|
-** sqlite3_changes() function is saved. After the trigger program
|
|
+** sqlite3_changes() function is saved. After the trigger program
|
|
** has finished, the original value is restored.)^
|
|
-**
|
|
-** <li> ^(Within a trigger program each INSERT, UPDATE and DELETE
|
|
-** statement sets the value returned by sqlite3_changes()
|
|
-** upon completion as normal. Of course, this value will not include
|
|
-** any changes performed by sub-triggers, as the sqlite3_changes()
|
|
+**
|
|
+** <li> ^(Within a trigger program each INSERT, UPDATE and DELETE
|
|
+** statement sets the value returned by sqlite3_changes()
|
|
+** upon completion as normal. Of course, this value will not include
|
|
+** any changes performed by sub-triggers, as the sqlite3_changes()
|
|
** value will be saved and restored after each sub-trigger has run.)^
|
|
** </ul>
|
|
-**
|
|
+**
|
|
** ^This means that if the changes() SQL function (or similar) is used
|
|
-** by the first INSERT, UPDATE or DELETE statement within a trigger, it
|
|
+** by the first INSERT, UPDATE or DELETE statement within a trigger, it
|
|
** returns the value as set when the calling statement began executing.
|
|
-** ^If it is used by the second or subsequent such statement within a trigger
|
|
-** program, the value returned reflects the number of rows modified by the
|
|
+** ^If it is used by the second or subsequent such statement within a trigger
|
|
+** program, the value returned reflects the number of rows modified by the
|
|
** previous INSERT, UPDATE or DELETE statement within the same trigger.
|
|
**
|
|
** If a separate thread makes changes on the same database connection
|
|
@@ -2475,20 +2600,25 @@ SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3*,sqlite3_int64);
|
|
** </ul>
|
|
*/
|
|
SQLITE_API int sqlite3_changes(sqlite3*);
|
|
+SQLITE_API sqlite3_int64 sqlite3_changes64(sqlite3*);
|
|
|
|
/*
|
|
** CAPI3REF: Total Number Of Rows Modified
|
|
** METHOD: sqlite3
|
|
**
|
|
-** ^This function returns the total number of rows inserted, modified or
|
|
+** ^These functions return the total number of rows inserted, modified or
|
|
** deleted by all [INSERT], [UPDATE] or [DELETE] statements completed
|
|
** since the database connection was opened, including those executed as
|
|
-** part of trigger programs. ^Executing any other type of SQL statement
|
|
-** does not affect the value returned by sqlite3_total_changes().
|
|
-**
|
|
+** part of trigger programs. The two functions are identical except for the
|
|
+** type of the return value and that if the number of rows modified by the
|
|
+** connection exceeds the maximum value supported by type "int", then
|
|
+** the return value of sqlite3_total_changes() is undefined. ^Executing
|
|
+** any other type of SQL statement does not affect the value returned by
|
|
+** sqlite3_total_changes().
|
|
+**
|
|
** ^Changes made as part of [foreign key actions] are included in the
|
|
** count, but those made as part of REPLACE constraint resolution are
|
|
-** not. ^Changes to a view that are intercepted by INSTEAD OF triggers
|
|
+** not. ^Changes to a view that are intercepted by INSTEAD OF triggers
|
|
** are not counted.
|
|
**
|
|
** The [sqlite3_total_changes(D)] interface only reports the number
|
|
@@ -2497,7 +2627,7 @@ SQLITE_API int sqlite3_changes(sqlite3*);
|
|
** To detect changes against a database file from other database
|
|
** connections use the [PRAGMA data_version] command or the
|
|
** [SQLITE_FCNTL_DATA_VERSION] [file control].
|
|
-**
|
|
+**
|
|
** If a separate thread makes changes on the same database connection
|
|
** while [sqlite3_total_changes()] is running then the value
|
|
** returned is unpredictable and not meaningful.
|
|
@@ -2512,6 +2642,7 @@ SQLITE_API int sqlite3_changes(sqlite3*);
|
|
** </ul>
|
|
*/
|
|
SQLITE_API int sqlite3_total_changes(sqlite3*);
|
|
+SQLITE_API sqlite3_int64 sqlite3_total_changes64(sqlite3*);
|
|
|
|
/*
|
|
** CAPI3REF: Interrupt A Long-Running Query
|
|
@@ -2539,7 +2670,7 @@ SQLITE_API int sqlite3_total_changes(sqlite3*);
|
|
**
|
|
** ^The sqlite3_interrupt(D) call is in effect until all currently running
|
|
** SQL statements on [database connection] D complete. ^Any new SQL statements
|
|
-** that are started after the sqlite3_interrupt() call and before the
|
|
+** that are started after the sqlite3_interrupt() call and before the
|
|
** running statement count reaches zero are interrupted as if they had been
|
|
** running prior to the sqlite3_interrupt() call. ^New SQL statements
|
|
** that are started after the running statement count reaches zero are
|
|
@@ -2547,8 +2678,12 @@ SQLITE_API int sqlite3_total_changes(sqlite3*);
|
|
** ^A call to sqlite3_interrupt(D) that occurs when there are no running
|
|
** SQL statements is a no-op and has no effect on SQL statements
|
|
** that are started after the sqlite3_interrupt() call returns.
|
|
+**
|
|
+** ^The [sqlite3_is_interrupted(D)] interface can be used to determine whether
|
|
+** or not an interrupt is currently in effect for [database connection] D.
|
|
*/
|
|
SQLITE_API void sqlite3_interrupt(sqlite3*);
|
|
+SQLITE_API int sqlite3_is_interrupted(sqlite3*);
|
|
|
|
/*
|
|
** CAPI3REF: Determine If An SQL Statement Is Complete
|
|
@@ -2571,7 +2706,7 @@ SQLITE_API void sqlite3_interrupt(sqlite3*);
|
|
** ^These routines do not parse the SQL statements thus
|
|
** will not detect syntactically incorrect SQL.
|
|
**
|
|
-** ^(If SQLite has not been initialized using [sqlite3_initialize()] prior
|
|
+** ^(If SQLite has not been initialized using [sqlite3_initialize()] prior
|
|
** to invoking sqlite3_complete16() then sqlite3_initialize() is invoked
|
|
** automatically by sqlite3_complete16(). If that initialization fails,
|
|
** then the return value from sqlite3_complete16() will be non-zero
|
|
@@ -2616,7 +2751,7 @@ SQLITE_API int sqlite3_complete16(const void *sql);
|
|
** The presence of a busy handler does not guarantee that it will be invoked
|
|
** when there is lock contention. ^If SQLite determines that invoking the busy
|
|
** handler could result in a deadlock, it will go ahead and return [SQLITE_BUSY]
|
|
-** to the application instead of invoking the
|
|
+** to the application instead of invoking the
|
|
** busy handler.
|
|
** Consider a scenario where one process is holding a read lock that
|
|
** it is trying to promote to a reserved lock and
|
|
@@ -2641,7 +2776,7 @@ SQLITE_API int sqlite3_complete16(const void *sql);
|
|
** database connection that invoked the busy handler. In other words,
|
|
** the busy handler is not reentrant. Any such actions
|
|
** result in undefined behavior.
|
|
-**
|
|
+**
|
|
** A busy handler must not close the database connection
|
|
** or [prepared statement] that invoked the busy handler.
|
|
*/
|
|
@@ -2759,7 +2894,7 @@ SQLITE_API void sqlite3_free_table(char **result);
|
|
** These routines are work-alikes of the "printf()" family of functions
|
|
** from the standard C library.
|
|
** These routines understand most of the common formatting options from
|
|
-** the standard library printf()
|
|
+** the standard library printf()
|
|
** plus some additional non-standard formats ([%q], [%Q], [%w], and [%z]).
|
|
** See the [built-in printf()] documentation for details.
|
|
**
|
|
@@ -2955,7 +3090,7 @@ SQLITE_API void sqlite3_randomness(int N, void *P);
|
|
** requested is ok. ^When the callback returns [SQLITE_DENY], the
|
|
** [sqlite3_prepare_v2()] or equivalent call that triggered the
|
|
** authorizer will fail with an error message explaining that
|
|
-** access is denied.
|
|
+** access is denied.
|
|
**
|
|
** ^The first parameter to the authorizer callback is a copy of the third
|
|
** parameter to the sqlite3_set_authorizer() interface. ^The second parameter
|
|
@@ -3008,7 +3143,7 @@ SQLITE_API void sqlite3_randomness(int N, void *P);
|
|
** database connections for the meaning of "modify" in this paragraph.
|
|
**
|
|
** ^When [sqlite3_prepare_v2()] is used to prepare a statement, the
|
|
-** statement might be re-prepared during [sqlite3_step()] due to a
|
|
+** statement might be re-prepared during [sqlite3_step()] due to a
|
|
** schema change. Hence, the application should ensure that the
|
|
** correct authorizer callback remains in place during the [sqlite3_step()].
|
|
**
|
|
@@ -3156,7 +3291,7 @@ SQLITE_API SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*,
|
|
** execution of the prepared statement, such as at the start of each
|
|
** trigger subprogram. ^The P argument is a pointer to the
|
|
** [prepared statement]. ^The X argument is a pointer to a string which
|
|
-** is the unexpanded SQL text of the prepared statement or an SQL comment
|
|
+** is the unexpanded SQL text of the prepared statement or an SQL comment
|
|
** that indicates the invocation of a trigger. ^The callback can compute
|
|
** the same text that would have been returned by the legacy [sqlite3_trace()]
|
|
** interface by using the X argument when X begins with "--" and invoking
|
|
@@ -3166,13 +3301,13 @@ SQLITE_API SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*,
|
|
** <dd>^An SQLITE_TRACE_PROFILE callback provides approximately the same
|
|
** information as is provided by the [sqlite3_profile()] callback.
|
|
** ^The P argument is a pointer to the [prepared statement] and the
|
|
-** X argument points to a 64-bit integer which is the estimated of
|
|
-** the number of nanosecond that the prepared statement took to run.
|
|
+** X argument points to a 64-bit integer which is approximately
|
|
+** the number of nanoseconds that the prepared statement took to run.
|
|
** ^The SQLITE_TRACE_PROFILE callback is invoked when the statement finishes.
|
|
**
|
|
** [[SQLITE_TRACE_ROW]] <dt>SQLITE_TRACE_ROW</dt>
|
|
** <dd>^An SQLITE_TRACE_ROW callback is invoked whenever a prepared
|
|
-** statement generates a single row of result.
|
|
+** statement generates a single row of result.
|
|
** ^The P argument is a pointer to the [prepared statement] and the
|
|
** X argument is unused.
|
|
**
|
|
@@ -3199,10 +3334,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
|
|
+** ^Each call to either sqlite3_trace() or sqlite3_trace_v2() overrides
|
|
** (cancels) any prior calls to sqlite3_trace() or sqlite3_trace_v2().
|
|
**
|
|
-** ^The X callback is invoked whenever any of the events identified by
|
|
+** ^The X callback is invoked whenever any of the events identified by
|
|
** mask M occur. ^The integer return value from the callback is currently
|
|
** ignored, though this may change in future releases. Callback
|
|
** implementations should return zero to ensure future compatibility.
|
|
@@ -3230,12 +3365,12 @@ SQLITE_API int sqlite3_trace_v2(
|
|
**
|
|
** ^The sqlite3_progress_handler(D,N,X,P) interface causes the callback
|
|
** function X to be invoked periodically during long running calls to
|
|
-** [sqlite3_exec()], [sqlite3_step()] and [sqlite3_get_table()] for
|
|
+** [sqlite3_step()] and [sqlite3_prepare()] and similar for
|
|
** database connection D. An example use for this
|
|
** interface is to keep a GUI updated during a large query.
|
|
**
|
|
-** ^The parameter P is passed through as the only parameter to the
|
|
-** callback function X. ^The parameter N is the approximate number of
|
|
+** ^The parameter P is passed through as the only parameter to the
|
|
+** callback function X. ^The parameter N is the approximate number of
|
|
** [virtual machine instructions] that are evaluated between successive
|
|
** invocations of the callback X. ^If N is less than one then the progress
|
|
** handler is disabled.
|
|
@@ -3255,6 +3390,13 @@ SQLITE_API int sqlite3_trace_v2(
|
|
** Note that [sqlite3_prepare_v2()] and [sqlite3_step()] both modify their
|
|
** database connections for the meaning of "modify" in this paragraph.
|
|
**
|
|
+** The progress handler callback would originally only be invoked from the
|
|
+** bytecode engine. It still might be invoked during [sqlite3_prepare()]
|
|
+** and similar because those routines might force a reparse of the schema
|
|
+** which involves running the bytecode engine. However, beginning with
|
|
+** SQLite version 3.41.0, the progress handler callback might also be
|
|
+** invoked directly from [sqlite3_prepare()] while analyzing and generating
|
|
+** code for complex queries.
|
|
*/
|
|
SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
|
|
|
|
@@ -3262,7 +3404,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
|
|
** CAPI3REF: Opening A New Database Connection
|
|
** CONSTRUCTOR: sqlite3
|
|
**
|
|
-** ^These routines open an SQLite database file as specified by the
|
|
+** ^These routines open an SQLite database file as specified by the
|
|
** filename argument. ^The filename argument is interpreted as UTF-8 for
|
|
** sqlite3_open() and sqlite3_open_v2() and as UTF-16 in the native byte
|
|
** order for sqlite3_open16(). ^(A [database connection] handle is usually
|
|
@@ -3291,13 +3433,18 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
|
|
**
|
|
** <dl>
|
|
** ^(<dt>[SQLITE_OPEN_READONLY]</dt>
|
|
-** <dd>The database is opened in read-only mode. If the database does not
|
|
-** already exist, an error is returned.</dd>)^
|
|
+** <dd>The database is opened in read-only mode. If the database does
|
|
+** not already exist, an error is returned.</dd>)^
|
|
**
|
|
** ^(<dt>[SQLITE_OPEN_READWRITE]</dt>
|
|
-** <dd>The database is opened for reading and writing if possible, or reading
|
|
-** only if the file is write protected by the operating system. In either
|
|
-** case the database must already exist, otherwise an error is returned.</dd>)^
|
|
+** <dd>The database is opened for reading and writing if possible, or
|
|
+** reading only if the file is write protected by the operating
|
|
+** system. In either case the database must already exist, otherwise
|
|
+** an error is returned. For historical reasons, if opening in
|
|
+** read-write mode fails due to OS-level permissions, an attempt is
|
|
+** made to open it in read-only mode. [sqlite3_db_readonly()] can be
|
|
+** used to determine whether the database is actually
|
|
+** read-write.</dd>)^
|
|
**
|
|
** ^(<dt>[SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]</dt>
|
|
** <dd>The database is opened for reading and writing, and is created if
|
|
@@ -3335,20 +3482,39 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
|
|
** <dd>The database is opened [shared cache] enabled, overriding
|
|
** the default shared cache setting provided by
|
|
** [sqlite3_enable_shared_cache()].)^
|
|
+** The [use of shared cache mode is discouraged] and hence shared cache
|
|
+** capabilities may be omitted from many builds of SQLite. In such cases,
|
|
+** this option is a no-op.
|
|
**
|
|
** ^(<dt>[SQLITE_OPEN_PRIVATECACHE]</dt>
|
|
** <dd>The database is opened [shared cache] disabled, overriding
|
|
** the default shared cache setting provided by
|
|
** [sqlite3_enable_shared_cache()].)^
|
|
**
|
|
+** [[OPEN_EXRESCODE]] ^(<dt>[SQLITE_OPEN_EXRESCODE]</dt>
|
|
+** <dd>The database connection comes up in "extended result code mode".
|
|
+** In other words, the database behaves has if
|
|
+** [sqlite3_extended_result_codes(db,1)] where called on the database
|
|
+** connection as soon as the connection is created. In addition to setting
|
|
+** the extended result code mode, this flag also causes [sqlite3_open_v2()]
|
|
+** to return an extended result code.</dd>
|
|
+**
|
|
** [[OPEN_NOFOLLOW]] ^(<dt>[SQLITE_OPEN_NOFOLLOW]</dt>
|
|
-** <dd>The database filename is not allowed to be a symbolic link</dd>
|
|
+** <dd>The database filename is not allowed to contain a symbolic link</dd>
|
|
** </dl>)^
|
|
**
|
|
** If the 3rd parameter to sqlite3_open_v2() is not one of the
|
|
** required combinations shown above optionally combined with other
|
|
** [SQLITE_OPEN_READONLY | SQLITE_OPEN_* bits]
|
|
-** then the behavior is undefined.
|
|
+** then the behavior is undefined. Historic versions of SQLite
|
|
+** have silently ignored surplus bits in the flags parameter to
|
|
+** sqlite3_open_v2(), however that behavior might not be carried through
|
|
+** into future versions of SQLite and so applications should not rely
|
|
+** upon it. Note in particular that the SQLITE_OPEN_EXCLUSIVE flag is a no-op
|
|
+** for sqlite3_open_v2(). The SQLITE_OPEN_EXCLUSIVE does *not* cause
|
|
+** the open to fail if the database already exists. The SQLITE_OPEN_EXCLUSIVE
|
|
+** flag is intended for use by the [sqlite3_vfs|VFS interface] only, and not
|
|
+** by sqlite3_open_v2().
|
|
**
|
|
** ^The fourth parameter to sqlite3_open_v2() is the name of the
|
|
** [sqlite3_vfs] object that defines the operating system interface that
|
|
@@ -3381,17 +3547,17 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
|
|
** information.
|
|
**
|
|
** URI filenames are parsed according to RFC 3986. ^If the URI contains an
|
|
-** authority, then it must be either an empty string or the string
|
|
-** "localhost". ^If the authority is not an empty string or "localhost", an
|
|
-** error is returned to the caller. ^The fragment component of a URI, if
|
|
+** authority, then it must be either an empty string or the string
|
|
+** "localhost". ^If the authority is not an empty string or "localhost", an
|
|
+** error is returned to the caller. ^The fragment component of a URI, if
|
|
** present, is ignored.
|
|
**
|
|
** ^SQLite uses the path component of the URI as the name of the disk file
|
|
-** which contains the database. ^If the path begins with a '/' character,
|
|
-** then it is interpreted as an absolute path. ^If the path does not begin
|
|
+** which contains the database. ^If the path begins with a '/' character,
|
|
+** then it is interpreted as an absolute path. ^If the path does not begin
|
|
** with a '/' (meaning that the authority section is omitted from the URI)
|
|
-** then the path is interpreted as a relative path.
|
|
-** ^(On windows, the first component of an absolute path
|
|
+** then the path is interpreted as a relative path.
|
|
+** ^(On windows, the first component of an absolute path
|
|
** is a drive specification (e.g. "C:").)^
|
|
**
|
|
** [[core URI query parameters]]
|
|
@@ -3411,13 +3577,13 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
|
|
**
|
|
** <li> <b>mode</b>: ^(The mode parameter may be set to either "ro", "rw",
|
|
** "rwc", or "memory". Attempting to set it to any other value is
|
|
-** an error)^.
|
|
-** ^If "ro" is specified, then the database is opened for read-only
|
|
-** access, just as if the [SQLITE_OPEN_READONLY] flag had been set in the
|
|
-** third argument to sqlite3_open_v2(). ^If the mode option is set to
|
|
-** "rw", then the database is opened for read-write (but not create)
|
|
-** access, as if SQLITE_OPEN_READWRITE (but not SQLITE_OPEN_CREATE) had
|
|
-** been set. ^Value "rwc" is equivalent to setting both
|
|
+** an error)^.
|
|
+** ^If "ro" is specified, then the database is opened for read-only
|
|
+** access, just as if the [SQLITE_OPEN_READONLY] flag had been set in the
|
|
+** third argument to sqlite3_open_v2(). ^If the mode option is set to
|
|
+** "rw", then the database is opened for read-write (but not create)
|
|
+** access, as if SQLITE_OPEN_READWRITE (but not SQLITE_OPEN_CREATE) had
|
|
+** been set. ^Value "rwc" is equivalent to setting both
|
|
** SQLITE_OPEN_READWRITE and SQLITE_OPEN_CREATE. ^If the mode option is
|
|
** set to "memory" then a pure [in-memory database] that never reads
|
|
** or writes from disk is used. ^It is an error to specify a value for
|
|
@@ -3427,7 +3593,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
|
|
** <li> <b>cache</b>: ^The cache parameter may be set to either "shared" or
|
|
** "private". ^Setting it to "shared" is equivalent to setting the
|
|
** SQLITE_OPEN_SHAREDCACHE bit in the flags argument passed to
|
|
-** sqlite3_open_v2(). ^Setting the cache parameter to "private" is
|
|
+** sqlite3_open_v2(). ^Setting the cache parameter to "private" is
|
|
** equivalent to setting the SQLITE_OPEN_PRIVATECACHE bit.
|
|
** ^If sqlite3_open_v2() is used and the "cache" parameter is present in
|
|
** a URI filename, its value overrides any behavior requested by setting
|
|
@@ -3453,7 +3619,7 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
|
|
** property on a database file that does in fact change can result
|
|
** in incorrect query results and/or [SQLITE_CORRUPT] errors.
|
|
** See also: [SQLITE_IOCAP_IMMUTABLE].
|
|
-**
|
|
+**
|
|
** </ul>
|
|
**
|
|
** ^Specifying an unknown parameter in the query component of a URI is not an
|
|
@@ -3465,36 +3631,37 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
|
|
**
|
|
** <table border="1" align=center cellpadding=5>
|
|
** <tr><th> URI filenames <th> Results
|
|
-** <tr><td> file:data.db <td>
|
|
+** <tr><td> file:data.db <td>
|
|
** Open the file "data.db" in the current directory.
|
|
** <tr><td> file:/home/fred/data.db<br>
|
|
-** file:///home/fred/data.db <br>
|
|
-** file://localhost/home/fred/data.db <br> <td>
|
|
+** file:///home/fred/data.db <br>
|
|
+** file://localhost/home/fred/data.db <br> <td>
|
|
** Open the database file "/home/fred/data.db".
|
|
-** <tr><td> file://darkstar/home/fred/data.db <td>
|
|
+** <tr><td> file://darkstar/home/fred/data.db <td>
|
|
** An error. "darkstar" is not a recognized authority.
|
|
-** <tr><td style="white-space:nowrap">
|
|
+** <tr><td style="white-space:nowrap">
|
|
** file:///C:/Documents%20and%20Settings/fred/Desktop/data.db
|
|
** <td> Windows only: Open the file "data.db" on fred's desktop on drive
|
|
-** C:. Note that the %20 escaping in this example is not strictly
|
|
+** C:. Note that the %20 escaping in this example is not strictly
|
|
** necessary - space characters can be used literally
|
|
** in URI filenames.
|
|
-** <tr><td> file:data.db?mode=ro&cache=private <td>
|
|
+** <tr><td> file:data.db?mode=ro&cache=private <td>
|
|
** Open file "data.db" in the current directory for read-only access.
|
|
** Regardless of whether or not shared-cache mode is enabled by
|
|
** default, use a private cache.
|
|
** <tr><td> file:/home/fred/data.db?vfs=unix-dotfile <td>
|
|
** Open file "/home/fred/data.db". Use the special VFS "unix-dotfile"
|
|
** that uses dot-files in place of posix advisory locking.
|
|
-** <tr><td> file:data.db?mode=readonly <td>
|
|
+** <tr><td> file:data.db?mode=readonly <td>
|
|
** An error. "readonly" is not a valid option for the "mode" parameter.
|
|
+** Use "ro" instead: "file:data.db?mode=ro".
|
|
** </table>
|
|
**
|
|
** ^URI hexadecimal escape sequences (%HH) are supported within the path and
|
|
** query components of a URI. A hexadecimal escape sequence consists of a
|
|
-** percent sign - "%" - followed by exactly two hexadecimal digits
|
|
+** percent sign - "%" - followed by exactly two hexadecimal digits
|
|
** specifying an octet value. ^Before the path or query components of a
|
|
-** URI filename are interpreted, they are encoded using UTF-8 and all
|
|
+** URI filename are interpreted, they are encoded using UTF-8 and all
|
|
** hexadecimal escape sequences replaced by a single byte containing the
|
|
** corresponding octet. If this process generates an invalid UTF-8 encoding,
|
|
** the results are undefined.
|
|
@@ -3530,14 +3697,25 @@ SQLITE_API int sqlite3_open_v2(
|
|
** CAPI3REF: Obtain Values For URI Parameters
|
|
**
|
|
** These are utility routines, useful to [VFS|custom VFS implementations],
|
|
-** that check if a database file was a URI that contained a specific query
|
|
+** that check if a database file was a URI that contained a specific query
|
|
** parameter, and if so obtains the value of that query parameter.
|
|
**
|
|
-** If F is the database filename pointer passed into the xOpen() method of
|
|
-** a VFS implementation or it is the return value of [sqlite3_db_filename()]
|
|
+** The first parameter to these interfaces (hereafter referred to
|
|
+** as F) must be one of:
|
|
+** <ul>
|
|
+** <li> A database filename pointer created by the SQLite core and
|
|
+** passed into the xOpen() method of a VFS implemention, or
|
|
+** <li> A filename obtained from [sqlite3_db_filename()], or
|
|
+** <li> A new filename constructed using [sqlite3_create_filename()].
|
|
+** </ul>
|
|
+** If the F parameter is not one of the above, then the behavior is
|
|
+** undefined and probably undesirable. Older versions of SQLite were
|
|
+** more tolerant of invalid F parameters than newer versions.
|
|
+**
|
|
+** If F is a suitable filename (as described in the previous paragraph)
|
|
** and if P is the name of the query parameter, then
|
|
** sqlite3_uri_parameter(F,P) returns the value of the P
|
|
-** parameter if it exists or a NULL pointer if P does not appear as a
|
|
+** parameter if it exists or a NULL pointer if P does not appear as a
|
|
** query parameter on F. If P is a query parameter of F and it
|
|
** has no explicit value, then sqlite3_uri_parameter(F,P) returns
|
|
** a pointer to an empty string.
|
|
@@ -3546,7 +3724,7 @@ SQLITE_API int sqlite3_open_v2(
|
|
** parameter and returns true (1) or false (0) according to the value
|
|
** of P. The sqlite3_uri_boolean(F,P,B) routine returns true (1) if the
|
|
** value of query parameter P is one of "yes", "true", or "on" in any
|
|
-** case or if the value begins with a non-zero number. The
|
|
+** case or if the value begins with a non-zero number. The
|
|
** sqlite3_uri_boolean(F,P,B) routines returns false (0) if the value of
|
|
** query parameter P is one of "no", "false", or "off" in any case or
|
|
** if the value begins with a numeric zero. If P is not a query
|
|
@@ -3564,7 +3742,7 @@ SQLITE_API int sqlite3_open_v2(
|
|
** parameters minus 1. The N value is zero-based so N should be 0 to obtain
|
|
** the name of the first query parameter, 1 for the second parameter, and
|
|
** so forth.
|
|
-**
|
|
+**
|
|
** If F is a NULL pointer, then sqlite3_uri_parameter(F,P) returns NULL and
|
|
** sqlite3_uri_boolean(F,P,B) returns B. If F is not a NULL pointer and
|
|
** is not a database file pathname pointer that the SQLite core passed
|
|
@@ -3581,10 +3759,10 @@ SQLITE_API int sqlite3_open_v2(
|
|
**
|
|
** See the [URI filename] documentation for additional information.
|
|
*/
|
|
-SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam);
|
|
-SQLITE_API int sqlite3_uri_boolean(const char *zFile, const char *zParam, int bDefault);
|
|
-SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int64);
|
|
-SQLITE_API const char *sqlite3_uri_key(const char *zFilename, int N);
|
|
+SQLITE_API const char *sqlite3_uri_parameter(sqlite3_filename z, const char *zParam);
|
|
+SQLITE_API int sqlite3_uri_boolean(sqlite3_filename z, const char *zParam, int bDefault);
|
|
+SQLITE_API sqlite3_int64 sqlite3_uri_int64(sqlite3_filename, const char*, sqlite3_int64);
|
|
+SQLITE_API const char *sqlite3_uri_key(sqlite3_filename z, int N);
|
|
|
|
/*
|
|
** CAPI3REF: Translate filenames
|
|
@@ -3613,21 +3791,93 @@ SQLITE_API const char *sqlite3_uri_key(const char *zFilename, int N);
|
|
** return value from [sqlite3_db_filename()], then the result is
|
|
** undefined and is likely a memory access violation.
|
|
*/
|
|
-SQLITE_API const char *sqlite3_filename_database(const char*);
|
|
-SQLITE_API const char *sqlite3_filename_journal(const char*);
|
|
-SQLITE_API const char *sqlite3_filename_wal(const char*);
|
|
+SQLITE_API const char *sqlite3_filename_database(sqlite3_filename);
|
|
+SQLITE_API const char *sqlite3_filename_journal(sqlite3_filename);
|
|
+SQLITE_API const char *sqlite3_filename_wal(sqlite3_filename);
|
|
+
|
|
+/*
|
|
+** CAPI3REF: Database File Corresponding To A Journal
|
|
+**
|
|
+** ^If X is the name of a rollback or WAL-mode journal file that is
|
|
+** passed into the xOpen method of [sqlite3_vfs], then
|
|
+** sqlite3_database_file_object(X) returns a pointer to the [sqlite3_file]
|
|
+** object that represents the main database file.
|
|
+**
|
|
+** This routine is intended for use in custom [VFS] implementations
|
|
+** only. It is not a general-purpose interface.
|
|
+** The argument sqlite3_file_object(X) must be a filename pointer that
|
|
+** has been passed into [sqlite3_vfs].xOpen method where the
|
|
+** flags parameter to xOpen contains one of the bits
|
|
+** [SQLITE_OPEN_MAIN_JOURNAL] or [SQLITE_OPEN_WAL]. Any other use
|
|
+** of this routine results in undefined and probably undesirable
|
|
+** behavior.
|
|
+*/
|
|
+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
|
|
+** are not useful outside of that context.
|
|
+**
|
|
+** The sqlite3_create_filename(D,J,W,N,P) allocates memory to hold a version of
|
|
+** database filename D with corresponding journal file J and WAL file W and
|
|
+** with N URI parameters key/values pairs in the array P. The result from
|
|
+** sqlite3_create_filename(D,J,W,N,P) is a pointer to a database filename that
|
|
+** is safe to pass to routines like:
|
|
+** <ul>
|
|
+** <li> [sqlite3_uri_parameter()],
|
|
+** <li> [sqlite3_uri_boolean()],
|
|
+** <li> [sqlite3_uri_int64()],
|
|
+** <li> [sqlite3_uri_key()],
|
|
+** <li> [sqlite3_filename_database()],
|
|
+** <li> [sqlite3_filename_journal()], or
|
|
+** <li> [sqlite3_filename_wal()].
|
|
+** </ul>
|
|
+** If a memory allocation error occurs, sqlite3_create_filename() might
|
|
+** return a NULL pointer. The memory obtained from sqlite3_create_filename(X)
|
|
+** must be released by a corresponding call to sqlite3_free_filename(Y).
|
|
+**
|
|
+** The P parameter in sqlite3_create_filename(D,J,W,N,P) should be an array
|
|
+** of 2*N pointers to strings. Each pair of pointers in this array corresponds
|
|
+** to a key and value for a query parameter. The P parameter may be a NULL
|
|
+** pointer if N is zero. None of the 2*N pointers in the P array may be
|
|
+** NULL pointers and key pointers should not be empty strings.
|
|
+** None of the D, J, or W parameters to sqlite3_create_filename(D,J,W,N,P) may
|
|
+** be NULL pointers, though they can be empty strings.
|
|
+**
|
|
+** The sqlite3_free_filename(Y) routine releases a memory allocation
|
|
+** previously obtained from sqlite3_create_filename(). Invoking
|
|
+** sqlite3_free_filename(Y) where Y is a NULL pointer is a harmless no-op.
|
|
+**
|
|
+** If the Y parameter to sqlite3_free_filename(Y) is anything other
|
|
+** than a NULL pointer or a pointer previously acquired from
|
|
+** sqlite3_create_filename(), then bad things such as heap
|
|
+** corruption or segfaults may occur. The value Y should not be
|
|
+** used again after sqlite3_free_filename(Y) has been called. This means
|
|
+** that if the [sqlite3_vfs.xOpen()] method of a VFS has been called using Y,
|
|
+** then the corresponding [sqlite3_module.xClose() method should also be
|
|
+** invoked prior to calling sqlite3_free_filename(Y).
|
|
+*/
|
|
+SQLITE_API sqlite3_filename sqlite3_create_filename(
|
|
+ const char *zDatabase,
|
|
+ const char *zJournal,
|
|
+ const char *zWal,
|
|
+ int nParam,
|
|
+ const char **azParam
|
|
+);
|
|
+SQLITE_API void sqlite3_free_filename(sqlite3_filename);
|
|
|
|
/*
|
|
** CAPI3REF: Error Codes And Messages
|
|
** METHOD: sqlite3
|
|
**
|
|
-** ^If the most recent sqlite3_* API call associated with
|
|
+** ^If the most recent sqlite3_* API call associated with
|
|
** [database connection] D failed, then the sqlite3_errcode(D) interface
|
|
** returns the numeric [result code] or [extended result code] for that
|
|
** API call.
|
|
** ^The sqlite3_extended_errcode()
|
|
-** interface is the same except that it always returns the
|
|
+** interface is the same except that it always returns the
|
|
** [extended result code] even when extended result codes are
|
|
** disabled.
|
|
**
|
|
@@ -3635,13 +3885,14 @@ SQLITE_API const char *sqlite3_filename_wal(const char*);
|
|
** sqlite3_extended_errcode() might change with each API call.
|
|
** Except, there are some interfaces that are guaranteed to never
|
|
** change the value of the error code. The error-code preserving
|
|
-** interfaces are:
|
|
+** interfaces include the following:
|
|
**
|
|
** <ul>
|
|
** <li> sqlite3_errcode()
|
|
** <li> sqlite3_extended_errcode()
|
|
** <li> sqlite3_errmsg()
|
|
** <li> sqlite3_errmsg16()
|
|
+** <li> sqlite3_error_offset()
|
|
** </ul>
|
|
**
|
|
** ^The sqlite3_errmsg() and sqlite3_errmsg16() return English-language
|
|
@@ -3656,6 +3907,13 @@ SQLITE_API const char *sqlite3_filename_wal(const char*);
|
|
** ^(Memory to hold the error message string is managed internally
|
|
** and must not be freed by the application)^.
|
|
**
|
|
+** ^If the most recent error references a specific token in the input
|
|
+** SQL, the sqlite3_error_offset() interface returns the byte offset
|
|
+** of the start of that token. ^The byte offset returned by
|
|
+** sqlite3_error_offset() assumes that the input SQL is UTF8.
|
|
+** ^If the most recent error does not reference a specific token in the input
|
|
+** SQL, then the sqlite3_error_offset() function returns -1.
|
|
+**
|
|
** When the serialized [threading mode] is in use, it might be the
|
|
** case that a second error occurs on a separate thread in between
|
|
** the time of the first error and the call to these interfaces.
|
|
@@ -3675,6 +3933,7 @@ SQLITE_API int sqlite3_extended_errcode(sqlite3 *db);
|
|
SQLITE_API const char *sqlite3_errmsg(sqlite3*);
|
|
SQLITE_API const void *sqlite3_errmsg16(sqlite3*);
|
|
SQLITE_API const char *sqlite3_errstr(int);
|
|
+SQLITE_API int sqlite3_error_offset(sqlite3 *db);
|
|
|
|
/*
|
|
** CAPI3REF: Prepared Statement Object
|
|
@@ -3684,7 +3943,7 @@ SQLITE_API const char *sqlite3_errstr(int);
|
|
** has been compiled into binary form and is ready to be evaluated.
|
|
**
|
|
** Think of each SQL statement as a separate computer program. The
|
|
-** original SQL text is source code. A prepared statement object
|
|
+** original SQL text is source code. A prepared statement object
|
|
** is the compiled object code. All SQL must be converted into a
|
|
** prepared statement before it can be run.
|
|
**
|
|
@@ -3714,7 +3973,7 @@ typedef struct sqlite3_stmt sqlite3_stmt;
|
|
** new limit for that construct.)^
|
|
**
|
|
** ^If the new limit is a negative number, the limit is unchanged.
|
|
-** ^(For each limit category SQLITE_LIMIT_<i>NAME</i> there is a
|
|
+** ^(For each limit category SQLITE_LIMIT_<i>NAME</i> there is a
|
|
** [limits | hard upper bound]
|
|
** set at compile-time by a C preprocessor macro called
|
|
** [limits | SQLITE_MAX_<i>NAME</i>].
|
|
@@ -3722,7 +3981,7 @@ typedef struct sqlite3_stmt sqlite3_stmt;
|
|
** ^Attempts to increase a limit above its hard upper bound are
|
|
** silently truncated to the hard upper bound.
|
|
**
|
|
-** ^Regardless of whether or not the limit was changed, the
|
|
+** ^Regardless of whether or not the limit was changed, the
|
|
** [sqlite3_limit()] interface returns the prior value of the limit.
|
|
** ^Hence, to find the current value of a limit without changing it,
|
|
** simply invoke this interface with the third parameter set to -1.
|
|
@@ -3827,7 +4086,7 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
|
|
** <dd>The SQLITE_PREPARE_PERSISTENT flag is a hint to the query planner
|
|
** that the prepared statement will be retained for a long time and
|
|
** probably reused many times.)^ ^Without this flag, [sqlite3_prepare_v3()]
|
|
-** and [sqlite3_prepare16_v3()] assume that the prepared statement will
|
|
+** and [sqlite3_prepare16_v3()] assume that the prepared statement will
|
|
** be used just once or at most a few times and then destroyed using
|
|
** [sqlite3_finalize()] relatively soon. The current implementation acts
|
|
** on this hint by avoiding the use of [lookaside memory] so as not to
|
|
@@ -3934,12 +4193,12 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
|
|
** </li>
|
|
**
|
|
** <li>
|
|
-** ^If the specific value bound to a [parameter | host parameter] in the
|
|
+** ^If the specific value bound to a [parameter | host parameter] in the
|
|
** WHERE clause might influence the choice of query plan for a statement,
|
|
-** then the statement will be automatically recompiled, as if there had been
|
|
+** then the statement will be automatically recompiled, as if there had been
|
|
** a schema change, on the first [sqlite3_step()] call following any change
|
|
-** to the [sqlite3_bind_text | bindings] of that [parameter].
|
|
-** ^The specific value of a WHERE-clause [parameter] might influence the
|
|
+** to the [sqlite3_bind_text | bindings] of that [parameter].
|
|
+** ^The specific value of a WHERE-clause [parameter] might influence the
|
|
** choice of query plan if the parameter is the left-hand side of a [LIKE]
|
|
** or [GLOB] operator or if the parameter is compared to an indexed column
|
|
** and the [SQLITE_ENABLE_STAT4] compile-time option is enabled.
|
|
@@ -4032,12 +4291,17 @@ SQLITE_API int sqlite3_prepare16_v3(
|
|
** are managed by SQLite and are automatically freed when the prepared
|
|
** statement is finalized.
|
|
** ^The string returned by sqlite3_expanded_sql(P), on the other hand,
|
|
-** is obtained from [sqlite3_malloc()] and must be free by the application
|
|
+** is obtained from [sqlite3_malloc()] and must be freed by the application
|
|
** by passing it to [sqlite3_free()].
|
|
+**
|
|
+** ^The sqlite3_normalized_sql() interface is only available if
|
|
+** the [SQLITE_ENABLE_NORMALIZE] compile-time option is defined.
|
|
*/
|
|
SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt);
|
|
SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt);
|
|
+#ifdef SQLITE_ENABLE_NORMALIZE
|
|
SQLITE_API const char *sqlite3_normalized_sql(sqlite3_stmt *pStmt);
|
|
+#endif
|
|
|
|
/*
|
|
** CAPI3REF: Determine If An SQL Statement Writes The Database
|
|
@@ -4048,8 +4312,8 @@ SQLITE_API const char *sqlite3_normalized_sql(sqlite3_stmt *pStmt);
|
|
** the content of the database file.
|
|
**
|
|
** Note that [application-defined SQL functions] or
|
|
-** [virtual tables] might change the database indirectly as a side effect.
|
|
-** ^(For example, if an application defines a function "eval()" that
|
|
+** [virtual tables] might change the database indirectly as a side effect.
|
|
+** ^(For example, if an application defines a function "eval()" that
|
|
** calls [sqlite3_exec()], then the following SQL statement would
|
|
** change the database file through side-effects:
|
|
**
|
|
@@ -4063,15 +4327,28 @@ SQLITE_API const char *sqlite3_normalized_sql(sqlite3_stmt *pStmt);
|
|
** ^Transaction control statements such as [BEGIN], [COMMIT], [ROLLBACK],
|
|
** [SAVEPOINT], and [RELEASE] cause sqlite3_stmt_readonly() to return true,
|
|
** since the statements themselves do not actually modify the database but
|
|
-** rather they control the timing of when other statements modify the
|
|
+** rather they control the timing of when other statements modify the
|
|
** database. ^The [ATTACH] and [DETACH] statements also cause
|
|
** sqlite3_stmt_readonly() to return true since, while those statements
|
|
-** change the configuration of a database connection, they do not make
|
|
+** change the configuration of a database connection, they do not make
|
|
** changes to the content of the database files on disk.
|
|
** ^The sqlite3_stmt_readonly() interface returns true for [BEGIN] since
|
|
** [BEGIN] merely sets internal flags, but the [BEGIN|BEGIN IMMEDIATE] and
|
|
** [BEGIN|BEGIN EXCLUSIVE] commands do touch the database and so
|
|
** sqlite3_stmt_readonly() returns false for those commands.
|
|
+**
|
|
+** ^This routine returns false if there is any possibility that the
|
|
+** statement might change the database file. ^A false return does
|
|
+** not guarantee that the statement will change the database file.
|
|
+** ^For example, an UPDATE statement might have a WHERE clause that
|
|
+** makes it a no-op, but the sqlite3_stmt_readonly() result would still
|
|
+** be false. ^Similarly, a CREATE TABLE IF NOT EXISTS statement is a
|
|
+** read-only no-op if the table already exists, but
|
|
+** sqlite3_stmt_readonly() still returns false for such a statement.
|
|
+**
|
|
+** ^If prepared statement X is an [EXPLAIN] or [EXPLAIN QUERY PLAN]
|
|
+** statement, then sqlite3_stmt_readonly(X) returns the same value as
|
|
+** if the EXPLAIN or EXPLAIN QUERY PLAN prefix were omitted.
|
|
*/
|
|
SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
|
|
|
|
@@ -4092,18 +4369,18 @@ SQLITE_API int sqlite3_stmt_isexplain(sqlite3_stmt *pStmt);
|
|
** METHOD: sqlite3_stmt
|
|
**
|
|
** ^The sqlite3_stmt_busy(S) interface returns true (non-zero) if the
|
|
-** [prepared statement] S has been stepped at least once using
|
|
+** [prepared statement] S has been stepped at least once using
|
|
** [sqlite3_step(S)] but has neither run to completion (returned
|
|
** [SQLITE_DONE] from [sqlite3_step(S)]) nor
|
|
** been reset using [sqlite3_reset(S)]. ^The sqlite3_stmt_busy(S)
|
|
-** interface returns false if S is a NULL pointer. If S is not a
|
|
+** interface returns false if S is a NULL pointer. If S is not a
|
|
** NULL pointer and is not a pointer to a valid [prepared statement]
|
|
** object, then the behavior is undefined and probably undesirable.
|
|
**
|
|
** This interface can be used in combination [sqlite3_next_stmt()]
|
|
-** to locate all prepared statements associated with a database
|
|
+** to locate all prepared statements associated with a database
|
|
** connection that are in need of being reset. This can be used,
|
|
-** for example, in diagnostic routines to search for prepared
|
|
+** for example, in diagnostic routines to search for prepared
|
|
** statements that are holding a transaction open.
|
|
*/
|
|
SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*);
|
|
@@ -4122,7 +4399,7 @@ SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*);
|
|
** will accept either a protected or an unprotected sqlite3_value.
|
|
** Every interface that accepts sqlite3_value arguments specifies
|
|
** whether or not it requires a protected sqlite3_value. The
|
|
-** [sqlite3_value_dup()] interface can be used to construct a new
|
|
+** [sqlite3_value_dup()] interface can be used to construct a new
|
|
** protected sqlite3_value from an unprotected sqlite3_value.
|
|
**
|
|
** The terms "protected" and "unprotected" refer to whether or not
|
|
@@ -4130,7 +4407,7 @@ SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*);
|
|
** sqlite3_value object but no mutex is held for an unprotected
|
|
** sqlite3_value object. If SQLite is compiled to be single-threaded
|
|
** (with [SQLITE_THREADSAFE=0] and with [sqlite3_threadsafe()] returning 0)
|
|
-** or if SQLite is run in one of reduced mutex modes
|
|
+** or if SQLite is run in one of reduced mutex modes
|
|
** [SQLITE_CONFIG_SINGLETHREAD] or [SQLITE_CONFIG_MULTITHREAD]
|
|
** then there is no distinction between protected and unprotected
|
|
** sqlite3_value objects and they can be used interchangeably. However,
|
|
@@ -4140,6 +4417,8 @@ SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*);
|
|
**
|
|
** ^The sqlite3_value objects that are passed as parameters into the
|
|
** implementation of [application-defined SQL functions] are protected.
|
|
+** ^The sqlite3_value objects returned by [sqlite3_vtab_rhs_value()]
|
|
+** are protected.
|
|
** ^The sqlite3_value object returned by
|
|
** [sqlite3_column_value()] is unprotected.
|
|
** Unprotected sqlite3_value objects may only be used as arguments
|
|
@@ -4199,12 +4478,30 @@ typedef struct sqlite3_context sqlite3_context;
|
|
** [sqlite3_bind_parameter_index()] API if desired. ^The index
|
|
** for "?NNN" parameters is the value of NNN.
|
|
** ^The NNN value must be between 1 and the [sqlite3_limit()]
|
|
-** parameter [SQLITE_LIMIT_VARIABLE_NUMBER] (default value: 999).
|
|
+** parameter [SQLITE_LIMIT_VARIABLE_NUMBER] (default value: 32766).
|
|
**
|
|
** ^The third argument is the value to bind to the parameter.
|
|
** ^If the third parameter to sqlite3_bind_text() or sqlite3_bind_text16()
|
|
** or sqlite3_bind_blob() is a NULL pointer then the fourth parameter
|
|
** is ignored and the end result is the same as sqlite3_bind_null().
|
|
+** ^If the third parameter to sqlite3_bind_text() is not NULL, then
|
|
+** it should be a pointer to well-formed UTF8 text.
|
|
+** ^If the third parameter to sqlite3_bind_text16() is not NULL, then
|
|
+** it should be a pointer to well-formed UTF16 text.
|
|
+** ^If the third parameter to sqlite3_bind_text64() is not NULL, then
|
|
+** it should be a pointer to a well-formed unicode string that is
|
|
+** either UTF8 if the sixth parameter is SQLITE_UTF8, or UTF16
|
|
+** otherwise.
|
|
+**
|
|
+** [[byte-order determination rules]] ^The byte-order of
|
|
+** UTF16 input text is determined by the byte-order mark (BOM, U+FEFF)
|
|
+** found in first character, which is removed, or in the absence of a BOM
|
|
+** the byte order is the native byte order of the host
|
|
+** machine for sqlite3_bind_text16() or the byte order specified in
|
|
+** the 6th parameter for sqlite3_bind_text64().)^
|
|
+** ^If UTF16 input text contains invalid unicode
|
|
+** characters, then SQLite might change those invalid characters
|
|
+** into the unicode replacement character: U+FFFD.
|
|
**
|
|
** ^(In those routines that have a fourth argument, its value is the
|
|
** number of bytes in the parameter. To be clear: the value is the
|
|
@@ -4218,23 +4515,27 @@ typedef struct sqlite3_context sqlite3_context;
|
|
** or sqlite3_bind_text16() or sqlite3_bind_text64() then
|
|
** that parameter must be the byte offset
|
|
** where the NUL terminator would occur assuming the string were NUL
|
|
-** terminated. If any NUL characters occur at byte offsets less than
|
|
+** terminated. If any NUL characters occurs at byte offsets less than
|
|
** the value of the fourth parameter then the resulting string value will
|
|
** contain embedded NULs. The result of expressions involving strings
|
|
** with embedded NULs is undefined.
|
|
**
|
|
-** ^The fifth argument to the BLOB and string binding interfaces
|
|
-** is a destructor used to dispose of the BLOB or
|
|
-** string after SQLite has finished with it. ^The destructor 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.
|
|
-** ^If the fifth argument is
|
|
-** the special value [SQLITE_STATIC], then SQLite assumes that the
|
|
-** information is in static, unmanaged space and does not need to be freed.
|
|
-** ^If the fifth argument has the value [SQLITE_TRANSIENT], then
|
|
-** SQLite makes its own private copy of the data immediately, before
|
|
-** the sqlite3_bind_*() routine returns.
|
|
+** ^The fifth argument to the BLOB and string binding interfaces controls
|
|
+** or indicates the lifetime of the object referenced by the third parameter.
|
|
+** These three options exist:
|
|
+** ^ (1) A destructor to dispose of the BLOB or string after SQLite has finished
|
|
+** 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
|
|
+** 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
|
|
+** bound to something else, whichever occurs sooner.
|
|
+** ^ (3) The constant, [SQLITE_TRANSIENT], may be passed to indicate that the
|
|
+** object is to be copied prior to the return from sqlite3_bind_*(). ^The
|
|
+** object and pointer to it must remain valid until then. ^SQLite will then
|
|
+** manage the lifetime of its private copy.
|
|
**
|
|
** ^The sixth argument to sqlite3_bind_text64() must be one of
|
|
** [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE]
|
|
@@ -4380,7 +4681,7 @@ SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt*);
|
|
** METHOD: sqlite3_stmt
|
|
**
|
|
** ^Return the number of columns in the result set returned by the
|
|
-** [prepared statement]. ^If this routine returns 0, that means the
|
|
+** [prepared statement]. ^If this routine returns 0, that means the
|
|
** [prepared statement] returns no data (for example an [UPDATE]).
|
|
** ^However, just because this routine returns a positive number does not
|
|
** mean that one or more rows of data will be returned. ^A SELECT statement
|
|
@@ -4562,7 +4863,7 @@ SQLITE_API const void *sqlite3_column_decltype16(sqlite3_stmt*,int);
|
|
** For all versions of SQLite up to and including 3.6.23.1, a call to
|
|
** [sqlite3_reset()] was required after sqlite3_step() returned anything
|
|
** other than [SQLITE_ROW] before any subsequent invocation of
|
|
-** sqlite3_step(). Failure to reset the prepared statement using
|
|
+** sqlite3_step(). Failure to reset the prepared statement using
|
|
** [sqlite3_reset()] would result in an [SQLITE_MISUSE] return from
|
|
** sqlite3_step(). But after [version 3.6.23.1] ([dateof:3.6.23.1],
|
|
** sqlite3_step() began
|
|
@@ -4653,7 +4954,7 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
|
|
** <tr><td><b>sqlite3_column_int64</b><td>→<td>64-bit INTEGER result
|
|
** <tr><td><b>sqlite3_column_text</b><td>→<td>UTF-8 TEXT result
|
|
** <tr><td><b>sqlite3_column_text16</b><td>→<td>UTF-16 TEXT result
|
|
-** <tr><td><b>sqlite3_column_value</b><td>→<td>The result as an
|
|
+** <tr><td><b>sqlite3_column_value</b><td>→<td>The result as an
|
|
** [sqlite3_value|unprotected sqlite3_value] object.
|
|
** <tr><td> <td> <td>
|
|
** <tr><td><b>sqlite3_column_bytes</b><td>→<td>Size of a BLOB
|
|
@@ -4701,7 +5002,7 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
|
|
** The return value of sqlite3_column_type() can be used to decide which
|
|
** of the first six interface should be used to extract the column value.
|
|
** The value returned by sqlite3_column_type() is only meaningful if no
|
|
-** automatic type conversions have occurred for the value in question.
|
|
+** automatic type conversions have occurred for the value in question.
|
|
** After a type conversion, the result of calling sqlite3_column_type()
|
|
** is undefined, though harmless. Future
|
|
** versions of SQLite may change the behavior of sqlite3_column_type()
|
|
@@ -4729,7 +5030,7 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
|
|
** the number of bytes in that string.
|
|
** ^If the result is NULL, then sqlite3_column_bytes16() returns zero.
|
|
**
|
|
-** ^The values returned by [sqlite3_column_bytes()] and
|
|
+** ^The values returned by [sqlite3_column_bytes()] and
|
|
** [sqlite3_column_bytes16()] do not include the zero terminators at the end
|
|
** of the string. ^For clarity: the values returned by
|
|
** [sqlite3_column_bytes()] and [sqlite3_column_bytes16()] are the number of
|
|
@@ -4739,6 +5040,10 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
|
|
** even empty strings, are always zero-terminated. ^The return
|
|
** value from sqlite3_column_blob() for a zero-length BLOB is a NULL pointer.
|
|
**
|
|
+** ^Strings returned by sqlite3_column_text16() always have the endianness
|
|
+** which is native to the platform, regardless of the text encoding set
|
|
+** for the database.
|
|
+**
|
|
** <b>Warning:</b> ^The object returned by [sqlite3_column_value()] is an
|
|
** [unprotected sqlite3_value] object. In a multithreaded environment,
|
|
** an unprotected sqlite3_value object may only be used safely with
|
|
@@ -4748,11 +5053,11 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
|
|
** to routines like [sqlite3_value_int()], [sqlite3_value_text()],
|
|
** or [sqlite3_value_bytes()], the behavior is not threadsafe.
|
|
** Hence, the sqlite3_column_value() interface
|
|
-** is normally only useful within the implementation of
|
|
+** is normally only useful within the implementation of
|
|
** [application-defined SQL functions] or [virtual tables], not within
|
|
** top-level application code.
|
|
**
|
|
-** The these routines may attempt to convert the datatype of the result.
|
|
+** These routines may attempt to convert the datatype of the result.
|
|
** ^For example, if the internal representation is FLOAT and a text result
|
|
** is requested, [sqlite3_snprintf()] is used internally to perform the
|
|
** conversion automatically. ^(The following table details the conversions
|
|
@@ -4777,7 +5082,7 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
|
|
** <tr><td> TEXT <td> BLOB <td> No change
|
|
** <tr><td> BLOB <td> INTEGER <td> [CAST] to INTEGER
|
|
** <tr><td> BLOB <td> FLOAT <td> [CAST] to REAL
|
|
-** <tr><td> BLOB <td> TEXT <td> Add a zero terminator if needed
|
|
+** <tr><td> BLOB <td> TEXT <td> [CAST] to TEXT, ensure zero terminator
|
|
** </table>
|
|
** </blockquote>)^
|
|
**
|
|
@@ -4923,8 +5228,8 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
|
|
** ^These functions (collectively known as "function creation routines")
|
|
** are used to add SQL functions or aggregates or to redefine the behavior
|
|
** of existing SQL functions or aggregates. The only differences between
|
|
-** the three "sqlite3_create_function*" routines are the text encoding
|
|
-** expected for the second parameter (the name of the function being
|
|
+** the three "sqlite3_create_function*" routines are the text encoding
|
|
+** expected for the second parameter (the name of the function being
|
|
** created) and the presence or absence of a destructor callback for
|
|
** the application data pointer. Function sqlite3_create_window_function()
|
|
** is similar, but allows the user to supply the extra callback functions
|
|
@@ -4938,7 +5243,7 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
|
|
** ^The second parameter is the name of the SQL function to be created or
|
|
** redefined. ^The length of the name is limited to 255 bytes in a UTF-8
|
|
** representation, exclusive of the zero-terminator. ^Note that the name
|
|
-** length limit is in UTF-8 bytes, not characters nor UTF-16 bytes.
|
|
+** length limit is in UTF-8 bytes, not characters nor UTF-16 bytes.
|
|
** ^Any attempt to create a function with a longer name
|
|
** will result in [SQLITE_MISUSE] being returned.
|
|
**
|
|
@@ -4953,7 +5258,7 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
|
|
** ^The fourth parameter, eTextRep, specifies what
|
|
** [SQLITE_UTF8 | text encoding] this SQL function prefers for
|
|
** its parameters. The application should set this parameter to
|
|
-** [SQLITE_UTF16LE] if the function implementation invokes
|
|
+** [SQLITE_UTF16LE] if the function implementation invokes
|
|
** [sqlite3_value_text16le()] on an input, or [SQLITE_UTF16BE] if the
|
|
** implementation invokes [sqlite3_value_text16be()] on an input, or
|
|
** [SQLITE_UTF16] if [sqlite3_value_text16()] is used, or [SQLITE_UTF8]
|
|
@@ -4976,17 +5281,15 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
|
|
** within VIEWs, TRIGGERs, CHECK constraints, generated column expressions,
|
|
** index expressions, or the WHERE clause of partial indexes.
|
|
**
|
|
-** <span style="background-color:#ffff90;">
|
|
** For best security, the [SQLITE_DIRECTONLY] flag is recommended for
|
|
** all application-defined SQL functions that do not need to be
|
|
** used inside of triggers, view, CHECK constraints, or other elements of
|
|
-** the database schema. This flags is especially recommended for SQL
|
|
+** the database schema. This flags is especially recommended for SQL
|
|
** functions that have side effects or reveal internal application state.
|
|
** Without this flag, an attacker might be able to modify the schema of
|
|
** a database file to include invocations of the function with parameters
|
|
** chosen by the attacker, which the application will then execute when
|
|
** the database file is opened and read.
|
|
-** </span>
|
|
**
|
|
** ^(The fifth parameter is an arbitrary pointer. The implementation of the
|
|
** function can gain access to this pointer using [sqlite3_user_data()].)^
|
|
@@ -5001,21 +5304,21 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
|
|
** SQL function or aggregate, pass NULL pointers for all three function
|
|
** callbacks.
|
|
**
|
|
-** ^The sixth, seventh, eighth and ninth parameters (xStep, xFinal, xValue
|
|
+** ^The sixth, seventh, eighth and ninth parameters (xStep, xFinal, xValue
|
|
** and xInverse) passed to sqlite3_create_window_function are pointers to
|
|
** C-language callbacks that implement the new function. xStep and xFinal
|
|
** must both be non-NULL. xValue and xInverse may either both be NULL, in
|
|
-** which case a regular aggregate function is created, or must both be
|
|
+** which case a regular aggregate function is created, or must both be
|
|
** non-NULL, in which case the new function may be used as either an aggregate
|
|
** or aggregate window function. More details regarding the implementation
|
|
-** of aggregate window functions are
|
|
+** of aggregate window functions are
|
|
** [user-defined window functions|available here].
|
|
**
|
|
** ^(If the final parameter to sqlite3_create_function_v2() or
|
|
** sqlite3_create_window_function() is not NULL, then it is destructor for
|
|
-** the application data pointer. The destructor is invoked when the function
|
|
-** is deleted, either by being overloaded or when the database connection
|
|
-** closes.)^ ^The destructor is also invoked if the call to
|
|
+** the application data pointer. The destructor is invoked when the function
|
|
+** is deleted, either by being overloaded or when the database connection
|
|
+** closes.)^ ^The destructor is also invoked if the call to
|
|
** sqlite3_create_function_v2() fails. ^When the destructor callback is
|
|
** invoked, it is passed a single argument which is a copy of the application
|
|
** data pointer which was the fifth parameter to sqlite3_create_function_v2().
|
|
@@ -5028,7 +5331,7 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
|
|
** nArg parameter is a better match than a function implementation with
|
|
** a negative nArg. ^A function where the preferred text encoding
|
|
** matches the database encoding is a better
|
|
-** match than a function where the encoding is different.
|
|
+** match than a function where the encoding is different.
|
|
** ^A function where the encoding difference is between UTF16le and UTF16be
|
|
** is a closer match than a function where the encoding difference is
|
|
** between UTF8 and UTF16.
|
|
@@ -5100,7 +5403,7 @@ SQLITE_API int sqlite3_create_window_function(
|
|
/*
|
|
** CAPI3REF: Function Flags
|
|
**
|
|
-** These constants may be ORed together with the
|
|
+** These constants may be ORed together with the
|
|
** [SQLITE_UTF8 | preferred text encoding] as the fourth argument
|
|
** to [sqlite3_create_function()], [sqlite3_create_function16()], or
|
|
** [sqlite3_create_function_v2()].
|
|
@@ -5116,16 +5419,27 @@ SQLITE_API int sqlite3_create_window_function(
|
|
** SQLite might also optimize deterministic functions by factoring them
|
|
** out of inner loops.
|
|
** </dd>
|
|
-**
|
|
+**
|
|
** [[SQLITE_DIRECTONLY]] <dt>SQLITE_DIRECTONLY</dt><dd>
|
|
** The SQLITE_DIRECTONLY flag means that the function may only be invoked
|
|
-** from top-level SQL, and cannot be used in VIEWs or TRIGGERs nor in
|
|
+** from top-level SQL, and cannot be used in VIEWs or TRIGGERs nor in
|
|
** schema structures such as [CHECK constraints], [DEFAULT clauses],
|
|
** [expression indexes], [partial indexes], or [generated columns].
|
|
-** The SQLITE_DIRECTONLY flags is a security feature which is recommended
|
|
-** for all [application-defined SQL functions], and especially for functions
|
|
-** that have side-effects or that could potentially leak sensitive
|
|
-** information.
|
|
+** <p>
|
|
+** The SQLITE_DIRECTONLY flag is recommended for any
|
|
+** [application-defined SQL function]
|
|
+** that has side-effects or that could potentially leak sensitive information.
|
|
+** This will prevent attacks in which an application is tricked
|
|
+** into using a database file that has had its schema surreptiously
|
|
+** modified to invoke the application-defined function in ways that are
|
|
+** harmful.
|
|
+** <p>
|
|
+** Some people say it is good practice to set SQLITE_DIRECTONLY on all
|
|
+** [application-defined SQL functions], regardless of whether or not they
|
|
+** are security sensitive, as doing so prevents those functions from being used
|
|
+** inside of the database schema, and thus ensures that the database
|
|
+** can be inspected and modified using generic tools (such as the [CLI])
|
|
+** that do not have access to the application-defined functions.
|
|
** </dd>
|
|
**
|
|
** [[SQLITE_INNOCUOUS]] <dt>SQLITE_INNOCUOUS</dt><dd>
|
|
@@ -5172,7 +5486,7 @@ SQLITE_API int sqlite3_create_window_function(
|
|
** DEPRECATED
|
|
**
|
|
** These functions are [deprecated]. In order to maintain
|
|
-** backwards compatibility with older code, these functions continue
|
|
+** backwards compatibility with older code, these functions continue
|
|
** to be supported. However, new applications should avoid
|
|
** the use of these functions. To encourage programmers to avoid
|
|
** these functions, we will not explain what they do.
|
|
@@ -5240,11 +5554,11 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6
|
|
** sqlite3_value_text16be() and sqlite3_value_text16le() interfaces
|
|
** extract UTF-16 strings as big-endian and little-endian respectively.
|
|
**
|
|
-** ^If [sqlite3_value] object V was initialized
|
|
+** ^If [sqlite3_value] object V was initialized
|
|
** using [sqlite3_bind_pointer(S,I,P,X,D)] or [sqlite3_result_pointer(C,P,X,D)]
|
|
** and if X and Y are strings that compare equal according to strcmp(X,Y),
|
|
** then sqlite3_value_pointer(V,Y) will return the pointer P. ^Otherwise,
|
|
-** sqlite3_value_pointer(V,Y) returns a NULL. The sqlite3_bind_pointer()
|
|
+** sqlite3_value_pointer(V,Y) returns a NULL. The sqlite3_bind_pointer()
|
|
** routine is part of the [pointer passing interface] added for SQLite 3.20.0.
|
|
**
|
|
** ^(The sqlite3_value_type(V) interface returns the
|
|
@@ -5331,6 +5645,28 @@ SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*);
|
|
SQLITE_API int sqlite3_value_nochange(sqlite3_value*);
|
|
SQLITE_API int sqlite3_value_frombind(sqlite3_value*);
|
|
|
|
+/*
|
|
+** CAPI3REF: Report the internal text encoding state of an sqlite3_value object
|
|
+** METHOD: sqlite3_value
|
|
+**
|
|
+** ^(The sqlite3_value_encoding(X) interface returns one of [SQLITE_UTF8],
|
|
+** [SQLITE_UTF16BE], or [SQLITE_UTF16LE] according to the current text encoding
|
|
+** of the value X, assuming that X has type TEXT.)^ If sqlite3_value_type(X)
|
|
+** returns something other than SQLITE_TEXT, then the return value from
|
|
+** sqlite3_value_encoding(X) is meaningless. ^Calls to
|
|
+** [sqlite3_value_text(X)], [sqlite3_value_text16(X)], [sqlite3_value_text16be(X)],
|
|
+** [sqlite3_value_text16le(X)], [sqlite3_value_bytes(X)], or
|
|
+** [sqlite3_value_bytes16(X)] might change the encoding of the value X and
|
|
+** thus change the return from subsequent calls to sqlite3_value_encoding(X).
|
|
+**
|
|
+** This routine is intended for used by applications that test and validate
|
|
+** the SQLite implementation. This routine is inquiring about the opaque
|
|
+** internal state of an [sqlite3_value] object. Ordinary applications should
|
|
+** not need to know what the internal state of an sqlite3_value object is and
|
|
+** hence should not need to use this interface.
|
|
+*/
|
|
+SQLITE_API int sqlite3_value_encoding(sqlite3_value*);
|
|
+
|
|
/*
|
|
** CAPI3REF: Finding The Subtype Of SQL Values
|
|
** METHOD: sqlite3_value
|
|
@@ -5351,7 +5687,8 @@ SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value*);
|
|
** object D and returns a pointer to that copy. ^The [sqlite3_value] returned
|
|
** is a [protected sqlite3_value] object even if the input is not.
|
|
** ^The sqlite3_value_dup(V) interface returns NULL if V is NULL or if a
|
|
-** memory allocation fails.
|
|
+** memory allocation fails. ^If V is a [pointer value], then the result
|
|
+** of sqlite3_value_dup(V) is a NULL value.
|
|
**
|
|
** ^The sqlite3_value_free(V) interface frees an [sqlite3_value] object
|
|
** previously obtained from [sqlite3_value_dup()]. ^If V is a NULL pointer
|
|
@@ -5367,7 +5704,7 @@ SQLITE_API void sqlite3_value_free(sqlite3_value*);
|
|
** Implementations of aggregate SQL functions use this
|
|
** routine to allocate memory for storing their state.
|
|
**
|
|
-** ^The first time the sqlite3_aggregate_context(C,N) routine is called
|
|
+** ^The first time the sqlite3_aggregate_context(C,N) routine is called
|
|
** for a particular aggregate function, SQLite allocates
|
|
** N bytes of memory, zeroes out that memory, and returns a pointer
|
|
** to the new memory. ^On second and subsequent calls to
|
|
@@ -5380,19 +5717,19 @@ SQLITE_API void sqlite3_value_free(sqlite3_value*);
|
|
** In those cases, sqlite3_aggregate_context() might be called for the
|
|
** first time from within xFinal().)^
|
|
**
|
|
-** ^The sqlite3_aggregate_context(C,N) routine returns a NULL pointer
|
|
+** ^The sqlite3_aggregate_context(C,N) routine returns a NULL pointer
|
|
** when first called if N is less than or equal to zero or if a memory
|
|
-** allocate error occurs.
|
|
+** allocation error occurs.
|
|
**
|
|
** ^(The amount of space allocated by sqlite3_aggregate_context(C,N) is
|
|
** determined by the N parameter on first successful call. Changing the
|
|
-** value of N in any subsequents call to sqlite3_aggregate_context() within
|
|
+** value of N in any subsequent call to sqlite3_aggregate_context() within
|
|
** the same aggregate function instance will not resize the memory
|
|
** allocation.)^ Within the xFinal callback, it is customary to set
|
|
-** N=0 in calls to sqlite3_aggregate_context(C,N) so that no
|
|
+** N=0 in calls to sqlite3_aggregate_context(C,N) so that no
|
|
** pointless memory allocations occur.
|
|
**
|
|
-** ^SQLite automatically frees the memory allocated by
|
|
+** ^SQLite automatically frees the memory allocated by
|
|
** sqlite3_aggregate_context() when the aggregate query concludes.
|
|
**
|
|
** The first parameter must be a copy of the
|
|
@@ -5442,7 +5779,7 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
|
|
** 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.
|
|
+** metadata associated with the pattern string.
|
|
** Then as long as the pattern string remains the same,
|
|
** the compiled regular expression can be reused on multiple
|
|
** invocations of the same function.
|
|
@@ -5468,10 +5805,10 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
|
|
** SQL statement)^, or
|
|
** <li> ^(when sqlite3_set_auxdata() is invoked again on the same
|
|
** parameter)^, or
|
|
-** <li> ^(during the original sqlite3_set_auxdata() call when a memory
|
|
+** <li> ^(during the original sqlite3_set_auxdata() call when a memory
|
|
** allocation error occurs.)^ </ul>
|
|
**
|
|
-** Note the last bullet in particular. The destructor X in
|
|
+** Note the last bullet in particular. The destructor X in
|
|
** sqlite3_set_auxdata(C,N,P,X) might be called immediately, before the
|
|
** sqlite3_set_auxdata() interface even returns. Hence sqlite3_set_auxdata()
|
|
** should be called near the end of the function implementation and the
|
|
@@ -5543,8 +5880,9 @@ typedef void (*sqlite3_destructor_type)(void*);
|
|
** 2nd parameter of sqlite3_result_error() or sqlite3_result_error16()
|
|
** as the text of an error message. ^SQLite interprets the error
|
|
** message string from sqlite3_result_error() as UTF-8. ^SQLite
|
|
-** interprets the string from sqlite3_result_error16() as UTF-16 in native
|
|
-** byte order. ^If the third parameter to sqlite3_result_error()
|
|
+** interprets the string from sqlite3_result_error16() as UTF-16 using
|
|
+** the same [byte-order determination rules] as [sqlite3_bind_text16()].
|
|
+** ^If the third parameter to sqlite3_result_error()
|
|
** or sqlite3_result_error16() is negative then SQLite takes as the error
|
|
** message all text up through the first zero character.
|
|
** ^If the third parameter to sqlite3_result_error() or
|
|
@@ -5586,9 +5924,10 @@ typedef void (*sqlite3_destructor_type)(void*);
|
|
** of [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE].
|
|
** ^SQLite takes the text result from the application from
|
|
** the 2nd parameter of the sqlite3_result_text* interfaces.
|
|
-** ^If the 3rd parameter to the sqlite3_result_text* interfaces
|
|
-** is negative, then SQLite takes result text from the 2nd parameter
|
|
-** through the first zero character.
|
|
+** ^If the 3rd parameter to any of the sqlite3_result_text* interfaces
|
|
+** other than sqlite3_result_text64() is negative, then SQLite computes
|
|
+** the string length itself by searching the 2nd parameter for the first
|
|
+** zero character.
|
|
** ^If the 3rd parameter to the sqlite3_result_text* interfaces
|
|
** is non-negative, then as many bytes (not characters) of the text
|
|
** pointed to by the 2nd parameter are taken as the application-defined
|
|
@@ -5612,6 +5951,25 @@ typedef void (*sqlite3_destructor_type)(void*);
|
|
** then SQLite makes a copy of the result into space obtained
|
|
** from [sqlite3_malloc()] before it returns.
|
|
**
|
|
+** ^For the sqlite3_result_text16(), sqlite3_result_text16le(), and
|
|
+** sqlite3_result_text16be() routines, and for sqlite3_result_text64()
|
|
+** when the encoding is not UTF8, if the input UTF16 begins with a
|
|
+** byte-order mark (BOM, U+FEFF) then the BOM is removed from the
|
|
+** string and the rest of the string is interpreted according to the
|
|
+** byte-order specified by the BOM. ^The byte-order specified by
|
|
+** the BOM at the beginning of the text overrides the byte-order
|
|
+** specified by the interface procedure. ^So, for example, if
|
|
+** sqlite3_result_text16le() is invoked with text that begins
|
|
+** with bytes 0xfe, 0xff (a big-endian byte-order mark) then the
|
|
+** first two bytes of input are skipped and the remaining input
|
|
+** is interpreted as UTF16BE text.
|
|
+**
|
|
+** ^For UTF16 input text to the sqlite3_result_text16(),
|
|
+** sqlite3_result_text16be(), sqlite3_result_text16le(), and
|
|
+** sqlite3_result_text64() routines, if the text contains invalid
|
|
+** UTF16 characters, the invalid characters might be converted
|
|
+** into the unicode replacement character, U+FFFD.
|
|
+**
|
|
** ^The sqlite3_result_value() interface sets the result of
|
|
** the application-defined function to be a copy of the
|
|
** [unprotected sqlite3_value] object specified by the 2nd parameter. ^The
|
|
@@ -5624,7 +5982,7 @@ typedef void (*sqlite3_destructor_type)(void*);
|
|
**
|
|
** ^The sqlite3_result_pointer(C,P,T,D) interface sets the result to an
|
|
** SQL NULL value, just like [sqlite3_result_null(C)], except that it
|
|
-** also associates the host-language pointer P or type T with that
|
|
+** also associates the host-language pointer P or type T with that
|
|
** NULL value such that the pointer can be retrieved within an
|
|
** [application-defined SQL function] using [sqlite3_value_pointer()].
|
|
** ^If the D parameter is not NULL, then it is a pointer to a destructor
|
|
@@ -5666,8 +6024,8 @@ SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n);
|
|
** METHOD: sqlite3_context
|
|
**
|
|
** The sqlite3_result_subtype(C,T) function causes the subtype of
|
|
-** the result from the [application-defined SQL function] with
|
|
-** [sqlite3_context] C to be the value T. Only the lower 8 bits
|
|
+** the result from the [application-defined SQL function] with
|
|
+** [sqlite3_context] C to be the value T. Only the lower 8 bits
|
|
** of the subtype T are preserved in current versions of SQLite;
|
|
** higher order bits are discarded.
|
|
** The number of subtype bytes preserved by SQLite might increase
|
|
@@ -5714,7 +6072,7 @@ SQLITE_API void sqlite3_result_subtype(sqlite3_context*,unsigned int);
|
|
** deleted. ^When all collating functions having the same name are deleted,
|
|
** that collation is no longer usable.
|
|
**
|
|
-** ^The collating function callback is invoked with a copy of the pArg
|
|
+** ^The collating function callback is invoked with a copy of the pArg
|
|
** application data pointer and with two strings in the encoding specified
|
|
** by the eTextRep argument. The two integer parameters to the collating
|
|
** function callback are the length of the two strings, in bytes. The collating
|
|
@@ -5745,36 +6103,36 @@ SQLITE_API void sqlite3_result_subtype(sqlite3_context*,unsigned int);
|
|
** calls to the collation creation functions or when the
|
|
** [database connection] is closed using [sqlite3_close()].
|
|
**
|
|
-** ^The xDestroy callback is <u>not</u> called if the
|
|
+** ^The xDestroy callback is <u>not</u> called if the
|
|
** sqlite3_create_collation_v2() function fails. Applications that invoke
|
|
-** sqlite3_create_collation_v2() with a non-NULL xDestroy argument should
|
|
+** sqlite3_create_collation_v2() with a non-NULL xDestroy argument should
|
|
** check the return code and dispose of the application data pointer
|
|
** themselves rather than expecting SQLite to deal with it for them.
|
|
-** This is different from every other SQLite interface. The inconsistency
|
|
-** is unfortunate but cannot be changed without breaking backwards
|
|
+** This is different from every other SQLite interface. The inconsistency
|
|
+** is unfortunate but cannot be changed without breaking backwards
|
|
** compatibility.
|
|
**
|
|
** See also: [sqlite3_collation_needed()] and [sqlite3_collation_needed16()].
|
|
*/
|
|
SQLITE_API int sqlite3_create_collation(
|
|
- sqlite3*,
|
|
- const char *zName,
|
|
- int eTextRep,
|
|
+ sqlite3*,
|
|
+ const char *zName,
|
|
+ int eTextRep,
|
|
void *pArg,
|
|
int(*xCompare)(void*,int,const void*,int,const void*)
|
|
);
|
|
SQLITE_API int sqlite3_create_collation_v2(
|
|
- sqlite3*,
|
|
- const char *zName,
|
|
- int eTextRep,
|
|
+ sqlite3*,
|
|
+ const char *zName,
|
|
+ int eTextRep,
|
|
void *pArg,
|
|
int(*xCompare)(void*,int,const void*,int,const void*),
|
|
void(*xDestroy)(void*)
|
|
);
|
|
SQLITE_API int sqlite3_create_collation16(
|
|
- sqlite3*,
|
|
+ sqlite3*,
|
|
const void *zName,
|
|
- int eTextRep,
|
|
+ int eTextRep,
|
|
void *pArg,
|
|
int(*xCompare)(void*,int,const void*,int,const void*)
|
|
);
|
|
@@ -5807,64 +6165,19 @@ SQLITE_API int sqlite3_create_collation16(
|
|
** [sqlite3_create_collation_v2()].
|
|
*/
|
|
SQLITE_API int sqlite3_collation_needed(
|
|
- sqlite3*,
|
|
- void*,
|
|
+ sqlite3*,
|
|
+ void*,
|
|
void(*)(void*,sqlite3*,int eTextRep,const char*)
|
|
);
|
|
SQLITE_API int sqlite3_collation_needed16(
|
|
- sqlite3*,
|
|
+ sqlite3*,
|
|
void*,
|
|
void(*)(void*,sqlite3*,int eTextRep,const void*)
|
|
);
|
|
|
|
-#ifdef SQLITE_HAS_CODEC
|
|
-/*
|
|
-** Specify the key for an encrypted database. This routine should be
|
|
-** called right after sqlite3_open().
|
|
-**
|
|
-** The code to implement this API is not available in the public release
|
|
-** of SQLite.
|
|
-*/
|
|
-SQLITE_API int sqlite3_key(
|
|
- sqlite3 *db, /* Database to be rekeyed */
|
|
- const void *pKey, int nKey /* The key */
|
|
-);
|
|
-SQLITE_API int sqlite3_key_v2(
|
|
- sqlite3 *db, /* Database to be rekeyed */
|
|
- const char *zDbName, /* Name of the database */
|
|
- const void *pKey, int nKey /* The key */
|
|
-);
|
|
-
|
|
-/*
|
|
-** Change the key on an open database. If the current database is not
|
|
-** encrypted, this routine will encrypt it. If pNew==0 or nNew==0, the
|
|
-** database is decrypted.
|
|
-**
|
|
-** The code to implement this API is not available in the public release
|
|
-** of SQLite.
|
|
-*/
|
|
-SQLITE_API int sqlite3_rekey(
|
|
- sqlite3 *db, /* Database to be rekeyed */
|
|
- const void *pKey, int nKey /* The new key */
|
|
-);
|
|
-SQLITE_API int sqlite3_rekey_v2(
|
|
- sqlite3 *db, /* Database to be rekeyed */
|
|
- const char *zDbName, /* Name of the database */
|
|
- const void *pKey, int nKey /* The new key */
|
|
-);
|
|
-
|
|
-/*
|
|
-** Specify the activation key for a SEE database. Unless
|
|
-** activated, none of the SEE routines will work.
|
|
-*/
|
|
-SQLITE_API void sqlite3_activate_see(
|
|
- const char *zPassPhrase /* Activation phrase */
|
|
-);
|
|
-#endif
|
|
-
|
|
#ifdef SQLITE_ENABLE_CEROD
|
|
/*
|
|
-** Specify the activation key for a CEROD database. Unless
|
|
+** Specify the activation key for a CEROD database. Unless
|
|
** activated, none of the CEROD routines will work.
|
|
*/
|
|
SQLITE_API void sqlite3_activate_cerod(
|
|
@@ -5920,7 +6233,7 @@ SQLITE_API int sqlite3_sleep(int);
|
|
** ^The [temp_store_directory pragma] may modify this variable and cause
|
|
** it to point to memory obtained from [sqlite3_malloc]. ^Furthermore,
|
|
** the [temp_store_directory pragma] always assumes that any string
|
|
-** that this variable points to is held in memory obtained from
|
|
+** that this variable points to is held in memory obtained from
|
|
** [sqlite3_malloc] and the pragma may attempt to free that memory
|
|
** using [sqlite3_free].
|
|
** Hence, if this variable is modified directly, either it should be
|
|
@@ -5977,7 +6290,7 @@ SQLITE_API SQLITE_EXTERN char *sqlite3_temp_directory;
|
|
** ^The [data_store_directory pragma] may modify this variable and cause
|
|
** it to point to memory obtained from [sqlite3_malloc]. ^Furthermore,
|
|
** the [data_store_directory pragma] always assumes that any string
|
|
-** that this variable points to is held in memory obtained from
|
|
+** that this variable points to is held in memory obtained from
|
|
** [sqlite3_malloc] and the pragma may attempt to free that memory
|
|
** using [sqlite3_free].
|
|
** Hence, if this variable is modified directly, either it should be
|
|
@@ -6058,6 +6371,28 @@ SQLITE_API int sqlite3_get_autocommit(sqlite3*);
|
|
*/
|
|
SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*);
|
|
|
|
+/*
|
|
+** CAPI3REF: Return The Schema Name For A Database Connection
|
|
+** METHOD: sqlite3
|
|
+**
|
|
+** ^The sqlite3_db_name(D,N) interface returns a pointer to the schema name
|
|
+** for the N-th database on database connection D, or a NULL pointer of N is
|
|
+** out of range. An N value of 0 means the main database file. An N of 1 is
|
|
+** the "temp" schema. Larger values of N correspond to various ATTACH-ed
|
|
+** databases.
|
|
+**
|
|
+** Space to hold the string that is returned by sqlite3_db_name() is managed
|
|
+** by SQLite itself. The string might be deallocated by any operation that
|
|
+** changes the schema, including [ATTACH] or [DETACH] or calls to
|
|
+** [sqlite3_serialize()] or [sqlite3_deserialize()], even operations that
|
|
+** occur on a different thread. Applications that need to
|
|
+** remember the string long-term should make their own copy. Applications that
|
|
+** are accessing the same database connection simultaneously on multiple
|
|
+** threads should mutex-protect calls to this API and should make their own
|
|
+** private copy of the result prior to releasing the mutex.
|
|
+*/
|
|
+SQLITE_API const char *sqlite3_db_name(sqlite3 *db, int N);
|
|
+
|
|
/*
|
|
** CAPI3REF: Return The Filename For A Database Connection
|
|
** METHOD: sqlite3
|
|
@@ -6088,7 +6423,7 @@ SQLITE_API sqlite3 *sqlite3_db_handle(sqlite3_stmt*);
|
|
** <li> [sqlite3_filename_wal()]
|
|
** </ul>
|
|
*/
|
|
-SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName);
|
|
+SQLITE_API sqlite3_filename sqlite3_db_filename(sqlite3 *db, const char *zDbName);
|
|
|
|
/*
|
|
** CAPI3REF: Determine if a database is read-only
|
|
@@ -6100,6 +6435,57 @@ SQLITE_API const char *sqlite3_db_filename(sqlite3 *db, const char *zDbName);
|
|
*/
|
|
SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName);
|
|
|
|
+/*
|
|
+** CAPI3REF: Determine the transaction state of a database
|
|
+** METHOD: sqlite3
|
|
+**
|
|
+** ^The sqlite3_txn_state(D,S) interface returns the current
|
|
+** [transaction state] of schema S in database connection D. ^If S is NULL,
|
|
+** then the highest transaction state of any schema on database connection D
|
|
+** is returned. Transaction states are (in order of lowest to highest):
|
|
+** <ol>
|
|
+** <li value="0"> SQLITE_TXN_NONE
|
|
+** <li value="1"> SQLITE_TXN_READ
|
|
+** <li value="2"> SQLITE_TXN_WRITE
|
|
+** </ol>
|
|
+** ^If the S argument to sqlite3_txn_state(D,S) is not the name of
|
|
+** a valid schema, then -1 is returned.
|
|
+*/
|
|
+SQLITE_API int sqlite3_txn_state(sqlite3*,const char *zSchema);
|
|
+
|
|
+/*
|
|
+** CAPI3REF: Allowed return values from [sqlite3_txn_state()]
|
|
+** KEYWORDS: {transaction state}
|
|
+**
|
|
+** These constants define the current transaction state of a database file.
|
|
+** ^The [sqlite3_txn_state(D,S)] interface returns one of these
|
|
+** constants in order to describe the transaction state of schema S
|
|
+** in [database connection] D.
|
|
+**
|
|
+** <dl>
|
|
+** [[SQLITE_TXN_NONE]] <dt>SQLITE_TXN_NONE</dt>
|
|
+** <dd>The SQLITE_TXN_NONE state means that no transaction is currently
|
|
+** pending.</dd>
|
|
+**
|
|
+** [[SQLITE_TXN_READ]] <dt>SQLITE_TXN_READ</dt>
|
|
+** <dd>The SQLITE_TXN_READ state means that the database is currently
|
|
+** in a read transaction. Content has been read from the database file
|
|
+** but nothing in the database file has changed. The transaction state
|
|
+** will advanced to SQLITE_TXN_WRITE if any changes occur and there are
|
|
+** no other conflicting concurrent write transactions. The transaction
|
|
+** state will revert to SQLITE_TXN_NONE following a [ROLLBACK] or
|
|
+** [COMMIT].</dd>
|
|
+**
|
|
+** [[SQLITE_TXN_WRITE]] <dt>SQLITE_TXN_WRITE</dt>
|
|
+** <dd>The SQLITE_TXN_WRITE state means that the database is currently
|
|
+** in a write transaction. Content has been written to the database file
|
|
+** but has not yet committed. The transaction state will change to
|
|
+** to SQLITE_TXN_NONE at the next [ROLLBACK] or [COMMIT].</dd>
|
|
+*/
|
|
+#define SQLITE_TXN_NONE 0
|
|
+#define SQLITE_TXN_READ 1
|
|
+#define SQLITE_TXN_WRITE 2
|
|
+
|
|
/*
|
|
** CAPI3REF: Find the next prepared statement
|
|
** METHOD: sqlite3
|
|
@@ -6166,6 +6552,72 @@ SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt);
|
|
SQLITE_API void *sqlite3_commit_hook(sqlite3*, int(*)(void*), void*);
|
|
SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
|
|
|
|
+/*
|
|
+** CAPI3REF: Autovacuum Compaction Amount Callback
|
|
+** METHOD: sqlite3
|
|
+**
|
|
+** ^The sqlite3_autovacuum_pages(D,C,P,X) interface registers a callback
|
|
+** function C that is invoked prior to each autovacuum of the database
|
|
+** file. ^The callback is passed a copy of the generic data pointer (P),
|
|
+** the schema-name of the attached database that is being autovacuumed,
|
|
+** the size of the database file in pages, the number of free pages,
|
|
+** and the number of bytes per page, respectively. The callback should
|
|
+** return the number of free pages that should be removed by the
|
|
+** autovacuum. ^If the callback returns zero, then no autovacuum happens.
|
|
+** ^If the value returned is greater than or equal to the number of
|
|
+** free pages, then a complete autovacuum happens.
|
|
+**
|
|
+** <p>^If there are multiple ATTACH-ed database files that are being
|
|
+** modified as part of a transaction commit, then the autovacuum pages
|
|
+** callback is invoked separately for each file.
|
|
+**
|
|
+** <p><b>The callback is not reentrant.</b> The callback function should
|
|
+** not attempt to invoke any other SQLite interface. If it does, bad
|
|
+** things may happen, including segmentation faults and corrupt database
|
|
+** files. The callback function should be a simple function that
|
|
+** does some arithmetic on its input parameters and returns a result.
|
|
+**
|
|
+** ^The X parameter to sqlite3_autovacuum_pages(D,C,P,X) is an optional
|
|
+** destructor for the P parameter. ^If X is not NULL, then X(P) is
|
|
+** invoked whenever the database connection closes or when the callback
|
|
+** is overwritten by another invocation of sqlite3_autovacuum_pages().
|
|
+**
|
|
+** <p>^There is only one autovacuum pages callback per database connection.
|
|
+** ^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
|
|
+** 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
|
|
+** return codes might be added in future releases.
|
|
+**
|
|
+** <p>If no autovacuum pages callback is specified (the usual case) or
|
|
+** a NULL pointer is provided for the callback,
|
|
+** then the default behavior is to vacuum all free pages. So, in other
|
|
+** words, the default behavior is the same as if the callback function
|
|
+** were something like this:
|
|
+**
|
|
+** <blockquote><pre>
|
|
+** unsigned int demonstration_autovac_pages_callback(
|
|
+** void *pClientData,
|
|
+** const char *zSchema,
|
|
+** unsigned int nDbPage,
|
|
+** unsigned int nFreePage,
|
|
+** unsigned int nBytePerPage
|
|
+** ){
|
|
+** return nFreePage;
|
|
+** }
|
|
+** </pre></blockquote>
|
|
+*/
|
|
+SQLITE_API int sqlite3_autovacuum_pages(
|
|
+ sqlite3 *db,
|
|
+ unsigned int(*)(void*,const char*,unsigned int,unsigned int,unsigned int),
|
|
+ void*,
|
|
+ void(*)(void*)
|
|
+);
|
|
+
|
|
+
|
|
/*
|
|
** CAPI3REF: Data Change Notification Callbacks
|
|
** METHOD: sqlite3
|
|
@@ -6190,7 +6642,7 @@ SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
|
|
** ^In the case of an update, this is the [rowid] after the update takes place.
|
|
**
|
|
** ^(The update hook is not invoked when internal system tables are
|
|
-** modified (i.e. sqlite_master and sqlite_sequence).)^
|
|
+** modified (i.e. sqlite_sequence).)^
|
|
** ^The update hook is not invoked when [WITHOUT ROWID] tables are modified.
|
|
**
|
|
** ^In the current implementation, the update hook
|
|
@@ -6216,7 +6668,7 @@ SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
|
|
** and [sqlite3_preupdate_hook()] interfaces.
|
|
*/
|
|
SQLITE_API void *sqlite3_update_hook(
|
|
- sqlite3*,
|
|
+ sqlite3*,
|
|
void(*)(void *,int ,char const *,char const *,sqlite3_int64),
|
|
void*
|
|
);
|
|
@@ -6229,8 +6681,13 @@ SQLITE_API void *sqlite3_update_hook(
|
|
** to the same database. Sharing is enabled if the argument is true
|
|
** and disabled if the argument is false.)^
|
|
**
|
|
+** This interface is omitted if SQLite is compiled with
|
|
+** [-DSQLITE_OMIT_SHARED_CACHE]. The [-DSQLITE_OMIT_SHARED_CACHE]
|
|
+** compile-time option is recommended because the
|
|
+** [use of shared cache mode is discouraged].
|
|
+**
|
|
** ^Cache sharing is enabled and disabled for an entire process.
|
|
-** This is a change as of SQLite [version 3.5.0] ([dateof:3.5.0]).
|
|
+** This is a change as of SQLite [version 3.5.0] ([dateof:3.5.0]).
|
|
** In prior versions of SQLite,
|
|
** sharing was enabled or disabled for each thread separately.
|
|
**
|
|
@@ -6251,8 +6708,8 @@ SQLITE_API void *sqlite3_update_hook(
|
|
** with the [SQLITE_OPEN_SHAREDCACHE] flag.
|
|
**
|
|
** Note: This method is disabled on MacOS X 10.7 and iOS version 5.0
|
|
-** and will always return SQLITE_MISUSE. On those systems,
|
|
-** shared cache mode should be enabled per-database connection via
|
|
+** and will always return SQLITE_MISUSE. On those systems,
|
|
+** shared cache mode should be enabled per-database connection via
|
|
** [sqlite3_open_v2()] with [SQLITE_OPEN_SHAREDCACHE].
|
|
**
|
|
** This interface is threadsafe on processors where writing a
|
|
@@ -6305,7 +6762,7 @@ SQLITE_API int sqlite3_db_release_memory(sqlite3*);
|
|
** as heap memory usages approaches the limit.
|
|
** ^The soft heap limit is "soft" because even though SQLite strives to stay
|
|
** below the limit, it will exceed the limit rather than generate
|
|
-** an [SQLITE_NOMEM] error. In other words, the soft heap limit
|
|
+** an [SQLITE_NOMEM] error. In other words, the soft heap limit
|
|
** is advisory only.
|
|
**
|
|
** ^The sqlite3_hard_heap_limit64(N) interface sets a hard upper bound of
|
|
@@ -6327,7 +6784,7 @@ SQLITE_API int sqlite3_db_release_memory(sqlite3*);
|
|
** ^The soft heap limit may not be greater than the hard heap limit.
|
|
** ^If the hard heap limit is enabled and if sqlite3_soft_heap_limit(N)
|
|
** is invoked with a value of N that is greater than the hard heap limit,
|
|
-** the the soft heap limit is set to the value of the hard heap limit.
|
|
+** the soft heap limit is set to the value of the hard heap limit.
|
|
** ^The soft heap limit is automatically enabled whenever the hard heap
|
|
** limit is enabled. ^When sqlite3_hard_heap_limit64(N) is invoked and
|
|
** the soft heap limit is outside the range of 1..N, then the soft heap
|
|
@@ -6421,7 +6878,7 @@ SQLITE_API SQLITE_DEPRECATED void sqlite3_soft_heap_limit(int N);
|
|
**
|
|
** ^If the specified table is actually a view, an [error code] is returned.
|
|
**
|
|
-** ^If the specified column is "rowid", "oid" or "_rowid_" and the table
|
|
+** ^If the specified column is "rowid", "oid" or "_rowid_" and the table
|
|
** is not a [WITHOUT ROWID] table and an
|
|
** [INTEGER PRIMARY KEY] column has been explicitly declared, then the output
|
|
** parameters are set for the explicitly declared column. ^(If there is no
|
|
@@ -6487,7 +6944,7 @@ SQLITE_API int sqlite3_table_column_metadata(
|
|
** prior to calling this API,
|
|
** otherwise an error will be returned.
|
|
**
|
|
-** <b>Security warning:</b> It is recommended that the
|
|
+** <b>Security warning:</b> It is recommended that the
|
|
** [SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION] method be used to enable only this
|
|
** interface. The use of the [sqlite3_enable_load_extension()] interface
|
|
** should be avoided. This will keep the SQL function [load_extension()]
|
|
@@ -6574,7 +7031,7 @@ SQLITE_API int sqlite3_auto_extension(void(*xEntryPoint)(void));
|
|
** ^The [sqlite3_cancel_auto_extension(X)] interface unregisters the
|
|
** initialization routine X that was registered using a prior call to
|
|
** [sqlite3_auto_extension(X)]. ^The [sqlite3_cancel_auto_extension(X)]
|
|
-** routine returns 1 if initialization routine X was successfully
|
|
+** routine returns 1 if initialization routine X was successfully
|
|
** unregistered and it returns 0 if X was not on the list of initialization
|
|
** routines.
|
|
*/
|
|
@@ -6588,15 +7045,6 @@ SQLITE_API int sqlite3_cancel_auto_extension(void(*xEntryPoint)(void));
|
|
*/
|
|
SQLITE_API void sqlite3_reset_auto_extension(void);
|
|
|
|
-/*
|
|
-** The interface to the virtual-table mechanism is currently considered
|
|
-** to be experimental. The interface might change in incompatible ways.
|
|
-** If this is a problem for you, do not use the interface at this time.
|
|
-**
|
|
-** When the virtual-table mechanism stabilizes, we will declare the
|
|
-** interface fixed, support it indefinitely, and remove this comment.
|
|
-*/
|
|
-
|
|
/*
|
|
** Structures used by the virtual table interface
|
|
*/
|
|
@@ -6609,8 +7057,8 @@ typedef struct sqlite3_module sqlite3_module;
|
|
** CAPI3REF: Virtual Table Object
|
|
** KEYWORDS: sqlite3_module {virtual table module}
|
|
**
|
|
-** This structure, sometimes called a "virtual table module",
|
|
-** defines the implementation of a [virtual table].
|
|
+** This structure, sometimes called a "virtual table module",
|
|
+** defines the implementation of a [virtual table].
|
|
** This structure consists mostly of methods for the module.
|
|
**
|
|
** ^A virtual table module is created by filling in a persistent
|
|
@@ -6649,7 +7097,7 @@ struct sqlite3_module {
|
|
void (**pxFunc)(sqlite3_context*,int,sqlite3_value**),
|
|
void **ppArg);
|
|
int (*xRename)(sqlite3_vtab *pVtab, const char *zNew);
|
|
- /* The methods above are in version 1 of the sqlite_module object. Those
|
|
+ /* The methods above are in version 1 of the sqlite_module object. Those
|
|
** below are for version 2 and greater. */
|
|
int (*xSavepoint)(sqlite3_vtab *pVTab, int);
|
|
int (*xRelease)(sqlite3_vtab *pVTab, int);
|
|
@@ -6699,7 +7147,7 @@ struct sqlite3_module {
|
|
** required by SQLite. If the table has at least 64 columns and any column
|
|
** to the right of the first 63 is required, then bit 63 of colUsed is also
|
|
** set. In other words, column iCol may be required if the expression
|
|
-** (colUsed & ((sqlite3_uint64)1 << (iCol>=63 ? 63 : iCol))) evaluates to
|
|
+** (colUsed & ((sqlite3_uint64)1 << (iCol>=63 ? 63 : iCol))) evaluates to
|
|
** non-zero.
|
|
**
|
|
** The [xBestIndex] method must fill aConstraintUsage[] with information
|
|
@@ -6715,10 +7163,10 @@ struct sqlite3_module {
|
|
** when the omit flag is true there is no guarantee that the constraint will
|
|
** not be checked again using byte code.)^
|
|
**
|
|
-** ^The idxNum and idxPtr values are recorded and passed into the
|
|
+** ^The idxNum and idxStr values are recorded and passed into the
|
|
** [xFilter] method.
|
|
-** ^[sqlite3_free()] is used to free idxPtr if and only if
|
|
-** needToFreeIdxPtr is true.
|
|
+** ^[sqlite3_free()] is used to free idxStr if and only if
|
|
+** needToFreeIdxStr is true.
|
|
**
|
|
** ^The orderByConsumed means that output from [xFilter]/[xNext] will occur in
|
|
** the correct order to satisfy the ORDER BY clause so that no separate
|
|
@@ -6726,17 +7174,17 @@ struct sqlite3_module {
|
|
**
|
|
** ^The estimatedCost value is an estimate of the cost of a particular
|
|
** strategy. A cost of N indicates that the cost of the strategy is similar
|
|
-** to a linear scan of an SQLite table with N rows. A cost of log(N)
|
|
+** to a linear scan of an SQLite table with N rows. A cost of log(N)
|
|
** indicates that the expense of the operation is similar to that of a
|
|
** binary search on a unique indexed field of an SQLite table with N rows.
|
|
**
|
|
** ^The estimatedRows value is an estimate of the number of rows that
|
|
** will be returned by the strategy.
|
|
**
|
|
-** The xBestIndex method may optionally populate the idxFlags field with a
|
|
+** The xBestIndex method may optionally populate the idxFlags field with a
|
|
** mask of SQLITE_INDEX_SCAN_* flags. Currently there is only one such flag -
|
|
** SQLITE_INDEX_SCAN_UNIQUE. If the xBestIndex method sets this flag, SQLite
|
|
-** assumes that the strategy may visit at most one row.
|
|
+** assumes that the strategy may visit at most one row.
|
|
**
|
|
** Additionally, if xBestIndex sets the SQLITE_INDEX_SCAN_UNIQUE flag, then
|
|
** SQLite also assumes that if a call to the xUpdate() method is made as
|
|
@@ -6749,14 +7197,14 @@ struct sqlite3_module {
|
|
** the xUpdate method are automatically rolled back by SQLite.
|
|
**
|
|
** IMPORTANT: The estimatedRows field was added to the sqlite3_index_info
|
|
-** structure for SQLite [version 3.8.2] ([dateof:3.8.2]).
|
|
+** structure for SQLite [version 3.8.2] ([dateof:3.8.2]).
|
|
** If a virtual table extension is
|
|
-** used with an SQLite version earlier than 3.8.2, the results of attempting
|
|
-** to read or write the estimatedRows field are undefined (but are likely
|
|
+** used with an SQLite version earlier than 3.8.2, the results of attempting
|
|
+** to read or write the estimatedRows field are undefined (but are likely
|
|
** to include crashing the application). The estimatedRows field should
|
|
** therefore only be used if [sqlite3_libversion_number()] returns a
|
|
** value greater than or equal to 3008002. Similarly, the idxFlags field
|
|
-** was added for [version 3.9.0] ([dateof:3.9.0]).
|
|
+** was added for [version 3.9.0] ([dateof:3.9.0]).
|
|
** It may therefore only be used if
|
|
** sqlite3_libversion_number() returns a value greater than or equal to
|
|
** 3009000.
|
|
@@ -6796,7 +7244,7 @@ struct sqlite3_index_info {
|
|
/*
|
|
** CAPI3REF: Virtual Table Scan Flags
|
|
**
|
|
-** Virtual table implementations are allowed to set the
|
|
+** Virtual table implementations are allowed to set the
|
|
** [sqlite3_index_info].idxFlags field to some combination of
|
|
** these bits.
|
|
*/
|
|
@@ -6807,24 +7255,56 @@ struct sqlite3_index_info {
|
|
**
|
|
** These macros define the allowed values for the
|
|
** [sqlite3_index_info].aConstraint[].op field. Each value represents
|
|
-** an operator that is part of a constraint term in the wHERE clause of
|
|
+** an operator that is part of a constraint term in the WHERE clause of
|
|
** a query that uses a [virtual table].
|
|
-*/
|
|
-#define SQLITE_INDEX_CONSTRAINT_EQ 2
|
|
-#define SQLITE_INDEX_CONSTRAINT_GT 4
|
|
-#define SQLITE_INDEX_CONSTRAINT_LE 8
|
|
-#define SQLITE_INDEX_CONSTRAINT_LT 16
|
|
-#define SQLITE_INDEX_CONSTRAINT_GE 32
|
|
-#define SQLITE_INDEX_CONSTRAINT_MATCH 64
|
|
-#define SQLITE_INDEX_CONSTRAINT_LIKE 65
|
|
-#define SQLITE_INDEX_CONSTRAINT_GLOB 66
|
|
-#define SQLITE_INDEX_CONSTRAINT_REGEXP 67
|
|
-#define SQLITE_INDEX_CONSTRAINT_NE 68
|
|
-#define SQLITE_INDEX_CONSTRAINT_ISNOT 69
|
|
-#define SQLITE_INDEX_CONSTRAINT_ISNOTNULL 70
|
|
-#define SQLITE_INDEX_CONSTRAINT_ISNULL 71
|
|
-#define SQLITE_INDEX_CONSTRAINT_IS 72
|
|
-#define SQLITE_INDEX_CONSTRAINT_FUNCTION 150
|
|
+**
|
|
+** ^The left-hand operand of the operator is given by the corresponding
|
|
+** aConstraint[].iColumn field. ^An iColumn of -1 indicates the left-hand
|
|
+** operand is the rowid.
|
|
+** The SQLITE_INDEX_CONSTRAINT_LIMIT and SQLITE_INDEX_CONSTRAINT_OFFSET
|
|
+** operators have no left-hand operand, and so for those operators the
|
|
+** corresponding aConstraint[].iColumn is meaningless and should not be
|
|
+** used.
|
|
+**
|
|
+** All operator values from SQLITE_INDEX_CONSTRAINT_FUNCTION through
|
|
+** value 255 are reserved to represent functions that are overloaded
|
|
+** by the [xFindFunction|xFindFunction method] of the virtual table
|
|
+** implementation.
|
|
+**
|
|
+** The right-hand operands for each constraint might be accessible using
|
|
+** the [sqlite3_vtab_rhs_value()] interface. Usually the right-hand
|
|
+** operand is only available if it appears as a single constant literal
|
|
+** in the input SQL. If the right-hand operand is another column or an
|
|
+** expression (even a constant expression) or a parameter, then the
|
|
+** sqlite3_vtab_rhs_value() probably will not be able to extract it.
|
|
+** ^The SQLITE_INDEX_CONSTRAINT_ISNULL and
|
|
+** SQLITE_INDEX_CONSTRAINT_ISNOTNULL operators have no right-hand operand
|
|
+** and hence calls to sqlite3_vtab_rhs_value() for those operators will
|
|
+** always return SQLITE_NOTFOUND.
|
|
+**
|
|
+** The collating sequence to be used for comparison can be found using
|
|
+** the [sqlite3_vtab_collation()] interface. For most real-world virtual
|
|
+** tables, the collating sequence of constraints does not matter (for example
|
|
+** because the constraints are numeric) and so the sqlite3_vtab_collation()
|
|
+** interface is not commonly needed.
|
|
+*/
|
|
+#define SQLITE_INDEX_CONSTRAINT_EQ 2
|
|
+#define SQLITE_INDEX_CONSTRAINT_GT 4
|
|
+#define SQLITE_INDEX_CONSTRAINT_LE 8
|
|
+#define SQLITE_INDEX_CONSTRAINT_LT 16
|
|
+#define SQLITE_INDEX_CONSTRAINT_GE 32
|
|
+#define SQLITE_INDEX_CONSTRAINT_MATCH 64
|
|
+#define SQLITE_INDEX_CONSTRAINT_LIKE 65
|
|
+#define SQLITE_INDEX_CONSTRAINT_GLOB 66
|
|
+#define SQLITE_INDEX_CONSTRAINT_REGEXP 67
|
|
+#define SQLITE_INDEX_CONSTRAINT_NE 68
|
|
+#define SQLITE_INDEX_CONSTRAINT_ISNOT 69
|
|
+#define SQLITE_INDEX_CONSTRAINT_ISNOTNULL 70
|
|
+#define SQLITE_INDEX_CONSTRAINT_ISNULL 71
|
|
+#define SQLITE_INDEX_CONSTRAINT_IS 72
|
|
+#define SQLITE_INDEX_CONSTRAINT_LIMIT 73
|
|
+#define SQLITE_INDEX_CONSTRAINT_OFFSET 74
|
|
+#define SQLITE_INDEX_CONSTRAINT_FUNCTION 150
|
|
|
|
/*
|
|
** CAPI3REF: Register A Virtual Table Implementation
|
|
@@ -6836,7 +7316,7 @@ struct sqlite3_index_info {
|
|
** preexisting [virtual table] for the module.
|
|
**
|
|
** ^The module name is registered on the [database connection] specified
|
|
-** by the first parameter. ^The name of the module is given by the
|
|
+** by the first parameter. ^The name of the module is given by the
|
|
** second parameter. ^The third parameter is a pointer to
|
|
** the implementation of the [virtual table module]. ^The fourth
|
|
** parameter is an arbitrary client data pointer that is passed through
|
|
@@ -6853,7 +7333,7 @@ struct sqlite3_index_info {
|
|
** destructor.
|
|
**
|
|
** ^If the third parameter (the pointer to the sqlite3_module object) is
|
|
-** NULL then no new module is create and any existing modules with the
|
|
+** NULL then no new module is created and any existing modules with the
|
|
** same name are dropped.
|
|
**
|
|
** See also: [sqlite3_drop_modules()]
|
|
@@ -6951,7 +7431,7 @@ SQLITE_API int sqlite3_declare_vtab(sqlite3*, const char *zSQL);
|
|
** METHOD: sqlite3
|
|
**
|
|
** ^(Virtual tables can provide alternative implementations of functions
|
|
-** using the [xFindFunction] method of the [virtual table module].
|
|
+** using the [xFindFunction] method of the [virtual table module].
|
|
** But global versions of those functions
|
|
** must exist in order to be overloaded.)^
|
|
**
|
|
@@ -6965,16 +7445,6 @@ SQLITE_API int sqlite3_declare_vtab(sqlite3*, const char *zSQL);
|
|
*/
|
|
SQLITE_API int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
|
|
|
|
-/*
|
|
-** The interface to the virtual-table mechanism defined above (back up
|
|
-** to a comment remarkably similar to this one) is currently considered
|
|
-** to be experimental. The interface might change in incompatible ways.
|
|
-** If this is a problem for you, do not use the interface at this time.
|
|
-**
|
|
-** When the virtual-table mechanism stabilizes, we will declare the
|
|
-** interface fixed, support it indefinitely, and remove this comment.
|
|
-*/
|
|
-
|
|
/*
|
|
** CAPI3REF: A Handle To An Open BLOB
|
|
** KEYWORDS: {BLOB handle} {BLOB handles}
|
|
@@ -7002,7 +7472,7 @@ typedef struct sqlite3_blob sqlite3_blob;
|
|
** SELECT zColumn FROM zDb.zTable WHERE [rowid] = iRow;
|
|
** </pre>)^
|
|
**
|
|
-** ^(Parameter zDb is not the filename that contains the database, but
|
|
+** ^(Parameter zDb is not the filename that contains the database, but
|
|
** rather the symbolic name of the database. For attached databases, this is
|
|
** the name that appears after the AS keyword in the [ATTACH] statement.
|
|
** For the main database file, the database name is "main". For TEMP
|
|
@@ -7015,28 +7485,28 @@ typedef struct sqlite3_blob sqlite3_blob;
|
|
** ^(On success, [SQLITE_OK] is returned and the new [BLOB handle] is stored
|
|
** in *ppBlob. Otherwise an [error code] is returned and, unless the error
|
|
** code is SQLITE_MISUSE, *ppBlob is set to NULL.)^ ^This means that, provided
|
|
-** the API is not misused, it is always safe to call [sqlite3_blob_close()]
|
|
+** the API is not misused, it is always safe to call [sqlite3_blob_close()]
|
|
** on *ppBlob after this function it returns.
|
|
**
|
|
** This function fails with SQLITE_ERROR if any of the following are true:
|
|
** <ul>
|
|
-** <li> ^(Database zDb does not exist)^,
|
|
-** <li> ^(Table zTable does not exist within database zDb)^,
|
|
-** <li> ^(Table zTable is a WITHOUT ROWID table)^,
|
|
+** <li> ^(Database zDb does not exist)^,
|
|
+** <li> ^(Table zTable does not exist within database zDb)^,
|
|
+** <li> ^(Table zTable is a WITHOUT ROWID table)^,
|
|
** <li> ^(Column zColumn does not exist)^,
|
|
** <li> ^(Row iRow is not present in the table)^,
|
|
** <li> ^(The specified column of row iRow contains a value that is not
|
|
** a TEXT or BLOB value)^,
|
|
-** <li> ^(Column zColumn is part of an index, PRIMARY KEY or UNIQUE
|
|
+** <li> ^(Column zColumn is part of an index, PRIMARY KEY or UNIQUE
|
|
** constraint and the blob is being opened for read/write access)^,
|
|
-** <li> ^([foreign key constraints | Foreign key constraints] are enabled,
|
|
+** <li> ^([foreign key constraints | Foreign key constraints] are enabled,
|
|
** column zColumn is part of a [child key] definition and the blob is
|
|
** being opened for read/write access)^.
|
|
** </ul>
|
|
**
|
|
-** ^Unless it returns SQLITE_MISUSE, this function sets the
|
|
-** [database connection] error code and message accessible via
|
|
-** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions.
|
|
+** ^Unless it returns SQLITE_MISUSE, this function sets the
|
|
+** [database connection] error code and message accessible via
|
|
+** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions.
|
|
**
|
|
** A BLOB referenced by sqlite3_blob_open() may be read using the
|
|
** [sqlite3_blob_read()] interface and modified by using
|
|
@@ -7062,7 +7532,7 @@ typedef struct sqlite3_blob sqlite3_blob;
|
|
** blob.
|
|
**
|
|
** ^The [sqlite3_bind_zeroblob()] and [sqlite3_result_zeroblob()] interfaces
|
|
-** and the built-in [zeroblob] SQL function may be used to create a
|
|
+** and the built-in [zeroblob] SQL function may be used to create a
|
|
** zero-filled blob to read or write using the incremental-blob interface.
|
|
**
|
|
** To avoid a resource leak, every open [BLOB handle] should eventually
|
|
@@ -7112,7 +7582,7 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);
|
|
** DESTRUCTOR: sqlite3_blob
|
|
**
|
|
** ^This function closes an open [BLOB handle]. ^(The BLOB handle is closed
|
|
-** unconditionally. Even if this routine returns an error code, the
|
|
+** unconditionally. Even if this routine returns an error code, the
|
|
** handle is still closed.)^
|
|
**
|
|
** ^If the blob handle being closed was opened for read-write access, and if
|
|
@@ -7122,10 +7592,10 @@ 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
|
|
-** with a null pointer (such as would be returned by a failed call to
|
|
+** open blob handle results in undefined behaviour. ^Calling this routine
|
|
+** with a null pointer (such as would be returned by a failed call to
|
|
** [sqlite3_blob_open()]) is a harmless no-op. ^Otherwise, if this function
|
|
-** is passed a valid open blob handle, the values returned by the
|
|
+** is passed a valid open blob handle, the values returned by the
|
|
** sqlite3_errcode() and sqlite3_errmsg() functions are set before returning.
|
|
*/
|
|
SQLITE_API int sqlite3_blob_close(sqlite3_blob *);
|
|
@@ -7134,7 +7604,7 @@ SQLITE_API int sqlite3_blob_close(sqlite3_blob *);
|
|
** CAPI3REF: Return The Size Of An Open BLOB
|
|
** METHOD: sqlite3_blob
|
|
**
|
|
-** ^Returns the size in bytes of the BLOB accessible via the
|
|
+** ^Returns the size in bytes of the BLOB accessible via the
|
|
** successfully opened [BLOB handle] in its only argument. ^The
|
|
** incremental blob I/O routines can only read or overwriting existing
|
|
** blob content; they cannot change the size of a blob.
|
|
@@ -7185,9 +7655,9 @@ SQLITE_API int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
|
|
**
|
|
** ^(On success, sqlite3_blob_write() returns SQLITE_OK.
|
|
** Otherwise, an [error code] or an [extended error code] is returned.)^
|
|
-** ^Unless SQLITE_MISUSE is returned, this function sets the
|
|
-** [database connection] error code and message accessible via
|
|
-** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions.
|
|
+** ^Unless SQLITE_MISUSE is returned, this function sets the
|
|
+** [database connection] error code and message accessible via
|
|
+** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions.
|
|
**
|
|
** ^If the [BLOB handle] passed as the first argument was not opened for
|
|
** writing (the flags parameter to [sqlite3_blob_open()] was zero),
|
|
@@ -7196,9 +7666,9 @@ SQLITE_API int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
|
|
** This function may only modify the contents of the BLOB; it is
|
|
** not possible to increase the size of a BLOB using this API.
|
|
** ^If offset iOffset is less than N bytes from the end of the BLOB,
|
|
-** [SQLITE_ERROR] is returned and no data is written. The size of the
|
|
-** BLOB (and hence the maximum value of N+iOffset) can be determined
|
|
-** using the [sqlite3_blob_bytes()] interface. ^If N or iOffset are less
|
|
+** [SQLITE_ERROR] is returned and no data is written. The size of the
|
|
+** BLOB (and hence the maximum value of N+iOffset) can be determined
|
|
+** using the [sqlite3_blob_bytes()] interface. ^If N or iOffset are less
|
|
** than zero [SQLITE_ERROR] is returned and no data is written.
|
|
**
|
|
** ^An attempt to write to an expired [BLOB handle] fails with an
|
|
@@ -7292,7 +7762,7 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
|
|
** <ul>
|
|
** <li> SQLITE_MUTEX_FAST
|
|
** <li> SQLITE_MUTEX_RECURSIVE
|
|
-** <li> SQLITE_MUTEX_STATIC_MASTER
|
|
+** <li> SQLITE_MUTEX_STATIC_MAIN
|
|
** <li> SQLITE_MUTEX_STATIC_MEM
|
|
** <li> SQLITE_MUTEX_STATIC_OPEN
|
|
** <li> SQLITE_MUTEX_STATIC_PRNG
|
|
@@ -7350,7 +7820,7 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
|
|
** ^(Some systems (for example, Windows 95) do not support the operation
|
|
** implemented by sqlite3_mutex_try(). On those systems, sqlite3_mutex_try()
|
|
** will always return SQLITE_BUSY. The SQLite core only ever uses
|
|
-** sqlite3_mutex_try() as an optimization so this is acceptable
|
|
+** sqlite3_mutex_try() as an optimization so this is acceptable
|
|
** behavior.)^
|
|
**
|
|
** ^The sqlite3_mutex_leave() routine exits a mutex that was
|
|
@@ -7494,7 +7964,7 @@ SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*);
|
|
*/
|
|
#define SQLITE_MUTEX_FAST 0
|
|
#define SQLITE_MUTEX_RECURSIVE 1
|
|
-#define SQLITE_MUTEX_STATIC_MASTER 2
|
|
+#define SQLITE_MUTEX_STATIC_MAIN 2
|
|
#define SQLITE_MUTEX_STATIC_MEM 3 /* sqlite3_malloc() */
|
|
#define SQLITE_MUTEX_STATIC_MEM2 4 /* NOT USED */
|
|
#define SQLITE_MUTEX_STATIC_OPEN 4 /* sqlite3BtreeOpen() */
|
|
@@ -7509,11 +7979,15 @@ SQLITE_API int sqlite3_mutex_notheld(sqlite3_mutex*);
|
|
#define SQLITE_MUTEX_STATIC_VFS2 12 /* For use by extension VFS */
|
|
#define SQLITE_MUTEX_STATIC_VFS3 13 /* For use by application VFS */
|
|
|
|
+/* Legacy compatibility: */
|
|
+#define SQLITE_MUTEX_STATIC_MASTER 2
|
|
+
|
|
+
|
|
/*
|
|
** CAPI3REF: Retrieve the mutex for a database connection
|
|
** METHOD: sqlite3
|
|
**
|
|
-** ^This interface returns a pointer the [sqlite3_mutex] object that
|
|
+** ^This interface returns a pointer the [sqlite3_mutex] object that
|
|
** serializes access to the [database connection] given in the argument
|
|
** when the [threading mode] is Serialized.
|
|
** ^If the [threading mode] is Single-thread or Multi-thread then this
|
|
@@ -7540,7 +8014,7 @@ SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
|
|
** method becomes the return value of this routine.
|
|
**
|
|
** A few opcodes for [sqlite3_file_control()] are handled directly
|
|
-** by the SQLite core and never invoke the
|
|
+** by the SQLite core and never invoke the
|
|
** sqlite3_io_methods.xFileControl method.
|
|
** ^The [SQLITE_FCNTL_FILE_POINTER] value for the op parameter causes
|
|
** a pointer to the underlying [sqlite3_file] object to be written into
|
|
@@ -7604,7 +8078,7 @@ SQLITE_API int sqlite3_test_control(int op, ...);
|
|
#define SQLITE_TESTCTRL_PENDING_BYTE 11
|
|
#define SQLITE_TESTCTRL_ASSERT 12
|
|
#define SQLITE_TESTCTRL_ALWAYS 13
|
|
-#define SQLITE_TESTCTRL_RESERVE 14
|
|
+#define SQLITE_TESTCTRL_RESERVE 14 /* NOT USED */
|
|
#define SQLITE_TESTCTRL_OPTIMIZATIONS 15
|
|
#define SQLITE_TESTCTRL_ISKEYWORD 16 /* NOT USED */
|
|
#define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */
|
|
@@ -7622,12 +8096,16 @@ SQLITE_API int sqlite3_test_control(int op, ...);
|
|
#define SQLITE_TESTCTRL_RESULT_INTREAL 27
|
|
#define SQLITE_TESTCTRL_PRNG_SEED 28
|
|
#define SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS 29
|
|
-#define SQLITE_TESTCTRL_LAST 29 /* Largest TESTCTRL */
|
|
+#define SQLITE_TESTCTRL_SEEK_COUNT 30
|
|
+#define SQLITE_TESTCTRL_TRACEFLAGS 31
|
|
+#define SQLITE_TESTCTRL_TUNE 32
|
|
+#define SQLITE_TESTCTRL_LOGEST 33
|
|
+#define SQLITE_TESTCTRL_LAST 33 /* Largest TESTCTRL */
|
|
|
|
/*
|
|
** CAPI3REF: SQL Keyword Checking
|
|
**
|
|
-** These routines provide access to the set of SQL language keywords
|
|
+** These routines provide access to the set of SQL language keywords
|
|
** recognized by SQLite. Applications can uses these routines to determine
|
|
** whether or not a specific identifier needs to be escaped (for example,
|
|
** by enclosing in double-quotes) so as not to confuse the parser.
|
|
@@ -7699,14 +8177,14 @@ typedef struct sqlite3_str sqlite3_str;
|
|
**
|
|
** ^The [sqlite3_str_new(D)] interface allocates and initializes
|
|
** a new [sqlite3_str] object. To avoid memory leaks, the object returned by
|
|
-** [sqlite3_str_new()] must be freed by a subsequent call to
|
|
+** [sqlite3_str_new()] must be freed by a subsequent call to
|
|
** [sqlite3_str_finish(X)].
|
|
**
|
|
** ^The [sqlite3_str_new(D)] interface always returns a pointer to a
|
|
** valid [sqlite3_str] object, though in the event of an out-of-memory
|
|
** error the returned object might be a special singleton that will
|
|
-** silently reject new text, always return SQLITE_NOMEM from
|
|
-** [sqlite3_str_errcode()], always return 0 for
|
|
+** silently reject new text, always return SQLITE_NOMEM from
|
|
+** [sqlite3_str_errcode()], always return 0 for
|
|
** [sqlite3_str_length()], and always return NULL from
|
|
** [sqlite3_str_finish(X)]. It is always safe to use the value
|
|
** returned by [sqlite3_str_new(D)] as the sqlite3_str parameter
|
|
@@ -7742,9 +8220,9 @@ SQLITE_API char *sqlite3_str_finish(sqlite3_str*);
|
|
** These interfaces add content to an sqlite3_str object previously obtained
|
|
** from [sqlite3_str_new()].
|
|
**
|
|
-** ^The [sqlite3_str_appendf(X,F,...)] and
|
|
+** ^The [sqlite3_str_appendf(X,F,...)] and
|
|
** [sqlite3_str_vappendf(X,F,V)] interfaces uses the [built-in printf]
|
|
-** functionality of SQLite to append formatted text onto the end of
|
|
+** functionality of SQLite to append formatted text onto the end of
|
|
** [sqlite3_str] object X.
|
|
**
|
|
** ^The [sqlite3_str_append(X,S,N)] method appends exactly N bytes from string S
|
|
@@ -7761,7 +8239,7 @@ SQLITE_API char *sqlite3_str_finish(sqlite3_str*);
|
|
** ^This method can be used, for example, to add whitespace indentation.
|
|
**
|
|
** ^The [sqlite3_str_reset(X)] method resets the string under construction
|
|
-** inside [sqlite3_str] object X back to zero bytes in length.
|
|
+** inside [sqlite3_str] object X back to zero bytes in length.
|
|
**
|
|
** These methods do not return a result code. ^If an error occurs, that fact
|
|
** is recorded in the [sqlite3_str] object and can be recovered by a
|
|
@@ -7863,7 +8341,7 @@ SQLITE_API int sqlite3_status64(
|
|
** <dd>This parameter records the largest memory allocation request
|
|
** handed to [sqlite3_malloc()] or [sqlite3_realloc()] (or their
|
|
** internal equivalents). Only the value returned in the
|
|
-** *pHighwater parameter to [sqlite3_status()] is of interest.
|
|
+** *pHighwater parameter to [sqlite3_status()] is of interest.
|
|
** The value written into the *pCurrent parameter is undefined.</dd>)^
|
|
**
|
|
** [[SQLITE_STATUS_MALLOC_COUNT]] ^(<dt>SQLITE_STATUS_MALLOC_COUNT</dt>
|
|
@@ -7872,11 +8350,11 @@ SQLITE_API int sqlite3_status64(
|
|
**
|
|
** [[SQLITE_STATUS_PAGECACHE_USED]] ^(<dt>SQLITE_STATUS_PAGECACHE_USED</dt>
|
|
** <dd>This parameter returns the number of pages used out of the
|
|
-** [pagecache memory allocator] that was configured using
|
|
+** [pagecache memory allocator] that was configured using
|
|
** [SQLITE_CONFIG_PAGECACHE]. The
|
|
** value returned is in pages, not in bytes.</dd>)^
|
|
**
|
|
-** [[SQLITE_STATUS_PAGECACHE_OVERFLOW]]
|
|
+** [[SQLITE_STATUS_PAGECACHE_OVERFLOW]]
|
|
** ^(<dt>SQLITE_STATUS_PAGECACHE_OVERFLOW</dt>
|
|
** <dd>This parameter returns the number of bytes of page cache
|
|
** allocation which could not be satisfied by the [SQLITE_CONFIG_PAGECACHE]
|
|
@@ -7889,7 +8367,7 @@ SQLITE_API int sqlite3_status64(
|
|
** [[SQLITE_STATUS_PAGECACHE_SIZE]] ^(<dt>SQLITE_STATUS_PAGECACHE_SIZE</dt>
|
|
** <dd>This parameter records the largest memory allocation request
|
|
** handed to the [pagecache memory allocator]. Only the value returned in the
|
|
-** *pHighwater parameter to [sqlite3_status()] is of interest.
|
|
+** *pHighwater parameter to [sqlite3_status()] is of interest.
|
|
** The value written into the *pCurrent parameter is undefined.</dd>)^
|
|
**
|
|
** [[SQLITE_STATUS_SCRATCH_USED]] <dt>SQLITE_STATUS_SCRATCH_USED</dt>
|
|
@@ -7902,7 +8380,7 @@ SQLITE_API int sqlite3_status64(
|
|
** <dd>No longer used.</dd>
|
|
**
|
|
** [[SQLITE_STATUS_PARSER_STACK]] ^(<dt>SQLITE_STATUS_PARSER_STACK</dt>
|
|
-** <dd>The *pHighwater parameter records the deepest parser stack.
|
|
+** <dd>The *pHighwater parameter records the deepest parser stack.
|
|
** The *pCurrent value is undefined. The *pHighwater value is only
|
|
** meaningful if SQLite is compiled with [YYTRACKMAXSTACKDEPTH].</dd>)^
|
|
** </dl>
|
|
@@ -7924,12 +8402,12 @@ SQLITE_API int sqlite3_status64(
|
|
** CAPI3REF: Database Connection Status
|
|
** METHOD: sqlite3
|
|
**
|
|
-** ^This interface is used to retrieve runtime status information
|
|
+** ^This interface is used to retrieve runtime status information
|
|
** about a single [database connection]. ^The first argument is the
|
|
** database connection object to be interrogated. ^The second argument
|
|
** is an integer constant, taken from the set of
|
|
** [SQLITE_DBSTATUS options], that
|
|
-** determines the parameter to interrogate. The set of
|
|
+** determines the parameter to interrogate. The set of
|
|
** [SQLITE_DBSTATUS options] is likely
|
|
** to grow in future releases of SQLite.
|
|
**
|
|
@@ -7964,7 +8442,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
|
|
** checked out.</dd>)^
|
|
**
|
|
** [[SQLITE_DBSTATUS_LOOKASIDE_HIT]] ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_HIT</dt>
|
|
-** <dd>This parameter returns the number of malloc attempts that were
|
|
+** <dd>This parameter returns the number of malloc attempts that were
|
|
** satisfied using lookaside memory. Only the high-water value is meaningful;
|
|
** the current value is always zero.)^
|
|
**
|
|
@@ -7989,7 +8467,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
|
|
** memory used by all pager caches associated with the database connection.)^
|
|
** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0.
|
|
**
|
|
-** [[SQLITE_DBSTATUS_CACHE_USED_SHARED]]
|
|
+** [[SQLITE_DBSTATUS_CACHE_USED_SHARED]]
|
|
** ^(<dt>SQLITE_DBSTATUS_CACHE_USED_SHARED</dt>
|
|
** <dd>This parameter is similar to DBSTATUS_CACHE_USED, except that if a
|
|
** pager cache is shared between two or more connections the bytes of heap
|
|
@@ -8004,7 +8482,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
|
|
** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(<dt>SQLITE_DBSTATUS_SCHEMA_USED</dt>
|
|
** <dd>This parameter returns the approximate number of bytes of heap
|
|
** memory used to store the schema for all databases associated
|
|
-** with the connection - main, temp, and any [ATTACH]-ed databases.)^
|
|
+** with the connection - main, temp, and any [ATTACH]-ed databases.)^
|
|
** ^The full amount of memory used by the schemas is reported, even if the
|
|
** schema memory is shared with other database connections due to
|
|
** [shared cache mode] being enabled.
|
|
@@ -8019,13 +8497,13 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
|
|
**
|
|
** [[SQLITE_DBSTATUS_CACHE_HIT]] ^(<dt>SQLITE_DBSTATUS_CACHE_HIT</dt>
|
|
** <dd>This parameter returns the number of pager cache hits that have
|
|
-** occurred.)^ ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_HIT
|
|
+** occurred.)^ ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_HIT
|
|
** is always 0.
|
|
** </dd>
|
|
**
|
|
** [[SQLITE_DBSTATUS_CACHE_MISS]] ^(<dt>SQLITE_DBSTATUS_CACHE_MISS</dt>
|
|
** <dd>This parameter returns the number of pager cache misses that have
|
|
-** occurred.)^ ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_MISS
|
|
+** occurred.)^ ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_MISS
|
|
** is always 0.
|
|
** </dd>
|
|
**
|
|
@@ -8083,7 +8561,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
|
|
** statements. For example, if the number of table steps greatly exceeds
|
|
** the number of table searches or result rows, that would tend to indicate
|
|
** that the prepared statement is using a full table scan rather than
|
|
-** an index.
|
|
+** an index.
|
|
**
|
|
** ^(This interface is used to retrieve and reset counter values from
|
|
** a [prepared statement]. The first argument is the prepared statement
|
|
@@ -8110,7 +8588,7 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
|
|
** [[SQLITE_STMTSTATUS_FULLSCAN_STEP]] <dt>SQLITE_STMTSTATUS_FULLSCAN_STEP</dt>
|
|
** <dd>^This is the number of times that SQLite has stepped forward in
|
|
** a table as part of a full table scan. Large numbers for this counter
|
|
-** may indicate opportunities for performance improvement through
|
|
+** may indicate opportunities for performance improvement through
|
|
** careful use of indices.</dd>
|
|
**
|
|
** [[SQLITE_STMTSTATUS_SORT]] <dt>SQLITE_STMTSTATUS_SORT</dt>
|
|
@@ -8128,14 +8606,14 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
|
|
** [[SQLITE_STMTSTATUS_VM_STEP]] <dt>SQLITE_STMTSTATUS_VM_STEP</dt>
|
|
** <dd>^This is the number of virtual machine operations executed
|
|
** by the prepared statement if that number is less than or equal
|
|
-** to 2147483647. The number of virtual machine operations can be
|
|
+** to 2147483647. The number of virtual machine operations can be
|
|
** used as a proxy for the total work done by the prepared statement.
|
|
** If the number of virtual machine operations exceeds 2147483647
|
|
** then the value returned by this statement status code is undefined.
|
|
**
|
|
** [[SQLITE_STMTSTATUS_REPREPARE]] <dt>SQLITE_STMTSTATUS_REPREPARE</dt>
|
|
** <dd>^This is the number of times that the prepare statement has been
|
|
-** automatically regenerated due to schema changes or changes to
|
|
+** automatically regenerated due to schema changes or changes to
|
|
** [bound parameters] that might affect the query plan.
|
|
**
|
|
** [[SQLITE_STMTSTATUS_RUN]] <dt>SQLITE_STMTSTATUS_RUN</dt>
|
|
@@ -8145,6 +8623,16 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
|
|
** The counter is incremented on the first [sqlite3_step()] call of each
|
|
** cycle.
|
|
**
|
|
+** [[SQLITE_STMTSTATUS_FILTER_MISS]]
|
|
+** [[SQLITE_STMTSTATUS_FILTER HIT]]
|
|
+** <dt>SQLITE_STMTSTATUS_FILTER_HIT<br>
|
|
+** SQLITE_STMTSTATUS_FILTER_MISS</dt>
|
|
+** <dd>^SQLITE_STMTSTATUS_FILTER_HIT is the number of times that a join
|
|
+** step was bypassed because a Bloom filter returned not-found. The
|
|
+** corresponding SQLITE_STMTSTATUS_FILTER_MISS value is the number of
|
|
+** times that the Bloom filter returned a find, and thus the join step
|
|
+** had to be processed as normal.
|
|
+**
|
|
** [[SQLITE_STMTSTATUS_MEMUSED]] <dt>SQLITE_STMTSTATUS_MEMUSED</dt>
|
|
** <dd>^This is the approximate number of bytes of heap memory
|
|
** used to store the prepared statement. ^This value is not actually
|
|
@@ -8159,6 +8647,8 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
|
|
#define SQLITE_STMTSTATUS_VM_STEP 4
|
|
#define SQLITE_STMTSTATUS_REPREPARE 5
|
|
#define SQLITE_STMTSTATUS_RUN 6
|
|
+#define SQLITE_STMTSTATUS_FILTER_MISS 7
|
|
+#define SQLITE_STMTSTATUS_FILTER_HIT 8
|
|
#define SQLITE_STMTSTATUS_MEMUSED 99
|
|
|
|
/*
|
|
@@ -8195,15 +8685,15 @@ struct sqlite3_pcache_page {
|
|
** KEYWORDS: {page cache}
|
|
**
|
|
** ^(The [sqlite3_config]([SQLITE_CONFIG_PCACHE2], ...) interface can
|
|
-** register an alternative page cache implementation by passing in an
|
|
+** register an alternative page cache implementation by passing in an
|
|
** instance of the sqlite3_pcache_methods2 structure.)^
|
|
-** In many applications, most of the heap memory allocated by
|
|
+** In many applications, most of the heap memory allocated by
|
|
** SQLite is used for the page cache.
|
|
-** By implementing a
|
|
+** By implementing a
|
|
** custom page cache using this API, an application can better control
|
|
-** the amount of memory consumed by SQLite, the way in which
|
|
-** that memory is allocated and released, and the policies used to
|
|
-** determine exactly which parts of a database file are cached and for
|
|
+** the amount of memory consumed by SQLite, the way in which
|
|
+** that memory is allocated and released, and the policies used to
|
|
+** determine exactly which parts of a database file are cached and for
|
|
** how long.
|
|
**
|
|
** The alternative page cache mechanism is an
|
|
@@ -8216,19 +8706,19 @@ struct sqlite3_pcache_page {
|
|
** [sqlite3_config()] returns.)^
|
|
**
|
|
** [[the xInit() page cache method]]
|
|
-** ^(The xInit() method is called once for each effective
|
|
+** ^(The xInit() method is called once for each effective
|
|
** call to [sqlite3_initialize()])^
|
|
** (usually only once during the lifetime of the process). ^(The xInit()
|
|
** method is passed a copy of the sqlite3_pcache_methods2.pArg value.)^
|
|
-** The intent of the xInit() method is to set up global data structures
|
|
-** required by the custom page cache implementation.
|
|
-** ^(If the xInit() method is NULL, then the
|
|
+** The intent of the xInit() method is to set up global data structures
|
|
+** required by the custom page cache implementation.
|
|
+** ^(If the xInit() method is NULL, then the
|
|
** built-in default page cache is used instead of the application defined
|
|
** page cache.)^
|
|
**
|
|
** [[the xShutdown() page cache method]]
|
|
** ^The xShutdown() method is called by [sqlite3_shutdown()].
|
|
-** It can be used to clean up
|
|
+** It can be used to clean up
|
|
** any outstanding resources before process shutdown, if required.
|
|
** ^The xShutdown() method may be NULL.
|
|
**
|
|
@@ -8247,7 +8737,7 @@ struct sqlite3_pcache_page {
|
|
** though this is not guaranteed. ^The
|
|
** first parameter, szPage, is the size in bytes of the pages that must
|
|
** be allocated by the cache. ^szPage will always a power of two. ^The
|
|
-** second parameter szExtra is a number of bytes of extra storage
|
|
+** second parameter szExtra is a number of bytes of extra storage
|
|
** associated with each page cache entry. ^The szExtra parameter will
|
|
** a number less than 250. SQLite will use the
|
|
** extra szExtra bytes on each page to store metadata about the underlying
|
|
@@ -8260,7 +8750,7 @@ struct sqlite3_pcache_page {
|
|
** it is purely advisory. ^On a cache where bPurgeable is false, SQLite will
|
|
** never invoke xUnpin() except to deliberately delete a page.
|
|
** ^In other words, calls to xUnpin() on a cache with bPurgeable set to
|
|
-** false will always have the "discard" flag set to true.
|
|
+** false will always have the "discard" flag set to true.
|
|
** ^Hence, a cache created with bPurgeable false will
|
|
** never contain any unpinned pages.
|
|
**
|
|
@@ -8275,12 +8765,12 @@ struct sqlite3_pcache_page {
|
|
** [[the xPagecount() page cache methods]]
|
|
** The xPagecount() method must return the number of pages currently
|
|
** stored in the cache, both pinned and unpinned.
|
|
-**
|
|
+**
|
|
** [[the xFetch() page cache methods]]
|
|
-** The xFetch() method locates a page in the cache and returns a pointer to
|
|
+** The xFetch() method locates a page in the cache and returns a pointer to
|
|
** an sqlite3_pcache_page object associated with that page, or a NULL pointer.
|
|
** The pBuf element of the returned sqlite3_pcache_page object will be a
|
|
-** pointer to a buffer of szPage bytes used to store the content of a
|
|
+** pointer to a buffer of szPage bytes used to store the content of a
|
|
** single database page. The pExtra element of sqlite3_pcache_page will be
|
|
** a pointer to the szExtra bytes of extra storage that SQLite has requested
|
|
** for each entry in the page cache.
|
|
@@ -8319,8 +8809,8 @@ struct sqlite3_pcache_page {
|
|
** page cache implementation. ^The page cache implementation
|
|
** may choose to evict unpinned pages at any time.
|
|
**
|
|
-** The cache must not perform any reference counting. A single
|
|
-** call to xUnpin() unpins the page regardless of the number of prior calls
|
|
+** The cache must not perform any reference counting. A single
|
|
+** call to xUnpin() unpins the page regardless of the number of prior calls
|
|
** to xFetch().
|
|
**
|
|
** [[the xRekey() page cache methods]]
|
|
@@ -8360,7 +8850,7 @@ struct sqlite3_pcache_methods2 {
|
|
int (*xPagecount)(sqlite3_pcache*);
|
|
sqlite3_pcache_page *(*xFetch)(sqlite3_pcache*, unsigned key, int createFlag);
|
|
void (*xUnpin)(sqlite3_pcache*, sqlite3_pcache_page*, int discard);
|
|
- void (*xRekey)(sqlite3_pcache*, sqlite3_pcache_page*,
|
|
+ void (*xRekey)(sqlite3_pcache*, sqlite3_pcache_page*,
|
|
unsigned oldKey, unsigned newKey);
|
|
void (*xTruncate)(sqlite3_pcache*, unsigned iLimit);
|
|
void (*xDestroy)(sqlite3_pcache*);
|
|
@@ -8405,7 +8895,7 @@ typedef struct sqlite3_backup sqlite3_backup;
|
|
**
|
|
** The backup API copies the content of one database into another.
|
|
** It is useful either for creating backups of databases or
|
|
-** for copying in-memory databases to or from persistent files.
|
|
+** for copying in-memory databases to or from persistent files.
|
|
**
|
|
** See Also: [Using the SQLite Online Backup API]
|
|
**
|
|
@@ -8416,36 +8906,36 @@ typedef struct sqlite3_backup sqlite3_backup;
|
|
** ^Thus, the backup may be performed on a live source database without
|
|
** preventing other database connections from
|
|
** reading or writing to the source database while the backup is underway.
|
|
-**
|
|
-** ^(To perform a backup operation:
|
|
+**
|
|
+** ^(To perform a backup operation:
|
|
** <ol>
|
|
** <li><b>sqlite3_backup_init()</b> is called once to initialize the
|
|
-** backup,
|
|
-** <li><b>sqlite3_backup_step()</b> is called one or more times to transfer
|
|
+** backup,
|
|
+** <li><b>sqlite3_backup_step()</b> is called one or more times to transfer
|
|
** the data between the two databases, and finally
|
|
-** <li><b>sqlite3_backup_finish()</b> is called to release all resources
|
|
-** associated with the backup operation.
|
|
+** <li><b>sqlite3_backup_finish()</b> is called to release all resources
|
|
+** associated with the backup operation.
|
|
** </ol>)^
|
|
** There should be exactly one call to sqlite3_backup_finish() for each
|
|
** successful call to sqlite3_backup_init().
|
|
**
|
|
** [[sqlite3_backup_init()]] <b>sqlite3_backup_init()</b>
|
|
**
|
|
-** ^The D and N arguments to sqlite3_backup_init(D,N,S,M) are the
|
|
-** [database connection] associated with the destination database
|
|
+** ^The D and N arguments to sqlite3_backup_init(D,N,S,M) are the
|
|
+** [database connection] associated with the destination database
|
|
** and the database name, respectively.
|
|
** ^The database name is "main" for the main database, "temp" for the
|
|
** temporary database, or the name specified after the AS keyword in
|
|
** an [ATTACH] statement for an attached database.
|
|
-** ^The S and M arguments passed to
|
|
+** ^The S and M arguments passed to
|
|
** sqlite3_backup_init(D,N,S,M) identify the [database connection]
|
|
** and database name of the source database, respectively.
|
|
** ^The source and destination [database connections] (parameters S and D)
|
|
** must be different or else sqlite3_backup_init(D,N,S,M) will fail with
|
|
** an error.
|
|
**
|
|
-** ^A call to sqlite3_backup_init() will fail, returning NULL, if
|
|
-** there is already a read or read-write transaction open on the
|
|
+** ^A call to sqlite3_backup_init() will fail, returning NULL, if
|
|
+** there is already a read or read-write transaction open on the
|
|
** destination database.
|
|
**
|
|
** ^If an error occurs within sqlite3_backup_init(D,N,S,M), then NULL is
|
|
@@ -8457,14 +8947,14 @@ typedef struct sqlite3_backup sqlite3_backup;
|
|
** ^A successful call to sqlite3_backup_init() returns a pointer to an
|
|
** [sqlite3_backup] object.
|
|
** ^The [sqlite3_backup] object may be used with the sqlite3_backup_step() and
|
|
-** sqlite3_backup_finish() functions to perform the specified backup
|
|
+** sqlite3_backup_finish() functions to perform the specified backup
|
|
** operation.
|
|
**
|
|
** [[sqlite3_backup_step()]] <b>sqlite3_backup_step()</b>
|
|
**
|
|
-** ^Function sqlite3_backup_step(B,N) will copy up to N pages between
|
|
+** ^Function sqlite3_backup_step(B,N) will copy up to N pages between
|
|
** the source and destination databases specified by [sqlite3_backup] object B.
|
|
-** ^If N is negative, all remaining source pages are copied.
|
|
+** ^If N is negative, all remaining source pages are copied.
|
|
** ^If sqlite3_backup_step(B,N) successfully copies N pages and there
|
|
** are still more pages to be copied, then the function returns [SQLITE_OK].
|
|
** ^If sqlite3_backup_step(B,N) successfully finishes copying all pages
|
|
@@ -8486,8 +8976,8 @@ typedef struct sqlite3_backup sqlite3_backup;
|
|
**
|
|
** ^If sqlite3_backup_step() cannot obtain a required file-system lock, then
|
|
** the [sqlite3_busy_handler | busy-handler function]
|
|
-** is invoked (if one is specified). ^If the
|
|
-** busy-handler returns non-zero before the lock is available, then
|
|
+** is invoked (if one is specified). ^If the
|
|
+** busy-handler returns non-zero before the lock is available, then
|
|
** [SQLITE_BUSY] is returned to the caller. ^In this case the call to
|
|
** sqlite3_backup_step() can be retried later. ^If the source
|
|
** [database connection]
|
|
@@ -8495,15 +8985,15 @@ typedef struct sqlite3_backup sqlite3_backup;
|
|
** is called, then [SQLITE_LOCKED] is returned immediately. ^Again, in this
|
|
** case the call to sqlite3_backup_step() can be retried later on. ^(If
|
|
** [SQLITE_IOERR_ACCESS | SQLITE_IOERR_XXX], [SQLITE_NOMEM], or
|
|
-** [SQLITE_READONLY] is returned, then
|
|
-** there is no point in retrying the call to sqlite3_backup_step(). These
|
|
-** errors are considered fatal.)^ The application must accept
|
|
-** that the backup operation has failed and pass the backup operation handle
|
|
+** [SQLITE_READONLY] is returned, then
|
|
+** there is no point in retrying the call to sqlite3_backup_step(). These
|
|
+** errors are considered fatal.)^ The application must accept
|
|
+** that the backup operation has failed and pass the backup operation handle
|
|
** to the sqlite3_backup_finish() to release associated resources.
|
|
**
|
|
** ^The first call to sqlite3_backup_step() obtains an exclusive lock
|
|
-** on the destination file. ^The exclusive lock is not released until either
|
|
-** sqlite3_backup_finish() is called or the backup operation is complete
|
|
+** on the destination file. ^The exclusive lock is not released until either
|
|
+** sqlite3_backup_finish() is called or the backup operation is complete
|
|
** and sqlite3_backup_step() returns [SQLITE_DONE]. ^Every call to
|
|
** sqlite3_backup_step() obtains a [shared lock] on the source database that
|
|
** lasts for the duration of the sqlite3_backup_step() call.
|
|
@@ -8512,18 +9002,18 @@ typedef struct sqlite3_backup sqlite3_backup;
|
|
** through the backup process. ^If the source database is modified by an
|
|
** external process or via a database connection other than the one being
|
|
** used by the backup operation, then the backup will be automatically
|
|
-** restarted by the next call to sqlite3_backup_step(). ^If the source
|
|
+** restarted by the next call to sqlite3_backup_step(). ^If the source
|
|
** database is modified by the using the same database connection as is used
|
|
** by the backup operation, then the backup database is automatically
|
|
** updated at the same time.
|
|
**
|
|
** [[sqlite3_backup_finish()]] <b>sqlite3_backup_finish()</b>
|
|
**
|
|
-** When sqlite3_backup_step() has returned [SQLITE_DONE], or when the
|
|
+** When sqlite3_backup_step() has returned [SQLITE_DONE], or when the
|
|
** application wishes to abandon the backup operation, the application
|
|
** should destroy the [sqlite3_backup] by passing it to sqlite3_backup_finish().
|
|
** ^The sqlite3_backup_finish() interfaces releases all
|
|
-** resources associated with the [sqlite3_backup] object.
|
|
+** resources associated with the [sqlite3_backup] object.
|
|
** ^If sqlite3_backup_step() has not yet returned [SQLITE_DONE], then any
|
|
** active write-transaction on the destination database is rolled back.
|
|
** The [sqlite3_backup] object is invalid
|
|
@@ -8563,23 +9053,23 @@ typedef struct sqlite3_backup sqlite3_backup;
|
|
** connections, then the source database connection may be used concurrently
|
|
** from within other threads.
|
|
**
|
|
-** However, the application must guarantee that the destination
|
|
-** [database connection] is not passed to any other API (by any thread) after
|
|
+** However, the application must guarantee that the destination
|
|
+** [database connection] is not passed to any other API (by any thread) after
|
|
** sqlite3_backup_init() is called and before the corresponding call to
|
|
** sqlite3_backup_finish(). SQLite does not currently check to see
|
|
** if the application incorrectly accesses the destination [database connection]
|
|
** and so no error code is reported, but the operations may malfunction
|
|
** nevertheless. Use of the destination database connection while a
|
|
-** backup is in progress might also also cause a mutex deadlock.
|
|
+** backup is in progress might also cause a mutex deadlock.
|
|
**
|
|
** If running in [shared cache mode], the application must
|
|
** guarantee that the shared cache used by the destination database
|
|
** is not accessed while the backup is running. In practice this means
|
|
-** that the application must guarantee that the disk file being
|
|
+** that the application must guarantee that the disk file being
|
|
** backed up to is not accessed by any connection within the process,
|
|
** not just the specific connection that was passed to sqlite3_backup_init().
|
|
**
|
|
-** The [sqlite3_backup] object itself is partially threadsafe. Multiple
|
|
+** The [sqlite3_backup] object itself is partially threadsafe. Multiple
|
|
** threads may safely make multiple concurrent calls to sqlite3_backup_step().
|
|
** However, the sqlite3_backup_remaining() and sqlite3_backup_pagecount()
|
|
** APIs are not strictly speaking threadsafe. If they are invoked at the
|
|
@@ -8604,8 +9094,8 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
|
|
** ^When running in shared-cache mode, a database operation may fail with
|
|
** an [SQLITE_LOCKED] error if the required locks on the shared-cache or
|
|
** individual tables within the shared-cache cannot be obtained. See
|
|
-** [SQLite Shared-Cache Mode] for a description of shared-cache locking.
|
|
-** ^This API may be used to register a callback that SQLite will invoke
|
|
+** [SQLite Shared-Cache Mode] for a description of shared-cache locking.
|
|
+** ^This API may be used to register a callback that SQLite will invoke
|
|
** when the connection currently holding the required lock relinquishes it.
|
|
** ^This API is only available if the library was compiled with the
|
|
** [SQLITE_ENABLE_UNLOCK_NOTIFY] C-preprocessor symbol defined.
|
|
@@ -8613,14 +9103,14 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
|
|
** See Also: [Using the SQLite Unlock Notification Feature].
|
|
**
|
|
** ^Shared-cache locks are released when a database connection concludes
|
|
-** its current transaction, either by committing it or rolling it back.
|
|
+** its current transaction, either by committing it or rolling it back.
|
|
**
|
|
** ^When a connection (known as the blocked connection) fails to obtain a
|
|
** shared-cache lock and SQLITE_LOCKED is returned to the caller, the
|
|
** identity of the database connection (the blocking connection) that
|
|
-** has locked the required resource is stored internally. ^After an
|
|
+** has locked the required resource is stored internally. ^After an
|
|
** application receives an SQLITE_LOCKED error, it may call the
|
|
-** sqlite3_unlock_notify() method with the blocked connection handle as
|
|
+** sqlite3_unlock_notify() method with the blocked connection handle as
|
|
** the first argument to register for a callback that will be invoked
|
|
** when the blocking connections current transaction is concluded. ^The
|
|
** callback is invoked from within the [sqlite3_step] or [sqlite3_close]
|
|
@@ -8634,15 +9124,15 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
|
|
**
|
|
** ^If the blocked connection is attempting to obtain a write-lock on a
|
|
** shared-cache table, and more than one other connection currently holds
|
|
-** a read-lock on the same table, then SQLite arbitrarily selects one of
|
|
+** a read-lock on the same table, then SQLite arbitrarily selects one of
|
|
** the other connections to use as the blocking connection.
|
|
**
|
|
-** ^(There may be at most one unlock-notify callback registered by a
|
|
+** ^(There may be at most one unlock-notify callback registered by a
|
|
** blocked connection. If sqlite3_unlock_notify() is called when the
|
|
** blocked connection already has a registered unlock-notify callback,
|
|
** then the new callback replaces the old.)^ ^If sqlite3_unlock_notify() is
|
|
** called with a NULL pointer as its second argument, then any existing
|
|
-** unlock-notify callback is canceled. ^The blocked connections
|
|
+** unlock-notify callback is canceled. ^The blocked connections
|
|
** unlock-notify callback may also be canceled by closing the blocked
|
|
** connection using [sqlite3_close()].
|
|
**
|
|
@@ -8655,7 +9145,7 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
|
|
**
|
|
** <b>Callback Invocation Details</b>
|
|
**
|
|
-** When an unlock-notify callback is registered, the application provides a
|
|
+** When an unlock-notify callback is registered, the application provides a
|
|
** single void* pointer that is passed to the callback when it is invoked.
|
|
** However, the signature of the callback function allows SQLite to pass
|
|
** it an array of void* context pointers. The first argument passed to
|
|
@@ -8668,12 +9158,12 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
|
|
** same callback function, then instead of invoking the callback function
|
|
** multiple times, it is invoked once with the set of void* context pointers
|
|
** specified by the blocked connections bundled together into an array.
|
|
-** This gives the application an opportunity to prioritize any actions
|
|
+** This gives the application an opportunity to prioritize any actions
|
|
** related to the set of unblocked database connections.
|
|
**
|
|
** <b>Deadlock Detection</b>
|
|
**
|
|
-** Assuming that after registering for an unlock-notify callback a
|
|
+** Assuming that after registering for an unlock-notify callback a
|
|
** database waits for the callback to be issued before taking any further
|
|
** action (a reasonable assumption), then using this API may cause the
|
|
** application to deadlock. For example, if connection X is waiting for
|
|
@@ -8696,7 +9186,7 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
|
|
**
|
|
** <b>The "DROP TABLE" Exception</b>
|
|
**
|
|
-** When a call to [sqlite3_step()] returns SQLITE_LOCKED, it is almost
|
|
+** When a call to [sqlite3_step()] returns SQLITE_LOCKED, it is almost
|
|
** always appropriate to call sqlite3_unlock_notify(). There is however,
|
|
** one exception. When executing a "DROP TABLE" or "DROP INDEX" statement,
|
|
** SQLite checks if there are any currently executing SELECT statements
|
|
@@ -8709,7 +9199,7 @@ SQLITE_API int sqlite3_backup_pagecount(sqlite3_backup *p);
|
|
** One way around this problem is to check the extended error code returned
|
|
** by an sqlite3_step() call. ^(If there is a blocking connection, then the
|
|
** extended error code is set to SQLITE_LOCKED_SHAREDCACHE. Otherwise, in
|
|
-** the special "DROP TABLE/INDEX" case, the extended error code is just
|
|
+** the special "DROP TABLE/INDEX" case, the extended error code is just
|
|
** SQLITE_LOCKED.)^
|
|
*/
|
|
SQLITE_API int sqlite3_unlock_notify(
|
|
@@ -8800,8 +9290,8 @@ SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...);
|
|
** ^The [sqlite3_wal_hook()] function is used to register a callback that
|
|
** is invoked each time data is committed to a database in wal mode.
|
|
**
|
|
-** ^(The callback is invoked by SQLite after the commit has taken place and
|
|
-** the associated write-lock on the database released)^, so the implementation
|
|
+** ^(The callback is invoked by SQLite after the commit has taken place and
|
|
+** the associated write-lock on the database released)^, so the implementation
|
|
** may read, write or [checkpoint] the database as required.
|
|
**
|
|
** ^The first parameter passed to the callback function when it is invoked
|
|
@@ -8820,15 +9310,16 @@ SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...);
|
|
** that does not correspond to any valid SQLite error code, the results
|
|
** are undefined.
|
|
**
|
|
-** A single database handle may have at most a single write-ahead log callback
|
|
+** A single database handle may have at most a single write-ahead log callback
|
|
** registered at one time. ^Calling [sqlite3_wal_hook()] replaces any
|
|
-** previously registered write-ahead log callback. ^Note that the
|
|
-** [sqlite3_wal_autocheckpoint()] interface and the
|
|
+** previously registered write-ahead log callback. ^The return value is
|
|
+** a copy of the third parameter from the previous call, if any, or 0.
|
|
+** ^Note that the [sqlite3_wal_autocheckpoint()] interface and the
|
|
** [wal_autocheckpoint pragma] both invoke [sqlite3_wal_hook()] and will
|
|
** overwrite any prior [sqlite3_wal_hook()] settings.
|
|
*/
|
|
SQLITE_API void *sqlite3_wal_hook(
|
|
- sqlite3*,
|
|
+ sqlite3*,
|
|
int(*)(void *,sqlite3*,const char*,int),
|
|
void*
|
|
);
|
|
@@ -8841,7 +9332,7 @@ SQLITE_API void *sqlite3_wal_hook(
|
|
** [sqlite3_wal_hook()] that causes any database on [database connection] D
|
|
** to automatically [checkpoint]
|
|
** after committing a transaction if there are N or
|
|
-** more frames in the [write-ahead log] file. ^Passing zero or
|
|
+** more frames in the [write-ahead log] file. ^Passing zero or
|
|
** a negative value as the nFrame parameter disables automatic
|
|
** checkpoints entirely.
|
|
**
|
|
@@ -8871,7 +9362,7 @@ SQLITE_API int sqlite3_wal_autocheckpoint(sqlite3 *db, int N);
|
|
** ^(The sqlite3_wal_checkpoint(D,X) is equivalent to
|
|
** [sqlite3_wal_checkpoint_v2](D,X,[SQLITE_CHECKPOINT_PASSIVE],0,0).)^
|
|
**
|
|
-** In brief, sqlite3_wal_checkpoint(D,X) causes the content in the
|
|
+** In brief, sqlite3_wal_checkpoint(D,X) causes the content in the
|
|
** [write-ahead log] for database X on [database connection] D to be
|
|
** transferred into the database file and for the write-ahead log to
|
|
** be reset. See the [checkpointing] documentation for addition
|
|
@@ -8897,10 +9388,10 @@ SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
|
|
**
|
|
** <dl>
|
|
** <dt>SQLITE_CHECKPOINT_PASSIVE<dd>
|
|
-** ^Checkpoint as many frames as possible without waiting for any database
|
|
-** readers or writers to finish, then sync the database file if all frames
|
|
+** ^Checkpoint as many frames as possible without waiting for any database
|
|
+** readers or writers to finish, then sync the database file if all frames
|
|
** in the log were checkpointed. ^The [busy-handler callback]
|
|
-** is never invoked in the SQLITE_CHECKPOINT_PASSIVE mode.
|
|
+** is never invoked in the SQLITE_CHECKPOINT_PASSIVE mode.
|
|
** ^On the other hand, passive mode might leave the checkpoint unfinished
|
|
** if there are concurrent readers or writers.
|
|
**
|
|
@@ -8914,9 +9405,9 @@ SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
|
|
**
|
|
** <dt>SQLITE_CHECKPOINT_RESTART<dd>
|
|
** ^This mode works the same way as SQLITE_CHECKPOINT_FULL with the addition
|
|
-** that after checkpointing the log file it blocks (calls the
|
|
+** that after checkpointing the log file it blocks (calls the
|
|
** [busy-handler callback])
|
|
-** until all readers are reading from the database file only. ^This ensures
|
|
+** until all readers are reading from the database file only. ^This ensures
|
|
** that the next writer will restart the log file from the beginning.
|
|
** ^Like SQLITE_CHECKPOINT_FULL, this mode blocks new
|
|
** database writer attempts while it is pending, but does not impede readers.
|
|
@@ -8938,31 +9429,31 @@ SQLITE_API int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
|
|
** truncated to zero bytes and so both *pnLog and *pnCkpt will be set to zero.
|
|
**
|
|
** ^All calls obtain an exclusive "checkpoint" lock on the database file. ^If
|
|
-** any other process is running a checkpoint operation at the same time, the
|
|
-** lock cannot be obtained and SQLITE_BUSY is returned. ^Even if there is a
|
|
+** any other process is running a checkpoint operation at the same time, the
|
|
+** lock cannot be obtained and SQLITE_BUSY is returned. ^Even if there is a
|
|
** busy-handler configured, it will not be invoked in this case.
|
|
**
|
|
-** ^The SQLITE_CHECKPOINT_FULL, RESTART and TRUNCATE modes also obtain the
|
|
+** ^The SQLITE_CHECKPOINT_FULL, RESTART and TRUNCATE modes also obtain the
|
|
** exclusive "writer" lock on the database file. ^If the writer lock cannot be
|
|
** obtained immediately, and a busy-handler is configured, it is invoked and
|
|
** the writer lock retried until either the busy-handler returns 0 or the lock
|
|
** is successfully obtained. ^The busy-handler is also invoked while waiting for
|
|
** database readers as described above. ^If the busy-handler returns 0 before
|
|
** the writer lock is obtained or while waiting for database readers, the
|
|
-** checkpoint operation proceeds from that point in the same way as
|
|
-** SQLITE_CHECKPOINT_PASSIVE - checkpointing as many frames as possible
|
|
+** checkpoint operation proceeds from that point in the same way as
|
|
+** SQLITE_CHECKPOINT_PASSIVE - checkpointing as many frames as possible
|
|
** without blocking any further. ^SQLITE_BUSY is returned in this case.
|
|
**
|
|
** ^If parameter zDb is NULL or points to a zero length string, then the
|
|
-** specified operation is attempted on all WAL databases [attached] to
|
|
+** specified operation is attempted on all WAL databases [attached] to
|
|
** [database connection] db. In this case the
|
|
-** values written to output parameters *pnLog and *pnCkpt are undefined. ^If
|
|
-** an SQLITE_BUSY error is encountered when processing one or more of the
|
|
-** attached WAL databases, the operation is still attempted on any remaining
|
|
-** attached databases and SQLITE_BUSY is returned at the end. ^If any other
|
|
-** error occurs while processing an attached database, processing is abandoned
|
|
-** and the error code is returned to the caller immediately. ^If no error
|
|
-** (SQLITE_BUSY or otherwise) is encountered while processing the attached
|
|
+** values written to output parameters *pnLog and *pnCkpt are undefined. ^If
|
|
+** an SQLITE_BUSY error is encountered when processing one or more of the
|
|
+** attached WAL databases, the operation is still attempted on any remaining
|
|
+** attached databases and SQLITE_BUSY is returned at the end. ^If any other
|
|
+** error occurs while processing an attached database, processing is abandoned
|
|
+** and the error code is returned to the caller immediately. ^If no error
|
|
+** (SQLITE_BUSY or otherwise) is encountered while processing the attached
|
|
** databases, SQLITE_OK is returned.
|
|
**
|
|
** ^If database zDb is the name of an attached database that is not in WAL
|
|
@@ -8997,7 +9488,7 @@ SQLITE_API int sqlite3_wal_checkpoint_v2(
|
|
*/
|
|
#define SQLITE_CHECKPOINT_PASSIVE 0 /* Do as much as possible w/o blocking */
|
|
#define SQLITE_CHECKPOINT_FULL 1 /* Wait for writers, then checkpoint */
|
|
-#define SQLITE_CHECKPOINT_RESTART 2 /* Like FULL but wait for for readers */
|
|
+#define SQLITE_CHECKPOINT_RESTART 2 /* Like FULL but wait for readers */
|
|
#define SQLITE_CHECKPOINT_TRUNCATE 3 /* Like RESTART but also truncate WAL */
|
|
|
|
/*
|
|
@@ -9022,7 +9513,7 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...);
|
|
|
|
/*
|
|
** CAPI3REF: Virtual Table Configuration Options
|
|
-** KEYWORDS: {virtual table configuration options}
|
|
+** KEYWORDS: {virtual table configuration options}
|
|
** KEYWORDS: {virtual table configuration option}
|
|
**
|
|
** These macros define the various options to the
|
|
@@ -9045,20 +9536,20 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...);
|
|
** If X is non-zero, then the virtual table implementation guarantees
|
|
** that if [xUpdate] returns [SQLITE_CONSTRAINT], it will do so before
|
|
** any modifications to internal or persistent data structures have been made.
|
|
-** If the [ON CONFLICT] mode is ABORT, FAIL, IGNORE or ROLLBACK, SQLite
|
|
+** If the [ON CONFLICT] mode is ABORT, FAIL, IGNORE or ROLLBACK, SQLite
|
|
** is able to roll back a statement or database transaction, and abandon
|
|
-** or continue processing the current SQL statement as appropriate.
|
|
+** or continue processing the current SQL statement as appropriate.
|
|
** If the ON CONFLICT mode is REPLACE and the [xUpdate] method returns
|
|
** [SQLITE_CONSTRAINT], SQLite handles this as if the ON CONFLICT mode
|
|
** had been ABORT.
|
|
**
|
|
** Virtual table implementations that are required to handle OR REPLACE
|
|
-** must do so within the [xUpdate] method. If a call to the
|
|
-** [sqlite3_vtab_on_conflict()] function indicates that the current ON
|
|
-** CONFLICT policy is REPLACE, the virtual table implementation should
|
|
+** must do so within the [xUpdate] method. If a call to the
|
|
+** [sqlite3_vtab_on_conflict()] function indicates that the current ON
|
|
+** CONFLICT policy is REPLACE, the virtual table implementation should
|
|
** silently replace the appropriate rows within the xUpdate callback and
|
|
** return SQLITE_OK. Or, if this is not possible, it may return
|
|
-** SQLITE_CONSTRAINT, in which case SQLite falls back to OR ABORT
|
|
+** SQLITE_CONSTRAINT, in which case SQLite falls back to OR ABORT
|
|
** constraint handling.
|
|
** </dd>
|
|
**
|
|
@@ -9102,10 +9593,11 @@ SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *);
|
|
** CAPI3REF: Determine If Virtual Table Column Access Is For UPDATE
|
|
**
|
|
** If the sqlite3_vtab_nochange(X) routine is called within the [xColumn]
|
|
-** method of a [virtual table], then it returns true if and only if the
|
|
+** method of a [virtual table], then it might return true if the
|
|
** column is being fetched as part of an UPDATE operation during which the
|
|
-** column value will not change. Applications might use this to substitute
|
|
-** a return value that is less expensive to compute and that the corresponding
|
|
+** column value will not change. The virtual table implementation can use
|
|
+** this hint as permission to substitute a return value that is less
|
|
+** expensive to compute and that the corresponding
|
|
** [xUpdate] method understands as a "no-change" value.
|
|
**
|
|
** If the [xColumn] method calls sqlite3_vtab_nochange() and finds that
|
|
@@ -9114,23 +9606,285 @@ SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *);
|
|
** any of the [sqlite3_result_int|sqlite3_result_xxxxx() interfaces].
|
|
** In that case, [sqlite3_value_nochange(X)] will return true for the
|
|
** same column in the [xUpdate] method.
|
|
+**
|
|
+** The sqlite3_vtab_nochange() routine is an optimization. Virtual table
|
|
+** implementations should continue to give a correct answer even if the
|
|
+** sqlite3_vtab_nochange() interface were to always return false. In the
|
|
+** current implementation, the sqlite3_vtab_nochange() interface does always
|
|
+** returns false for the enhanced [UPDATE FROM] statement.
|
|
*/
|
|
SQLITE_API int sqlite3_vtab_nochange(sqlite3_context*);
|
|
|
|
/*
|
|
** CAPI3REF: Determine The Collation For a Virtual Table Constraint
|
|
+** METHOD: sqlite3_index_info
|
|
**
|
|
** This function may only be called from within a call to the [xBestIndex]
|
|
-** method of a [virtual table].
|
|
+** method of a [virtual table]. This function returns a pointer to a string
|
|
+** that is the name of the appropriate collation sequence to use for text
|
|
+** comparisons on the constraint identified by its arguments.
|
|
+**
|
|
+** The first argument must be the pointer to the [sqlite3_index_info] object
|
|
+** that is the first parameter to the xBestIndex() method. The second argument
|
|
+** must be an index into the aConstraint[] array belonging to the
|
|
+** sqlite3_index_info structure passed to xBestIndex.
|
|
+**
|
|
+** Important:
|
|
+** The first parameter must be the same pointer that is passed into the
|
|
+** xBestMethod() method. The first parameter may not be a pointer to a
|
|
+** different [sqlite3_index_info] object, even an exact copy.
|
|
+**
|
|
+** The return value is computed as follows:
|
|
**
|
|
-** The first argument must be the sqlite3_index_info object that is the
|
|
-** first parameter to the xBestIndex() method. The second argument must be
|
|
-** an index into the aConstraint[] array belonging to the sqlite3_index_info
|
|
-** structure passed to xBestIndex. This function returns a pointer to a buffer
|
|
-** containing the name of the collation sequence for the corresponding
|
|
-** constraint.
|
|
+** <ol>
|
|
+** <li><p> If the constraint comes from a WHERE clause expression that contains
|
|
+** a [COLLATE operator], then the name of the collation specified by
|
|
+** that COLLATE operator is returned.
|
|
+** <li><p> If there is no COLLATE operator, but the column that is the subject
|
|
+** of the constraint specifies an alternative collating sequence via
|
|
+** a [COLLATE clause] on the column definition within the CREATE TABLE
|
|
+** statement that was passed into [sqlite3_declare_vtab()], then the
|
|
+** name of that alternative collating sequence is returned.
|
|
+** <li><p> Otherwise, "BINARY" is returned.
|
|
+** </ol>
|
|
+*/
|
|
+SQLITE_API const char *sqlite3_vtab_collation(sqlite3_index_info*,int);
|
|
+
|
|
+/*
|
|
+** CAPI3REF: Determine if a virtual table query is DISTINCT
|
|
+** METHOD: sqlite3_index_info
|
|
+**
|
|
+** This API may only be used from within an [xBestIndex|xBestIndex method]
|
|
+** of a [virtual table] implementation. The result of calling this
|
|
+** interface from outside of xBestIndex() is undefined and probably harmful.
|
|
+**
|
|
+** ^The sqlite3_vtab_distinct() interface returns an integer between 0 and
|
|
+** 3. The integer returned by sqlite3_vtab_distinct()
|
|
+** gives the virtual table additional information about how the query
|
|
+** planner wants the output to be ordered. As long as the virtual table
|
|
+** can meet the ordering requirements of the query planner, it may set
|
|
+** the "orderByConsumed" flag.
|
|
+**
|
|
+** <ol><li value="0"><p>
|
|
+** ^If the sqlite3_vtab_distinct() interface returns 0, that means
|
|
+** that the query planner needs the virtual table to return all rows in the
|
|
+** sort order defined by the "nOrderBy" and "aOrderBy" fields of the
|
|
+** [sqlite3_index_info] object. This is the default expectation. If the
|
|
+** virtual table outputs all rows in sorted order, then it is always safe for
|
|
+** the xBestIndex method to set the "orderByConsumed" flag, regardless of
|
|
+** the return value from sqlite3_vtab_distinct().
|
|
+** <li value="1"><p>
|
|
+** ^(If the sqlite3_vtab_distinct() interface returns 1, that means
|
|
+** that the query planner does not need the rows to be returned in sorted order
|
|
+** as long as all rows with the same values in all columns identified by the
|
|
+** "aOrderBy" field are adjacent.)^ This mode is used when the query planner
|
|
+** is doing a GROUP BY.
|
|
+** <li value="2"><p>
|
|
+** ^(If the sqlite3_vtab_distinct() interface returns 2, that means
|
|
+** that the query planner does not need the rows returned in any particular
|
|
+** order, as long as rows with the same values in all "aOrderBy" columns
|
|
+** are adjacent.)^ ^(Furthermore, only a single row for each particular
|
|
+** combination of values in the columns identified by the "aOrderBy" field
|
|
+** needs to be returned.)^ ^It is always ok for two or more rows with the same
|
|
+** values in all "aOrderBy" columns to be returned, as long as all such rows
|
|
+** are adjacent. ^The virtual table may, if it chooses, omit extra rows
|
|
+** that have the same value for all columns identified by "aOrderBy".
|
|
+** ^However omitting the extra rows is optional.
|
|
+** This mode is used for a DISTINCT query.
|
|
+** <li value="3"><p>
|
|
+** ^(If the sqlite3_vtab_distinct() interface returns 3, that means
|
|
+** that the query planner needs only distinct rows but it does need the
|
|
+** rows to be sorted.)^ ^The virtual table implementation is free to omit
|
|
+** rows that are identical in all aOrderBy columns, if it wants to, but
|
|
+** it is not required to omit any rows. This mode is used for queries
|
|
+** that have both DISTINCT and ORDER BY clauses.
|
|
+** </ol>
|
|
+**
|
|
+** ^For the purposes of comparing virtual table output values to see if the
|
|
+** values are same value for sorting purposes, two NULL values are considered
|
|
+** to be the same. In other words, the comparison operator is "IS"
|
|
+** (or "IS NOT DISTINCT FROM") and not "==".
|
|
+**
|
|
+** If a virtual table implementation is unable to meet the requirements
|
|
+** specified above, then it must not set the "orderByConsumed" flag in the
|
|
+** [sqlite3_index_info] object or an incorrect answer may result.
|
|
+**
|
|
+** ^A virtual table implementation is always free to return rows in any order
|
|
+** it wants, as long as the "orderByConsumed" flag is not set. ^When the
|
|
+** the "orderByConsumed" flag is unset, the query planner will add extra
|
|
+** [bytecode] to ensure that the final results returned by the SQL query are
|
|
+** ordered correctly. The use of the "orderByConsumed" flag and the
|
|
+** sqlite3_vtab_distinct() interface is merely an optimization. ^Careful
|
|
+** use of the sqlite3_vtab_distinct() interface and the "orderByConsumed"
|
|
+** flag might help queries against a virtual table to run faster. Being
|
|
+** overly aggressive and setting the "orderByConsumed" flag when it is not
|
|
+** valid to do so, on the other hand, might cause SQLite to return incorrect
|
|
+** results.
|
|
+*/
|
|
+SQLITE_API int sqlite3_vtab_distinct(sqlite3_index_info*);
|
|
+
|
|
+/*
|
|
+** CAPI3REF: Identify and handle IN constraints in xBestIndex
|
|
+**
|
|
+** This interface may only be used from within an
|
|
+** [xBestIndex|xBestIndex() method] of a [virtual table] implementation.
|
|
+** The result of invoking this interface from any other context is
|
|
+** undefined and probably harmful.
|
|
+**
|
|
+** ^(A constraint on a virtual table of the form
|
|
+** "[IN operator|column IN (...)]" is
|
|
+** 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
|
|
+** 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
|
|
+** only sees a single value from the right-hand side of the IN operator
|
|
+** at a time.
|
|
+**
|
|
+** In some cases, however, it would be advantageous for the virtual
|
|
+** table to see all values on the right-hand of the IN operator all at
|
|
+** once. The sqlite3_vtab_in() interfaces facilitates this in two ways:
|
|
+**
|
|
+** <ol>
|
|
+** <li><p>
|
|
+** ^A call to sqlite3_vtab_in(P,N,-1) will return true (non-zero)
|
|
+** if and only if the [sqlite3_index_info|P->aConstraint][N] constraint
|
|
+** is an [IN operator] that can be processed all at once. ^In other words,
|
|
+** sqlite3_vtab_in() with -1 in the third argument is a mechanism
|
|
+** by which the virtual table can ask SQLite if all-at-once processing
|
|
+** of the IN operator is even possible.
|
|
+**
|
|
+** <li><p>
|
|
+** ^A call to sqlite3_vtab_in(P,N,F) with F==1 or F==0 indicates
|
|
+** to SQLite that the virtual table does or does not want to process
|
|
+** the IN operator all-at-once, respectively. ^Thus when the third
|
|
+** parameter (F) is non-negative, this interface is the mechanism by
|
|
+** which the virtual table tells SQLite how it wants to process the
|
|
+** IN operator.
|
|
+** </ol>
|
|
+**
|
|
+** ^The sqlite3_vtab_in(P,N,F) interface can be invoked multiple times
|
|
+** within the same xBestIndex method call. ^For any given P,N pair,
|
|
+** the return value from sqlite3_vtab_in(P,N,F) will always be the same
|
|
+** within the same xBestIndex call. ^If the interface returns true
|
|
+** (non-zero), that means that the constraint is an IN operator
|
|
+** that can be processed all-at-once. ^If the constraint is not an IN
|
|
+** operator or cannot be processed all-at-once, then the interface returns
|
|
+** false.
|
|
+**
|
|
+** ^(All-at-once processing of the IN operator is selected if both of the
|
|
+** following conditions are met:
|
|
+**
|
|
+** <ol>
|
|
+** <li><p> The P->aConstraintUsage[N].argvIndex value is set to a positive
|
|
+** integer. This is how the virtual table tells SQLite that it wants to
|
|
+** use the N-th constraint.
|
|
+**
|
|
+** <li><p> The last call to sqlite3_vtab_in(P,N,F) for which F was
|
|
+** non-negative had F>=1.
|
|
+** </ol>)^
|
|
+**
|
|
+** ^If either or both of the conditions above are false, then SQLite uses
|
|
+** the traditional one-at-a-time processing strategy for the IN constraint.
|
|
+** ^If both conditions are true, then the argvIndex-th parameter to the
|
|
+** xFilter method will be an [sqlite3_value] that appears to be NULL,
|
|
+** but which can be passed to [sqlite3_vtab_in_first()] and
|
|
+** [sqlite3_vtab_in_next()] to find all values on the right-hand side
|
|
+** of the IN constraint.
|
|
*/
|
|
-SQLITE_API SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_info*,int);
|
|
+SQLITE_API int sqlite3_vtab_in(sqlite3_index_info*, int iCons, int bHandle);
|
|
+
|
|
+/*
|
|
+** CAPI3REF: Find all elements on the right-hand side of an IN constraint.
|
|
+**
|
|
+** These interfaces are only useful from within the
|
|
+** [xFilter|xFilter() method] of a [virtual table] implementation.
|
|
+** The result of invoking these interfaces from any other context
|
|
+** is undefined and probably harmful.
|
|
+**
|
|
+** The X parameter in a call to sqlite3_vtab_in_first(X,P) or
|
|
+** sqlite3_vtab_in_next(X,P) should be one of the parameters to the
|
|
+** xFilter method which invokes these routines, and specifically
|
|
+** a parameter that was previously selected for all-at-once IN constraint
|
|
+** processing use the [sqlite3_vtab_in()] interface in the
|
|
+** [xBestIndex|xBestIndex method]. ^(If the X parameter is not
|
|
+** an xFilter argument that was selected for all-at-once IN constraint
|
|
+** processing, then these routines return [SQLITE_ERROR].)^
|
|
+**
|
|
+** ^(Use these routines to access all values on the right-hand side
|
|
+** of the IN constraint using code like the following:
|
|
+**
|
|
+** <blockquote><pre>
|
|
+** for(rc=sqlite3_vtab_in_first(pList, &pVal);
|
|
+** rc==SQLITE_OK && pVal;
|
|
+** rc=sqlite3_vtab_in_next(pList, &pVal)
|
|
+** ){
|
|
+** // do something with pVal
|
|
+** }
|
|
+** if( rc!=SQLITE_OK ){
|
|
+** // an error has occurred
|
|
+** }
|
|
+** </pre></blockquote>)^
|
|
+**
|
|
+** ^On success, the sqlite3_vtab_in_first(X,P) and sqlite3_vtab_in_next(X,P)
|
|
+** routines return SQLITE_OK and set *P to point to the first or next value
|
|
+** on the RHS of the IN constraint. ^If there are no more values on the
|
|
+** right hand side of the IN constraint, then *P is set to NULL and these
|
|
+** routines return [SQLITE_DONE]. ^The return value might be
|
|
+** some other value, such as SQLITE_NOMEM, in the event of a malfunction.
|
|
+**
|
|
+** The *ppOut values returned by these routines are only valid until the
|
|
+** next call to either of these routines or until the end of the xFilter
|
|
+** method from which these routines were called. If the virtual table
|
|
+** implementation needs to retain the *ppOut values for longer, it must make
|
|
+** copies. The *ppOut values are [protected sqlite3_value|protected].
|
|
+*/
|
|
+SQLITE_API int sqlite3_vtab_in_first(sqlite3_value *pVal, sqlite3_value **ppOut);
|
|
+SQLITE_API int sqlite3_vtab_in_next(sqlite3_value *pVal, sqlite3_value **ppOut);
|
|
+
|
|
+/*
|
|
+** CAPI3REF: Constraint values in xBestIndex()
|
|
+** METHOD: sqlite3_index_info
|
|
+**
|
|
+** This API may only be used from within the [xBestIndex|xBestIndex method]
|
|
+** of a [virtual table] implementation. The result of calling this interface
|
|
+** from outside of an xBestIndex method are undefined and probably harmful.
|
|
+**
|
|
+** ^When the sqlite3_vtab_rhs_value(P,J,V) interface is invoked from within
|
|
+** the [xBestIndex] method of a [virtual table] implementation, with P being
|
|
+** a copy of the [sqlite3_index_info] object pointer passed into xBestIndex and
|
|
+** J being a 0-based index into P->aConstraint[], then this routine
|
|
+** attempts to set *V to the value of the right-hand operand of
|
|
+** that constraint if the right-hand operand is known. ^If the
|
|
+** right-hand operand is not known, then *V is set to a NULL pointer.
|
|
+** ^The sqlite3_vtab_rhs_value(P,J,V) interface returns SQLITE_OK if
|
|
+** and only if *V is set to a value. ^The sqlite3_vtab_rhs_value(P,J,V)
|
|
+** inteface returns SQLITE_NOTFOUND if the right-hand side of the J-th
|
|
+** constraint is not available. ^The sqlite3_vtab_rhs_value() interface
|
|
+** can return an result code other than SQLITE_OK or SQLITE_NOTFOUND if
|
|
+** something goes wrong.
|
|
+**
|
|
+** The sqlite3_vtab_rhs_value() interface is usually only successful if
|
|
+** the right-hand operand of a constraint is a literal value in the original
|
|
+** SQL statement. If the right-hand operand is an expression or a reference
|
|
+** to some other column or a [host parameter], then sqlite3_vtab_rhs_value()
|
|
+** will probably return [SQLITE_NOTFOUND].
|
|
+**
|
|
+** ^(Some constraints, such as [SQLITE_INDEX_CONSTRAINT_ISNULL] and
|
|
+** [SQLITE_INDEX_CONSTRAINT_ISNOTNULL], have no right-hand operand. For such
|
|
+** constraints, sqlite3_vtab_rhs_value() always returns SQLITE_NOTFOUND.)^
|
|
+**
|
|
+** ^The [sqlite3_value] object returned in *V is a protected sqlite3_value
|
|
+** and remains valid for the duration of the xBestIndex method call.
|
|
+** ^When xBestIndex returns, the sqlite3_value object returned by
|
|
+** sqlite3_vtab_rhs_value() is automatically deallocated.
|
|
+**
|
|
+** The "_rhs_" in the name of this routine is an abbreviation for
|
|
+** "Right-Hand Side".
|
|
+*/
|
|
+SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value **ppVal);
|
|
|
|
/*
|
|
** CAPI3REF: Conflict resolution modes
|
|
@@ -9162,6 +9916,10 @@ SQLITE_API SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_
|
|
** managed by the prepared statement S and will be automatically freed when
|
|
** S is finalized.
|
|
**
|
|
+** Not all values are available for all query elements. When a value is
|
|
+** not available, the output variable is set to -1 if the value is numeric,
|
|
+** or to NULL if it is a string (SQLITE_SCANSTAT_NAME).
|
|
+**
|
|
** <dl>
|
|
** [[SQLITE_SCANSTAT_NLOOP]] <dt>SQLITE_SCANSTAT_NLOOP</dt>
|
|
** <dd>^The [sqlite3_int64] variable pointed to by the V parameter will be
|
|
@@ -9189,12 +9947,24 @@ SQLITE_API SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_
|
|
** to a zero-terminated UTF-8 string containing the [EXPLAIN QUERY PLAN]
|
|
** description for the X-th loop.
|
|
**
|
|
-** [[SQLITE_SCANSTAT_SELECTID]] <dt>SQLITE_SCANSTAT_SELECT</dt>
|
|
+** [[SQLITE_SCANSTAT_SELECTID]] <dt>SQLITE_SCANSTAT_SELECTID</dt>
|
|
** <dd>^The "int" variable pointed to by the V parameter will be set to the
|
|
-** "select-id" for the X-th loop. The select-id identifies which query or
|
|
-** subquery the loop is part of. The main query has a select-id of zero.
|
|
-** The select-id is the same value as is output in the first column
|
|
-** of an [EXPLAIN QUERY PLAN] query.
|
|
+** id for the X-th query plan element. The id value is unique within the
|
|
+** statement. The select-id is the same value as is output in the first
|
|
+** column of an [EXPLAIN QUERY PLAN] query.
|
|
+**
|
|
+** [[SQLITE_SCANSTAT_PARENTID]] <dt>SQLITE_SCANSTAT_PARENTID</dt>
|
|
+** <dd>The "int" variable pointed to by the V parameter will be set to the
|
|
+** the id of the parent of the current query element, if applicable, or
|
|
+** to zero if the query element has no parent. This is the same value as
|
|
+** returned in the second column of an [EXPLAIN QUERY PLAN] query.
|
|
+**
|
|
+** [[SQLITE_SCANSTAT_NCYCLE]] <dt>SQLITE_SCANSTAT_NCYCLE</dt>
|
|
+** <dd>The sqlite3_int64 output value is set to the number of cycles,
|
|
+** according to the processor time-stamp counter, that elapsed while the
|
|
+** query element was being processed. This value is not available for
|
|
+** all query elements - if it is unavailable the output variable is
|
|
+** set to -1.
|
|
** </dl>
|
|
*/
|
|
#define SQLITE_SCANSTAT_NLOOP 0
|
|
@@ -9203,12 +9973,14 @@ SQLITE_API SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_
|
|
#define SQLITE_SCANSTAT_NAME 3
|
|
#define SQLITE_SCANSTAT_EXPLAIN 4
|
|
#define SQLITE_SCANSTAT_SELECTID 5
|
|
+#define SQLITE_SCANSTAT_PARENTID 6
|
|
+#define SQLITE_SCANSTAT_NCYCLE 7
|
|
|
|
/*
|
|
** CAPI3REF: Prepared Statement Scan Status
|
|
** METHOD: sqlite3_stmt
|
|
**
|
|
-** This interface returns information about the predicted and measured
|
|
+** These interfaces return information about the predicted and measured
|
|
** performance for pStmt. Advanced applications can use this
|
|
** interface to compare the predicted and the measured performance and
|
|
** issue warnings and/or rerun [ANALYZE] if discrepancies are found.
|
|
@@ -9219,19 +9991,25 @@ SQLITE_API SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_
|
|
**
|
|
** The "iScanStatusOp" parameter determines which status information to return.
|
|
** The "iScanStatusOp" must be one of the [scanstatus options] or the behavior
|
|
-** of this interface is undefined.
|
|
-** ^The requested measurement is written into a variable pointed to by
|
|
-** the "pOut" parameter.
|
|
-** Parameter "idx" identifies the specific loop to retrieve statistics for.
|
|
-** Loops are numbered starting from zero. ^If idx is out of range - less than
|
|
-** zero or greater than or equal to the total number of loops used to implement
|
|
-** the statement - a non-zero value is returned and the variable that pOut
|
|
-** points to is unchanged.
|
|
-**
|
|
-** ^Statistics might not be available for all loops in all statements. ^In cases
|
|
-** where there exist loops with no available statistics, this function behaves
|
|
-** as if the loop did not exist - it returns non-zero and leave the variable
|
|
-** that pOut points to unchanged.
|
|
+** of this interface is undefined. ^The requested measurement is written into
|
|
+** a variable pointed to by the "pOut" parameter.
|
|
+**
|
|
+** The "flags" parameter must be passed a mask of flags. At present only
|
|
+** one flag is defined - SQLITE_SCANSTAT_COMPLEX. If SQLITE_SCANSTAT_COMPLEX
|
|
+** is specified, then status information is available for all elements
|
|
+** of a query plan that are reported by "EXPLAIN QUERY PLAN" output. If
|
|
+** SQLITE_SCANSTAT_COMPLEX is not specified, then only query plan elements
|
|
+** that correspond to query loops (the "SCAN..." and "SEARCH..." elements of
|
|
+** the EXPLAIN QUERY PLAN output) are available. Invoking API
|
|
+** sqlite3_stmt_scanstatus() is equivalent to calling
|
|
+** sqlite3_stmt_scanstatus_v2() with a zeroed flags parameter.
|
|
+**
|
|
+** Parameter "idx" identifies the specific query element to retrieve statistics
|
|
+** for. Query elements are numbered starting from zero. A value of -1 may be
|
|
+** to query for statistics regarding the entire query. ^If idx is out of range
|
|
+** - less than -1 or greater than or equal to the total number of query
|
|
+** elements used to implement the statement - a non-zero value is returned and
|
|
+** the variable that pOut points to is unchanged.
|
|
**
|
|
** See also: [sqlite3_stmt_scanstatus_reset()]
|
|
*/
|
|
@@ -9240,7 +10018,20 @@ SQLITE_API int sqlite3_stmt_scanstatus(
|
|
int idx, /* Index of loop to report on */
|
|
int iScanStatusOp, /* Information desired. SQLITE_SCANSTAT_* */
|
|
void *pOut /* Result written here */
|
|
-);
|
|
+);
|
|
+SQLITE_API int sqlite3_stmt_scanstatus_v2(
|
|
+ sqlite3_stmt *pStmt, /* Prepared statement for which info desired */
|
|
+ int idx, /* Index of loop to report on */
|
|
+ int iScanStatusOp, /* Information desired. SQLITE_SCANSTAT_* */
|
|
+ int flags, /* Mask of flags defined below */
|
|
+ void *pOut /* Result written here */
|
|
+);
|
|
+
|
|
+/*
|
|
+** CAPI3REF: Prepared Statement Scan Status
|
|
+** KEYWORDS: {scan status flags}
|
|
+*/
|
|
+#define SQLITE_SCANSTAT_COMPLEX 0x0001
|
|
|
|
/*
|
|
** CAPI3REF: Zero Scan-Status Counters
|
|
@@ -9255,18 +10046,19 @@ SQLITE_API void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*);
|
|
|
|
/*
|
|
** CAPI3REF: Flush caches to disk mid-transaction
|
|
+** METHOD: sqlite3
|
|
**
|
|
** ^If a write-transaction is open on [database connection] D when the
|
|
** [sqlite3_db_cacheflush(D)] interface invoked, any dirty
|
|
-** pages in the pager-cache that are not currently in use are written out
|
|
+** pages in the pager-cache that are not currently in use are written out
|
|
** to disk. A dirty page may be in use if a database cursor created by an
|
|
** active SQL statement is reading from it, or if it is page 1 of a database
|
|
** file (page 1 is always "in use"). ^The [sqlite3_db_cacheflush(D)]
|
|
** interface flushes caches for all schemas - "main", "temp", and
|
|
** any [attached] databases.
|
|
**
|
|
-** ^If this function needs to obtain extra database locks before dirty pages
|
|
-** can be flushed to disk, it does so. ^If those locks cannot be obtained
|
|
+** ^If this function needs to obtain extra database locks before dirty pages
|
|
+** can be flushed to disk, it does so. ^If those locks cannot be obtained
|
|
** immediately and there is a busy-handler callback configured, it is invoked
|
|
** in the usual manner. ^If the required lock still cannot be obtained, then
|
|
** the database is skipped and an attempt made to flush any dirty pages
|
|
@@ -9287,6 +10079,7 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*);
|
|
|
|
/*
|
|
** CAPI3REF: The pre-update hook.
|
|
+** METHOD: sqlite3
|
|
**
|
|
** ^These interfaces are only available if SQLite is compiled using the
|
|
** [SQLITE_ENABLE_PREUPDATE_HOOK] compile-time option.
|
|
@@ -9304,7 +10097,7 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*);
|
|
**
|
|
** ^The preupdate hook only fires for changes to real database tables; the
|
|
** preupdate hook is not invoked for changes to [virtual tables] or to
|
|
-** system tables like sqlite_master or sqlite_stat1.
|
|
+** system tables like sqlite_sequence or sqlite_stat1.
|
|
**
|
|
** ^The second parameter to the preupdate callback is a pointer to
|
|
** the [database connection] that registered the preupdate hook.
|
|
@@ -9313,21 +10106,25 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*);
|
|
** kind of update operation that is about to occur.
|
|
** ^(The fourth parameter to the preupdate callback is the name of the
|
|
** database within the database connection that is being modified. This
|
|
-** will be "main" for the main database or "temp" for TEMP tables or
|
|
+** will be "main" for the main database or "temp" for TEMP tables or
|
|
** the name given after the AS keyword in the [ATTACH] statement for attached
|
|
** databases.)^
|
|
** ^The fifth parameter to the preupdate callback is the name of the
|
|
** table that is being modified.
|
|
**
|
|
** For an UPDATE or DELETE operation on a [rowid table], the sixth
|
|
-** parameter passed to the preupdate callback is the initial [rowid] of the
|
|
+** parameter passed to the preupdate callback is the initial [rowid] of the
|
|
** row being modified or deleted. For an INSERT operation on a rowid table,
|
|
-** or any operation on a WITHOUT ROWID table, the value of the sixth
|
|
+** or any operation on a WITHOUT ROWID table, the value of the sixth
|
|
** parameter is undefined. For an INSERT or UPDATE on a rowid table the
|
|
** seventh parameter is the final rowid value of the row being inserted
|
|
** or updated. The value of the seventh parameter passed to the callback
|
|
** function is not defined for operations on WITHOUT ROWID tables, or for
|
|
-** INSERT operations on rowid tables.
|
|
+** DELETE operations on rowid tables.
|
|
+**
|
|
+** ^The sqlite3_preupdate_hook(D,C,P) function returns the P argument from
|
|
+** the previous call on the same [database connection] D, or NULL for
|
|
+** the first call on D.
|
|
**
|
|
** The [sqlite3_preupdate_old()], [sqlite3_preupdate_new()],
|
|
** [sqlite3_preupdate_count()], and [sqlite3_preupdate_depth()] interfaces
|
|
@@ -9361,10 +10158,19 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*);
|
|
**
|
|
** ^The [sqlite3_preupdate_depth(D)] interface returns 0 if the preupdate
|
|
** callback was invoked as a result of a direct insert, update, or delete
|
|
-** operation; or 1 for inserts, updates, or deletes invoked by top-level
|
|
+** operation; or 1 for inserts, updates, or deletes invoked by top-level
|
|
** triggers; or 2 for changes resulting from triggers called by top-level
|
|
** triggers; and so forth.
|
|
**
|
|
+** When the [sqlite3_blob_write()] API is used to update a blob column,
|
|
+** the pre-update hook is invoked with SQLITE_DELETE. This is because the
|
|
+** in this case the new values are not available. In this case, when a
|
|
+** callback made with op==SQLITE_DELETE is actuall a write using the
|
|
+** sqlite3_blob_write() API, the [sqlite3_preupdate_blobwrite()] returns
|
|
+** the index of the column being written. In other cases, where the
|
|
+** pre-update hook is being invoked for some other reason, including a
|
|
+** regular DELETE, sqlite3_preupdate_blobwrite() returns -1.
|
|
+**
|
|
** See also: [sqlite3_update_hook()]
|
|
*/
|
|
#if defined(SQLITE_ENABLE_PREUPDATE_HOOK)
|
|
@@ -9385,17 +10191,19 @@ SQLITE_API int sqlite3_preupdate_old(sqlite3 *, int, sqlite3_value **);
|
|
SQLITE_API int sqlite3_preupdate_count(sqlite3 *);
|
|
SQLITE_API int sqlite3_preupdate_depth(sqlite3 *);
|
|
SQLITE_API int sqlite3_preupdate_new(sqlite3 *, int, sqlite3_value **);
|
|
+SQLITE_API int sqlite3_preupdate_blobwrite(sqlite3 *);
|
|
#endif
|
|
|
|
/*
|
|
** CAPI3REF: Low-level system error code
|
|
+** METHOD: sqlite3
|
|
**
|
|
** ^Attempt to return the underlying operating system error code or error
|
|
** number that caused the most recent I/O error or failure to open a file.
|
|
** The return value is OS-dependent. For example, on unix systems, after
|
|
** [sqlite3_open_v2()] returns [SQLITE_CANTOPEN], this interface could be
|
|
** called to get back the underlying "errno" that caused the problem, such
|
|
-** as ENOSPC, EAUTH, EISDIR, and so forth.
|
|
+** as ENOSPC, EAUTH, EISDIR, and so forth.
|
|
*/
|
|
SQLITE_API int sqlite3_system_errno(sqlite3*);
|
|
|
|
@@ -9433,12 +10241,12 @@ typedef struct sqlite3_snapshot {
|
|
** [sqlite3_snapshot_get(D,S,P)] interface writes a pointer to the newly
|
|
** created [sqlite3_snapshot] object into *P and returns SQLITE_OK.
|
|
** If there is not already a read-transaction open on schema S when
|
|
-** this function is called, one is opened automatically.
|
|
+** this function is called, one is opened automatically.
|
|
**
|
|
** The following must be true for this function to succeed. If any of
|
|
** the following statements are false when sqlite3_snapshot_get() is
|
|
** called, SQLITE_ERROR is returned. The final value of *P is undefined
|
|
-** in this case.
|
|
+** in this case.
|
|
**
|
|
** <ul>
|
|
** <li> The database handle must not be in [autocommit mode].
|
|
@@ -9450,13 +10258,13 @@ typedef struct sqlite3_snapshot {
|
|
**
|
|
** <li> One or more transactions must have been written to the current wal
|
|
** file since it was created on disk (by any connection). This means
|
|
-** that a snapshot cannot be taken on a wal mode database with no wal
|
|
+** that a snapshot cannot be taken on a wal mode database with no wal
|
|
** file immediately after it is first opened. At least one transaction
|
|
** must be written to it first.
|
|
** </ul>
|
|
**
|
|
** This function may also return SQLITE_NOMEM. If it is called with the
|
|
-** database handle in autocommit mode but fails for some other reason,
|
|
+** database handle in autocommit mode but fails for some other reason,
|
|
** whether or not a read transaction is opened on schema S is undefined.
|
|
**
|
|
** The [sqlite3_snapshot] object returned from a successful call to
|
|
@@ -9476,38 +10284,38 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get(
|
|
** CAPI3REF: Start a read transaction on an historical snapshot
|
|
** METHOD: sqlite3_snapshot
|
|
**
|
|
-** ^The [sqlite3_snapshot_open(D,S,P)] interface either starts a new read
|
|
-** transaction or upgrades an existing one for schema S of
|
|
-** [database connection] D such that the read transaction refers to
|
|
-** historical [snapshot] P, rather than the most recent change to the
|
|
-** database. ^The [sqlite3_snapshot_open()] interface returns SQLITE_OK
|
|
+** ^The [sqlite3_snapshot_open(D,S,P)] interface either starts a new read
|
|
+** transaction or upgrades an existing one for schema S of
|
|
+** [database connection] D such that the read transaction refers to
|
|
+** historical [snapshot] P, rather than the most recent change to the
|
|
+** database. ^The [sqlite3_snapshot_open()] interface returns SQLITE_OK
|
|
** on success or an appropriate [error code] if it fails.
|
|
**
|
|
-** ^In order to succeed, the database connection must not be in
|
|
+** ^In order to succeed, the database connection must not be in
|
|
** [autocommit mode] when [sqlite3_snapshot_open(D,S,P)] is called. If there
|
|
** is already a read transaction open on schema S, then the database handle
|
|
** must have no active statements (SELECT statements that have been passed
|
|
-** to sqlite3_step() but not sqlite3_reset() or sqlite3_finalize()).
|
|
+** to sqlite3_step() but not sqlite3_reset() or sqlite3_finalize()).
|
|
** SQLITE_ERROR is returned if either of these conditions is violated, or
|
|
** if schema S does not exist, or if the snapshot object is invalid.
|
|
**
|
|
** ^A call to sqlite3_snapshot_open() will fail to open if the specified
|
|
-** snapshot has been overwritten by a [checkpoint]. In this case
|
|
+** snapshot has been overwritten by a [checkpoint]. In this case
|
|
** SQLITE_ERROR_SNAPSHOT is returned.
|
|
**
|
|
-** If there is already a read transaction open when this function is
|
|
+** If there is already a read transaction open when this function is
|
|
** invoked, then the same read transaction remains open (on the same
|
|
** database snapshot) if SQLITE_ERROR, SQLITE_BUSY or SQLITE_ERROR_SNAPSHOT
|
|
** is returned. If another error code - for example SQLITE_PROTOCOL or an
|
|
** SQLITE_IOERR error code - is returned, then the final state of the
|
|
-** read transaction is undefined. If SQLITE_OK is returned, then the
|
|
+** read transaction is undefined. If SQLITE_OK is returned, then the
|
|
** read transaction is now open on database snapshot P.
|
|
**
|
|
** ^(A call to [sqlite3_snapshot_open(D,S,P)] will fail if the
|
|
** database connection D does not know that the database file for
|
|
** schema S is in [WAL mode]. A database connection might not know
|
|
** that the database file is in [WAL mode] if there has been no prior
|
|
-** I/O on that database connection, or if the database entered [WAL mode]
|
|
+** I/O on that database connection, or if the database entered [WAL mode]
|
|
** after the most recent I/O on the database connection.)^
|
|
** (Hint: Run "[PRAGMA application_id]" against a newly opened
|
|
** database connection in order to make it ready to use snapshots.)
|
|
@@ -9539,17 +10347,17 @@ SQLITE_API SQLITE_EXPERIMENTAL void sqlite3_snapshot_free(sqlite3_snapshot*);
|
|
** METHOD: sqlite3_snapshot
|
|
**
|
|
** The sqlite3_snapshot_cmp(P1, P2) interface is used to compare the ages
|
|
-** of two valid snapshot handles.
|
|
+** of two valid snapshot handles.
|
|
**
|
|
-** If the two snapshot handles are not associated with the same database
|
|
-** file, the result of the comparison is undefined.
|
|
+** If the two snapshot handles are not associated with the same database
|
|
+** file, the result of the comparison is undefined.
|
|
**
|
|
** Additionally, the result of the comparison is only valid if both of the
|
|
** snapshot handles were obtained by calling sqlite3_snapshot_get() since the
|
|
** last time the wal file was deleted. The wal file is deleted when the
|
|
** database is changed back to rollback mode or when the number of database
|
|
-** clients drops to zero. If either snapshot handle was obtained before the
|
|
-** wal file was last deleted, the value returned by this function
|
|
+** clients drops to zero. If either snapshot handle was obtained before the
|
|
+** wal file was last deleted, the value returned by this function
|
|
** is undefined.
|
|
**
|
|
** Otherwise, this API returns a negative value if P1 refers to an older
|
|
@@ -9614,7 +10422,7 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const c
|
|
** representation of the database will usually only exist if there has
|
|
** been a prior call to [sqlite3_deserialize(D,S,...)] with the same
|
|
** values of D and S.
|
|
-** The size of the database is written into *P even if the
|
|
+** The size of the database is written into *P even if the
|
|
** SQLITE_SERIALIZE_NOCOPY bit is set but no contiguous copy
|
|
** of the database exists.
|
|
**
|
|
@@ -9622,8 +10430,8 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const c
|
|
** SQLITE_SERIALIZE_NOCOPY bit is omitted from argument F if a memory
|
|
** allocation error occurs.
|
|
**
|
|
-** This interface is only available if SQLite is compiled with the
|
|
-** [SQLITE_ENABLE_DESERIALIZE] option.
|
|
+** This interface is omitted if SQLite is compiled with the
|
|
+** [SQLITE_OMIT_DESERIALIZE] option.
|
|
*/
|
|
SQLITE_API unsigned char *sqlite3_serialize(
|
|
sqlite3 *db, /* The database connection */
|
|
@@ -9651,7 +10459,7 @@ SQLITE_API unsigned char *sqlite3_serialize(
|
|
/*
|
|
** CAPI3REF: Deserialize a database
|
|
**
|
|
-** The sqlite3_deserialize(D,S,P,N,M,F) interface causes the
|
|
+** The sqlite3_deserialize(D,S,P,N,M,F) interface causes the
|
|
** [database connection] D to disconnect from database S and then
|
|
** reopen S as an in-memory database based on the serialization contained
|
|
** in P. The serialized database P is N bytes in size. M is the size of
|
|
@@ -9670,12 +10478,16 @@ SQLITE_API unsigned char *sqlite3_serialize(
|
|
** database is currently in a read transaction or is involved in a backup
|
|
** operation.
|
|
**
|
|
-** If sqlite3_deserialize(D,S,P,N,M,F) fails for any reason and if the
|
|
+** It is not possible to deserialized into the TEMP database. If the
|
|
+** S argument to sqlite3_deserialize(D,S,P,N,M,F) is "temp" then the
|
|
+** function returns SQLITE_ERROR.
|
|
+**
|
|
+** 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.
|
|
**
|
|
-** This interface is only available if SQLite is compiled with the
|
|
-** [SQLITE_ENABLE_DESERIALIZE] option.
|
|
+** This interface is omitted if SQLite is compiled with the
|
|
+** [SQLITE_OMIT_DESERIALIZE] option.
|
|
*/
|
|
SQLITE_API int sqlite3_deserialize(
|
|
sqlite3 *db, /* The database connection */
|
|
@@ -9719,6 +10531,19 @@ SQLITE_API int sqlite3_deserialize(
|
|
# undef double
|
|
#endif
|
|
|
|
+#if defined(__wasi__)
|
|
+# undef SQLITE_WASI
|
|
+# define SQLITE_WASI 1
|
|
+# undef SQLITE_OMIT_WAL
|
|
+# define SQLITE_OMIT_WAL 1/* because it requires shared memory APIs */
|
|
+# ifndef SQLITE_OMIT_LOAD_EXTENSION
|
|
+# define SQLITE_OMIT_LOAD_EXTENSION
|
|
+# endif
|
|
+# ifndef SQLITE_THREADSAFE
|
|
+# define SQLITE_THREADSAFE 0
|
|
+# endif
|
|
+#endif
|
|
+
|
|
#ifdef __cplusplus
|
|
} /* End of the 'extern "C"' block */
|
|
#endif
|
|
@@ -9785,7 +10610,7 @@ struct sqlite3_rtree_geometry {
|
|
};
|
|
|
|
/*
|
|
-** Register a 2nd-generation geometry callback named zScore that can be
|
|
+** Register a 2nd-generation geometry callback named zScore that can be
|
|
** used as part of an R-Tree geometry query as follows:
|
|
**
|
|
** SELECT ... FROM <rtree> WHERE <rtree col> MATCH $zQueryFunc(... params ...)
|
|
@@ -9800,7 +10625,7 @@ SQLITE_API int sqlite3_rtree_query_callback(
|
|
|
|
|
|
/*
|
|
-** A pointer to a structure of the following type is passed as the
|
|
+** A pointer to a structure of the following type is passed as the
|
|
** argument to scored geometry callback registered using
|
|
** sqlite3_rtree_query_callback().
|
|
**
|
|
@@ -9895,7 +10720,7 @@ typedef struct sqlite3_changeset_iter sqlite3_changeset_iter;
|
|
** is not possible for an application to register a pre-update hook on a
|
|
** database handle that has one or more session objects attached. Nor is
|
|
** it possible to create a session object attached to a database handle for
|
|
-** which a pre-update hook is already defined. The results of attempting
|
|
+** which a pre-update hook is already defined. The results of attempting
|
|
** either of these things are undefined.
|
|
**
|
|
** The session object will be used to create changesets for tables in
|
|
@@ -9913,17 +10738,49 @@ SQLITE_API int sqlite3session_create(
|
|
** CAPI3REF: Delete A Session Object
|
|
** DESTRUCTOR: sqlite3_session
|
|
**
|
|
-** Delete a session object previously allocated using
|
|
+** Delete a session object previously allocated using
|
|
** [sqlite3session_create()]. Once a session object has been deleted, the
|
|
** results of attempting to use pSession with any other session module
|
|
** function are undefined.
|
|
**
|
|
** Session objects must be deleted before the database handle to which they
|
|
-** are attached is closed. Refer to the documentation for
|
|
+** are attached is closed. Refer to the documentation for
|
|
** [sqlite3session_create()] for details.
|
|
*/
|
|
SQLITE_API void sqlite3session_delete(sqlite3_session *pSession);
|
|
|
|
+/*
|
|
+** CAPIREF: Conigure a Session Object
|
|
+** METHOD: sqlite3_session
|
|
+**
|
|
+** This method is used to configure a session object after it has been
|
|
+** created. At present the only valid value for the second parameter is
|
|
+** [SQLITE_SESSION_OBJCONFIG_SIZE].
|
|
+**
|
|
+** Arguments for sqlite3session_object_config()
|
|
+**
|
|
+** The following values may passed as the the 4th parameter to
|
|
+** sqlite3session_object_config().
|
|
+**
|
|
+** <dt>SQLITE_SESSION_OBJCONFIG_SIZE <dd>
|
|
+** This option is used to set, clear or query the flag that enables
|
|
+** the [sqlite3session_changeset_size()] API. Because it imposes some
|
|
+** computational overhead, this API is disabled by default. Argument
|
|
+** pArg must point to a value of type (int). If the value is initially
|
|
+** 0, then the sqlite3session_changeset_size() API is disabled. If it
|
|
+** is greater than 0, then the same API is enabled. Or, if the initial
|
|
+** value is less than zero, no change is made. In all cases the (int)
|
|
+** variable is set to 1 if the sqlite3session_changeset_size() API is
|
|
+** enabled following the current call, or 0 otherwise.
|
|
+**
|
|
+** 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
|
|
|
|
/*
|
|
** CAPI3REF: Enable Or Disable A Session Object
|
|
@@ -9937,10 +10794,10 @@ SQLITE_API void sqlite3session_delete(sqlite3_session *pSession);
|
|
** the eventual changesets.
|
|
**
|
|
** Passing zero to this function disables the session. Passing a value
|
|
-** greater than zero enables it. Passing a value less than zero is a
|
|
+** greater than zero enables it. Passing a value less than zero is a
|
|
** no-op, and may be used to query the current state of the session.
|
|
**
|
|
-** The return value indicates the final state of the session object: 0 if
|
|
+** The return value indicates the final state of the session object: 0 if
|
|
** the session is disabled, or 1 if it is enabled.
|
|
*/
|
|
SQLITE_API int sqlite3session_enable(sqlite3_session *pSession, int bEnable);
|
|
@@ -9955,7 +10812,7 @@ SQLITE_API int sqlite3session_enable(sqlite3_session *pSession, int bEnable);
|
|
** <ul>
|
|
** <li> The session object "indirect" flag is set when the change is
|
|
** made, or
|
|
-** <li> The change is made by an SQL trigger or foreign key action
|
|
+** <li> The change is made by an SQL trigger or foreign key action
|
|
** instead of directly as a result of a users SQL statement.
|
|
** </ul>
|
|
**
|
|
@@ -9967,10 +10824,10 @@ SQLITE_API int sqlite3session_enable(sqlite3_session *pSession, int bEnable);
|
|
** flag. If the second argument passed to this function is zero, then the
|
|
** indirect flag is cleared. If it is greater than zero, the indirect flag
|
|
** is set. Passing a value less than zero does not modify the current value
|
|
-** of the indirect flag, and may be used to query the current state of the
|
|
+** of the indirect flag, and may be used to query the current state of the
|
|
** indirect flag for the specified session object.
|
|
**
|
|
-** The return value indicates the final state of the indirect flag: 0 if
|
|
+** The return value indicates the final state of the indirect flag: 0 if
|
|
** it is clear, or 1 if it is set.
|
|
*/
|
|
SQLITE_API int sqlite3session_indirect(sqlite3_session *pSession, int bIndirect);
|
|
@@ -9980,20 +10837,20 @@ SQLITE_API int sqlite3session_indirect(sqlite3_session *pSession, int bIndirect)
|
|
** METHOD: sqlite3_session
|
|
**
|
|
** If argument zTab is not NULL, then it is the name of a table to attach
|
|
-** to the session object passed as the first argument. All subsequent changes
|
|
-** made to the table while the session object is enabled will be recorded. See
|
|
+** to the session object passed as the first argument. All subsequent changes
|
|
+** made to the table while the session object is enabled will be recorded. See
|
|
** documentation for [sqlite3session_changeset()] for further details.
|
|
**
|
|
** Or, if argument zTab is NULL, then changes are recorded for all tables
|
|
-** in the database. If additional tables are added to the database (by
|
|
-** executing "CREATE TABLE" statements) after this call is made, changes for
|
|
+** in the database. If additional tables are added to the database (by
|
|
+** executing "CREATE TABLE" statements) after this call is made, changes for
|
|
** the new tables are also recorded.
|
|
**
|
|
** Changes can only be recorded for tables that have a PRIMARY KEY explicitly
|
|
-** defined as part of their CREATE TABLE statement. It does not matter if the
|
|
+** defined as part of their CREATE TABLE statement. It does not matter if the
|
|
** PRIMARY KEY is an "INTEGER PRIMARY KEY" (rowid alias) or not. The PRIMARY
|
|
** KEY may consist of a single column, or may be a composite key.
|
|
-**
|
|
+**
|
|
** It is not an error if the named table does not exist in the database. Nor
|
|
** is it an error if the named table does not have a PRIMARY KEY. However,
|
|
** no changes will be recorded in either of these scenarios.
|
|
@@ -10001,29 +10858,29 @@ SQLITE_API int sqlite3session_indirect(sqlite3_session *pSession, int bIndirect)
|
|
** Changes are not recorded for individual rows that have NULL values stored
|
|
** in one or more of their PRIMARY KEY columns.
|
|
**
|
|
-** SQLITE_OK is returned if the call completes without error. Or, if an error
|
|
+** SQLITE_OK is returned if the call completes without error. Or, if an error
|
|
** occurs, an SQLite error code (e.g. SQLITE_NOMEM) is returned.
|
|
**
|
|
** <h3>Special sqlite_stat1 Handling</h3>
|
|
**
|
|
-** As of SQLite version 3.22.0, the "sqlite_stat1" table is an exception to
|
|
+** As of SQLite version 3.22.0, the "sqlite_stat1" table is an exception to
|
|
** some of the rules above. In SQLite, the schema of sqlite_stat1 is:
|
|
** <pre>
|
|
-** CREATE TABLE sqlite_stat1(tbl,idx,stat)
|
|
+** CREATE TABLE sqlite_stat1(tbl,idx,stat)
|
|
** </pre>
|
|
**
|
|
-** Even though sqlite_stat1 does not have a PRIMARY KEY, changes are
|
|
-** recorded for it as if the PRIMARY KEY is (tbl,idx). Additionally, changes
|
|
+** Even though sqlite_stat1 does not have a PRIMARY KEY, changes are
|
|
+** recorded for it as if the PRIMARY KEY is (tbl,idx). Additionally, changes
|
|
** are recorded for rows for which (idx IS NULL) is true. However, for such
|
|
** rows a zero-length blob (SQL value X'') is stored in the changeset or
|
|
** patchset instead of a NULL value. This allows such changesets to be
|
|
** manipulated by legacy implementations of sqlite3changeset_invert(),
|
|
** concat() and similar.
|
|
**
|
|
-** The sqlite3changeset_apply() function automatically converts the
|
|
+** The sqlite3changeset_apply() function automatically converts the
|
|
** zero-length blob back to a NULL value when updating the sqlite_stat1
|
|
** table. However, if the application calls sqlite3changeset_new(),
|
|
-** sqlite3changeset_old() or sqlite3changeset_conflict on a changeset
|
|
+** sqlite3changeset_old() or sqlite3changeset_conflict on a changeset
|
|
** iterator directly (including on a changeset iterator passed to a
|
|
** conflict-handler callback) then the X'' value is returned. The application
|
|
** must translate X'' to NULL itself if required.
|
|
@@ -10042,10 +10899,10 @@ SQLITE_API int sqlite3session_attach(
|
|
** CAPI3REF: Set a table filter on a Session Object.
|
|
** METHOD: sqlite3_session
|
|
**
|
|
-** The second argument (xFilter) is the "filter callback". For changes to rows
|
|
+** The second argument (xFilter) is the "filter callback". For changes to rows
|
|
** in tables that are not attached to the Session object, the filter is called
|
|
-** to determine whether changes to the table's rows should be tracked or not.
|
|
-** If xFilter returns 0, changes are not tracked. Note that once a table is
|
|
+** to determine whether changes to the table's rows should be tracked or not.
|
|
+** If xFilter returns 0, changes are not tracked. Note that once a table is
|
|
** attached, xFilter will not be called again.
|
|
*/
|
|
SQLITE_API void sqlite3session_table_filter(
|
|
@@ -10061,9 +10918,9 @@ SQLITE_API void sqlite3session_table_filter(
|
|
** CAPI3REF: Generate A Changeset From A Session Object
|
|
** METHOD: sqlite3_session
|
|
**
|
|
-** Obtain a changeset containing changes to the tables attached to the
|
|
-** session object passed as the first argument. If successful,
|
|
-** set *ppChangeset to point to a buffer containing the changeset
|
|
+** Obtain a changeset containing changes to the tables attached to the
|
|
+** session object passed as the first argument. If successful,
|
|
+** set *ppChangeset to point to a buffer containing the changeset
|
|
** and *pnChangeset to the size of the changeset in bytes before returning
|
|
** SQLITE_OK. If an error occurs, set both *ppChangeset and *pnChangeset to
|
|
** zero and return an SQLite error code.
|
|
@@ -10078,7 +10935,7 @@ SQLITE_API void sqlite3session_table_filter(
|
|
** modifies the values of primary key columns. If such a change is made, it
|
|
** is represented in a changeset as a DELETE followed by an INSERT.
|
|
**
|
|
-** Changes are not recorded for rows that have NULL values stored in one or
|
|
+** Changes are not recorded for rows that have NULL values stored in one or
|
|
** more of their PRIMARY KEY columns. If such a row is inserted or deleted,
|
|
** no corresponding change is present in the changesets returned by this
|
|
** function. If an existing row with one or more NULL values stored in
|
|
@@ -10131,14 +10988,14 @@ SQLITE_API void sqlite3session_table_filter(
|
|
** <ul>
|
|
** <li> For each record generated by an insert, the database is queried
|
|
** for a row with a matching primary key. If one is found, an INSERT
|
|
-** change is added to the changeset. If no such row is found, no change
|
|
+** change is added to the changeset. If no such row is found, no change
|
|
** is added to the changeset.
|
|
**
|
|
-** <li> For each record generated by an update or delete, the database is
|
|
+** <li> For each record generated by an update or delete, the database is
|
|
** queried for a row with a matching primary key. If such a row is
|
|
** found and one or more of the non-primary key fields have been
|
|
-** modified from their original values, an UPDATE change is added to
|
|
-** the changeset. Or, if no such row is found in the table, a DELETE
|
|
+** modified from their original values, an UPDATE change is added to
|
|
+** the changeset. Or, if no such row is found in the table, a DELETE
|
|
** change is added to the changeset. If there is a row with a matching
|
|
** primary key in the database, but all fields contain their original
|
|
** values, no change is added to the changeset.
|
|
@@ -10146,7 +11003,7 @@ SQLITE_API void sqlite3session_table_filter(
|
|
**
|
|
** This means, amongst other things, that if a row is inserted and then later
|
|
** deleted while a session object is active, neither the insert nor the delete
|
|
-** will be present in the changeset. Or if a row is deleted and then later a
|
|
+** will be present in the changeset. Or if a row is deleted and then later a
|
|
** row with the same primary key values inserted while a session object is
|
|
** active, the resulting changeset will contain an UPDATE change instead of
|
|
** a DELETE and an INSERT.
|
|
@@ -10155,10 +11012,10 @@ SQLITE_API void sqlite3session_table_filter(
|
|
** it does not accumulate records when rows are inserted, updated or deleted.
|
|
** This may appear to have some counter-intuitive effects if a single row
|
|
** is written to more than once during a session. For example, if a row
|
|
-** is inserted while a session object is enabled, then later deleted while
|
|
+** is inserted while a session object is enabled, then later deleted while
|
|
** the same session object is disabled, no INSERT record will appear in the
|
|
** changeset, even though the delete took place while the session was disabled.
|
|
-** Or, if one field of a row is updated while a session is disabled, and
|
|
+** Or, if one field of a row is updated while a session is disabled, and
|
|
** another field of the same row is updated while the session is enabled, the
|
|
** resulting changeset will contain an UPDATE change that updates both fields.
|
|
*/
|
|
@@ -10168,6 +11025,22 @@ SQLITE_API int sqlite3session_changeset(
|
|
void **ppChangeset /* OUT: Buffer containing changeset */
|
|
);
|
|
|
|
+/*
|
|
+** CAPI3REF: Return An Upper-limit For The Size Of The Changeset
|
|
+** METHOD: sqlite3_session
|
|
+**
|
|
+** By default, this function always returns 0. For it to return
|
|
+** a useful result, the sqlite3_session object must have been configured
|
|
+** to enable this API using sqlite3session_object_config() with the
|
|
+** SQLITE_SESSION_OBJCONFIG_SIZE verb.
|
|
+**
|
|
+** When enabled, this function returns an upper limit, in bytes, for the size
|
|
+** of the changeset that might be produced if sqlite3session_changeset() were
|
|
+** called. The final changeset size might be equal to or smaller than the
|
|
+** size in bytes returned by this function.
|
|
+*/
|
|
+SQLITE_API sqlite3_int64 sqlite3session_changeset_size(sqlite3_session *pSession);
|
|
+
|
|
/*
|
|
** CAPI3REF: Load The Difference Between Tables Into A Session
|
|
** METHOD: sqlite3_session
|
|
@@ -10179,7 +11052,7 @@ SQLITE_API int sqlite3session_changeset(
|
|
** an error).
|
|
**
|
|
** Argument zFromDb must be the name of a database ("main", "temp" etc.)
|
|
-** attached to the same database handle as the session object that contains
|
|
+** attached to the same database handle as the session object that contains
|
|
** a table compatible with the table attached to the session by this function.
|
|
** A table is considered compatible if it:
|
|
**
|
|
@@ -10195,25 +11068,25 @@ SQLITE_API int sqlite3session_changeset(
|
|
** APIs, tables without PRIMARY KEYs are simply ignored.
|
|
**
|
|
** This function adds a set of changes to the session object that could be
|
|
-** used to update the table in database zFrom (call this the "from-table")
|
|
-** so that its content is the same as the table attached to the session
|
|
+** used to update the table in database zFrom (call this the "from-table")
|
|
+** so that its content is the same as the table attached to the session
|
|
** object (call this the "to-table"). Specifically:
|
|
**
|
|
** <ul>
|
|
-** <li> For each row (primary key) that exists in the to-table but not in
|
|
+** <li> For each row (primary key) that exists in the to-table but not in
|
|
** the from-table, an INSERT record is added to the session object.
|
|
**
|
|
-** <li> For each row (primary key) that exists in the to-table but not in
|
|
+** <li> For each row (primary key) that exists in the to-table but not in
|
|
** the from-table, a DELETE record is added to the session object.
|
|
**
|
|
-** <li> For each row (primary key) that exists in both tables, but features
|
|
+** <li> For each row (primary key) that exists in both tables, but features
|
|
** different non-PK values in each, an UPDATE record is added to the
|
|
-** session.
|
|
+** session.
|
|
** </ul>
|
|
**
|
|
** To clarify, if this function is called and then a changeset constructed
|
|
-** using [sqlite3session_changeset()], then after applying that changeset to
|
|
-** database zFrom the contents of the two compatible tables would be
|
|
+** using [sqlite3session_changeset()], then after applying that changeset to
|
|
+** database zFrom the contents of the two compatible tables would be
|
|
** identical.
|
|
**
|
|
** It an error if database zFrom does not exist or does not contain the
|
|
@@ -10221,7 +11094,7 @@ SQLITE_API int sqlite3session_changeset(
|
|
**
|
|
** If the operation is successful, SQLITE_OK is returned. Otherwise, an SQLite
|
|
** error code. In this case, if argument pzErrMsg is not NULL, *pzErrMsg
|
|
-** may be set to point to a buffer containing an English language error
|
|
+** may be set to point to a buffer containing an English language error
|
|
** message. It is the responsibility of the caller to free this buffer using
|
|
** sqlite3_free().
|
|
*/
|
|
@@ -10240,19 +11113,19 @@ SQLITE_API int sqlite3session_diff(
|
|
** The differences between a patchset and a changeset are that:
|
|
**
|
|
** <ul>
|
|
-** <li> DELETE records consist of the primary key fields only. The
|
|
+** <li> DELETE records consist of the primary key fields only. The
|
|
** original values of other fields are omitted.
|
|
-** <li> The original values of any modified fields are omitted from
|
|
+** <li> The original values of any modified fields are omitted from
|
|
** UPDATE records.
|
|
** </ul>
|
|
**
|
|
-** A patchset blob may be used with up to date versions of all
|
|
-** sqlite3changeset_xxx API functions except for sqlite3changeset_invert(),
|
|
+** A patchset blob may be used with up to date versions of all
|
|
+** sqlite3changeset_xxx API functions except for sqlite3changeset_invert(),
|
|
** which returns SQLITE_CORRUPT if it is passed a patchset. Similarly,
|
|
** attempting to use a patchset blob with old versions of the
|
|
-** sqlite3changeset_xxx APIs also provokes an SQLITE_CORRUPT error.
|
|
+** sqlite3changeset_xxx APIs also provokes an SQLITE_CORRUPT error.
|
|
**
|
|
-** Because the non-primary key "old.*" fields are omitted, no
|
|
+** Because the non-primary key "old.*" fields are omitted, no
|
|
** SQLITE_CHANGESET_DATA conflicts can be detected or reported if a patchset
|
|
** is passed to the sqlite3changeset_apply() API. Other conflict types work
|
|
** in the same way as for changesets.
|
|
@@ -10271,22 +11144,30 @@ SQLITE_API int sqlite3session_patchset(
|
|
/*
|
|
** CAPI3REF: Test if a changeset has recorded any changes.
|
|
**
|
|
-** Return non-zero if no changes to attached tables have been recorded by
|
|
-** the session object passed as the first argument. Otherwise, if one or
|
|
+** Return non-zero if no changes to attached tables have been recorded by
|
|
+** the session object passed as the first argument. Otherwise, if one or
|
|
** more changes have been recorded, return zero.
|
|
**
|
|
** Even if this function returns zero, it is possible that calling
|
|
** [sqlite3session_changeset()] on the session handle may still return a
|
|
-** changeset that contains no changes. This can happen when a row in
|
|
-** an attached table is modified and then later on the original values
|
|
+** changeset that contains no changes. This can happen when a row in
|
|
+** an attached table is modified and then later on the original values
|
|
** are restored. However, if this function returns non-zero, then it is
|
|
-** guaranteed that a call to sqlite3session_changeset() will return a
|
|
+** guaranteed that a call to sqlite3session_changeset() will return a
|
|
** changeset containing zero changes.
|
|
*/
|
|
SQLITE_API int sqlite3session_isempty(sqlite3_session *pSession);
|
|
|
|
/*
|
|
-** CAPI3REF: Create An Iterator To Traverse A Changeset
|
|
+** CAPI3REF: Query for the amount of heap memory used by a session object.
|
|
+**
|
|
+** This API returns the total amount of heap memory in bytes currently
|
|
+** used by the session object passed as the only argument.
|
|
+*/
|
|
+SQLITE_API sqlite3_int64 sqlite3session_memory_used(sqlite3_session *pSession);
|
|
+
|
|
+/*
|
|
+** CAPI3REF: Create An Iterator To Traverse A Changeset
|
|
** CONSTRUCTOR: sqlite3_changeset_iter
|
|
**
|
|
** Create an iterator used to iterate through the contents of a changeset.
|
|
@@ -10294,7 +11175,7 @@ SQLITE_API int sqlite3session_isempty(sqlite3_session *pSession);
|
|
** is returned. Otherwise, if an error occurs, *pp is set to zero and an
|
|
** SQLite error code is returned.
|
|
**
|
|
-** The following functions can be used to advance and query a changeset
|
|
+** The following functions can be used to advance and query a changeset
|
|
** iterator created by this function:
|
|
**
|
|
** <ul>
|
|
@@ -10311,12 +11192,12 @@ SQLITE_API int sqlite3session_isempty(sqlite3_session *pSession);
|
|
**
|
|
** Assuming the changeset blob was created by one of the
|
|
** [sqlite3session_changeset()], [sqlite3changeset_concat()] or
|
|
-** [sqlite3changeset_invert()] functions, all changes within the changeset
|
|
-** that apply to a single table are grouped together. This means that when
|
|
-** an application iterates through a changeset using an iterator created by
|
|
-** this function, all changes that relate to a single table are visited
|
|
-** consecutively. There is no chance that the iterator will visit a change
|
|
-** the applies to table X, then one for table Y, and then later on visit
|
|
+** [sqlite3changeset_invert()] functions, all changes within the changeset
|
|
+** that apply to a single table are grouped together. This means that when
|
|
+** an application iterates through a changeset using an iterator created by
|
|
+** this function, all changes that relate to a single table are visited
|
|
+** consecutively. There is no chance that the iterator will visit a change
|
|
+** the applies to table X, then one for table Y, and then later on visit
|
|
** another change for table X.
|
|
**
|
|
** The behavior of sqlite3changeset_start_v2() and its streaming equivalent
|
|
@@ -10367,12 +11248,12 @@ SQLITE_API int sqlite3changeset_start_v2(
|
|
** point to the first change in the changeset. Each subsequent call advances
|
|
** the iterator to point to the next change in the changeset (if any). If
|
|
** no error occurs and the iterator points to a valid change after a call
|
|
-** to sqlite3changeset_next() has advanced it, SQLITE_ROW is returned.
|
|
+** to sqlite3changeset_next() has advanced it, SQLITE_ROW is returned.
|
|
** Otherwise, if all changes in the changeset have already been visited,
|
|
** SQLITE_DONE is returned.
|
|
**
|
|
-** If an error occurs, an SQLite error code is returned. Possible error
|
|
-** codes include SQLITE_CORRUPT (if the changeset buffer is corrupt) or
|
|
+** If an error occurs, an SQLite error code is returned. Possible error
|
|
+** codes include SQLITE_CORRUPT (if the changeset buffer is corrupt) or
|
|
** SQLITE_NOMEM.
|
|
*/
|
|
SQLITE_API int sqlite3changeset_next(sqlite3_changeset_iter *pIter);
|
|
@@ -10387,18 +11268,23 @@ SQLITE_API int sqlite3changeset_next(sqlite3_changeset_iter *pIter);
|
|
** call to [sqlite3changeset_next()] must have returned [SQLITE_ROW]. If this
|
|
** is not the case, this function returns [SQLITE_MISUSE].
|
|
**
|
|
-** If argument pzTab is not NULL, then *pzTab is set to point to a
|
|
-** nul-terminated utf-8 encoded string containing the name of the table
|
|
-** affected by the current change. The buffer remains valid until either
|
|
-** sqlite3changeset_next() is called on the iterator or until the
|
|
-** conflict-handler function returns. If pnCol is not NULL, then *pnCol is
|
|
-** set to the number of columns in the table affected by the change. If
|
|
-** pbIndirect is not NULL, then *pbIndirect is set to true (1) if the change
|
|
+** Arguments pOp, pnCol and pzTab may not be NULL. Upon return, three
|
|
+** outputs are set through these pointers:
|
|
+**
|
|
+** *pOp is set to one of [SQLITE_INSERT], [SQLITE_DELETE] or [SQLITE_UPDATE],
|
|
+** depending on the type of change that the iterator currently points to;
|
|
+**
|
|
+** *pnCol is set to the number of columns in the table affected by the change; and
|
|
+**
|
|
+** *pzTab is set to point to a nul-terminated utf-8 encoded string containing
|
|
+** the name of the table affected by the current change. The buffer remains
|
|
+** valid until either sqlite3changeset_next() is called on the iterator
|
|
+** or until the conflict-handler function returns.
|
|
+**
|
|
+** If pbIndirect is not NULL, then *pbIndirect is set to true (1) if the change
|
|
** is an indirect change, or false (0) otherwise. See the documentation for
|
|
** [sqlite3session_indirect()] for a description of direct and indirect
|
|
-** changes. Finally, if pOp is not NULL, then *pOp is set to one of
|
|
-** [SQLITE_INSERT], [SQLITE_DELETE] or [SQLITE_UPDATE], depending on the
|
|
-** type of change that the iterator currently points to.
|
|
+** changes.
|
|
**
|
|
** If no error occurs, SQLITE_OK is returned. If an error does occur, an
|
|
** SQLite error code is returned. The values of the output variables may not
|
|
@@ -10451,7 +11337,7 @@ SQLITE_API int sqlite3changeset_pk(
|
|
** The pIter argument passed to this function may either be an iterator
|
|
** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator
|
|
** created by [sqlite3changeset_start()]. In the latter case, the most recent
|
|
-** call to [sqlite3changeset_next()] must have returned SQLITE_ROW.
|
|
+** call to [sqlite3changeset_next()] must have returned SQLITE_ROW.
|
|
** Furthermore, it may only be called if the type of change that the iterator
|
|
** currently points to is either [SQLITE_DELETE] or [SQLITE_UPDATE]. Otherwise,
|
|
** this function returns [SQLITE_MISUSE] and sets *ppValue to NULL.
|
|
@@ -10461,9 +11347,9 @@ SQLITE_API int sqlite3changeset_pk(
|
|
** [SQLITE_RANGE] is returned and *ppValue is set to NULL.
|
|
**
|
|
** If successful, this function sets *ppValue to point to a protected
|
|
-** sqlite3_value object containing the iVal'th value from the vector of
|
|
+** sqlite3_value object containing the iVal'th value from the vector of
|
|
** original row values stored as part of the UPDATE or DELETE change and
|
|
-** returns SQLITE_OK. The name of the function comes from the fact that this
|
|
+** returns SQLITE_OK. The name of the function comes from the fact that this
|
|
** is similar to the "old.*" columns available to update or delete triggers.
|
|
**
|
|
** If some other error occurs (e.g. an OOM condition), an SQLite error code
|
|
@@ -10482,7 +11368,7 @@ SQLITE_API int sqlite3changeset_old(
|
|
** The pIter argument passed to this function may either be an iterator
|
|
** passed to a conflict-handler by [sqlite3changeset_apply()], or an iterator
|
|
** created by [sqlite3changeset_start()]. In the latter case, the most recent
|
|
-** call to [sqlite3changeset_next()] must have returned SQLITE_ROW.
|
|
+** call to [sqlite3changeset_next()] must have returned SQLITE_ROW.
|
|
** Furthermore, it may only be called if the type of change that the iterator
|
|
** currently points to is either [SQLITE_UPDATE] or [SQLITE_INSERT]. Otherwise,
|
|
** this function returns [SQLITE_MISUSE] and sets *ppValue to NULL.
|
|
@@ -10492,12 +11378,12 @@ SQLITE_API int sqlite3changeset_old(
|
|
** [SQLITE_RANGE] is returned and *ppValue is set to NULL.
|
|
**
|
|
** If successful, this function sets *ppValue to point to a protected
|
|
-** sqlite3_value object containing the iVal'th value from the vector of
|
|
+** sqlite3_value object containing the iVal'th value from the vector of
|
|
** new row values stored as part of the UPDATE or INSERT change and
|
|
** returns SQLITE_OK. If the change is an UPDATE and does not include
|
|
-** a new value for the requested column, *ppValue is set to NULL and
|
|
-** SQLITE_OK returned. The name of the function comes from the fact that
|
|
-** this is similar to the "new.*" columns available to update or delete
|
|
+** a new value for the requested column, *ppValue is set to NULL and
|
|
+** SQLITE_OK returned. The name of the function comes from the fact that
|
|
+** this is similar to the "new.*" columns available to update or delete
|
|
** triggers.
|
|
**
|
|
** If some other error occurs (e.g. an OOM condition), an SQLite error code
|
|
@@ -10524,7 +11410,7 @@ SQLITE_API int sqlite3changeset_new(
|
|
** [SQLITE_RANGE] is returned and *ppValue is set to NULL.
|
|
**
|
|
** If successful, this function sets *ppValue to point to a protected
|
|
-** sqlite3_value object containing the iVal'th value from the
|
|
+** sqlite3_value object containing the iVal'th value from the
|
|
** "conflicting row" associated with the current conflict-handler callback
|
|
** and returns SQLITE_OK.
|
|
**
|
|
@@ -10568,7 +11454,7 @@ SQLITE_API int sqlite3changeset_fk_conflicts(
|
|
** call has no effect.
|
|
**
|
|
** If an error was encountered within a call to an sqlite3changeset_xxx()
|
|
-** function (for example an [SQLITE_CORRUPT] in [sqlite3changeset_next()] or an
|
|
+** function (for example an [SQLITE_CORRUPT] in [sqlite3changeset_next()] or an
|
|
** [SQLITE_NOMEM] in [sqlite3changeset_new()]) then an error code corresponding
|
|
** to that error is returned by this function. Otherwise, SQLITE_OK is
|
|
** returned. This is to allow the following pattern (pseudo-code):
|
|
@@ -10580,7 +11466,7 @@ SQLITE_API int sqlite3changeset_fk_conflicts(
|
|
** }
|
|
** rc = sqlite3changeset_finalize();
|
|
** if( rc!=SQLITE_OK ){
|
|
-** // An error has occurred
|
|
+** // An error has occurred
|
|
** }
|
|
** </pre>
|
|
*/
|
|
@@ -10608,7 +11494,7 @@ SQLITE_API int sqlite3changeset_finalize(sqlite3_changeset_iter *pIter);
|
|
** zeroed and an SQLite error code returned.
|
|
**
|
|
** It is the responsibility of the caller to eventually call sqlite3_free()
|
|
-** on the *ppOut pointer to free the buffer allocation following a successful
|
|
+** on the *ppOut pointer to free the buffer allocation following a successful
|
|
** call to this function.
|
|
**
|
|
** WARNING/TODO: This function currently assumes that the input is a valid
|
|
@@ -10622,11 +11508,11 @@ SQLITE_API int sqlite3changeset_invert(
|
|
/*
|
|
** CAPI3REF: Concatenate Two Changeset Objects
|
|
**
|
|
-** This function is used to concatenate two changesets, A and B, into a
|
|
+** This function is used to concatenate two changesets, A and B, into a
|
|
** single changeset. The result is a changeset equivalent to applying
|
|
-** changeset A followed by changeset B.
|
|
+** changeset A followed by changeset B.
|
|
**
|
|
-** This function combines the two input changesets using an
|
|
+** This function combines the two input changesets using an
|
|
** sqlite3_changegroup object. Calling it produces similar results as the
|
|
** following code fragment:
|
|
**
|
|
@@ -10658,7 +11544,7 @@ SQLITE_API int sqlite3changeset_concat(
|
|
/*
|
|
** CAPI3REF: Changegroup Handle
|
|
**
|
|
-** A changegroup is an object used to combine two or more
|
|
+** A changegroup is an object used to combine two or more
|
|
** [changesets] or [patchsets]
|
|
*/
|
|
typedef struct sqlite3_changegroup sqlite3_changegroup;
|
|
@@ -10674,7 +11560,7 @@ typedef struct sqlite3_changegroup sqlite3_changegroup;
|
|
**
|
|
** If successful, this function returns SQLITE_OK and populates (*pp) with
|
|
** a pointer to a new sqlite3_changegroup object before returning. The caller
|
|
-** should eventually free the returned object using a call to
|
|
+** should eventually free the returned object using a call to
|
|
** sqlite3changegroup_delete(). If an error occurs, an SQLite error code
|
|
** (i.e. SQLITE_NOMEM) is returned and *pp is set to NULL.
|
|
**
|
|
@@ -10686,7 +11572,7 @@ typedef struct sqlite3_changegroup sqlite3_changegroup;
|
|
** <li> Zero or more changesets (or patchsets) are added to the object
|
|
** by calling sqlite3changegroup_add().
|
|
**
|
|
-** <li> The result of combining all input changesets together is obtained
|
|
+** <li> The result of combining all input changesets together is obtained
|
|
** by the application via a call to sqlite3changegroup_output().
|
|
**
|
|
** <li> The object is deleted using a call to sqlite3changegroup_delete().
|
|
@@ -10695,7 +11581,7 @@ typedef struct sqlite3_changegroup sqlite3_changegroup;
|
|
** Any number of calls to add() and output() may be made between the calls to
|
|
** new() and delete(), and in any order.
|
|
**
|
|
-** As well as the regular sqlite3changegroup_add() and
|
|
+** As well as the regular sqlite3changegroup_add() and
|
|
** sqlite3changegroup_output() functions, also available are the streaming
|
|
** versions sqlite3changegroup_add_strm() and sqlite3changegroup_output_strm().
|
|
*/
|
|
@@ -10706,7 +11592,7 @@ SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp);
|
|
** METHOD: sqlite3_changegroup
|
|
**
|
|
** Add all changes within the changeset (or patchset) in buffer pData (size
|
|
-** nData bytes) to the changegroup.
|
|
+** nData bytes) to the changegroup.
|
|
**
|
|
** If the buffer contains a patchset, then all prior calls to this function
|
|
** on the same changegroup object must also have specified patchsets. Or, if
|
|
@@ -10733,7 +11619,7 @@ SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp);
|
|
** changeset was recorded immediately after the changesets already
|
|
** added to the changegroup.
|
|
** <tr><td>INSERT <td>UPDATE <td>
|
|
-** The INSERT change remains in the changegroup. The values in the
|
|
+** The INSERT change remains in the changegroup. The values in the
|
|
** INSERT change are modified as if the row was inserted by the
|
|
** existing change and then updated according to the new change.
|
|
** <tr><td>INSERT <td>DELETE <td>
|
|
@@ -10744,17 +11630,17 @@ SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp);
|
|
** changeset was recorded immediately after the changesets already
|
|
** added to the changegroup.
|
|
** <tr><td>UPDATE <td>UPDATE <td>
|
|
-** The existing UPDATE remains within the changegroup. It is amended
|
|
-** so that the accompanying values are as if the row was updated once
|
|
+** The existing UPDATE remains within the changegroup. It is amended
|
|
+** so that the accompanying values are as if the row was updated once
|
|
** by the existing change and then again by the new change.
|
|
** <tr><td>UPDATE <td>DELETE <td>
|
|
** The existing UPDATE is replaced by the new DELETE within the
|
|
** changegroup.
|
|
** <tr><td>DELETE <td>INSERT <td>
|
|
** If one or more of the column values in the row inserted by the
|
|
-** new change differ from those in the row deleted by the existing
|
|
+** new change differ from those in the row deleted by the existing
|
|
** change, the existing DELETE is replaced by an UPDATE within the
|
|
-** changegroup. Otherwise, if the inserted row is exactly the same
|
|
+** changegroup. Otherwise, if the inserted row is exactly the same
|
|
** as the deleted row, the existing DELETE is simply discarded.
|
|
** <tr><td>DELETE <td>UPDATE <td>
|
|
** The new change is ignored. This case does not occur if the new
|
|
@@ -10799,7 +11685,7 @@ SQLITE_API int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pDa
|
|
**
|
|
** If an error occurs, an SQLite error code is returned and the output
|
|
** variables (*pnData) and (*ppData) are set to 0. Otherwise, SQLITE_OK
|
|
-** is returned and the output variables are set to the size of and a
|
|
+** is returned and the output variables are set to the size of and a
|
|
** pointer to the output buffer, respectively. In this case it is the
|
|
** responsibility of the caller to eventually free the buffer using a
|
|
** call to sqlite3_free().
|
|
@@ -10821,7 +11707,7 @@ SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup*);
|
|
**
|
|
** Apply a changeset or patchset to a database. These functions attempt to
|
|
** update the "main" database attached to handle db with the changes found in
|
|
-** the changeset passed via the second and third arguments.
|
|
+** the changeset passed via the second and third arguments.
|
|
**
|
|
** The fourth argument (xFilter) passed to these functions is the "filter
|
|
** callback". If it is not NULL, then for each table affected by at least one
|
|
@@ -10832,16 +11718,16 @@ SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup*);
|
|
** Otherwise, if the return value is non-zero or the xFilter argument to
|
|
** is NULL, all changes related to the table are attempted.
|
|
**
|
|
-** For each table that is not excluded by the filter callback, this function
|
|
-** tests that the target database contains a compatible table. A table is
|
|
+** For each table that is not excluded by the filter callback, this function
|
|
+** tests that the target database contains a compatible table. A table is
|
|
** considered compatible if all of the following are true:
|
|
**
|
|
** <ul>
|
|
-** <li> The table has the same name as the name recorded in the
|
|
+** <li> The table has the same name as the name recorded in the
|
|
** changeset, and
|
|
-** <li> The table has at least as many columns as recorded in the
|
|
+** <li> The table has at least as many columns as recorded in the
|
|
** changeset, and
|
|
-** <li> The table has primary key columns in the same position as
|
|
+** <li> The table has primary key columns in the same position as
|
|
** recorded in the changeset.
|
|
** </ul>
|
|
**
|
|
@@ -10850,11 +11736,11 @@ SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup*);
|
|
** via the sqlite3_log() mechanism with the error code SQLITE_SCHEMA. At most
|
|
** one such warning is issued for each table in the changeset.
|
|
**
|
|
-** For each change for which there is a compatible table, an attempt is made
|
|
-** to modify the table contents according to the UPDATE, INSERT or DELETE
|
|
-** change. If a change cannot be applied cleanly, the conflict handler
|
|
-** function passed as the fifth argument to sqlite3changeset_apply() may be
|
|
-** invoked. A description of exactly when the conflict handler is invoked for
|
|
+** For each change for which there is a compatible table, an attempt is made
|
|
+** to modify the table contents according to the UPDATE, INSERT or DELETE
|
|
+** change. If a change cannot be applied cleanly, the conflict handler
|
|
+** function passed as the fifth argument to sqlite3changeset_apply() may be
|
|
+** invoked. A description of exactly when the conflict handler is invoked for
|
|
** each type of change is below.
|
|
**
|
|
** Unlike the xFilter argument, xConflict may not be passed NULL. The results
|
|
@@ -10862,23 +11748,23 @@ SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup*);
|
|
** argument are undefined.
|
|
**
|
|
** Each time the conflict handler function is invoked, it must return one
|
|
-** of [SQLITE_CHANGESET_OMIT], [SQLITE_CHANGESET_ABORT] or
|
|
+** of [SQLITE_CHANGESET_OMIT], [SQLITE_CHANGESET_ABORT] or
|
|
** [SQLITE_CHANGESET_REPLACE]. SQLITE_CHANGESET_REPLACE may only be returned
|
|
** if the second argument passed to the conflict handler is either
|
|
** SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT. If the conflict-handler
|
|
** returns an illegal value, any changes already made are rolled back and
|
|
-** the call to sqlite3changeset_apply() returns SQLITE_MISUSE. Different
|
|
+** the call to sqlite3changeset_apply() returns SQLITE_MISUSE. Different
|
|
** actions are taken by sqlite3changeset_apply() depending on the value
|
|
** returned by each invocation of the conflict-handler function. Refer to
|
|
-** the documentation for the three
|
|
+** the documentation for the three
|
|
** [SQLITE_CHANGESET_OMIT|available return values] for details.
|
|
**
|
|
** <dl>
|
|
** <dt>DELETE Changes<dd>
|
|
-** For each DELETE change, the function checks if the target database
|
|
-** contains a row with the same primary key value (or values) as the
|
|
-** original row values stored in the changeset. If it does, and the values
|
|
-** stored in all non-primary key columns also match the values stored in
|
|
+** For each DELETE change, the function checks if the target database
|
|
+** contains a row with the same primary key value (or values) as the
|
|
+** original row values stored in the changeset. If it does, and the values
|
|
+** stored in all non-primary key columns also match the values stored in
|
|
** the changeset the row is deleted from the target database.
|
|
**
|
|
** If a row with matching primary key values is found, but one or more of
|
|
@@ -10907,22 +11793,22 @@ SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup*);
|
|
** database table, the trailing fields are populated with their default
|
|
** values.
|
|
**
|
|
-** If the attempt to insert the row fails because the database already
|
|
+** If the attempt to insert the row fails because the database already
|
|
** contains a row with the same primary key values, the conflict handler
|
|
-** function is invoked with the second argument set to
|
|
+** function is invoked with the second argument set to
|
|
** [SQLITE_CHANGESET_CONFLICT].
|
|
**
|
|
** If the attempt to insert the row fails because of some other constraint
|
|
-** violation (e.g. NOT NULL or UNIQUE), the conflict handler function is
|
|
+** violation (e.g. NOT NULL or UNIQUE), the conflict handler function is
|
|
** invoked with the second argument set to [SQLITE_CHANGESET_CONSTRAINT].
|
|
-** This includes the case where the INSERT operation is re-attempted because
|
|
-** an earlier call to the conflict handler function returned
|
|
+** This includes the case where the INSERT operation is re-attempted because
|
|
+** an earlier call to the conflict handler function returned
|
|
** [SQLITE_CHANGESET_REPLACE].
|
|
**
|
|
** <dt>UPDATE Changes<dd>
|
|
-** For each UPDATE change, the function checks if the target database
|
|
-** contains a row with the same primary key value (or values) as the
|
|
-** original row values stored in the changeset. If it does, and the values
|
|
+** For each UPDATE change, the function checks if the target database
|
|
+** contains a row with the same primary key value (or values) as the
|
|
+** original row values stored in the changeset. If it does, and the values
|
|
** stored in all modified non-primary key columns also match the values
|
|
** stored in the changeset the row is updated within the target database.
|
|
**
|
|
@@ -10938,12 +11824,12 @@ SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup*);
|
|
** the conflict-handler function is invoked with [SQLITE_CHANGESET_NOTFOUND]
|
|
** passed as the second argument.
|
|
**
|
|
-** If the UPDATE operation is attempted, but SQLite returns
|
|
-** SQLITE_CONSTRAINT, the conflict-handler function is invoked with
|
|
+** If the UPDATE operation is attempted, but SQLite returns
|
|
+** SQLITE_CONSTRAINT, the conflict-handler function is invoked with
|
|
** [SQLITE_CHANGESET_CONSTRAINT] passed as the second argument.
|
|
-** This includes the case where the UPDATE operation is attempted after
|
|
+** This includes the case where the UPDATE operation is attempted after
|
|
** an earlier call to the conflict handler function returned
|
|
-** [SQLITE_CHANGESET_REPLACE].
|
|
+** [SQLITE_CHANGESET_REPLACE].
|
|
** </dl>
|
|
**
|
|
** It is safe to execute SQL statements, including those that write to the
|
|
@@ -10954,12 +11840,12 @@ SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup*);
|
|
** All changes made by these functions are enclosed in a savepoint transaction.
|
|
** If any other error (aside from a constraint failure when attempting to
|
|
** write to the target database) occurs, then the savepoint transaction is
|
|
-** rolled back, restoring the target database to its original state, and an
|
|
+** rolled back, restoring the target database to its original state, and an
|
|
** SQLite error code returned.
|
|
**
|
|
** If the output parameters (ppRebase) and (pnRebase) are non-NULL and
|
|
** the input is a changeset (not a patchset), then sqlite3changeset_apply_v2()
|
|
-** may set (*ppRebase) to point to a "rebase" that may be used with the
|
|
+** may set (*ppRebase) to point to a "rebase" that may be used with the
|
|
** sqlite3_rebaser APIs buffer before returning. In this case (*pnRebase)
|
|
** is set to the size of the buffer in bytes. It is the responsibility of the
|
|
** caller to eventually free any such buffer using sqlite3_free(). The buffer
|
|
@@ -11020,7 +11906,7 @@ SQLITE_API int sqlite3changeset_apply_v2(
|
|
** SAVEPOINT is committed if the changeset or patchset is successfully
|
|
** applied, or rolled back if an error occurs. Specifying this flag
|
|
** causes the sessions module to omit this savepoint. In this case, if the
|
|
-** caller has an open transaction or savepoint when apply_v2() is called,
|
|
+** caller has an open transaction or savepoint when apply_v2() is called,
|
|
** it may revert the partially applied changeset by rolling it back.
|
|
**
|
|
** <dt>SQLITE_CHANGESETAPPLY_INVERT <dd>
|
|
@@ -11031,7 +11917,7 @@ SQLITE_API int sqlite3changeset_apply_v2(
|
|
#define SQLITE_CHANGESETAPPLY_NOSAVEPOINT 0x0001
|
|
#define SQLITE_CHANGESETAPPLY_INVERT 0x0002
|
|
|
|
-/*
|
|
+/*
|
|
** CAPI3REF: Constants Passed To The Conflict Handler
|
|
**
|
|
** Values that may be passed as the second argument to a conflict-handler.
|
|
@@ -11040,32 +11926,32 @@ SQLITE_API int sqlite3changeset_apply_v2(
|
|
** <dt>SQLITE_CHANGESET_DATA<dd>
|
|
** The conflict handler is invoked with CHANGESET_DATA as the second argument
|
|
** when processing a DELETE or UPDATE change if a row with the required
|
|
-** PRIMARY KEY fields is present in the database, but one or more other
|
|
-** (non primary-key) fields modified by the update do not contain the
|
|
+** PRIMARY KEY fields is present in the database, but one or more other
|
|
+** (non primary-key) fields modified by the update do not contain the
|
|
** expected "before" values.
|
|
-**
|
|
+**
|
|
** The conflicting row, in this case, is the database row with the matching
|
|
** primary key.
|
|
-**
|
|
+**
|
|
** <dt>SQLITE_CHANGESET_NOTFOUND<dd>
|
|
** The conflict handler is invoked with CHANGESET_NOTFOUND as the second
|
|
** argument when processing a DELETE or UPDATE change if a row with the
|
|
** required PRIMARY KEY fields is not present in the database.
|
|
-**
|
|
+**
|
|
** There is no conflicting row in this case. The results of invoking the
|
|
** sqlite3changeset_conflict() API are undefined.
|
|
-**
|
|
+**
|
|
** <dt>SQLITE_CHANGESET_CONFLICT<dd>
|
|
** CHANGESET_CONFLICT is passed as the second argument to the conflict
|
|
-** handler while processing an INSERT change if the operation would result
|
|
+** handler while processing an INSERT change if the operation would result
|
|
** in duplicate primary key values.
|
|
-**
|
|
+**
|
|
** The conflicting row in this case is the database row with the matching
|
|
** primary key.
|
|
**
|
|
** <dt>SQLITE_CHANGESET_FOREIGN_KEY<dd>
|
|
** If foreign key handling is enabled, and applying a changeset leaves the
|
|
-** database in a state containing foreign key violations, the conflict
|
|
+** database in a state containing foreign key violations, the conflict
|
|
** handler is invoked with CHANGESET_FOREIGN_KEY as the second argument
|
|
** exactly once before the changeset is committed. If the conflict handler
|
|
** returns CHANGESET_OMIT, the changes, including those that caused the
|
|
@@ -11075,12 +11961,12 @@ SQLITE_API int sqlite3changeset_apply_v2(
|
|
** No current or conflicting row information is provided. The only function
|
|
** it is possible to call on the supplied sqlite3_changeset_iter handle
|
|
** is sqlite3changeset_fk_conflicts().
|
|
-**
|
|
+**
|
|
** <dt>SQLITE_CHANGESET_CONSTRAINT<dd>
|
|
-** If any other constraint violation occurs while applying a change (i.e.
|
|
-** a UNIQUE, CHECK or NOT NULL constraint), the conflict handler is
|
|
+** If any other constraint violation occurs while applying a change (i.e.
|
|
+** a UNIQUE, CHECK or NOT NULL constraint), the conflict handler is
|
|
** invoked with CHANGESET_CONSTRAINT as the second argument.
|
|
-**
|
|
+**
|
|
** There is no conflicting row in this case. The results of invoking the
|
|
** sqlite3changeset_conflict() API are undefined.
|
|
**
|
|
@@ -11092,7 +11978,7 @@ SQLITE_API int sqlite3changeset_apply_v2(
|
|
#define SQLITE_CHANGESET_CONSTRAINT 4
|
|
#define SQLITE_CHANGESET_FOREIGN_KEY 5
|
|
|
|
-/*
|
|
+/*
|
|
** CAPI3REF: Constants Returned By The Conflict Handler
|
|
**
|
|
** A conflict handler callback must return one of the following three values.
|
|
@@ -11100,13 +11986,13 @@ SQLITE_API int sqlite3changeset_apply_v2(
|
|
** <dl>
|
|
** <dt>SQLITE_CHANGESET_OMIT<dd>
|
|
** If a conflict handler returns this value no special action is taken. The
|
|
-** change that caused the conflict is not applied. The session module
|
|
+** change that caused the conflict is not applied. The session module
|
|
** continues to the next change in the changeset.
|
|
**
|
|
** <dt>SQLITE_CHANGESET_REPLACE<dd>
|
|
** This value may only be returned if the second argument to the conflict
|
|
** handler was SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT. If this
|
|
-** is not the case, any changes applied so far are rolled back and the
|
|
+** is not the case, any changes applied so far are rolled back and the
|
|
** call to sqlite3changeset_apply() returns SQLITE_MISUSE.
|
|
**
|
|
** If CHANGESET_REPLACE is returned by an SQLITE_CHANGESET_DATA conflict
|
|
@@ -11119,7 +12005,7 @@ SQLITE_API int sqlite3changeset_apply_v2(
|
|
** the original row is restored to the database before continuing.
|
|
**
|
|
** <dt>SQLITE_CHANGESET_ABORT<dd>
|
|
-** If this value is returned, any changes applied so far are rolled back
|
|
+** If this value is returned, any changes applied so far are rolled back
|
|
** and the call to sqlite3changeset_apply() returns SQLITE_ABORT.
|
|
** </dl>
|
|
*/
|
|
@@ -11127,20 +12013,20 @@ SQLITE_API int sqlite3changeset_apply_v2(
|
|
#define SQLITE_CHANGESET_REPLACE 1
|
|
#define SQLITE_CHANGESET_ABORT 2
|
|
|
|
-/*
|
|
+/*
|
|
** CAPI3REF: Rebasing changesets
|
|
** EXPERIMENTAL
|
|
**
|
|
** Suppose there is a site hosting a database in state S0. And that
|
|
** modifications are made that move that database to state S1 and a
|
|
** changeset recorded (the "local" changeset). Then, a changeset based
|
|
-** on S0 is received from another site (the "remote" changeset) and
|
|
-** applied to the database. The database is then in state
|
|
+** on S0 is received from another site (the "remote" changeset) and
|
|
+** applied to the database. The database is then in state
|
|
** (S1+"remote"), where the exact state depends on any conflict
|
|
** resolution decisions (OMIT or REPLACE) made while applying "remote".
|
|
-** Rebasing a changeset is to update it to take those conflict
|
|
+** Rebasing a changeset is to update it to take those conflict
|
|
** resolution decisions into account, so that the same conflicts
|
|
-** do not have to be resolved elsewhere in the network.
|
|
+** do not have to be resolved elsewhere in the network.
|
|
**
|
|
** For example, if both the local and remote changesets contain an
|
|
** INSERT of the same key on "CREATE TABLE t1(a PRIMARY KEY, b)":
|
|
@@ -11159,7 +12045,7 @@ SQLITE_API int sqlite3changeset_apply_v2(
|
|
**
|
|
** <dl>
|
|
** <dt>Local INSERT<dd>
|
|
-** This may only conflict with a remote INSERT. If the conflict
|
|
+** This may only conflict with a remote INSERT. If the conflict
|
|
** resolution was OMIT, then add an UPDATE change to the rebased
|
|
** changeset. Or, if the conflict resolution was REPLACE, add
|
|
** nothing to the rebased changeset.
|
|
@@ -11183,12 +12069,12 @@ SQLITE_API int sqlite3changeset_apply_v2(
|
|
** the old.* values are rebased using the new.* values in the remote
|
|
** change. Or, if the resolution is REPLACE, then the change is copied
|
|
** into the rebased changeset with updates to columns also updated by
|
|
-** the conflicting remote UPDATE removed. If this means no columns would
|
|
+** the conflicting remote UPDATE removed. If this means no columns would
|
|
** be updated, the change is omitted.
|
|
** </dl>
|
|
**
|
|
-** A local change may be rebased against multiple remote changes
|
|
-** simultaneously. If a single key is modified by multiple remote
|
|
+** A local change may be rebased against multiple remote changes
|
|
+** simultaneously. If a single key is modified by multiple remote
|
|
** changesets, they are combined as follows before the local changeset
|
|
** is rebased:
|
|
**
|
|
@@ -11201,10 +12087,10 @@ SQLITE_API int sqlite3changeset_apply_v2(
|
|
** of the OMIT resolutions.
|
|
** </ul>
|
|
**
|
|
-** Note that conflict resolutions from multiple remote changesets are
|
|
-** combined on a per-field basis, not per-row. This means that in the
|
|
-** case of multiple remote UPDATE operations, some fields of a single
|
|
-** local change may be rebased for REPLACE while others are rebased for
|
|
+** Note that conflict resolutions from multiple remote changesets are
|
|
+** combined on a per-field basis, not per-row. This means that in the
|
|
+** case of multiple remote UPDATE operations, some fields of a single
|
|
+** local change may be rebased for REPLACE while others are rebased for
|
|
** OMIT.
|
|
**
|
|
** In order to rebase a local changeset, the remote changeset must first
|
|
@@ -11212,7 +12098,7 @@ SQLITE_API int sqlite3changeset_apply_v2(
|
|
** the buffer of rebase information captured. Then:
|
|
**
|
|
** <ol>
|
|
-** <li> An sqlite3_rebaser object is created by calling
|
|
+** <li> An sqlite3_rebaser object is created by calling
|
|
** sqlite3rebaser_create().
|
|
** <li> The new object is configured with the rebase buffer obtained from
|
|
** sqlite3changeset_apply_v2() by calling sqlite3rebaser_configure().
|
|
@@ -11233,8 +12119,8 @@ typedef struct sqlite3_rebaser sqlite3_rebaser;
|
|
**
|
|
** Allocate a new changeset rebaser object. If successful, set (*ppNew) to
|
|
** point to the new object and return SQLITE_OK. Otherwise, if an error
|
|
-** occurs, return an SQLite error code (e.g. SQLITE_NOMEM) and set (*ppNew)
|
|
-** to NULL.
|
|
+** occurs, return an SQLite error code (e.g. SQLITE_NOMEM) and set (*ppNew)
|
|
+** to NULL.
|
|
*/
|
|
SQLITE_API int sqlite3rebaser_create(sqlite3_rebaser **ppNew);
|
|
|
|
@@ -11248,9 +12134,9 @@ SQLITE_API int sqlite3rebaser_create(sqlite3_rebaser **ppNew);
|
|
** sqlite3changeset_apply_v2().
|
|
*/
|
|
SQLITE_API int sqlite3rebaser_configure(
|
|
- sqlite3_rebaser*,
|
|
+ sqlite3_rebaser*,
|
|
int nRebase, const void *pRebase
|
|
-);
|
|
+);
|
|
|
|
/*
|
|
** CAPI3REF: Rebase a changeset
|
|
@@ -11260,7 +12146,7 @@ SQLITE_API int sqlite3rebaser_configure(
|
|
** in size. This function allocates and populates a buffer with a copy
|
|
** of the changeset rebased according to the configuration of the
|
|
** rebaser object passed as the first argument. If successful, (*ppOut)
|
|
-** is set to point to the new buffer containing the rebased changeset and
|
|
+** is set to point to the new buffer containing the rebased changeset and
|
|
** (*pnOut) to its size in bytes and SQLITE_OK returned. It is the
|
|
** responsibility of the caller to eventually free the new buffer using
|
|
** sqlite3_free(). Otherwise, if an error occurs, (*ppOut) and (*pnOut)
|
|
@@ -11268,8 +12154,8 @@ SQLITE_API int sqlite3rebaser_configure(
|
|
*/
|
|
SQLITE_API int sqlite3rebaser_rebase(
|
|
sqlite3_rebaser*,
|
|
- int nIn, const void *pIn,
|
|
- int *pnOut, void **ppOut
|
|
+ int nIn, const void *pIn,
|
|
+ int *pnOut, void **ppOut
|
|
);
|
|
|
|
/*
|
|
@@ -11280,30 +12166,30 @@ SQLITE_API int sqlite3rebaser_rebase(
|
|
** should be one call to this function for each successful invocation
|
|
** of sqlite3rebaser_create().
|
|
*/
|
|
-SQLITE_API void sqlite3rebaser_delete(sqlite3_rebaser *p);
|
|
+SQLITE_API void sqlite3rebaser_delete(sqlite3_rebaser *p);
|
|
|
|
/*
|
|
** CAPI3REF: Streaming Versions of API functions.
|
|
**
|
|
-** The six streaming API xxx_strm() functions serve similar purposes to the
|
|
+** The six streaming API xxx_strm() functions serve similar purposes to the
|
|
** corresponding non-streaming API functions:
|
|
**
|
|
** <table border=1 style="margin-left:8ex;margin-right:8ex">
|
|
** <tr><th>Streaming function<th>Non-streaming equivalent</th>
|
|
-** <tr><td>sqlite3changeset_apply_strm<td>[sqlite3changeset_apply]
|
|
-** <tr><td>sqlite3changeset_apply_strm_v2<td>[sqlite3changeset_apply_v2]
|
|
-** <tr><td>sqlite3changeset_concat_strm<td>[sqlite3changeset_concat]
|
|
-** <tr><td>sqlite3changeset_invert_strm<td>[sqlite3changeset_invert]
|
|
-** <tr><td>sqlite3changeset_start_strm<td>[sqlite3changeset_start]
|
|
-** <tr><td>sqlite3session_changeset_strm<td>[sqlite3session_changeset]
|
|
-** <tr><td>sqlite3session_patchset_strm<td>[sqlite3session_patchset]
|
|
+** <tr><td>sqlite3changeset_apply_strm<td>[sqlite3changeset_apply]
|
|
+** <tr><td>sqlite3changeset_apply_strm_v2<td>[sqlite3changeset_apply_v2]
|
|
+** <tr><td>sqlite3changeset_concat_strm<td>[sqlite3changeset_concat]
|
|
+** <tr><td>sqlite3changeset_invert_strm<td>[sqlite3changeset_invert]
|
|
+** <tr><td>sqlite3changeset_start_strm<td>[sqlite3changeset_start]
|
|
+** <tr><td>sqlite3session_changeset_strm<td>[sqlite3session_changeset]
|
|
+** <tr><td>sqlite3session_patchset_strm<td>[sqlite3session_patchset]
|
|
** </table>
|
|
**
|
|
** Non-streaming functions that accept changesets (or patchsets) as input
|
|
-** require that the entire changeset be stored in a single buffer in memory.
|
|
-** Similarly, those that return a changeset or patchset do so by returning
|
|
-** a pointer to a single large buffer allocated using sqlite3_malloc().
|
|
-** Normally this is convenient. However, if an application running in a
|
|
+** require that the entire changeset be stored in a single buffer in memory.
|
|
+** Similarly, those that return a changeset or patchset do so by returning
|
|
+** a pointer to a single large buffer allocated using sqlite3_malloc().
|
|
+** Normally this is convenient. However, if an application running in a
|
|
** low-memory environment is required to handle very large changesets, the
|
|
** large contiguous memory allocations required can become onerous.
|
|
**
|
|
@@ -11325,12 +12211,12 @@ SQLITE_API void sqlite3rebaser_delete(sqlite3_rebaser *p);
|
|
** </pre>
|
|
**
|
|
** Each time the xInput callback is invoked by the sessions module, the first
|
|
-** argument passed is a copy of the supplied pIn context pointer. The second
|
|
-** argument, pData, points to a buffer (*pnData) bytes in size. Assuming no
|
|
-** error occurs the xInput method should copy up to (*pnData) bytes of data
|
|
-** into the buffer and set (*pnData) to the actual number of bytes copied
|
|
-** before returning SQLITE_OK. If the input is completely exhausted, (*pnData)
|
|
-** should be set to zero to indicate this. Or, if an error occurs, an SQLite
|
|
+** argument passed is a copy of the supplied pIn context pointer. The second
|
|
+** argument, pData, points to a buffer (*pnData) bytes in size. Assuming no
|
|
+** error occurs the xInput method should copy up to (*pnData) bytes of data
|
|
+** into the buffer and set (*pnData) to the actual number of bytes copied
|
|
+** before returning SQLITE_OK. If the input is completely exhausted, (*pnData)
|
|
+** should be set to zero to indicate this. Or, if an error occurs, an SQLite
|
|
** error code should be returned. In all cases, if an xInput callback returns
|
|
** an error, all processing is abandoned and the streaming API function
|
|
** returns a copy of the error code to the caller.
|
|
@@ -11338,7 +12224,7 @@ SQLITE_API void sqlite3rebaser_delete(sqlite3_rebaser *p);
|
|
** In the case of sqlite3changeset_start_strm(), the xInput callback may be
|
|
** invoked by the sessions module at any point during the lifetime of the
|
|
** iterator. If such an xInput callback returns an error, the iterator enters
|
|
-** an error state, whereby all subsequent calls to iterator functions
|
|
+** an error state, whereby all subsequent calls to iterator functions
|
|
** immediately fail with the same error code as returned by xInput.
|
|
**
|
|
** Similarly, streaming API functions that return changesets (or patchsets)
|
|
@@ -11368,7 +12254,7 @@ SQLITE_API void sqlite3rebaser_delete(sqlite3_rebaser *p);
|
|
** is immediately abandoned and the streaming API function returns a copy
|
|
** of the xOutput error code to the application.
|
|
**
|
|
-** The sessions module never invokes an xOutput callback with the third
|
|
+** The sessions module never invokes an xOutput callback with the third
|
|
** parameter set to a value less than or equal to zero. Other than this,
|
|
** no guarantees are made as to the size of the chunks of data returned.
|
|
*/
|
|
@@ -11439,12 +12325,12 @@ SQLITE_API int sqlite3session_patchset_strm(
|
|
int (*xOutput)(void *pOut, const void *pData, int nData),
|
|
void *pOut
|
|
);
|
|
-SQLITE_API int sqlite3changegroup_add_strm(sqlite3_changegroup*,
|
|
+SQLITE_API int sqlite3changegroup_add_strm(sqlite3_changegroup*,
|
|
int (*xInput)(void *pIn, void *pData, int *pnData),
|
|
void *pIn
|
|
);
|
|
SQLITE_API int sqlite3changegroup_output_strm(sqlite3_changegroup*,
|
|
- int (*xOutput)(void *pOut, const void *pData, int nData),
|
|
+ int (*xOutput)(void *pOut, const void *pData, int nData),
|
|
void *pOut
|
|
);
|
|
SQLITE_API int sqlite3rebaser_rebase_strm(
|
|
@@ -11459,16 +12345,16 @@ SQLITE_API int sqlite3rebaser_rebase_strm(
|
|
** CAPI3REF: Configure global parameters
|
|
**
|
|
** The sqlite3session_config() interface is used to make global configuration
|
|
-** changes to the sessions module in order to tune it to the specific needs
|
|
+** changes to the sessions module in order to tune it to the specific needs
|
|
** of the application.
|
|
**
|
|
** The sqlite3session_config() interface is not threadsafe. If it is invoked
|
|
** while any other thread is inside any other sessions method then the
|
|
** results are undefined. Furthermore, if it is invoked after any sessions
|
|
-** related objects have been created, the results are also undefined.
|
|
+** related objects have been created, the results are also undefined.
|
|
**
|
|
** The first argument to the sqlite3session_config() function must be one
|
|
-** of the SQLITE_SESSION_CONFIG_XXX constants defined below. The
|
|
+** of the SQLITE_SESSION_CONFIG_XXX constants defined below. The
|
|
** interpretation of the (void*) value passed as the second parameter and
|
|
** the effect of calling this function depends on the value of the first
|
|
** parameter.
|
|
@@ -11518,7 +12404,7 @@ SQLITE_API int sqlite3session_config(int op, void *pArg);
|
|
**
|
|
******************************************************************************
|
|
**
|
|
-** Interfaces to extend FTS5. Using the interfaces defined in this file,
|
|
+** Interfaces to extend FTS5. Using the interfaces defined in this file,
|
|
** FTS5 may be extended with:
|
|
**
|
|
** * custom tokenizers, and
|
|
@@ -11562,19 +12448,19 @@ struct Fts5PhraseIter {
|
|
** EXTENSION API FUNCTIONS
|
|
**
|
|
** xUserData(pFts):
|
|
-** Return a copy of the context pointer the extension function was
|
|
+** Return a copy of the context pointer the extension function was
|
|
** registered with.
|
|
**
|
|
** xColumnTotalSize(pFts, iCol, pnToken):
|
|
** If parameter iCol is less than zero, set output variable *pnToken
|
|
** to the total number of tokens in the FTS5 table. Or, if iCol is
|
|
** non-negative but less than the number of columns in the table, return
|
|
-** the total number of tokens in column iCol, considering all rows in
|
|
+** the total number of tokens in column iCol, considering all rows in
|
|
** the FTS5 table.
|
|
**
|
|
** If parameter iCol is greater than or equal to the number of columns
|
|
** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g.
|
|
-** an OOM condition or IO error), an appropriate SQLite error code is
|
|
+** an OOM condition or IO error), an appropriate SQLite error code is
|
|
** returned.
|
|
**
|
|
** xColumnCount(pFts):
|
|
@@ -11588,7 +12474,7 @@ struct Fts5PhraseIter {
|
|
**
|
|
** If parameter iCol is greater than or equal to the number of columns
|
|
** in the table, SQLITE_RANGE is returned. Or, if an error occurs (e.g.
|
|
-** an OOM condition or IO error), an appropriate SQLite error code is
|
|
+** an OOM condition or IO error), an appropriate SQLite error code is
|
|
** returned.
|
|
**
|
|
** This function may be quite inefficient if used with an FTS5 table
|
|
@@ -11615,8 +12501,8 @@ struct Fts5PhraseIter {
|
|
** an error code (i.e. SQLITE_NOMEM) if an error occurs.
|
|
**
|
|
** This API can be quite slow if used with an FTS5 table created with the
|
|
-** "detail=none" or "detail=column" option. If the FTS5 table is created
|
|
-** with either "detail=none" or "detail=column" and "content=" option
|
|
+** "detail=none" or "detail=column" option. If the FTS5 table is created
|
|
+** with either "detail=none" or "detail=column" and "content=" option
|
|
** (i.e. if it is a contentless table), then this API always returns 0.
|
|
**
|
|
** xInst:
|
|
@@ -11631,7 +12517,7 @@ struct Fts5PhraseIter {
|
|
** code (i.e. SQLITE_NOMEM) if an error occurs.
|
|
**
|
|
** This API can be quite slow if used with an FTS5 table created with the
|
|
-** "detail=none" or "detail=column" option.
|
|
+** "detail=none" or "detail=column" option.
|
|
**
|
|
** xRowid:
|
|
** Returns the rowid of the current row.
|
|
@@ -11647,11 +12533,11 @@ struct Fts5PhraseIter {
|
|
**
|
|
** with $p set to a phrase equivalent to the phrase iPhrase of the
|
|
** current query is executed. Any column filter that applies to
|
|
-** phrase iPhrase of the current query is included in $p. For each
|
|
-** row visited, the callback function passed as the fourth argument
|
|
-** is invoked. The context and API objects passed to the callback
|
|
+** phrase iPhrase of the current query is included in $p. For each
|
|
+** row visited, the callback function passed as the fourth argument
|
|
+** is invoked. The context and API objects passed to the callback
|
|
** function may be used to access the properties of each matched row.
|
|
-** Invoking Api.xUserData() returns a copy of the pointer passed as
|
|
+** Invoking Api.xUserData() returns a copy of the pointer passed as
|
|
** the third argument to pUserData.
|
|
**
|
|
** If the callback function returns any value other than SQLITE_OK, the
|
|
@@ -11666,14 +12552,14 @@ struct Fts5PhraseIter {
|
|
**
|
|
** xSetAuxdata(pFts5, pAux, xDelete)
|
|
**
|
|
-** Save the pointer passed as the second argument as the extension function's
|
|
+** Save the pointer passed as the second argument as the extension function's
|
|
** "auxiliary data". The pointer may then be retrieved by the current or any
|
|
** future invocation of the same fts5 extension function made as part of
|
|
** the same MATCH query using the xGetAuxdata() API.
|
|
**
|
|
** Each extension function is allocated a single auxiliary data slot for
|
|
-** each FTS query (MATCH expression). If the extension function is invoked
|
|
-** more than once for a single FTS query, then all invocations share a
|
|
+** each FTS query (MATCH expression). If the extension function is invoked
|
|
+** more than once for a single FTS query, then all invocations share a
|
|
** single auxiliary data context.
|
|
**
|
|
** If there is already an auxiliary data pointer when this function is
|
|
@@ -11692,7 +12578,7 @@ struct Fts5PhraseIter {
|
|
**
|
|
** xGetAuxdata(pFts5, bClear)
|
|
**
|
|
-** Returns the current auxiliary data pointer for the fts5 extension
|
|
+** Returns the current auxiliary data pointer for the fts5 extension
|
|
** function. See the xSetAuxdata() method for details.
|
|
**
|
|
** If the bClear argument is non-zero, then the auxiliary data is cleared
|
|
@@ -11712,7 +12598,7 @@ struct Fts5PhraseIter {
|
|
** method, to iterate through all instances of a single query phrase within
|
|
** the current row. This is the same information as is accessible via the
|
|
** xInstCount/xInst APIs. While the xInstCount/xInst APIs are more convenient
|
|
-** to use, this API may be faster under some circumstances. To iterate
|
|
+** to use, this API may be faster under some circumstances. To iterate
|
|
** through instances of phrase iPhrase, use the following code:
|
|
**
|
|
** Fts5PhraseIter iter;
|
|
@@ -11730,8 +12616,8 @@ struct Fts5PhraseIter {
|
|
** xPhraseFirstColumn() and xPhraseNextColumn() as illustrated below).
|
|
**
|
|
** This API can be quite slow if used with an FTS5 table created with the
|
|
-** "detail=none" or "detail=column" option. If the FTS5 table is created
|
|
-** with either "detail=none" or "detail=column" and "content=" option
|
|
+** "detail=none" or "detail=column" option. If the FTS5 table is created
|
|
+** with either "detail=none" or "detail=column" and "content=" option
|
|
** (i.e. if it is a contentless table), then this API always iterates
|
|
** through an empty set (all calls to xPhraseFirst() set iCol to -1).
|
|
**
|
|
@@ -11755,16 +12641,16 @@ struct Fts5PhraseIter {
|
|
** }
|
|
**
|
|
** This API can be quite slow if used with an FTS5 table created with the
|
|
-** "detail=none" option. If the FTS5 table is created with either
|
|
-** "detail=none" "content=" option (i.e. if it is a contentless table),
|
|
-** then this API always iterates through an empty set (all calls to
|
|
+** "detail=none" option. If the FTS5 table is created with either
|
|
+** "detail=none" "content=" option (i.e. if it is a contentless table),
|
|
+** then this API always iterates through an empty set (all calls to
|
|
** xPhraseFirstColumn() set iCol to -1).
|
|
**
|
|
** The information accessed using this API and its companion
|
|
** xPhraseFirstColumn() may also be obtained using xPhraseFirst/xPhraseNext
|
|
** (or xInst/xInstCount). The chief advantage of this API is that it is
|
|
** significantly more efficient than those alternatives when used with
|
|
-** "detail=column" tables.
|
|
+** "detail=column" tables.
|
|
**
|
|
** xPhraseNextColumn()
|
|
** See xPhraseFirstColumn above.
|
|
@@ -11778,7 +12664,7 @@ struct Fts5ExtensionApi {
|
|
int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow);
|
|
int (*xColumnTotalSize)(Fts5Context*, int iCol, sqlite3_int64 *pnToken);
|
|
|
|
- int (*xTokenize)(Fts5Context*,
|
|
+ int (*xTokenize)(Fts5Context*,
|
|
const char *pText, int nText, /* Text to tokenize */
|
|
void *pCtx, /* Context passed to xToken() */
|
|
int (*xToken)(void*, int, const char*, int, int, int) /* Callback */
|
|
@@ -11807,15 +12693,15 @@ struct Fts5ExtensionApi {
|
|
void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol);
|
|
};
|
|
|
|
-/*
|
|
+/*
|
|
** CUSTOM AUXILIARY FUNCTIONS
|
|
*************************************************************************/
|
|
|
|
/*************************************************************************
|
|
** CUSTOM TOKENIZERS
|
|
**
|
|
-** Applications may also register custom tokenizer types. A tokenizer
|
|
-** is registered by providing fts5 with a populated instance of the
|
|
+** Applications may also register custom tokenizer types. A tokenizer
|
|
+** is registered by providing fts5 with a populated instance of the
|
|
** following structure. All structure methods must be defined, setting
|
|
** any member of the fts5_tokenizer struct to NULL leads to undefined
|
|
** behaviour. The structure methods are expected to function as follows:
|
|
@@ -11826,16 +12712,16 @@ struct Fts5ExtensionApi {
|
|
**
|
|
** The first argument passed to this function is a copy of the (void*)
|
|
** pointer provided by the application when the fts5_tokenizer object
|
|
-** was registered with FTS5 (the third argument to xCreateTokenizer()).
|
|
+** was registered with FTS5 (the third argument to xCreateTokenizer()).
|
|
** The second and third arguments are an array of nul-terminated strings
|
|
** containing the tokenizer arguments, if any, specified following the
|
|
** tokenizer name as part of the CREATE VIRTUAL TABLE statement used
|
|
** to create the FTS5 table.
|
|
**
|
|
-** The final argument is an output variable. If successful, (*ppOut)
|
|
+** The final argument is an output variable. If successful, (*ppOut)
|
|
** should be set to point to the new tokenizer handle and SQLITE_OK
|
|
** returned. If an error occurs, some value other than SQLITE_OK should
|
|
-** be returned. In this case, fts5 assumes that the final value of *ppOut
|
|
+** be returned. In this case, fts5 assumes that the final value of *ppOut
|
|
** is undefined.
|
|
**
|
|
** xDelete:
|
|
@@ -11844,7 +12730,7 @@ struct Fts5ExtensionApi {
|
|
** be invoked exactly once for each successful call to xCreate().
|
|
**
|
|
** xTokenize:
|
|
-** This function is expected to tokenize the nText byte string indicated
|
|
+** This function is expected to tokenize the nText byte string indicated
|
|
** by argument pText. pText may or may not be nul-terminated. The first
|
|
** argument passed to this function is a pointer to an Fts5Tokenizer object
|
|
** returned by an earlier call to xCreate().
|
|
@@ -11858,8 +12744,8 @@ struct Fts5ExtensionApi {
|
|
** determine the set of tokens to add to (or delete from) the
|
|
** FTS index.
|
|
**
|
|
-** <li> <b>FTS5_TOKENIZE_QUERY</b> - A MATCH query is being executed
|
|
-** against the FTS index. The tokenizer is being called to tokenize
|
|
+** <li> <b>FTS5_TOKENIZE_QUERY</b> - A MATCH query is being executed
|
|
+** against the FTS index. The tokenizer is being called to tokenize
|
|
** a bareword or quoted string specified as part of the query.
|
|
**
|
|
** <li> <b>(FTS5_TOKENIZE_QUERY | FTS5_TOKENIZE_PREFIX)</b> - Same as
|
|
@@ -11867,10 +12753,10 @@ struct Fts5ExtensionApi {
|
|
** followed by a "*" character, indicating that the last token
|
|
** returned by the tokenizer will be treated as a token prefix.
|
|
**
|
|
-** <li> <b>FTS5_TOKENIZE_AUX</b> - The tokenizer is being invoked to
|
|
+** <li> <b>FTS5_TOKENIZE_AUX</b> - The tokenizer is being invoked to
|
|
** satisfy an fts5_api.xTokenize() request made by an auxiliary
|
|
** function. Or an fts5_api.xColumnSize() request made by the same
|
|
-** on a columnsize=0 database.
|
|
+** on a columnsize=0 database.
|
|
** </ul>
|
|
**
|
|
** For each token in the input string, the supplied callback xToken() must
|
|
@@ -11882,10 +12768,10 @@ struct Fts5ExtensionApi {
|
|
** which the token is derived within the input.
|
|
**
|
|
** The second argument passed to the xToken() callback ("tflags") should
|
|
-** normally be set to 0. The exception is if the tokenizer supports
|
|
+** normally be set to 0. The exception is if the tokenizer supports
|
|
** synonyms. In this case see the discussion below for details.
|
|
**
|
|
-** FTS5 assumes the xToken() callback is invoked for each token in the
|
|
+** FTS5 assumes the xToken() callback is invoked for each token in the
|
|
** order that they occur within the input text.
|
|
**
|
|
** If an xToken() callback returns any value other than SQLITE_OK, then
|
|
@@ -11899,7 +12785,7 @@ struct Fts5ExtensionApi {
|
|
** SYNONYM SUPPORT
|
|
**
|
|
** Custom tokenizers may also support synonyms. Consider a case in which a
|
|
-** user wishes to query for a phrase such as "first place". Using the
|
|
+** user wishes to query for a phrase such as "first place". Using the
|
|
** built-in tokenizers, the FTS5 query 'first + place' will match instances
|
|
** of "first place" within the document set, but not alternative forms
|
|
** such as "1st place". In some applications, it would be better to match
|
|
@@ -11919,34 +12805,34 @@ struct Fts5ExtensionApi {
|
|
**
|
|
** <li> By querying the index for all synonyms of each query term
|
|
** separately. In this case, when tokenizing query text, the
|
|
-** tokenizer may provide multiple synonyms for a single term
|
|
-** within the document. FTS5 then queries the index for each
|
|
+** tokenizer may provide multiple synonyms for a single term
|
|
+** within the document. FTS5 then queries the index for each
|
|
** synonym individually. For example, faced with the query:
|
|
**
|
|
** <codeblock>
|
|
** ... MATCH 'first place'</codeblock>
|
|
**
|
|
** the tokenizer offers both "1st" and "first" as synonyms for the
|
|
-** first token in the MATCH query and FTS5 effectively runs a query
|
|
+** first token in the MATCH query and FTS5 effectively runs a query
|
|
** similar to:
|
|
**
|
|
** <codeblock>
|
|
** ... MATCH '(first OR 1st) place'</codeblock>
|
|
**
|
|
** except that, for the purposes of auxiliary functions, the query
|
|
-** still appears to contain just two phrases - "(first OR 1st)"
|
|
+** still appears to contain just two phrases - "(first OR 1st)"
|
|
** being treated as a single phrase.
|
|
**
|
|
** <li> By adding multiple synonyms for a single term to the FTS index.
|
|
** Using this method, when tokenizing document text, the tokenizer
|
|
-** provides multiple synonyms for each token. So that when a
|
|
+** provides multiple synonyms for each token. So that when a
|
|
** document such as "I won first place" is tokenized, entries are
|
|
** added to the FTS index for "i", "won", "first", "1st" and
|
|
** "place".
|
|
**
|
|
** This way, even if the tokenizer does not provide synonyms
|
|
** when tokenizing query text (it should not - to do so would be
|
|
-** inefficient), it doesn't matter if the user queries for
|
|
+** inefficient), it doesn't matter if the user queries for
|
|
** 'first + place' or '1st + place', as there are entries in the
|
|
** FTS index corresponding to both forms of the first token.
|
|
** </ol>
|
|
@@ -11967,11 +12853,11 @@ struct Fts5ExtensionApi {
|
|
**
|
|
** It is an error to specify the FTS5_TOKEN_COLOCATED flag the first time
|
|
** xToken() is called. Multiple synonyms may be specified for a single token
|
|
-** by making multiple calls to xToken(FTS5_TOKEN_COLOCATED) in sequence.
|
|
+** by making multiple calls to xToken(FTS5_TOKEN_COLOCATED) in sequence.
|
|
** There is no limit to the number of synonyms that may be provided for a
|
|
** single token.
|
|
**
|
|
-** In many cases, method (1) above is the best approach. It does not add
|
|
+** In many cases, method (1) above is the best approach. It does not add
|
|
** extra data to the FTS index or require FTS5 to query for multiple terms,
|
|
** so it is efficient in terms of disk space and query speed. However, it
|
|
** does not support prefix queries very well. If, as suggested above, the
|
|
@@ -11983,18 +12869,18 @@ struct Fts5ExtensionApi {
|
|
** will not match documents that contain the token "1st" (as the tokenizer
|
|
** will probably not map "1s" to any prefix of "first").
|
|
**
|
|
-** For full prefix support, method (3) may be preferred. In this case,
|
|
+** For full prefix support, method (3) may be preferred. In this case,
|
|
** because the index contains entries for both "first" and "1st", prefix
|
|
** queries such as 'fi*' or '1s*' will match correctly. However, because
|
|
** extra entries are added to the FTS index, this method uses more space
|
|
** within the database.
|
|
**
|
|
** Method (2) offers a midpoint between (1) and (3). Using this method,
|
|
-** a query such as '1s*' will match documents that contain the literal
|
|
+** a query such as '1s*' will match documents that contain the literal
|
|
** token "1st", but not "first" (assuming the tokenizer is not able to
|
|
** provide synonyms for prefixes). However, a non-prefix query like '1st'
|
|
** will match against "1st" and "first". This method does not require
|
|
-** extra disk space, as no extra entries are added to the FTS index.
|
|
+** extra disk space, as no extra entries are added to the FTS index.
|
|
** On the other hand, it may require more CPU cycles to run MATCH queries,
|
|
** as separate queries of the FTS index are required for each synonym.
|
|
**
|
|
@@ -12008,10 +12894,10 @@ typedef struct fts5_tokenizer fts5_tokenizer;
|
|
struct fts5_tokenizer {
|
|
int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut);
|
|
void (*xDelete)(Fts5Tokenizer*);
|
|
- int (*xTokenize)(Fts5Tokenizer*,
|
|
+ int (*xTokenize)(Fts5Tokenizer*,
|
|
void *pCtx,
|
|
int flags, /* Mask of FTS5_TOKENIZE_* flags */
|
|
- const char *pText, int nText,
|
|
+ const char *pText, int nText,
|
|
int (*xToken)(
|
|
void *pCtx, /* Copy of 2nd argument to xTokenize() */
|
|
int tflags, /* Mask of FTS5_TOKEN_* flags */
|
|
diff --git a/pdf_viewer/sqlite3ext.h b/pdf_viewer/sqlite3ext.h
|
|
index bdd0a85ed..19e030028 100644
|
|
--- a/pdf_viewer/sqlite3ext.h
|
|
+++ b/pdf_viewer/sqlite3ext.h
|
|
@@ -330,6 +330,37 @@ struct sqlite3_api_routines {
|
|
const char *(*filename_database)(const char*);
|
|
const char *(*filename_journal)(const char*);
|
|
const char *(*filename_wal)(const char*);
|
|
+ /* Version 3.32.0 and later */
|
|
+ const char *(*create_filename)(const char*,const char*,const char*,
|
|
+ int,const char**);
|
|
+ void (*free_filename)(const char*);
|
|
+ sqlite3_file *(*database_file_object)(const char*);
|
|
+ /* Version 3.34.0 and later */
|
|
+ int (*txn_state)(sqlite3*,const char*);
|
|
+ /* Version 3.36.1 and later */
|
|
+ sqlite3_int64 (*changes64)(sqlite3*);
|
|
+ sqlite3_int64 (*total_changes64)(sqlite3*);
|
|
+ /* Version 3.37.0 and later */
|
|
+ int (*autovacuum_pages)(sqlite3*,
|
|
+ unsigned int(*)(void*,const char*,unsigned int,unsigned int,unsigned int),
|
|
+ void*, void(*)(void*));
|
|
+ /* Version 3.38.0 and later */
|
|
+ int (*error_offset)(sqlite3*);
|
|
+ int (*vtab_rhs_value)(sqlite3_index_info*,int,sqlite3_value**);
|
|
+ int (*vtab_distinct)(sqlite3_index_info*);
|
|
+ int (*vtab_in)(sqlite3_index_info*,int,int);
|
|
+ int (*vtab_in_first)(sqlite3_value*,sqlite3_value**);
|
|
+ int (*vtab_in_next)(sqlite3_value*,sqlite3_value**);
|
|
+ /* Version 3.39.0 and later */
|
|
+ int (*deserialize)(sqlite3*,const char*,unsigned char*,
|
|
+ sqlite3_int64,sqlite3_int64,unsigned);
|
|
+ unsigned char *(*serialize)(sqlite3*,const char *,sqlite3_int64*,
|
|
+ unsigned int);
|
|
+ const char *(*db_name)(sqlite3*,int);
|
|
+ /* Version 3.40.0 and later */
|
|
+ int (*value_encoding)(sqlite3_value*);
|
|
+ /* Version 3.41.0 and later */
|
|
+ int (*is_interrupted)(sqlite3*);
|
|
};
|
|
|
|
/*
|
|
@@ -630,6 +661,34 @@ typedef int (*sqlite3_loadext_entry)(
|
|
#define sqlite3_filename_database sqlite3_api->filename_database
|
|
#define sqlite3_filename_journal sqlite3_api->filename_journal
|
|
#define sqlite3_filename_wal sqlite3_api->filename_wal
|
|
+/* Version 3.32.0 and later */
|
|
+#define sqlite3_create_filename sqlite3_api->create_filename
|
|
+#define sqlite3_free_filename sqlite3_api->free_filename
|
|
+#define sqlite3_database_file_object sqlite3_api->database_file_object
|
|
+/* Version 3.34.0 and later */
|
|
+#define sqlite3_txn_state sqlite3_api->txn_state
|
|
+/* Version 3.36.1 and later */
|
|
+#define sqlite3_changes64 sqlite3_api->changes64
|
|
+#define sqlite3_total_changes64 sqlite3_api->total_changes64
|
|
+/* Version 3.37.0 and later */
|
|
+#define sqlite3_autovacuum_pages sqlite3_api->autovacuum_pages
|
|
+/* Version 3.38.0 and later */
|
|
+#define sqlite3_error_offset sqlite3_api->error_offset
|
|
+#define sqlite3_vtab_rhs_value sqlite3_api->vtab_rhs_value
|
|
+#define sqlite3_vtab_distinct sqlite3_api->vtab_distinct
|
|
+#define sqlite3_vtab_in sqlite3_api->vtab_in
|
|
+#define sqlite3_vtab_in_first sqlite3_api->vtab_in_first
|
|
+#define sqlite3_vtab_in_next sqlite3_api->vtab_in_next
|
|
+/* Version 3.39.0 and later */
|
|
+#ifndef SQLITE_OMIT_DESERIALIZE
|
|
+#define sqlite3_deserialize sqlite3_api->deserialize
|
|
+#define sqlite3_serialize sqlite3_api->serialize
|
|
+#endif
|
|
+#define sqlite3_db_name sqlite3_api->db_name
|
|
+/* Version 3.40.0 and later */
|
|
+#define sqlite3_value_encoding sqlite3_api->value_encoding
|
|
+/* Version 3.41.0 and later */
|
|
+#define sqlite3_is_interrupted sqlite3_api->is_interrupted
|
|
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
|
|
|
|
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
|